Skip to content

Commit

Permalink
added ublox rover gps driver
Browse files Browse the repository at this point in the history
  • Loading branch information
umroverPerception committed Feb 2, 2025
1 parent 6ba068b commit b62a9c4
Show file tree
Hide file tree
Showing 9 changed files with 172 additions and 18 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ install(PROGRAMS
navigation/stuck_detector/stuck_detector.py
localization/gps_linearization.py
localization/basestation_gps_driver.py
localization/rover_gps_driver.py
superstructure/superstructure.py
scripts/debug_course_publisher.py
scripts/visualizer.py
Expand Down
3 changes: 2 additions & 1 deletion ansible/roles/esw/files/rules/99-gps.rules
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6015", SYMLINK+="gps"
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6015", SYMLINK+="unicore_gps"
SUBSYSTEM=="tty", ATTRS{idVendor}=="1546", ATTRS{idProduct}=="01a9", SYMLINK+="ublox_gps"
12 changes: 7 additions & 5 deletions config/localization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

basestation_gps_driver:
ros__parameters:
#TODO: change this
port: /dev/ttyACM0
baud: 38400

Expand All @@ -22,7 +21,10 @@ gps_linearization:

rover_gps_driver:
ros__parameters:
#TODO: change this
port: /dev/gps
baud: 115200
frame_id: "base_link"
port_unicore: /dev/unicore_gps
baud_unicore: 115200

port_ublox: /dev/ublox_gps
baud_ublox: 38400

frame_id: "base_link"
4 changes: 2 additions & 2 deletions config/navigation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ navigation:
post_radius: 0.7

# TODO(quintin): Avoid storing these in multiple config files
ref_lat: 38.4225202
ref_lon: -110.7844653
ref_lat: 42.293195
ref_lon: -83.7096706
ref_alt: 0.0
world_frame: "map"
rover_frame: "base_link"
Expand Down
9 changes: 8 additions & 1 deletion launch/localization.launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,16 @@

def generate_launch_description():

# rover_gps_driver_node = Node(
# package="mrover",
# executable="rover_gps_driver",
# name="rover_gps_driver",
# parameters=[os.path.join(get_package_share_directory("mrover"), "config", "localization.yaml")],
# )

rover_gps_driver_node = Node(
package="mrover",
executable="rover_gps_driver",
executable="rover_gps_driver.py",
name="rover_gps_driver",
parameters=[os.path.join(get_package_share_directory("mrover"), "config", "localization.yaml")],
)
Expand Down
15 changes: 9 additions & 6 deletions localization/basestation_gps_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from rclpy.executors import ExternalShutdownException
from rclpy.node import Node
from rtcm_msgs.msg import Message as RTCMMessage
from mrover.msg import SatelliteSignal


class BaseStationDriverNode(Node):
Expand All @@ -31,6 +32,7 @@ def __init__(self) -> None:
baud = self.get_parameter("baud").value

self.rtcm_pub = self.create_publisher(RTCMMessage, "rtcm", 10)
self.satellite_signal_pub = self.create_publisher(SatelliteSignal, "basestation/satellite_signal", 10)

self.svin_started = False
self.svin_complete = False
Expand All @@ -39,6 +41,7 @@ def __init__(self) -> None:
self.reader = UBXReader(self.serial, protfilter=UBX_PROTOCOL | RTCM3_PROTOCOL)

def spin(self) -> None:

while rclpy.ok():
if self.serial.in_waiting:
raw_msg, msg = self.reader.read()
Expand Down Expand Up @@ -66,17 +69,17 @@ def spin(self) -> None:
gnssId = getattr(msg, f"gnssId_{i+1:02d}")
cno = getattr(msg, f"cno_{i+1:02d}")
if gnssId == 0:
self.get_logger().info(f"GPS signal strength: {cno}")
self.satellite_signal_pub.publish(SatelliteSignal(constellation="GPS", signal_strength=cno))
elif gnssId == 1:
self.get_logger().info(f"SBAS signal strength: {cno}")
self.satellite_signal_pub.publish(SatelliteSignal(constellation="SBAS", signal_strength=cno))
elif gnssId == 2:
self.get_logger().info(f"Galileo signal strength: {cno}")
self.satellite_signal_pub.publish(SatelliteSignal(constellation="Galileo", signal_strength=cno))
elif gnssId == 3:
self.get_logger().info(f"BeiDou signal strength: {cno}")
self.satellite_signal_pub.publish(SatelliteSignal(constellation="BeiDou", signal_strength=cno))
elif gnssId == 5:
self.get_logger().info(f"QZSS signal strength: {cno}")
self.satellite_signal_pub.publish(SatelliteSignal(constellation="QZSS", signal_strength=cno))
elif gnssId == 6:
self.get_logger().info(f"GLONASS signal strength: {cno}")
self.satellite_signal_pub.publish(SatelliteSignal(constellation="GLONASS", signal_strength=cno))

rclpy.spin_once(self, timeout_sec=0)

Expand Down
2 changes: 1 addition & 1 deletion localization/gps_linearization.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def synced_gps_imu_callback(self, gps_msg: NavSatFix, imu_msg: Imu):
x, y, z = geodetic2enu(
gps_msg.latitude, gps_msg.longitude, gps_msg.altitude, self.ref_lat, self.ref_lon, self.ref_alt, deg=True
)
pose = SE3(position=np.array([x, y, z]), quaternion=quaternion)
pose = SE3(position=np.array([x, y, 0]), quaternion=quaternion)

to_tf_tree(tf_broadcaster=self.tf_broadcaster, se3=pose, child_frame="base_link", parent_frame=self.world_frame)

Expand Down
140 changes: 140 additions & 0 deletions localization/rover_gps_driver.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
#!/usr/bin/env python3

"""
Reads and parses NMEA messages from the onboard GPS to provide
location data to the rover over LCM (/gps). Subscribes to
/rtcm and passes RTCM messages to the onboard gps to
acquire an RTK fix.
"""

from __future__ import annotations

import sys

import serial
from pyubx2 import UBXReader, UBX_PROTOCOL, RTCM3_PROTOCOL

import rclpy
from mrover.msg import FixStatus, SatelliteSignal
from rclpy import Parameter
from rclpy.executors import ExternalShutdownException
from rclpy.node import Node
from rtcm_msgs.msg import Message as RTCMMessage
from sensor_msgs.msg import NavSatFix
from std_msgs.msg import Header


class RoverGpsDriverNode(Node):
def __init__(self) -> None:
super().__init__("gps_driver")

self.declare_parameters(
"",
[
("port_ublox", Parameter.Type.STRING),
("baud_ublox", Parameter.Type.INTEGER),
],
)
self.port = self.get_parameter("port").value
self.baud = self.get_parameter("baud").value

self.gps_pub = self.create_publisher(NavSatFix, "gps/fix", 10)
self.gps_status_pub = self.create_publisher(FixStatus, "gps_fix_status", 10)
self.satellite_signal_pub = self.create_publisher(SatelliteSignal, "gps/satellite_signal", 10)

self.base_station_sub = self.create_subscription(RTCMMessage, "rtcm", self.process_rtcm, 10)

self.serial = serial.Serial(self.port, self.baud)
self.reader = UBXReader(self.serial, protfilter=UBX_PROTOCOL | RTCM3_PROTOCOL)

def process_rtcm(self, data: RTCMMessage) -> None:
self.serial.write(data.message)

def parse_ubx_message(self, msg) -> None:
if not msg:
return

match msg.identity:
case "RXM-RTCM":
match msg.msgUsed:
case 0:
self.get_logger().warn("RTCM usage unknown")
case 1:
self.get_logger().warn("RTCM message not used")
case 2:
self.get_logger().debug("RTCM message successfully used by receiver")

case "NAV-PVT":
if msg.lat == 0 or msg.lon == 0:
self.get_logger().warn("Zero satellite fix. Are we inside?")
return

self.gps_pub.publish(
NavSatFix(
header=Header(stamp=self.get_clock().now().to_msg(), frame_id="base_link"),
latitude=msg.lat,
longitude=msg.lon,
altitude=msg.hMSL,
)
)

self.gps_status_pub.publish(
FixStatus(
header=Header(stamp=self.get_clock().now().to_msg(), frame_id="base_link"),
fix_status = msg.carrSoln
)
)

if msg.difSoln == 1:
self.get_logger().debug("Differential correction applied")
if msg.carrSoln == 0:
self.get_logger().warn("No RTK")
elif msg.carrSoln == 1:
self.get_logger().debug("Floating RTK Fix")
elif msg.carrSoln == 2:
self.get_logger().debug("RTK FIX")

case "NAV-SAT":
for i in range(msg.numSvs):
gnssId = getattr(msg, f"gnssId_{i+1:02d}")
cno = getattr(msg, f"cno_{i+1:02d}")
if gnssId == 0:
self.satellite_signal_pub.publish(SatelliteSignal(constellation="GPS", signal_strength=cno))
elif gnssId == 1:
self.satellite_signal_pub.publish(SatelliteSignal(constellation="SBAS", signal_strength=cno))
elif gnssId == 2:
self.satellite_signal_pub.publish(SatelliteSignal(constellation="Galileo", signal_strength=cno))
elif gnssId == 3:
self.satellite_signal_pub.publish(SatelliteSignal(constellation="BeiDou", signal_strength=cno))
elif gnssId == 5:
self.satellite_signal_pub.publish(SatelliteSignal(constellation="QZSS", signal_strength=cno))
elif gnssId == 6:
self.satellite_signal_pub.publish(SatelliteSignal(constellation="GLONASS", signal_strength=cno))

case "NAV-STATUS":
pass

def spin(self) -> None:
while rclpy.ok():
if self.serial.in_waiting:
raw, msg = self.reader.read()
self.parse_ubx_message(msg)
rclpy.spin_once(self, timeout_sec=0)

def __del__(self) -> None:
self.serial.close()


def main() -> None:
try:
rclpy.init(args=sys.argv)
RoverGpsDriverNode().spin()
rclpy.shutdown()
except KeyboardInterrupt:
pass
except ExternalShutdownException:
sys.exit(1)


if __name__ == "__main__":
main()
4 changes: 2 additions & 2 deletions localization/rover_gps_driver/rover_gps_driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ namespace mrover {
RoverGPSDriver::RoverGPSDriver(boost::asio::io_context& io) : Node("rover_gps_driver"), serial(io) {

// connect to serial
declare_parameter("port", rclcpp::ParameterType::PARAMETER_STRING);
declare_parameter("baud", rclcpp::ParameterType::PARAMETER_INTEGER);
declare_parameter("port_unicore", rclcpp::ParameterType::PARAMETER_STRING);
declare_parameter("baud_unicore", rclcpp::ParameterType::PARAMETER_INTEGER);
declare_parameter("frame_id", rclcpp::ParameterType::PARAMETER_STRING);

port = get_parameter("port").as_string();
Expand Down

0 comments on commit b62a9c4

Please sign in to comment.