Skip to content

Commit a1b1bb3

Browse files
committed
samples: gnss: Add ability to enable RTK
Expand this sample to also work with GNSS_RTK through a serial client. Make this compatible to work with VMU_RT1170 which requires using the F9P, instead of the M8 UBX module. Signed-off-by: Luis Ubieda <luisf@croxel.com>
1 parent 4f3545b commit a1b1bb3

File tree

8 files changed

+155
-9
lines changed

8 files changed

+155
-9
lines changed

samples/drivers/gnss/README.rst

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,37 @@ Sample Output
2626
gnss has fix!
2727
gnss: gnss_satellite: {prn: 1, snr: 30, elevation 71, azimuth 276, system: GLONASS, is_tracked: 1}
2828
gnss: gnss_satellite: {prn: 11, snr: 31, elevation 62, azimuth 221, system: GLONASS, is_tracked: 1}
29-
gnss reported 2 satellites!
29+
gnss reported 2 satellites (of which 2 tracked, of which 0 has RTK corrections)!
30+
31+
Real-Time Kinematics (RTK)
32+
**************************
33+
34+
This sample may also be configured to enable Real-Time Kinematics (RTK) positioning for
35+
enhanced accuracy, with the assistance of a local base station.
36+
37+
RTK Requirements
38+
****************
39+
40+
This sample requires the following setup to work with RTK:
41+
42+
* A UBlox F9P GNSS module connected to your board to act as a rover
43+
* A second UBlox F9P module connected to a PC to act as a base station
44+
45+
Base Station Setup
46+
******************
47+
48+
To enable RTK functionality:
49+
50+
1. Connect the base station F9P module to your PC via USB.
51+
2. Also, connect the rover's serial port (running the sample) to your PC via USB.
52+
3. Note the serial port the rover is connected through (e.g., /dev/ttyUSB0)
53+
4. Run the base station script:
54+
55+
.. code-block:: console
56+
57+
python3 base_station/base_station_f9p.py --port /dev/ttyUSB0
58+
59+
The script configures the F9P module as a base station and streams RTCM3
60+
correction data to the rover. The base station will perform a survey-in
61+
process to determine its precise position before starting to transmit
62+
corrections.
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Copyright (c) 2025, Croxel Inc
2+
# Copyright (c) 2025, CogniPilot Foundation
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
6+
import argparse
7+
8+
import pyrtcm
9+
import pyubx2
10+
import serial
11+
12+
UBX_F9P_VID = 0x1546
13+
UBX_F9P_PID = 0x01A9
14+
15+
16+
def parse_args():
17+
parser = argparse.ArgumentParser(allow_abbrev=False)
18+
parser.add_argument(
19+
'-p', '--port', required=True, help='Serial Port connected to the Rover (e.g: /dev/ttyUSB0)'
20+
)
21+
22+
return parser.parse_args()
23+
24+
25+
def getF9PBaseStationSerialPort():
26+
from serial.tools import list_ports
27+
28+
for port in list_ports.comports():
29+
if port.vid == UBX_F9P_VID and port.pid == UBX_F9P_PID:
30+
return port.device
31+
32+
raise RuntimeError(
33+
f'Could not find any Serial Port with VID: {hex(UBX_F9P_VID)}, PID: {hex(UBX_F9P_PID)}'
34+
)
35+
36+
37+
def enableBaseStationMode(serialEndpoint: serial.Serial):
38+
frame = pyubx2.UBXMessage.config_set(
39+
layers=1,
40+
transaction=0,
41+
cfgData=[
42+
("CFG_MSGOUT_RTCM_3X_TYPE1005_USB", 1),
43+
("CFG_MSGOUT_RTCM_3X_TYPE1074_USB", 1),
44+
("CFG_MSGOUT_RTCM_3X_TYPE1077_USB", 1),
45+
("CFG_MSGOUT_RTCM_3X_TYPE1084_USB", 1),
46+
("CFG_MSGOUT_RTCM_3X_TYPE1087_USB", 1),
47+
("CFG_MSGOUT_RTCM_3X_TYPE1094_USB", 1),
48+
("CFG_MSGOUT_RTCM_3X_TYPE1097_USB", 1),
49+
("CFG_MSGOUT_RTCM_3X_TYPE1124_USB", 1),
50+
("CFG_MSGOUT_RTCM_3X_TYPE1127_USB", 1),
51+
("CFG_MSGOUT_RTCM_3X_TYPE1230_USB", 1),
52+
],
53+
)
54+
serialEndpoint.write(frame.serialize())
55+
56+
frame = pyubx2.UBXMessage.config_set(
57+
layers=1,
58+
transaction=0,
59+
cfgData=[
60+
("CFG_TMODE_MODE", 1),
61+
("CFG_TMODE_SVIN_ACC_LIMIT", 250),
62+
("CFG_TMODE_SVIN_MIN_DUR", 60),
63+
],
64+
)
65+
serialEndpoint.write(frame.serialize())
66+
67+
68+
def main():
69+
args = parse_args()
70+
71+
with (
72+
serial.Serial(getF9PBaseStationSerialPort(), 115200) as serialIn,
73+
serial.Serial(args.port, 115200) as serialOut,
74+
):
75+
enableBaseStationMode(serialIn)
76+
77+
for raw, parsed in pyrtcm.RTCMReader(serialIn):
78+
print(parsed)
79+
serialOut.write(raw)
80+
81+
82+
if __name__ == '__main__':
83+
main()
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pyubx2>=1.2.53
2+
pyrtcm>=1.1.8
3+
pyserial>=3.5
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Copyright (c) 2025 Croxel Inc.
2+
# Copyright (c) 2025 CogniPilot Foundation
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
CONFIG_SHELL=n
6+
CONFIG_SERIAL=y
7+
CONFIG_UART_INTERRUPT_DRIVEN=y

samples/drivers/gnss/boards/vmu_rt1170_mimxrt1176_cm7.overlay

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
aliases {
99
gnss = &gnss;
1010
};
11+
chosen {
12+
zephyr,rtk-serial = &lpuart1;
13+
};
1114
};
1215

1316
&lpuart3 {
@@ -16,7 +19,6 @@
1619

1720
gnss: gnss {
1821
status = "okay";
19-
compatible = "u-blox,m8";
20-
initial-baudrate = <115200>;
22+
compatible = "u-blox,f9p";
2123
};
2224
};

samples/drivers/gnss/overlay-rtk.conf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Copyright (c) 2025 Croxel Inc.
2+
# Copyright (c) 2025 CogniPilot Foundation
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
CONFIG_GNSS_RTK=y
6+
CONFIG_GNSS_RTK_SERIAL=y

samples/drivers/gnss/sample.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,14 @@ tests:
1111
filter: dt_alias_exists("gnss")
1212
integration_platforms:
1313
- mimxrt1062_fmurt6
14+
15+
sample.drivers.gnss.rtk:
16+
harness: rtk
17+
tags:
18+
- drivers
19+
- gnss
20+
- rtk
21+
filter: dt_chosen_enabled("zephyr,rtk-serial") and dt_alias_exists("gnss")
22+
extra_args: EXTRA_CONF_FILE=overlay-rtk.conf
23+
integration_platforms:
24+
- vmu_rt1170/mimxrt1176/cm7

samples/drivers/gnss/src/main.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111

1212
#define GNSS_MODEM DEVICE_DT_GET(DT_ALIAS(gnss))
1313

14-
LOG_MODULE_REGISTER(gnss_sample, CONFIG_GNSS_LOG_LEVEL);
15-
1614
static void gnss_data_cb(const struct device *dev, const struct gnss_data *data)
1715
{
1816
uint64_t timepulse_ns;
@@ -21,9 +19,10 @@ static void gnss_data_cb(const struct device *dev, const struct gnss_data *data)
2119
if (data->info.fix_status != GNSS_FIX_STATUS_NO_FIX) {
2220
if (gnss_get_latest_timepulse(dev, &timepulse) == 0) {
2321
timepulse_ns = k_ticks_to_ns_near64(timepulse);
24-
printf("Got a fix @ %lld ns\n", timepulse_ns);
22+
printf("Got a fix (type: %d) @ %lld ns\n", data->info.fix_status,
23+
timepulse_ns);
2524
} else {
26-
printf("Got a fix!\n");
25+
printf("Got a fix (type: %d)\n", data->info.fix_status);
2726
}
2827
}
2928
}
@@ -34,12 +33,14 @@ static void gnss_satellites_cb(const struct device *dev, const struct gnss_satel
3433
uint16_t size)
3534
{
3635
unsigned int tracked_count = 0;
36+
unsigned int corrected_count = 0;
3737

3838
for (unsigned int i = 0; i != size; ++i) {
3939
tracked_count += satellites[i].is_tracked;
40+
corrected_count += satellites[i].is_corrected;
4041
}
41-
printf("%u satellite%s reported (of which %u tracked)!\n",
42-
size, size > 1 ? "s" : "", tracked_count);
42+
printf("%u satellite%s reported (of which %u tracked, of which %u has RTK corrections)!\n",
43+
size, size > 1 ? "s" : "", tracked_count, corrected_count);
4344
}
4445
#endif
4546
GNSS_SATELLITES_CALLBACK_DEFINE(GNSS_MODEM, gnss_satellites_cb);

0 commit comments

Comments
 (0)