1. GPS

At present, the GPS module model we have tested is the BH-ATGM332D module.

1.1. BH-ATGM332D Introduction

BH-ATGM332D is a high-performance, low-power GPS and Beidou dual-mode positioning module designed by Embedfire. It adopts the ATGM332D-5N-31 module solution of Zhongke Microelectronics Company. It can output GPS and Beidou positioning information to the microcontroller system and computer through the serial port. It is simple and convenient to use. Its appearance is shown in the figure below.

../../../_images/ATGM332D001.png

BH-ATGM332D module pin description is as follows:

../../../_images/ATGM332D002.png

The resources of the BH-ATGM332D module are as follows:

../../../_images/ATGM332D003.png

The BH-ATGM332D module and its matching active antenna are connected as follows:

../../../_images/ATGM332D004.png

1.2. Test BH-ATGM332D

This experiment is demonstrated with the LubanCat-1N board. The operation of other boards is similar to this experiment, so we won’t go into details here. The test system is Debian, and Ubuntu is similar.

1.2.1. Hardware wiring

The test uses the serial port on pin 8 and pin 10 on the board. For the specific corresponding serial port number, please view the 40PIN pin diagram.

“RK356x series board 40PIN pin diagram (LubanCat Zero, 1, 2)”

“RK3588 series board 40PIN pin diagram (LubanCat 4, 5)”

The wiring between Lubanmao 1N and GPS module is as follows:

Lubancat     --------  GPS module
5V(4)        --------  VCC
GND(6)       --------  GND
UART_RX(10)  --------  TXD
UART_TX(8)   --------  RXD
../../../_images/ATGM332D005.jpg

1.2.2. Enable UART serial port

  1. From the above pin diagram, we can see that pins 8 and 10 of the Lubancat 1N board correspond to UART3_M1. If you need to use the GPS module, you need to open the /boot/uEnv.txt file to enable the serial port 3 device tree plug-in.

../../../_images/ATGM332D006.png

2、Restart the Lubancat.

3、After restarting, check whether there is a newly opened serial device in the dev directory:

ls /dev/tty*
ls /dev/ttyS*

提示

When /dev/ttyS3 exists, it means that the serial port 3 device has been opened.

../../../_images/ATGM332D007.png

1.2.3. Verify that the module is working properly

  1. To verify whether the module is working, first check whether the power supply is normal and connect according to the above hardware wiring. The LED light of the BH-ATGM332D module will light up.

2、After ensuring that the power supply of the module is normal, enter the following command in the terminal to monitor the information sent by the module.

cat /dev/ttyS3

If the following content is output, it means that the module is working normally:

../../../_images/ATGM332D008.png

Pay attention to the input content $GPTXT,01,01,01,ANTENNA OK*35, which indicates that the module is running normally. Of course, it may also be other situations, such as:

../../../_images/ATGM332D009.png

The three states in the picture are open circuit (OPEN), SHORT (short circuit) and OK (normal). Please ensure that the antenna is in the OK state when testing.

If the output data is as shown in the figure below, it means that the module cannot search for satellite signals.

../../../_images/ATGM332D010.png

提示

When the module has no signal, the position of the module antenna should be moved. Generally, satellite signals will be poor indoors, so you can test in open areas outdoors (such as rooftops, balconies, and windows).

1.3. NMEA-0183

1.3.1. NMEA-0183 Protocol introduction

The BH-ATGM332D module outputs positioning data information through the TTL serial port. This information uses the NMEA-0183 4.0 protocol by default. The output information is as shown in the previous log.

NMEA is a standard format developed by the National Marine Electronics Association for marine electronic equipment. It has now become a unified RTCM standard protocol for GPS navigation equipment. The NMEA 4.0 version protocol used by this module supports positioning systems such as GPS, Beidou, and Hignes. NMEA-0183 is a set of standard messages that define receiver output. It comes in several different formats, each is an independently related ASCII format, uses commas to separate data, the data stream length varies from 30-100 characters, and the output is usually selected at per second intervals. The most commonly used format is “GGA”, which includes positioning time, latitude, longitude, altitude, number of satellites used for positioning, DOP value, differential status and correction period, etc. Others include speed, tracking, date, etc. NMEA has become virtually the most common data output format for all positioning receivers.

1.3.2. NMEA decoding library

After understanding the NMEA format, we can write the corresponding decoding program, and the programmer Tim (xtimor@gmail.com) provides a very complete NMEA decoding library, which can be downloaded at the following URL: http://nmea .sourceforge.net/ . Using this decoding library directly avoids reinventing the wheel. The source code of the decoding library is also included in the “NMEA0183 decoding library source code” folder of the GPS module information provided by Embedfire. The program provided by Embedfire uses this library to decode NMEA sentences.

The latest version of this decoding library is currently version 0.5.3. It is written in the C programming language, supports windows, winCE, and UNIX platforms, and supports parsing of five statements: GPGGA, GPGSA, GPGSV, GPRMC, and GPVTG (these five statements already provide enough GPS information). The analyzed GPS data information is stored in a structure, with geography-related functions added to support navigation and other data work. In addition to parsing NMEA statements, it can also generate NMEA statements based on random numbers to facilitate simulation. On top of this decoding library, Embedfire extends its support for NMEA-0183 version 4.0.

1.4. Using BH-ATGM332D module on Lubancat

This experiment is demonstrated with LubanCat-1N board, and the test system is Debian.

1.4.1. Update software source list

sudo apt update

1.4.3. Pull nmealib repository

The nmealib warehouse has been released on github and gitee. Embedfire has modified the library to support parsing the NMEA-0183 4.0 protocol.

Pull nmealib repository from github:

git clone https://github.com/Embedfire/nmealib.git

Pull nmealib repository from gitee:

git clone https://github.com/Embedfire/nmealib.git

1.4.4. Routine analysis

The nmealib warehouse released by Embedfire has provided relevant demo routines. There are 5 folders in the samples directory, namely: generate, generator, math, parse, and parse_ebf_module.

../../../_images/ATGM332D011.png

They all correspond to different routines:

generate/generator

These two demos generate random NMEA-0183 standard information and can be used for debugging.

math

Math library, used to convert these NMEA-0183 standard information into math-related data, such as longitude, latitude, azimuth, etc.

parse

Demo of parsing NMEA-0183 standard information. These NMEA-0183 standard information are written in an array.

parse_ebf_module

A demo for parsing the NMEA-0183 standard information of the Embedfire Beidou positioning module. It obtains the BH-ATGM332D data by reading the serial port 3 device, and then calls the nmealib library to parse it.

1.4.5. Modify the serial number of the demo code

Before compiling and running the example, you need to modify the serial number of the code. The sample code is as follows:

nmealib/samples/parse_ebf_module/main.c
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#include <nmea/nmea.h>

#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdint.h>
#include <termios.h>
#include <sys/ioctl.h>

void GMTconvert(nmeaTIME *SourceTime, nmeaTIME *ConvertTime, uint8_t GMT,uint8_t AREA);

void error(const char *str, int str_size)
{
    printf("Error: ");
    write(1, str, str_size);
    printf("\n");
}

int main()
{
    int fd;
    int len;

    nmeaINFO info;
    nmeaPARSER parser;
    nmeaTIME beiJingTime;    //北京时间
    double deg_lat;//转换成[degree].[degree]格式的纬度
    double deg_lon;//转换成[degree].[degree]格式的经度

    char tmp_buf[200];
    char buff[4096];

    int size, it = 0;
    nmeaPOS dpos;

    fd = open("/dev/ttymxc2", O_RDONLY);

    printf("fopen %d\n", fd);

    if(!fd)
        return -1;

    // nmea_property()->trace_func = &trace;
    nmea_property()->error_func = &error;

    nmea_zero_INFO(&info);
    nmea_parser_init(&parser);

    struct termios opt;

    //清空串口接收缓冲区
    tcflush(fd, TCIOFLUSH);
    // 获取串口参数opt
    tcgetattr(fd, &opt);

    //设置串口输出波特率
    cfsetospeed(&opt, B9600);
    //设置串口输入波特率
    cfsetispeed(&opt, B9600);
    //设置数据位数
    opt.c_cflag &= ~CSIZE;
    opt.c_cflag |= CS8;
    //校验位
    opt.c_cflag &= ~PARENB;
    opt.c_iflag &= ~INPCK;
    //设置停止位
    opt.c_cflag &= ~CSTOPB;

    //更新配置
    tcsetattr(fd, TCSANOW, &opt);

    while(1)
    {
        memset(buff, 0, 4096);
        size = 0;
        len = 0;
        nmea_zero_INFO(&info);
        nmea_parser_init(&parser);
        for(it = 0; it < 32; it++) {
            memset(tmp_buf, 0, 100);
            size = (int)read(fd, tmp_buf, 100);
            if (size > 1) {
                memcpy(buff + len, tmp_buf, size);
                len += size;
                memcpy(buff + len - 1, "\r\n", 2);
                len += 1;
            }
            
        }

        nmea_parse(&parser, buff, len, &info);

         // info.lat lon中的格式为[degree][min].[sec/60],使用以下函数转换成[degree].[degree]格式
        deg_lat = nmea_ndeg2degree(info.lat);
        deg_lon = nmea_ndeg2degree(info.lon);

        GMTconvert(&info.utc,&beiJingTime,8,1);

        // // /* 输出解码得到的信息 */
        printf("\r\n时间:%d-%02d-%02d,%d:%d:%d\r\n", beiJingTime.year+1900, beiJingTime.mon,beiJingTime.day,beiJingTime.hour,beiJingTime.min,beiJingTime.sec);

        printf("\r\n纬度:%f,经度%f\r\n",deg_lat,deg_lon);
        printf("\r\n海拔高度:%f 米 ", info.elv);
        printf("\r\n速度:%f km/h ", info.speed);
        printf("\r\n航向:%f 度", info.direction);
        
        printf("\r\n正在使用的GPS卫星:%d,可见GPS卫星:%d",info.satinfo.inuse,info.satinfo.inview);

        printf("\r\n正在使用的北斗卫星:%d,可见北斗卫星:%d",info.satinfo.inuse,info.satinfo.inview);
        printf("\r\nPDOP:%f,HDOP:%f,VDOP:%f\n",info.PDOP,info.HDOP,info.VDOP);
    }

    nmea_parser_destroy(&parser);
    close(fd);

    return 0;
}

提示

The code of the example is relatively simple. The main process is to read data from the serial port 3 device. The process of reading data is basically as follows: open the device and configure the parameters for reading information, such as baud rate, stop bit, check bit, etc. Then read the data and cache it in a buff; call the nmea_parse() function to parse the data and print it out.

We need to change line 40 of the code:

fd = open("/dev/ttymxc2", O_RDONLY);

Modify to the currently used serial port as follows:

fd = open("/dev/ttyS3", O_RDONLY);

You can use vim, nano and other text editors to modify it. If it is a desktop image, you can also use gedit. Of course, you can also use VSCode SSH to remotely log in to the board to modify it.

提示

Regarding using VSCode to remotely log in to the board, you can refer to “vscode Convenient Debugging and Development”

1.4.6. Compile & Run

Enter the nmealib directory and run the make command directly to compile. The compilation information is as follows.

../../../_images/ATGM332D012.png

You can see that the libnmea.a library file is generated by compilation, and all samples are compiled. The output results are in the build/ directory, and the corresponding executable file is generated. We run directly:

./build/samples_parse_ebf_module

提示

After running, the window will print information such as time, longitude and latitude. Because the antenna is lying flat at this time, the speed and heading data are both 0.

../../../_images/ATGM332D013.png

1.5. A brief introduction to the nmea library

The above code uses many data structures of the nmea library, so I would like to introduce the relevant knowledge:

1.5.1. Structures nmeaPARSER and nmeaINFO

The data types nmeaPARSER and nmeaINFO of the parser and info variables in the above parameters are data structures unique to the NMEA decoding library, as follows:

nmealib/include/nmea/parser.h
1
2
3
4
5
6
7
8
9
typedef struct _nmeaPARSER
{
    void *top_node;
    void *end_node;
    unsigned char *buffer;
    int buff_size;
    int buff_use;

} nmeaPARSER;

提示

As you can see, nmeaPARSER is a linked list. During decoding, the NMEA library will push the input GPS raw data into the linked list of nmeaPARSER structure to facilitate data management and decoding. Before using this structure, you need to call the nmea_parser_init() function to allocate dynamic space. When decoding ends, the nmea_parser_destroy() function is called to release the allocated space.

nmealib/include/nmea/info.h
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
typedef struct _nmeaINFO
{
    int     smask;      /**< Mask specifying types of packages from which data have been obtained */

    nmeaTIME utc;       /**< UTC of position */

    int     sig;        /**< GPS quality indicator (0 = Invalid; 1 = Fix; 2 = Differential, 3 = Sensitive) */
    int     fix;        /**< Operating mode, used for navigation (1 = Fix not available; 2 = 2D; 3 = 3D) */

    double  PDOP;       /**< Position Dilution Of Precision */
    double  HDOP;       /**< Horizontal Dilution Of Precision */
    double  VDOP;       /**< Vertical Dilution Of Precision */
   
    double  lat;        /**< Latitude in NDEG - +/-[degree][min].[sec/60] */
    double  lon;        /**< Longitude in NDEG - +/-[degree][min].[sec/60] */
    double  elv;        /**< Antenna altitude above/below mean sea level (geoid) in meters */
    double  sog;        /**< 数值 对地速度,单位为节 */
    double  speed;      /**< Speed over the ground in kilometers/hour */
    double  direction;  /**< Track angle in degrees True */
    double  declination; /**< Magnetic variation degrees (Easterly var. subtracts from true course) */
    char    mode;       /**< 字符 定位模式标志 (A = 自主模式, D = 差分模式, E = 估算模式, N = 数据无效) */
    nmeaSATINFO satinfo; /**< satellites information */
    nmeaSATINFO BDsatinfo; /**北斗卫星信息*/
		
    int txt_level;
    char *txt;
		
} nmeaINFO;

The description of its structure is as follows:

../../../_images/ATGM332D014.png

提示

The good encapsulation characteristics of the NMEA decoding library prevent us from paying attention to the deeper internal implementation. We only need to take a look at the nmeaINFO data structure. All GPS decoding results are stored in this structure. After calling the nmea_parse() function to complete the analysis, directly query the data of the nmeaINFO structure to get the decoding result.