Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update NMEA support #128

Merged
merged 30 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
d96536e
Add u-blox support and deprecate NMEA support
hmakelin Aug 1, 2024
71db1eb
Remove geographic_msgs as dependency for gisnav_msgs as BoundingBox m…
hmakelin Aug 1, 2024
69125ba
Update launch arg descriptions
hmakelin Aug 1, 2024
93910fc
Update documentation relating to running GISNav locally to reflect NM…
hmakelin Aug 1, 2024
d104a8a
Fix local launch file name in deploy-for-development.md examples
hmakelin Aug 1, 2024
056a34f
Use 3rd party ublox node and ROS instead of publishing directly to se…
hmakelin Aug 1, 2024
a4305ee
Depict new ubx middleware service in system architecture docs
hmakelin Aug 2, 2024
b630d05
Run UBX middleware in a separate service to improve separation of con…
hmakelin Aug 2, 2024
facdc92
Reduce code duplication between UORBNode and UBXNode
hmakelin Aug 2, 2024
d054cf9
Use abstract base class for UBXNode and UORBNode to reduce amount of …
hmakelin Aug 2, 2024
e6b9593
Do not use narrow_types decorator on TypedDict as it is not properly …
hmakelin Aug 3, 2024
5ea10bc
Fix ublox_node package and executable names
hmakelin Aug 3, 2024
7154afd
Use custom UBX publisher instead of ublox package in ROS index
hmakelin Aug 3, 2024
eea8d41
Use new custom ublox executable in launch files
hmakelin Aug 3, 2024
8bb26e6
Fix various smaller issues with NavPVT message field and publish topi…
hmakelin Aug 3, 2024
93b146b
Update px4 service to accept UBX messages
hmakelin Aug 3, 2024
c22a69c
Fix pyubx2 UBXMessage constructor scaling
hmakelin Aug 4, 2024
68acbb8
Fix socat bridge baudrate and path
hmakelin Aug 5, 2024
6212fc2
WIP: Make NMEA downstream integration work
hmakelin Aug 5, 2024
96a2f54
Fix unintentional udp/tcp switch in networking definition
hmakelin Aug 6, 2024
893e1d5
Make NMEA the default protocol for dev
hmakelin Aug 6, 2024
7b83e2d
Clean up comments in docker-compose.dependencies.yaml
hmakelin Aug 6, 2024
c9706b0
Update service architecture and ROS topography diagrams
hmakelin Aug 6, 2024
7696aa4
Fix Python code formatting via precommit
hmakelin Aug 6, 2024
1b15697
Update NMEA related information on introduction page
hmakelin Aug 6, 2024
377c985
Fix unit test path
hmakelin Aug 6, 2024
d12c0bb
Remove unnecessary port mappings from ubx and nmea middleware services
hmakelin Aug 7, 2024
4e76b6e
Remove dead code in NMEANode and its launch file
hmakelin Aug 7, 2024
146d6c7
Automatically start gps at /dev/pts/1 in px4 service to receive NMEA …
hmakelin Aug 7, 2024
543e874
Update local launch documentation [skip ci]
hmakelin Aug 7, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
SHELL := /bin/bash

# Default output protocol for mock GPS messages
PROTOCOL=nmea

.PHONY: docs
docs:
@cd docs/sphinx && sphinx-build -M markdown ./source ./build
Expand Down Expand Up @@ -62,13 +65,19 @@ format: lint
check: lint test
@echo "Running code quality checks..."

.PHONY: dev
dev:
@echo "Launching GISNav locally using $(PROTOCOL) protocol..."
@ros2 launch gisnav local.launch.py protocol:=$(PROTOCOL)

.PHONY: help
help:
@echo "Available targets:"
@echo " docs - Build the documentation"
@echo " docs preview - Preview the documentation"
@echo " docs dev - Run the documentation development server"
@echo " build - Build the project"
@echo " dev - Run GISNav locally"
@echo " dist - Create a distribution package"
@echo " clean - Clean up all generated files"
@echo " clean docs - Clean up documentation build files only"
Expand Down
3 changes: 3 additions & 0 deletions docker/.env
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,6 @@ GISNAV_VIDEO_BIND_PORT=5600
#TINYOWS_MAPFILE=/etc/mapserver/default.map

SIM_HEADLESS=0

# TCP port for bridging serial output from middleware to simulation container
SOCAT_BRIDGE_PORT=15000
206 changes: 0 additions & 206 deletions docker/Makefile
Original file line number Diff line number Diff line change
@@ -1,45 +1,3 @@
# This Makefile is used as a Docker container orchestration tool to deploy
# various Docker Compose services that support GISNav.
#
# The terminology used in this Makefile includes the following:
# - FMU: Flight Management Unit, the onboard flight controller computer
# board (e.g., Pixhawk) that runs the autopilot software.
# - HIL: Hardware-In-The-Loop, a simulation mode where the autopilot runs
# onboard the FMU.
# - SITL: Software-In-The-Loop, a simulation mode where the autopilot is
# executed offboard on a separate computer, replicating the drone's
# flight dynamics and sensors, enabling testing and development without
# using actual hardware.
# - Offboard: Refers to services that run on a computer not carried by the
# drone and not powered by the drone battery (e.g., a powerful desktop).
# - Onboard: Refers to services that run on the drone itself, powered by the
# drone's battery, like the FMU and onboard companion computer (e.g.,
# Nvidia Jetson Nano). In the case of GISNav, all onboard services are
# intended to run on the companion computer and not e.g. on the FMU.
# - Middleware: Software that sits between the autopilot and GISNav, enabling
# communication between them.
# - QGC: QGroundControl, a ground control station software used to monitor
# and control drones.
# - Gazebo: A robotics simulator used to simulate the drone's environment and
# its interactions with the world.
#
# The target options in the Makefile are as follows:
# - onboard-hil-*: Targets for onboard hardware-in-the-loop services,
# including GIS server, ROS middleware, autoheal, and GISNav.
# - onboard-sitl-*: Targets for onboard software-in-the-loop services, with
# the same services as onboard HIL but using a different middleware
# configuration.
# - offboard-sitl-*: Targets for offboard software-in-the-loop services,
# including Gazebo simulation and QGroundControl.
# - offboard-sitl-test-*: Targets for SITL testing services, which exclude
# GISNav and QGC for automated testing scenarios. Gazebo in headless mode.
# - offboard-sitl-dev-*: Targets for SITL development services, including
# Gazebo simulation, ROS middleware, mapserver, and QGC, but
# excluding GISNav whose development version is assumed to be run locally.
# - demo-*: Shortcut targets for demo purposes, setting up all SITL services
# offboard, including GIS server, ROS middleware, Gazebo simulation, QGC,
# and GISNav.

SHELL := /bin/bash

# Supported autopilots, must match docker/docker-compose.yaml service name
Expand All @@ -48,125 +6,6 @@ AUTOPILOTS := px4 ardupilot
# Prefix for Docker Compose service images
PROJECT_NAME := gisnav

# Define a reusable template for creating Docker Compose targets
# Parameters:
# 1. The prefix for the target name.
# 2. The dependency target.
# 3. The optional Docker Compose override files to include (if any).
# 4. The Docker Compose services to start or build - use $$* here for
# autopilot, the first '$' is to escape the second '$'.
define compose_template

# Create phony create targets with the specified prefix for each autopilot
.PHONY: $(addprefix create-$(1)-, $(AUTOPILOTS))

# Generate rules for the build prefixed targets, depending on the specified build dependency target
$(addprefix create-$(1)-, $(AUTOPILOTS)): $(if $(2),create-$(1)-%: create-$(2)-%,create-$(2)-%)
# Evaluate the additional Docker Compose files
$$(eval compose_files := $(if $(3),-f docker-compose.yaml $(foreach file,$(3),-f $(file))))
# Build the specified Docker Compose services and create the containers
@docker compose -p $(PROJECT_NAME) $$(compose_files) create $(4)

# Create phony build targets with the specified prefix for each autopilot
.PHONY: $(addprefix build-$(1)-, $(AUTOPILOTS))

# Generate rules for the build prefixed targets, depending on the specified build dependency target
$(addprefix build-$(1)-, $(AUTOPILOTS)): $(if $(2),build-$(1)-%: build-$(2)-%,build-$(2)-%)
# Evaluate the additional Docker Compose files
$$(eval compose_files := $(if $(3),-f docker-compose.yaml $(foreach file,$(3),-f $(file))))
# Build the specified Docker Compose services
@docker compose -p $(PROJECT_NAME) $$(compose_files) build $(4)

# Create phony up targets with the specified prefix for each autopilot
.PHONY: $(addprefix up-$(1)-, $(AUTOPILOTS))

# Generate rules for the prefixed up targets, depending on the specified up
# dependency target
# IMPORTANT: Need to depend on create targets here before up targets to first
# expose xhost to containers before running them
$(addprefix up-$(1)-, $(AUTOPILOTS)): $(if $(2),up-$(1)-%: create-$(1)-% expose-xhost up-$(2)-%,up-$(1)-%: create-$(1)-% expose-xhost)
# Evaluate the additional Docker Compose files
$$(eval compose_files := $(if $(3),-f docker-compose.yaml $(foreach file,$(3),-f $(file))))
# Run Docker Compose with the specified services
@docker compose -p $(PROJECT_NAME) $$(compose_files) up -d $(4)
endef

# Define a reusable template for creating Docker Compose middleware targets
#
# Parameters:
# 1. The prefix for the target name.
# 2. The additional Docker Compose options, such as file overrides.
define middleware_template
.PHONY: up-$(1)-% build-$(1)-% create-$(1)-%

up-$(1)-%:
$$(call run_middleware, $(2), up -d)

build-$(1)-%:
$$(call run_middleware, $(2), build)

create-$(1)-%:
$$(call run_middleware, $(2), create)
endef

# The run_middleware function is a helper function for executing middleware
# targets with the necessary Docker Compose options.
#
# Parameters:
# 1. Additional Docker Compose options, such as file overrides.
# 2. The Docker Compose command to execute (either 'up -d' or 'build').
define run_middleware
@if [ "$*" = "px4" ]; then \
docker compose -p $(PROJECT_NAME) $(1) $(2) mavros; \
elif [ "$*" = "ardupilot" ]; then \
docker compose -p $(PROJECT_NAME) $(1) $(2) mavros; \
else \
echo "Unsupported target '$*' (try 'px4' or 'ardupilot')."; \
fi
endef

# The empty argument check for some reason is not working in the compose_template.
# So we will pass a dummy dependency as a dependency target instead of an empty
# argument.
.PHONY: $(addprefix build-dummy-dependency-, $(AUTOPILOTS))
.PHONY: $(addprefix create-dummy-dependency-, $(AUTOPILOTS))
.PHONY: $(addprefix up-dummy-dependency-, $(AUTOPILOTS))

build-dummy-dependency-px4:

create-dummy-dependency-px4:

up-dummy-dependency-px4:

build-dummy-dependency-ardupilot:

create-dummy-dependency-ardupilot:

up-dummy-dependency-ardupilot:

# Define middleware targets
$(eval $(call middleware_template,onboard-hil-middleware,-f docker-compose.yaml -f docker-compose.serial.yaml))
$(eval $(call middleware_template,onboard-sitl-middleware,))
$(eval $(call middleware_template,offboard-sitl-middleware,)) # same as onboard

# onboard HIL services: GIS server, ROS middleware, autoheal, gscam and GISNav
$(eval $(call compose_template,onboard-hil,onboard-hil-middleware,docker-compose.arm64.yaml,mapserver autoheal gscam gisnav))

# onboard SITL services: Same as with HIL but middleware is same as offboard (UDP, not serial)
$(eval $(call compose_template,onboard-sitl,offboard-sitl-middleware,docker-compose.arm64.yaml,mapserver gscam gisnav))

# offboard SITL services: Gazebo simulation, QGC
$(eval $(call compose_template,offboard-sitl,dummy-dependency,,$$* qgc))

# SITL testing services: Gazebo simulation, ROS middleware, mapserver, gscam, but excluding GISNav and QGC
$(eval $(call compose_template,offboard-sitl-test,offboard-sitl-middleware,docker-compose.headless.yaml,$$* gscam mapserver))

# SITL development services: Gazebo simulation, ROS middleware, mapserver, QGC, gscam rviz, but excluding GISNav
$(eval $(call compose_template,offboard-sitl-dev,offboard-sitl-middleware,,$$* qgc gscam mapserver rviz))

# All SITL services offboard: GIS server, ROS middleware, Gazebo simulation, QGC, gscam, gisnav
$(eval $(call compose_template,demo,offboard-sitl-dev,,gisnav))

# List of Docker Compose service names that need GUI access
GUI_SERVICES = px4 ardupilot qgc rviz gisnav fileserver

Expand All @@ -182,48 +21,3 @@ expose-xhost:
fi; \
done; \
fi


# shutdown any and all services (stop and remove containers)
.PHONY: down
down:
@docker compose -p $(PROJECT_NAME) down

# start existing containers
# Note: You should create the containers with the "make create-..." first,
# otherwise you will get an error like "no container found for project "gisnav":
# not found"
.PHONY: start
start:
@docker compose -p $(PROJECT_NAME) start

# shutdown any and all services (stop but do not remove containers)
.PHONY: stop
stop:
@docker compose -p $(PROJECT_NAME) stop

# build all services
# Note: This builds many services with overlapping functionality such as px4 and
# arudpilot, you may want to be more specific about what to build
.PHONY: build
build:
@docker compose -p $(PROJECT_NAME) build

.PHONY: dev-nmea
dev-nmea:
@echo "Setting up NMEA output..."
@socat pty,link=/tmp/gisnav-pty-link,raw,echo=0 tcp:localhost:15000 || echo "Could not establish serial-to-TCP bridge" &
@sleep 3 # Give socat time to create the pty
@echo PTS device created at: `readlink /tmp/gisnav-pty-link`
@ros2 launch gisnav local.launch.py protocol:=nmea port:=`readlink /tmp/gisnav-pty-link` baudrate:=9600

.PHONY: dev-uorb
dev-uorb:
@ros2 launch gisnav local.launch.py protocol:=uorb

# shortcut for demo
.PHONY: demo
demo:
docker compose -p gisnav create gisnav
$(MAKE) expose-xhost
docker compose -p gisnav up gisnav px4
6 changes: 6 additions & 0 deletions docker/docker-compose.commands.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ services:
- "-p"
- "camera_info_url:=file:///etc/gscam/camera_calibration.yaml"

ubx:
command: "ros2 run ubx_publisher ubx_publisher_node --ros-args --log-level debug -p serial_port:=/dev/pts/0" # pty created in entrypoint script, TODO try to $(readlink /tmp/gisnav-pty-link) instead of hard-coding /dev/pts/0 here

nmea:
command: "ros2 run nmea_publisher nmea_publisher_node --ros-args --log-level debug -p serial_port:=/dev/pts/0" # pty created in entrypoint script, TODO try to $(readlink /tmp/gisnav-pty-link) instead of hard-coding /dev/pts/0 here

fileserver:
command: apache2ctl -D FOREGROUND

Expand Down
3 changes: 3 additions & 0 deletions docker/docker-compose.dependencies.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ name: gisnav

services:

# TODO: have separate profiles for uros/ubx/nmea middleware
gisnav:
depends_on:
- micro-ros-agent
# - ubx
- nmea
- mavros
- gscam
- mapserver
Expand Down
16 changes: 16 additions & 0 deletions docker/docker-compose.healthcheck.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,22 @@ services:
]
<<: *settings

ubx:
healthcheck:
test: [ "CMD", "bash", "-c", "
timeout 30 tcpdump -i any -c 1 tcp src port ${SOCAT_BRIDGE_PORT:?empty or not set} > /tmp/tcp_check.log 2>&1 &&
grep -q 'TCP' /tmp/tcp_check.log"
]
<<: *settings

nmea:
healthcheck:
test: [ "CMD", "bash", "-c", "
timeout 30 tcpdump -i any -c 1 tcp src port ${SOCAT_BRIDGE_PORT:?empty or not set} > /tmp/tcp_check.log 2>&1 &&
grep -q 'TCP' /tmp/tcp_check.log"
]
<<: *settings

mavros:
healthcheck:
test: ["CMD", "bash", "-c", "
Expand Down
14 changes: 14 additions & 0 deletions docker/docker-compose.labels.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,20 @@ services:
homepage.name: micro-ROS agent
homepage.description: uORB to ROS (PX4) middleware

ubx:
labels:
<<: *labels
homepage.group: Middleware services
homepage.name: UBX agent
homepage.description: UBX to ROS middleware

nmea:
labels:
<<: *labels
homepage.group: Middleware services
homepage.name: NMEA ROS to serial bridge
homepage.description: Publishes ROS NMEA sentences to serial port

qgc:
labels:
<<: *labels
Expand Down
19 changes: 19 additions & 0 deletions docker/docker-compose.networking.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,24 @@ services:
environment:
UXRCE_DDS_PRT: ${UXRCE_DDS_PRT:?empty or not set}

ubx:
networks:
- dds
environment:
SOCAT_BRIDGE_PORT: ${SOCAT_BRIDGE_PORT:?empty or not set}
GISNAV_FCU_URL: ${GISNAV_FCU_URL:?empty or not set} # todo TCP bridge only for simulation?
extra_hosts:
- "host.docker.internal:host-gateway" # for socat

nmea:
networks:
- dds
environment:
SOCAT_BRIDGE_PORT: ${SOCAT_BRIDGE_PORT:?empty or not set}
GISNAV_FCU_URL: ${GISNAV_FCU_URL:?empty or not set} # todo TCP bridge only for simulation?
extra_hosts:
- "host.docker.internal:host-gateway" # for socat

qgc:
network_mode: host

Expand All @@ -38,6 +56,7 @@ services:
network_mode: host
environment:
UXRCE_DDS_PRT: ${UXRCE_DDS_PRT:?empty or not set}
SOCAT_BRIDGE_PORT: ${SOCAT_BRIDGE_PORT:?empty or not set}
GISNAV_COMPANION_HOST: ${GISNAV_COMPANION_HOST:?empty or not set}
GISNAV_CMP_MAVROS_BIND_PORT: ${GISNAV_CMP_MAVROS_BIND_PORT:?empty or not set}
extra_hosts:
Expand Down
12 changes: 12 additions & 0 deletions docker/docker-compose.ros.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,15 @@ services:
args:
ROS_DISTRO: humble
<<: *ros

ubx:
build:
args:
ROS_DISTRO: humble
<<: *ros

nmea:
build:
args:
ROS_DISTRO: humble
<<: *ros
8 changes: 8 additions & 0 deletions docker/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@ services:
build:
context: gscam

ubx:
build:
context: ubx

nmea:
build:
context: nmea

autoheal:
image: willfarrell/autoheal
restart: always
Expand Down
Loading