├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── config ├── moving_base.txt ├── rover.txt └── zed_f9p.yaml ├── launch └── ublox.launch ├── package.xml ├── resources └── gnss_hardware_setup.drawio └── src └── ublox2nmea.cc /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16.3) 2 | project(ublox_utils) 3 | 4 | find_package(catkin 5 | REQUIRED COMPONENTS 6 | roscpp 7 | nmea_msgs 8 | ublox_msgs 9 | rtcm_msgs 10 | mavros_msgs 11 | ) 12 | 13 | include_directories(include ${catkin_INCLUDE_DIRS}) 14 | 15 | catkin_package() 16 | 17 | set(CMAKE_CXX_STANDARD 17) 18 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") 19 | set(CMAKE_BUILD_TYPE Release) 20 | 21 | ############ 22 | # Binaries # 23 | ############ 24 | add_executable(ublox2nmea src/ublox2nmea.cc) 25 | target_link_libraries(ublox2nmea ${catkin_LIBRARIES}) 26 | 27 | ########## 28 | # EXPORT # 29 | ########## 30 | install(TARGETS ublox2nmea 31 | ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} 32 | LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} 33 | RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} 34 | ) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Rik Baehnemann, ASL, ETH Zurich, Switzerland 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ublox_utils 2 | Repository with ROS tools for the u-blox RTK receiver. 3 | 4 | ## Table of Contents 5 | 1. [Installation](#installation) 6 | 2. [Hardware Setup](#hardware-setup) 7 | 1. [Electronics](#electronics) 8 | 2. [Part List](#part-list) 9 | 3. [Firmware](#firmware) 10 | 4. [ROS Sensor Launch](#ros-sensor-launch) 11 | 1. [Single Receiver](#single-receiver) 12 | 2. [Dual Receivers](#dual-receivers) 13 | 3. [NTRIP Corrections](#ntrip-corrections) 14 | 4. [Dual Receivers with NTRIP](#dual-receivers-with-ntrip) 15 | 16 | ## Installation 17 | ``` 18 | source /opt/ros/noetic/setup.bash 19 | export ROS_VERSION=`rosversion -d` 20 | 21 | sudo apt install -y python3-catkin-tools \ 22 | ros-$ROS_VERSION-ublox \ 23 | ros-$ROS_VERSION-ntrip-client \ 24 | ros-$ROS_VERSION-nmea-msgs \ 25 | ros-$ROS_VERSION-mavros-msgs \ 26 | ros-$ROS_VERSION-rtcm-msgs 27 | 28 | cd ~ 29 | mkdir -p catkin_ws/src 30 | cd catkin_ws 31 | catkin init 32 | cd ~/catkin_ws/src 33 | git clone git@github.com:ethz-asl/ublox_utils.git 34 | catkin build 35 | ``` 36 | 37 | ## Hardware Setup 38 | This section describes the hardware setup with one or two receivers on the rover. 39 | The following considerations should be taken into account: 40 | - Optimal **sky coverage** of the antennas. 41 | - Antennas **far distanced** from other electronics to avoid interference (especially LiDAR and USB 3.0 devices). 42 | - **Omnidirectional helical antennas** preferable over patch antennas as they do not require ground plane and have a better attitude coverage (see [ZED-FP9 Moving base applications, p.8](https://content.u-blox.com/sites/default/files/ZED-F9P-MovingBase_AppNote_%28UBX-19009093%29.pdf)). 43 | - **Multi-band antennas** that support all receiver frequencies with well-defined phase center and small phase center variation (see for example [HC882 Dual-Band Helical Antenna + L-Band](https://www.tallysman.com/app/uploads/2018/03/Tallysman%C2%AE-HC882-Datasheet_March-2022.pdf)). 44 | - **Known phase center position** with respect to rover body frame (see r_BP and r_BM in Figure below). 45 | - Rover antenna **at least 20cm** distanced from moving base antenna (see [ZED-FP9 Moving base applications, p.7](https://content.u-blox.com/sites/default/files/ZED-F9P-MovingBase_AppNote_%28UBX-19009093%29.pdf)). 46 | 47 | ![Hardware GNSS setup.](https://user-images.githubusercontent.com/11293852/169337168-dd9f23a8-5c68-41e9-bf57-185111bd45fb.png) 48 | 49 | ### Electronics 50 | The NTRIP setup does not require a base station. 51 | Instead the corrections are provided by an NTRIP caster online. 52 | The wiring is shown in the Figure below. 53 | In case of a moving baseline setup, corrections from the moving base receiver (Receiver 1) will be sent to the rover (Receiver 2) via UART2. 54 | 55 | ![Electronic wiring of dual RTK setup.](https://user-images.githubusercontent.com/11293852/169337161-7a531299-0cdd-4294-901e-e4295f50c316.png) 56 | 57 | ### Part List 58 | This is the part list for the standard moving baseline setup above. 59 | The prices are regular retail prices. 60 | For some, e.g., NTRIP corrections or Tallysman antennas research discounts may apply. 61 | 62 | | No. | Pc. No. | Description | Source Object | Supplier | Supplier Number | Cost per Unit | Cost Total | 63 | |:---:|:-------:|:---------------------------------------------|:----------------|:----------|:--------------------|:----------------|:----------------| 64 | | 1 | 2 | Sparkfun u-blox ZED-F9P GPS-RTK-SMA receiver | GPS-16481 | digikey | 1568-GPS-16481-ND | CHF 260.- | CHF 520.- | 65 | | 2 | 2 | Tallysman HC882 dual-band helical antenna | 33-HC882-28 | digikey | 1526-33-HC882-28-ND | CHF 250.- | CHF 500.- | 66 | | 3 | 1 | Swipos GIS/GEO NTRIP license | swipos GIS/GEO | swisstopo | swipos-GIS/GEO | CHF 2000.- p.a. | CHF 2000.- p.a. | 67 | | 4 | 2 | USB-C connector cable (300mm) | CAB-15426 | digikey | 1568-CAB-15426-ND | CHF 4.- | CHF 8.- | 68 | | 5 | 2 | Coaxial SMA to SMA (500mm) | 415-0031-MM500 | digikey | J10300-ND | CHF 16.- | CHF 32.- | 69 | 70 | ### Firmware 71 | The latest tested firmware was **1.32** on ZED-F9P receiver. 72 | To update the firmware follow the [sparkfun tutorial](https://learn.sparkfun.com/tutorials/how-to-upgrade-firmware-of-a-u-blox-gnss-receiver). 73 | 74 | When using a dual receiver setup update the configuration of the [moving base receiver](config/moving_base.txt) and [rover receiver](config/rover.txt). 75 | The configuration is elaborated in [ZED-FP9 Moving base applications, p.16](https://content.u-blox.com/sites/default/files/ZED-F9P-MovingBase_AppNote_%28UBX-19009093%29.pdf). 76 | To flash the configuration go to u-center and select `View->Generation 9 Configuration View->Advanced Configuration->Load from file...->Send config changes` 77 | 78 | **Note**: If you are only using a single rover, the default config is fine. 79 | 80 | To revert to the default config select `View->Messages view->UBX->CFG->CFG->Revert to default configuration->Send`. 81 | ## ROS Sensor Launch 82 | [ublox.launch](./launch/ublox.launch) provides the launch file to start the u-blox receivers ROS interface. 83 | 84 | ### Single Receiver 85 | The default startup with a single receiver is 86 | ``` 87 | roslaunch ublox_utils ublox.launch device_position_receiver:=/dev/ttyACM0 88 | ``` 89 | The relevant ROS topics are 90 | ``` 91 | /ublox_position_receiver/fix 92 | /ublox_moving_baseline_receiver/fix_velocity 93 | ``` 94 | 95 | Additionally, you should monitor the fix status. 96 | ``` 97 | /ublox_position_receiver/navstatus 98 | ``` 99 | 100 | ### Dual Receivers 101 | At first use, setup the [firmware](#firmware). 102 | 103 | To startup two receivers where the second receiver estimates the moving baseline run 104 | ``` 105 | roslaunch ublox_utils ublox.launch device_position_receiver:=/dev/ttyACM0 use_moving_baseline:=true device_moving_baseline_receiver:=/dev/ttyACM1 106 | ``` 107 | The relevant ROS topic is 108 | ``` 109 | /ublox_moving_baseline_receiver/navheading 110 | ``` 111 | Additionally, you should monitor a valid fix flag as well as the distance between the antennas in 112 | ``` 113 | /ublox_moving_baseline_receiver/navrelposned 114 | ``` 115 | 116 | **Note**: You may want to find a smart way to allocate the device ID. 117 | 118 | ### NTRIP Corrections 119 | We use the [swipos-GIS/GEO](https://www.swisstopo.admin.ch/de/geodata/geoservices/swipos/swipos-dienste/swipos-gisgeo.html) caster in conjunction with the [ROS ntrip client](http://wiki.ros.org/ntrip_client). 120 | Our [ublox2nmea](src/ublox2nmea.cc) node makes sure the caster receives the current VRS location. 121 | It receives the [NavPVT](http://docs.ros.org/en/noetic/api/ublox_msgs/html/msg/NavPVT.html) from the u-blox receiver and outputs it as [NMEA $GPGGA sentence](http://docs.ros.org/en/api/nmea_msgs/html/msg/Sentence.html). 122 | ``` 123 | roslaunch ublox_utils ublox.launch device_position_receiver:=/dev/ttyACM0 use_ntrip:=true ntrip_username:=YOUR_USER ntrip_password:=YOUR_PASSWORD 124 | ``` 125 | 126 | The rosgraph should look like this: 127 | ![Rosgaph of NTRIP connection.](https://user-images.githubusercontent.com/11293852/169337693-09c338d6-1e9d-416b-b12d-9ae0bfa735db.png) 128 | 129 | ### Dual Receivers with NTRIP 130 | ``` 131 | roslaunch ublox_utils ublox.launch device_position_receiver:=/dev/ttyACM0 use_moving_baseline:=true device_moving_baseline_receiver:=/dev/ttyACM1 use_ntrip:=true ntrip_username:=YOUR_USER ntrip_password:=YOUR_PASSWORD 132 | ``` 133 | -------------------------------------------------------------------------------- /config/moving_base.txt: -------------------------------------------------------------------------------- 1 | # Config changes format version 1.0 2 | # created by u-center version 22.02 at 19:07:31 on Friday, 20 May 2022 3 | [del] 4 | [set] 5 | RAM CFG-RATE-MEAS 0x7d # write value 125 0x7d to item id 0x30210001 in layer 0 6 | Flash CFG-RATE-MEAS 0x7d # write value 125 0x7d to item id 0x30210001 in layer 2 7 | RAM CFG-UART1-BAUDRATE 0x70800 # write value 460800 0x70800 to item id 0x40520001 in layer 0 8 | Flash CFG-UART1-BAUDRATE 0x70800 # write value 460800 0x70800 to item id 0x40520001 in layer 2 9 | RAM CFG-UART2-BAUDRATE 0x70800 # write value 460800 0x70800 to item id 0x40530001 in layer 0 10 | Flash CFG-UART2-BAUDRATE 0x70800 # write value 460800 0x70800 to item id 0x40530001 in layer 2 11 | RAM CFG-MSGOUT-RTCM_3X_TYPE1074_UART2 0x1 # write value 1 0x1 to item id 0x20910360 i 12 | Flash CFG-MSGOUT-RTCM_3X_TYPE1074_UART2 0x1 # write value 1 0x1 to item id 0x20910360 i 13 | RAM CFG-MSGOUT-RTCM_3X_TYPE1084_UART2 0x1 # write value 1 0x1 to item id 0x20910365 i 14 | Flash CFG-MSGOUT-RTCM_3X_TYPE1084_UART2 0x1 # write value 1 0x1 to item id 0x20910365 i 15 | RAM CFG-MSGOUT-RTCM_3X_TYPE1094_UART2 0x1 # write value 1 0x1 to item id 0x2091036a i 16 | Flash CFG-MSGOUT-RTCM_3X_TYPE1094_UART2 0x1 # write value 1 0x1 to item id 0x2091036a i 17 | RAM CFG-MSGOUT-RTCM_3X_TYPE1124_UART2 0x1 # write value 1 0x1 to item id 0x2091036f i 18 | Flash CFG-MSGOUT-RTCM_3X_TYPE1124_UART2 0x1 # write value 1 0x1 to item id 0x2091036f i 19 | RAM CFG-MSGOUT-RTCM_3X_TYPE1230_UART2 0x1 # write value 1 0x1 to item id 0x20910305 i 20 | Flash CFG-MSGOUT-RTCM_3X_TYPE1230_UART2 0x1 # write value 1 0x1 to item id 0x20910305 i 21 | RAM CFG-MSGOUT-RTCM_3X_TYPE4072_0_UART2 0x1 # write value 1 0x1 to item id 0x20910300 22 | Flash CFG-MSGOUT-RTCM_3X_TYPE4072_0_UART2 0x1 # write value 1 0x1 to item id 0x20910300 23 | 24 | -------------------------------------------------------------------------------- /config/rover.txt: -------------------------------------------------------------------------------- 1 | # Config changes format version 1.0 2 | # created by u-center version 22.02 at 19:14:30 on Friday, 20 May 2022 3 | [del] 4 | [set] 5 | RAM CFG-RATE-MEAS 0x7d # write value 125 0x7d to item id 0x30210001 in layer 0 6 | Flash CFG-RATE-MEAS 0x7d # write value 125 0x7d to item id 0x30210001 in layer 2 7 | RAM CFG-UART1-BAUDRATE 0x70800 # write value 460800 0x70800 to item id 0x40520001 in layer 0 8 | Flash CFG-UART1-BAUDRATE 0x70800 # write value 460800 0x70800 to item id 0x40520001 in layer 2 9 | RAM CFG-UART2-BAUDRATE 0x70800 # write value 460800 0x70800 to item id 0x40530001 in layer 0 10 | Flash CFG-UART2-BAUDRATE 0x70800 # write value 460800 0x70800 to item id 0x40530001 in layer 2 11 | RAM CFG-MSGOUT-UBX_NAV_RELPOSNED_UART1 0x1 # write value 1 0x1 to item id 0x2091008e 12 | Flash CFG-MSGOUT-UBX_NAV_RELPOSNED_UART1 0x1 # write value 1 0x1 to item id 0x2091008e 13 | -------------------------------------------------------------------------------- /config/zed_f9p.yaml: -------------------------------------------------------------------------------- 1 | config_on_startup: false 2 | publish: 3 | nav: 4 | relposned: true 5 | status: true 6 | pvt: true 7 | rxm: 8 | rtcm: true 9 | gnss: 10 | gps: true 11 | glonass: true 12 | galileo: true 13 | beidou: true 14 | dynamic_model: airborne1 15 | debug: 0 -------------------------------------------------------------------------------- /launch/ublox.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 68 | 69 | 70 | 71 | 72 | 73 | 75 | 76 | 77 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | ublox_utils 4 | 1.0.0 5 | 6 | Repository with ROS tools for the u-blox RTK receiver. 7 | 8 | Rik Bähnemann 9 | Rik Bähnemann 10 | 11 | MIT 12 | 13 | catkin 14 | 15 | roscpp 16 | nmea_msgs 17 | ublox_msgs 18 | 19 | roscpp 20 | nmea_msgs 21 | ublox_msgs 22 | mavros_msgs 23 | rtcm_msgs 24 | ntrip_client 25 | 26 | -------------------------------------------------------------------------------- /resources/gnss_hardware_setup.drawio: -------------------------------------------------------------------------------- 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 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | -------------------------------------------------------------------------------- /src/ublox2nmea.cc: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | Copyright (c) 2022 Rik Baehnemann, ASL, ETH Zurich, Switzerland 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 18 | SOFTWARE. 19 | */ 20 | 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | class Transformer { 29 | public: 30 | Transformer(); 31 | 32 | private: 33 | ros::Publisher nmea_pub_; 34 | ros::Subscriber navpvt_sub_; 35 | 36 | void receiveNavPVT(const ublox_msgs::NavPVT::ConstPtr &navsat_msg); 37 | }; 38 | 39 | Transformer::Transformer() { 40 | ros::NodeHandle nh; 41 | navpvt_sub_ = nh.subscribe("navpvt", 1, &Transformer::receiveNavPVT, this); 42 | ROS_INFO("Subscribing to NavPVT topic %s", navpvt_sub_.getTopic().c_str()); 43 | nmea_pub_ = nh.advertise("nmea", 1); 44 | ROS_INFO("Advertising NMEA topic %s", nmea_pub_.getTopic().c_str()); 45 | } 46 | 47 | void Transformer::receiveNavPVT(const ublox_msgs::NavPVT::ConstPtr &navpvt_msg) { 48 | ROS_INFO_ONCE("Received first NavPVT message."); 49 | 50 | char buf[255]; 51 | 52 | // Time conversion 53 | auto now = ros::Time::now(); 54 | auto time = now.toBoost().time_of_day(); 55 | long int deci_seconds = now.nsec / 1e7; 56 | 57 | // Lat conversion 58 | char lat_dir = navpvt_msg->lat < 0 ? 'S' : 'N'; 59 | int8_t lat_degs = navpvt_msg->lat / 1e7; 60 | double lat_mins = (navpvt_msg->lat - lat_degs * 1e7) / 1e7 * 60.0; 61 | 62 | // Lon conversion 63 | char lon_dir = navpvt_msg->lon < 0 ? 'W' : 'E'; 64 | int8_t lon_degs = navpvt_msg->lon / 1e7; 65 | double lon_mins = (navpvt_msg->lon - lon_degs * 1e7) / 1e7 * 60.0; 66 | 67 | // Status conversion 68 | int8_t status = (navpvt_msg->fixType == ublox_msgs::NavPVT::FIX_TYPE_3D) ? 1 : 0; 69 | 70 | uint8_t 71 | len = sprintf(buf, 72 | "$GPGGA,%02ld%02ld%02ld.%ld,%02d%08.5f,%c,%03d%08.5f,%c,%d,%d,%.1f,%d.%d,M,%d.%d,M,,", 73 | time.hours(), 74 | time.minutes(), 75 | time.seconds(), 76 | deci_seconds, 77 | lat_degs, 78 | lat_mins, 79 | lat_dir, 80 | lon_degs, 81 | lon_mins, 82 | lon_dir, 83 | status, 84 | navpvt_msg->numSV, 85 | navpvt_msg->pDOP / 100.0, 86 | navpvt_msg->hMSL / 1000, 87 | navpvt_msg->hMSL % 1000, 88 | (navpvt_msg->height - navpvt_msg->hMSL) / 1000, 89 | std::abs((navpvt_msg->height - navpvt_msg->hMSL)) % 1000 90 | ); 91 | // Calculate checksum of sentence and add it to the end of the sentence 92 | uint8_t checksum = 0; 93 | for (int i = 1; i < len; i++) { 94 | checksum ^= buf[i]; 95 | } 96 | sprintf(&buf[len], "*%02X\r\n", checksum); 97 | 98 | nmea_msgs::Sentence nmea_msg; 99 | nmea_msg.header.stamp = now; 100 | nmea_msg.header.frame_id = "gps"; 101 | nmea_msg.sentence = buf; 102 | nmea_pub_.publish(nmea_msg); 103 | } 104 | 105 | int main(int argc, char **argv) { 106 | ros::init(argc, argv, "ublox2nmea"); 107 | 108 | Transformer transformer; 109 | 110 | ros::spin(); 111 | return 0; 112 | } 113 | --------------------------------------------------------------------------------