28. starling-mavros

This image acts to bridge MAVLink communications to ROS2 topics. At present this is achieved by a ROS1/2 bridge and the ROS1 version of MAVROS. The ROS2 port of MAVROS is currently under development and we anticipate switching over in the future, eliminating the need for the ROS1/2 bridge.

28.1 Contents

28.2 Overview

The image is a wrapper around MAVROS, as such, most of the documentation for MAVROS is of use when working with this image. The image has both mavros and mavros-extras installed so all plugins should be available.

The published topics are namespaced to allow for running multiple vehicles on the same ROS network. By default, this namespace will be /vehicle_N, where N is the MAVLink system ID of the vehicle. MAVROS topics are published within this namespace, e.g. /vehicle_1/mavros/state.

The image has been setup to automatically configure itself in some scenarios:

  • Running on a vehicle
  • Running in Kubernetes

There are also some additional general nodes running in the background. In particular:

  • Emergency Stop listener on the /emergency_stop topic of type std_msgs/msg/Empty. It is hard-wired to forcefully disarm the vehicle (stop motors) for both PX4 and Ardupilot in simulation and reality.

28.3 Configuration Options

There are many configuration options available for this image to allow it to be used flexibly across different deployment scenarios. The most important of these are those relating to the vehicle and GCS connections, and MAVROS configuration. A full summary is given in the table below.

Name Default Value Description
MAVROS_FCU_CONN "udp" Protocol for autogenerated FCU URL
MAVROS_FCU_IP "" IP for autogenerated FCU_URL
MAVROS_FCU_UDP_BASE "14830" Base port for autogenerated FCU_URL
MAVROS_TGT_SYSTEM "auto" Target system ID, if set to a number, this will override the automatic behaviour
PX4_INSTANCE_BASE 0 Base instance for autogenerated instance matching
MAVROS_TGT_FIRMWARE "px4" Firmware profile used by MAVROS. Only other valid value currently is "apm"
MAVROS_GCS_URL "udp-pb://@:14550" MAVROS URL for ground control station connection
MAVROS_FCU_URL {unset} MAVROS URL for FCU connection. Set to override automatic behaviour
VEHICLE_NAMESPACE {unset} Namespace for mavros topics. Set to override default value of vehicle_${TGT_SYSTEM}
MAVROS_PLUGINLISTS_PATH "/mavros_pluginlists_px4.yaml" Path for MAVROS pluginlists file
MAVROS_CONFIG_PATH "/mavros_config_px4.yaml" Path for initial MAVROS configuration file
MAVROS_MOD_CONFIG_PATH "/mavros_config_mod.yaml" Path for modified MAVROS config to be written to
BRIDGE_CONFIG_PATH "/bridge_config.yaml" Path for initial bridge config file
BRIDGE_MOD_CONFIG_PATH "/bridge_config_mod.yaml" Path for modified bridge config to be written to
BRIDGE_LAUNCH_DELAY 2.0 Time delay in seconds between starting ROS1 mavros and the ROS1-2 bridge. Increasing this value reduces the chance of a race condition causing mavros failure due to the bridge being unable to read ros1 parameters. See this issue for more details. Recommendation is to increase the value to 10 seconds if this occurs.

28.3.1 Configuring the Connection

MAVROS is told to connect to a MAVLink source with a URL. This URL can be configured in a number of ways. The most straightforward is to simply set the MAVROS_FCU_URL environment variable. This will override any other behaviour.

docker run -e MAVROS_FCU_URL=serial:///dev/ttyUSB0:115200 uobflightlabstarling/starling-mavros

When setting MAVROS_FCU_URL directly, note that a query string (e.g. ?ids=n,240) will be added during launch. You need to ensure that your input for MAVROS_FCU_URL supports this syntax. Of particular note is the need for a trailing / in most formats, but not for the serial:// format. Also note that the plain file format does not support this. See the MAVROS docs for more information on URL formats.

MAVROS_FCU_URL is can also be set automatically by the container depending on its environment. If there is a vehicle.config file mounted in the image, the value of VEHICLE_FCU_URL from that file will be used as the fcu_url. This is especially useful when deploying the container onto physical vehicles. The same warning about trailing slashes above goes for the value put in vehicle.config.

If there is no vehicle.config file, the image will configure itself based on the values of MAVROS_FCU_CONN, MAVROS_FCU_IP and MAVROS_FCU_UDP_BASE. An additional parameter, INSTANCE is also used in the construction of the URL. This is generated based on the container hostname and is intended for use in Kubernetes deployments to distinguish multiple instances. PX4_INSTANCE_BASE can be used to offset the fcu_url will be constructed as below:


With all values at default, this ends up as:


28.3.2 Configuring the Target System

Another important configuration option is the target system ID. This controls the target system that MAVROS sends in some messages. As for the fcu_url, the value can be explicitly overridden, this time using the MAVROS_TGT_SYSTEM environment variable. Setting this will overrise all other values. If it is set to an invalid system ID, MAVROS will be set to use a target ID of 1.

If the environment variable is left at its default value of auto, a similar flow to the fcu_url occurs: if a vehicle.config file exists, the value of VEHICLE_MAVLINK_SYSID from that file will be used. Otherwise, the value is autogenerated based on the INSTANCE parameter derived from the container hostname. Note that the INSTANCE number is 0-indexed, while MAVLink system IDs start at 1. Therefore, the system ID is set to one more than the INSTANCE.

28.3.3 Configuring the MAVROS Configuration

Two sets of config.yaml and pluginlists.yaml files are installed in the root directory to provide alternatives for PX4 and ArduPilot autopilots. These are named: /mavros_config_px4.yaml and /mavros_pluginlists_px4.yaml for the PX4 versions and /mavros_config_ap.yaml and /mavros_pluginlists_ap.yaml for the ArduPilot versions.

The easiest way to choose between the two is to set the MAVROS_CONFIG_PATH and MAVROS_PLUGINLISTS_PATH environment variables. By default these point to the PX4 versions. To use the ArduPilot versions set both variables as below:

docker run -e MAVROS_CONFIG_PATH=/mavros_config_ap.yaml -e MAVROS_PLUGINLISTS_PATH=/mavros_pluginlists_ap.yaml ...

It is also possible to mount alternative configurations into the image and use the environment variables to configure MAVROS with them.

TODO: Example of mounted configuration

28.4 Deployments

28.4.1 Running on a vehicle

If the container is running on a drone, it expects to be able to find the /etc/starling/vehicle.config file. This file contains some information that MAVROS needs to be able to communicate with the flight controller. An example vehicle.config file is included below.

Note that the extended form of the serial URL is required for MAVROS's target "query string" to work.


28.4.2 Running under Kubernetes StatefulSet

When running as part of a Kubernetes StatefulSet, each pod's hostname has a trailing ordinal, of the form: HOSTNAME-N. The setup script parses the ordinal of its containing pod from the hostname and uses this, in combination with the PX4_INSTANCE_BASE variable to determine the INSTANCE parameter. As outlined above, this is used to set up the ports and the system ID. By default, these are configured to match those generated by a PX4 SITL instance set up with the same ordinal. If the setup script fails to get the ordinal from the hostname, it will attempt to connect to a PX4 SITL with PX4_INSTANCE=0.


MAVROS_TGT_SYSTEM will end up as $((INSTANCE + 1))

28.4.3 Running isolated

Default values will be used, equivalent to the Kubernetes case with ORDINAL=0

28.5 Implementation Details

28.5.1 Build Process

To ensure support for custom message types, ros1_bridge needs to be built from source with the messages types to be bridged available in both ROS1 and ROS2. The Dockerfile first installs MAVROS for ROS1 and the MAVROS messages for ROS2. There are some additional steps to complete the installation of MAVROS under ROS1. Following this, the bridge is built. This takes a long time (~20min) and gives little output, but have faith!

28.5.2 Entrypoint

The entrypoint to the container is the ros_entrypoint.sh script. This script sources the environment setup files for both the ROS1 and ROS2 environments. It then sources the environment setup file for the bridge, and finally the mavros_setup.sh file. This file contains the logic that sets up MAVROS in a specific way based on both environment variables and files potentially mounted in the image.

The first part of this is checking for the existance of the /stc/starling/vehicle.config file. If this file exists, it is assumed that the container is running on a real vehicle. In this case, the file is sourced and values for the MAVLink system ID, vehicle name, FCU URL, and firmware type are obtained.

The next phase is determining the appropriate target system ID. This is configured by the

Once the setup script has run, the default behaviour is to launch the mavros_bridge.launch.xml file. This behaviour should be usable in almost all cases. This is a ROS2 launch file. It instructs ros2 launch to run the ros1_bridge node and an instance of ROS1's roslaunch. This in turn launches the ROS1 mavros.launch file, which contains instructions to run the MAVROS node.

The ROS2 mavros_bridge.launch.xml script defines a set of arguments to enable configuration of the MAVROS node. These are ususally filled by the environment variables defined above. If the configurability provided here is insufficient, the image can be run with a different command.

28.5.3 Names

MAVROS has a set of frame names that are embedded in its config file. To enable the use of multiple vehicles, vehicle-specific frames need to be made unique. To that end a bunch of sedding happens at the end of mavros_setup.sh to modify the frame names before they are passed on to MAVROS.

A similar scenario occurs with the topic names for the parameter bridge. This is hopefully a short-term problem while MAVROS finishes its port to ROS2.

28.6 Advanced Topics

28.6.1 Adding additional MAVROS plugins

This should be possible by mounting a volume with your plugin into the container. Assuming ROS tools are able to find it, MAVROS should load the plugin (if directed by the pluginlists file).