In various applications, achieving centimeter-level accuracy is crucial. However, using expensive RTK (Real-Time Kinematic) setups may not always be feasible. The solution lies in compensating for errors at the receiver level using Networked Transport of RTCM via Internet Protocol (NTRIP).
Project OverviewThis project explores using the ZED-F9P-01B-01.module for precise GNSS measurements, leveraging its "Point Perfect" capabilities. While the ZED-F9P can be used in RTK setups, we focus on alternative methods to achieve accuracy.
Identifying NTRIP ServersThe first step is identifying suitable NTRIP servers based on your GNSS application location. Refer to the public and private NTRIP server lists provided in the references section. Once you identify a server, you can create a client to connect to it.
ZED-F9P certainly can be used in RTK setup too, however, here we are trying to use "Point Perfect" aspect of this module.
First question is where are the NTRIP servers. The answer depends to where you are using the GNSS. Check the list [REF:SERVERS].
Once you have one server found, create a client. Usually you will be given server in an address like
products.igs-ip.net on port 2101
Once you have that, you need to run it, check this simple Python cod that takes care about client.
Python Code for NTRIP Clientimport requests
from requests.auth import HTTPBasicAuth
import serial
# NTRIP Server details
url = "https://ntrip.data.gnss.ga.gov.au:443/<YOUR LOCATION>"
username = "GET YOUR USERNAME"
password = "GET YOUR PASSWORD"
# Setup serial port to communicate with GNSS receiver
serial_port = '/dev/ttyACM0'
baudrate = 9600 # Adjust baud rate as per your device's configuration
ser = serial.Serial(serial_port, baudrate)
def stream_ntrip():
headers = {
'Ntrip-Version': 'Ntrip/2.0',
'User-Agent': 'NTRIP PythonClient/1.0',
'Connection': 'close'
}
try:
# Connect to NTRIP caster
response = requests.get(url, headers=headers, stream=True,
auth=HTTPBasicAuth(username, password))
print("Connected to NTRIP Caster.")
# Stream the corrections
for chunk in response.iter_content(chunk_size=1024):
# Write the RTCM data directly to the GNSS receiver
ser.write(chunk)
print("Sending RTCM data to GNSS receiver...", chunk)
except requests.exceptions.RequestException as e:
print(f"Error connecting to NTRIP caster: {e}")
finally:
ser.close()
print("Serial port closed.")
if __name__ == "__main__":
stream_ntrip()
Reading Location Data from the u-blox Board
import serial
from pyubx2 import UBXReader, UBXMessage
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
class UBXHandler:
def __init__(self, port='/dev/ttyACM0', baudrate=9600):
self.serial_port = serial.Serial(port, baudrate, timeout=3)
self.ubx_reader = UBXReader(self.serial_port, validate=True)
self.positions = [] # Store (latitude, longitude, height) tuples
self.hAcc = [] # Store horizontal accuracy
self.vAcc = [] # Store vertical accuracy
def read_and_process_data(self):
try:
while True:
raw_data, parsed_data = self.ubx_reader.read()
if isinstance(parsed_data, UBXMessage):
self.process_data(parsed_data)
except KeyboardInterrupt:
print("Stopped reading data.")
except Exception as e:
print(f"An error occurred: {e}")
def process_data(self, msg: UBXMessage):
identity = msg.identity
if identity in ("NAV-POSLLH", "NAV-HPPOSLLH"):
self._process_nav_posllh(msg)
if identity in ("NAV-PVT"):
self._process_nav_pvt(msg)
def _process_nav_posllh(self, msg: UBXMessage):
latitude = msg.lat
longitude = msg.lon
height = msg.hMSL / 1000 # Convert to meters
self.positions.append((latitude, longitude, height))
print(f"Position: {latitude}, {longitude}, Height: {height}m")
def _process_nav_pvt(self, msg: UBXMessage):
hAcc = msg.hAcc / 1000 # Convert to meters
vAcc = msg.vAcc / 1000 # Convert to meters
self.hAcc.append(hAcc)
self.vAcc.append(vAcc)
print(f"Horizontal Accuracy: {hAcc}m, Vertical Accuracy: {vAcc}m")
def close(self):
self.serial_port.close()
def plot_accuracy(self):
fig, ax = plt.subplots()
line, = ax.plot([], [], 'ro', label='Horizontal Accuracy')
line2, = ax.plot([], [], 'bo', label='Vertical Accuracy')
def init():
ax.set_xlim(0, 100) # Set limits
ax.set_ylim(0, max(max(self.hAcc, default=0), max(self.vAcc, default=0)) + 5)
return line, line2
def update(frame):
line.set_data(range(len(self.hAcc)), self.hAcc)
line2.set_data(range(len(self.vAcc)), self.vAcc)
return line, line2
ani = FuncAnimation(fig, update, frames=np.arange(1, 100), init_func=init, blit=True)
plt.legend()
plt.show()
# Example usage:
if __name__ == "__main__":
handler = UBXHandler()
try:
handler.read_and_process_data()
finally:
handler.close()
handler.plot_accuracy()
Python RequirementsTo run the provided code, you will need the following Python packages:
- matplotlib
- pyproj
- pyubx2
- pyserial
- requests
- utm
- pyrtcm
- pandas
- pymongo
- geopy
RESULTS:
We got now a good accurate readout reading and plotting.
If you use u-center, you will have something like:
Today is raining and I'm working in the balcony, so no clear sky and the rain is not in our favor. Anyways, the accuracy and the stability of the location are good.
- Public [NTRIP] Servers: UNAVCO, SAPOS, AusCORS, EUREF-IP, IGS RTS
- Private NTRIP Servers: Trimble VRS Now, Leica SmartNet, Topcon TopNET, RTK Networks, OmniSTAR
- NTRIP: Technology to improve GPS accuracy.
- [RTK]: High-precision GNSS technology.
Note: The ZED-F9P can be used in RTK setups, but here we emphasize its "Point Perfect" functionality for achieving precise GNSS measurements without the expense of RTK setups.
Comments
Please log in or sign up to comment.