2023-03-12 23:18:29 -03:00
# Testing with DDS/micro-Ros
## Architecture
2023-09-05 10:52:38 -03:00
Ardupilot contains the DDS Client library, which can run as SITL. Then, the DDS application runs a ROS 2 node, an eProsima Integration Service, and the MicroXRCE Agent. The two systems communicate over serial or UDP.
2023-05-23 12:54:29 -03:00
```mermaid
---
title: UDP Loopback
---
graph LR
subgraph Linux Computer
subgraph Ardupilot SITL
veh[sim_vehicle.py] < -- > xrceClient[EProsima Micro XRCE DDS Client]
xrceClient < -- > port1[udp:2019]
end
subgraph DDS Application
2023-09-05 10:52:38 -03:00
ros[ROS 2 Node] < -- > agent[Micro ROS Agent]
2023-05-23 12:54:29 -03:00
agent < -- > port1[udp:2019]
end
loopback
end
```
2023-03-12 23:18:29 -03:00
```mermaid
---
title: Hardware Serial Port Loopback
---
graph LR
subgraph Linux Computer
subgraph Ardupilot SITL
veh[sim_vehicle.py] < -- > xrceClient[EProsima Micro XRCE DDS Client]
xrceClient < -- > port1[devUSB1]
end
subgraph DDS Application
2023-09-05 10:52:38 -03:00
ros[ROS 2 Node] < -- > agent[Micro ROS Agent]
2023-03-12 23:18:29 -03:00
agent < -- > port2[devUSB2]
end
port1 < -- > port2
end
```
## Installing Build Dependencies
While DDS support in Ardupilot is mostly through git submodules, another tool needs to be available on your system: Micro XRCE DDS Gen.
2024-08-24 16:29:40 -03:00
Follow the wiki [here ](https://ardupilot.org/dev/docs/ros2.html#installation-ubuntu ) to set up your environment.
2023-03-12 23:18:29 -03:00
2023-05-23 12:54:29 -03:00
### Serial Only: Set up serial for SITL with DDS
2023-03-12 23:18:29 -03:00
2023-03-27 11:05:51 -03:00
On Linux, creating a virtual serial port will be necessary to use serial in SITL, because of that install socat.
2023-03-12 23:18:29 -03:00
```
sudo apt-get update
sudo apt-get install socat
```
2023-03-27 11:05:51 -03:00
## Setup ardupilot for SITL with DDS
2023-03-12 23:18:29 -03:00
Set up your [SITL ](https://ardupilot.org/dev/docs/setting-up-sitl-on-linux.html ).
2023-05-23 12:54:29 -03:00
Run the simulator with the following command. If using UDP, the only parameter you need to set it `DDS_ENABLE` .
2023-08-10 23:18:56 -03:00
| Name | Description | Default |
| - | - | - |
| DDS_ENABLE | Set to 1 to enable DDS, or 0 to disable | 1 |
| SERIAL1_BAUD | The serial baud rate for DDS | 57 |
| SERIAL1_PROTOCOL | Set this to 45 to use DDS on the serial port | 0 |
2024-09-20 02:55:16 -03:00
2023-09-05 10:52:38 -03:00
```console
2023-03-12 23:18:29 -03:00
# Wipe params till you see "AP: ArduPilot Ready"
# Select your favorite vehicle type
2023-05-23 12:54:29 -03:00
sim_vehicle.py -w -v ArduPlane --console -DG --enable-dds
2023-03-12 23:18:29 -03:00
2023-08-10 23:18:56 -03:00
# Only set this for Serial, which means 115200 baud
2023-03-12 23:18:29 -03:00
param set SERIAL1_BAUD 115
# See libraries/AP_SerialManager/AP_SerialManager.h AP_SerialManager SerialProtocol_DDS_XRCE
param set SERIAL1_PROTOCOL 45
```
2023-08-10 23:18:56 -03:00
DDS is currently enabled by default, if it's part of the build. To disable it, run the following and reboot the simulator.
```
param set DDS_ENABLE 0
REBOOT
```
2023-03-27 11:05:51 -03:00
## Setup ROS 2 and micro-ROS
2023-03-12 23:18:29 -03:00
Follow the steps to use the microROS Agent
- Install ROS Humble (as described here)
- https://docs.ros.org/en/humble/Installation/Ubuntu-Install-Debians.html
2023-04-18 14:23:03 -03:00
- Install geographic_msgs
2023-09-05 10:52:38 -03:00
```console
2023-04-18 14:23:03 -03:00
sudo apt install ros-humble-geographic-msgs
```
2023-10-11 04:41:52 -03:00
- Install and run the microROS agent (as described here). Make sure to use the `humble` branch.
2023-03-27 11:05:51 -03:00
- Follow [the instructions ](https://micro.ros.org/docs/tutorials/core/first_application_linux/ ) for the following:
2023-03-12 23:18:29 -03:00
2023-03-27 11:05:51 -03:00
- Do "Installing ROS 2 and the micro-ROS build system"
- Skip the docker run command, build it locally instead
- Skip "Creating a new firmware workspace"
- Skip "Building the firmware"
- Do "Creating the micro-ROS agent"
- Source your ROS workspace
2023-03-12 23:18:29 -03:00
2023-09-05 10:52:38 -03:00
## Using the ROS 2 CLI to Read Ardupilot Data
2023-03-12 23:18:29 -03:00
2023-03-27 11:05:51 -03:00
After your setups are complete, do the following:
2023-09-05 10:52:38 -03:00
- Source the ROS 2 installation
```console
2023-03-26 13:07:20 -03:00
source /opt/ros/humble/setup.bash
```
2023-05-23 12:54:29 -03:00
Next, follow the associated section for your chosen transport, and finally you can use the ROS 2 CLI.
### UDP (recommended for SITL)
- Run the microROS agent
2023-09-05 10:52:38 -03:00
```console
2023-05-23 12:54:29 -03:00
cd ardupilot/libraries/AP_DDS
2024-05-23 10:34:27 -03:00
ros2 run micro_ros_agent micro_ros_agent udp4 -p 2019
2023-05-23 12:54:29 -03:00
```
- Run SITL (remember to kill any terminals running ardupilot SITL beforehand)
2023-09-05 10:52:38 -03:00
```console
2023-05-23 12:54:29 -03:00
sim_vehicle.py -v ArduPlane -DG --console --enable-dds
```
### Serial
2023-03-27 11:05:51 -03:00
- Start a virtual serial port with socat. Take note of the two `/dev/pts/*` ports. If yours are different, substitute as needed.
2023-09-05 10:52:38 -03:00
```console
2023-03-27 11:05:51 -03:00
socat -d -d pty,raw,echo=0 pty,raw,echo=0
>>> 2023/02/21 05:26:06 socat[334] N PTY is /dev/pts/1
>>> 2023/02/21 05:26:06 socat[334] N PTY is /dev/pts/2
>>> 2023/02/21 05:26:06 socat[334] N starting data transfer loop with FDs [5,5] and [7,7]
```
2023-03-26 13:07:20 -03:00
- Run the microROS agent
2023-09-05 10:52:38 -03:00
```console
2023-03-26 13:07:20 -03:00
cd ardupilot/libraries/AP_DDS
2023-05-23 12:54:29 -03:00
# assuming we are using tty/pts/2 for DDS Application
2024-05-23 10:34:27 -03:00
ros2 run micro_ros_agent micro_ros_agent serial -b 115200 -D /dev/pts/2
2023-03-26 13:07:20 -03:00
```
2023-03-27 11:05:51 -03:00
- Run SITL (remember to kill any terminals running ardupilot SITL beforehand)
2023-09-05 10:52:38 -03:00
```console
2023-05-23 12:54:29 -03:00
# assuming we are using /dev/pts/1 for Ardupilot SITL
2023-12-11 15:21:14 -04:00
sim_vehicle.py -v ArduPlane -DG --console --enable-dds -A "--serial1=uart:/dev/pts/1"
2023-03-26 13:07:20 -03:00
```
2023-05-23 12:54:29 -03:00
## Use ROS 2 CLI
2023-09-05 10:52:38 -03:00
You should be able to see the agent here and view the data output.
2023-03-12 23:18:29 -03:00
2023-09-05 10:52:38 -03:00
```bash
$ ros2 node list
2023-09-29 13:12:38 -03:00
/ardupilot_dds
2023-09-05 10:52:38 -03:00
```
```bash
2024-03-06 14:34:40 -04:00
$ ros2 topic list -v
2023-09-05 10:52:38 -03:00
Published topics:
2024-10-08 12:58:31 -03:00
* /ap/airspeed [geometry_msgs/msg/Vector3] 1 publisher
2024-10-02 19:10:37 -03:00
* /ap/battery [sensor_msgs/msg/BatteryState] 1 publisher
2023-09-05 10:52:38 -03:00
* /ap/clock [rosgraph_msgs/msg/Clock] 1 publisher
* /ap/geopose/filtered [geographic_msgs/msg/GeoPoseStamped] 1 publisher
2024-03-06 14:34:40 -04:00
* /ap/gps_global_origin/filtered [geographic_msgs/msg/GeoPointStamped] 1 publisher
* /ap/imu/experimental/data [sensor_msgs/msg/Imu] 1 publisher
2024-10-20 21:42:39 -03:00
* /ap/navsat [sensor_msgs/msg/NavSatFix] 1 publisher
2023-09-05 10:52:38 -03:00
* /ap/pose/filtered [geometry_msgs/msg/PoseStamped] 1 publisher
* /ap/tf_static [tf2_msgs/msg/TFMessage] 1 publisher
* /ap/time [builtin_interfaces/msg/Time] 1 publisher
* /ap/twist/filtered [geometry_msgs/msg/TwistStamped] 1 publisher
* /parameter_events [rcl_interfaces/msg/ParameterEvent] 1 publisher
* /rosout [rcl_interfaces/msg/Log] 1 publisher
Subscribed topics:
2023-12-07 02:49:01 -04:00
* /ap/cmd_gps_pose [ardupilot_msgs/msg/GlobalPosition] 1 subscriber
2023-09-05 10:52:38 -03:00
* /ap/cmd_vel [geometry_msgs/msg/TwistStamped] 1 subscriber
* /ap/joy [sensor_msgs/msg/Joy] 1 subscriber
2023-10-06 17:42:28 -03:00
* /ap/tf [tf2_msgs/msg/TFMessage] 1 subscriber
2023-09-05 10:52:38 -03:00
```
```bash
$ ros2 topic hz /ap/time
average rate: 50.115
min: 0.012s max: 0.024s std dev: 0.00328s window: 52
```
```bash
$ ros2 topic echo /ap/time
sec: 1678668735
nanosec: 729410000
```
```bash
$ ros2 service list
/ap/arm_motors
2023-08-19 10:22:41 -03:00
/ap/mode_switch
2024-10-29 12:21:16 -03:00
/ap/prearm_check
2024-11-21 04:00:05 -04:00
/ap/experimental/takeoff
2023-09-05 10:52:38 -03:00
---
```
2023-04-05 03:16:36 -03:00
2023-09-05 10:52:38 -03:00
The static transforms for enabled sensors are also published, and can be received like so:
2023-06-27 03:46:06 -03:00
2023-09-05 10:52:38 -03:00
```bash
ros2 topic echo /ap/tf_static --qos-depth 1 --qos-history keep_last --qos-reliability reliable --qos-durability transient_local --once
```
2023-06-27 03:46:06 -03:00
2023-09-05 10:52:38 -03:00
In order to consume the transforms, it's highly recommended to [create and run a transform broadcaster in ROS 2 ](https://docs.ros.org/en/humble/Concepts/About-Tf2.html#tutorials ).
2023-06-27 03:46:06 -03:00
2023-09-05 10:52:38 -03:00
## Using ROS 2 services
2023-06-27 03:46:06 -03:00
2024-09-20 02:55:16 -03:00
The `AP_DDS` library exposes services which are automatically mapped to ROS 2
2023-09-05 10:52:38 -03:00
services using appropriate naming conventions for topics and message and service
types. An earlier version of `AP_DDS` required the use of the eProsima
[Integration Service ](https://github.com/eProsima/Integration-Service ) to map
the request / reply topics from DDS to ROS 2, but this is no longer required.
2023-06-27 03:46:06 -03:00
2023-09-05 10:52:38 -03:00
List the available services:
```bash
$ ros2 service list -t
/ap/arm_motors [ardupilot_msgs/srv/ArmMotors]
2023-08-19 10:22:41 -03:00
/ap/mode_switch [ardupilot_msgs/srv/ModeSwitch]
2024-10-29 12:21:16 -03:00
/ap/prearm_check [std_srvs/srv/Trigger]
2024-11-21 04:00:05 -04:00
/ap/experimental/takeoff [ardupilot_msgs/srv/Takeoff]
2023-09-05 10:52:38 -03:00
```
Call the arm motors service:
```bash
$ ros2 service call /ap/arm_motors ardupilot_msgs/srv/ArmMotors "{arm: True}"
requester: making request: ardupilot_msgs.srv.ArmMotors_Request(arm=True)
2023-04-17 21:47:22 -03:00
2023-09-05 10:52:38 -03:00
response:
ardupilot_msgs.srv.ArmMotors_Response(result=True)
```
2023-08-19 10:22:41 -03:00
Call the mode switch service:
```bash
$ ros2 service call /ap/mode_switch ardupilot_msgs/srv/ModeSwitch "{mode: 4}"
requester: making request: ardupilot_msgs.srv.ModeSwitch_Request(mode=4)
response:
ardupilot_msgs.srv.ModeSwitch_Response(status=True, curr_mode=4)
```
2024-09-20 02:55:16 -03:00
2024-10-29 12:21:16 -03:00
Call the prearm check service:
```bash
$ ros2 service call /ap/prearm_check std_srvs/srv/Trigger
requester: making request: std_srvs.srv.Trigger_Request()
response:
std_srvs.srv.Trigger_Response(success=False, message='Vehicle is Not Armable')
or
std_srvs.srv.Trigger_Response(success=True, message='Vehicle is Armable')
```
2024-11-21 04:00:05 -04:00
Call the takeoff service:
```bash
$ ros2 service call /ap/experimental/takeoff ardupilot_msgs/srv/Takeoff "{alt: 10.5}"
requester: making request: ardupilot_msgs.srv.Takeoff_Request(alt=10.5)
response:
ardupilot_msgs.srv.Takeoff_Response(status=True)
```
2024-09-20 02:55:16 -03:00
## Commanding using ROS 2 Topics
The following topic can be used to control the vehicle.
- `/ap/joy` (type `sensor_msgs/msg/Joy` ): overrides a maximum of 8 RC channels,
at least 4 axes must be sent. Values are clamped between -1.0 and 1.0.
Use `NaN` to disable the override of a single channel.
A channel defaults back to RC after 1 second of not receiving commands.
```bash
ros2 topic pub /ap/joy sensor_msgs/msg/Joy "{axes: [0.0, 0.0, 0.0, 0.0]}"
publisher: beginning loop
publishing #1: sensor_msgs.msg.Joy(header=std_msgs.msg.Header(stamp=builtin_interfaces.msg.Time(sec=0, nanosec=0), frame_id=''), axes=[0.0, 0.0, 0.0, 0.0], buttons=[])
```
- `/ap/cmd_gps_pose` (type `ardupilot_msgs/msg/GlobalPosition` ): sends
a waypoint to head to when the selected mode is GUIDED.
```bash
ros2 topic pub /ap/cmd_gps_pose ardupilot_msgs/msg/GlobalPosition "{latitude: 34, longitude: 118, altitude: 1000}"
publisher: beginning loop
publishing #1: ardupilot_msgs.msg.GlobalPosition(header=std_msgs.msg.Header(stamp=builtin_interfaces.msg.Time(sec=0, nanosec=0), frame_id=''), coordinate_frame=0, type_mask=0, latitude=34.0, longitude=118.0, altitude=1000.0, velocity=geometry_msgs.msg.Twist(linear=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=0.0), angular=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=0.0)), acceleration_or_force=geometry_msgs.msg.Twist(linear=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=0.0), angular=geometry_msgs.msg.Vector3(x=0.0, y=0.0, z=0.0)), yaw=0.0)
```
2024-11-21 04:00:05 -04:00
2023-09-05 10:52:38 -03:00
## Contributing to `AP_DDS` library
2023-04-17 21:47:22 -03:00
### Adding DDS messages to Ardupilot
2023-03-12 23:18:29 -03:00
Unlike the use of ROS 2 `.msg` files, since Ardupilot supports native DDS, the message files follow [OMG IDL DDS v4.2 ](https://www.omg.org/spec/IDL/4.2/PDF ).
2023-04-05 10:23:19 -03:00
This package is intended to work with any `.idl` file complying with those extensions.
2023-03-12 23:18:29 -03:00
2023-05-23 12:54:29 -03:00
Over time, these restrictions will ideally go away.
2023-03-12 23:18:29 -03:00
2023-09-05 10:52:38 -03:00
To get a new IDL file from ROS 2, follow this process:
```bash
2023-03-12 23:18:29 -03:00
cd ardupilot
source /opt/ros/humble/setup.bash
2023-09-05 10:52:38 -03:00
2023-03-12 23:18:29 -03:00
# Find the IDL file
find /opt/ros/$ROS_DISTRO -type f -wholename \*builtin_interfaces/msg/Time.idl
2023-09-05 10:52:38 -03:00
2023-04-05 10:23:19 -03:00
# Create the directory in the source tree if it doesn't exist similar to the one found in the ros directory
mkdir -p libraries/AP_DDS/Idl/builtin_interfaces/msg/
2023-09-05 10:52:38 -03:00
2023-03-12 23:18:29 -03:00
# Copy the IDL
2023-04-05 10:23:19 -03:00
cp /opt/ros/humble/share/builtin_interfaces/msg/Time.idl libraries/AP_DDS/Idl/builtin_interfaces/msg/
2023-09-05 10:52:38 -03:00
2023-05-23 12:54:29 -03:00
# Build the code again with the `--enable-dds` flag as described above
2023-03-12 23:18:29 -03:00
```
2023-04-17 21:47:22 -03:00
2023-12-07 02:49:01 -04:00
If the message is custom for ardupilot, first create the ROS message in `Tools/ros2/ardupilot_msgs/msg/GlobalPosition.msg` .
Then, build ardupilot_msgs with colcon.
Finally, copy the IDL folder from the install directory into the source tree.
2024-05-23 10:34:27 -03:00
### Rules for adding topics and services
2023-09-05 10:52:38 -03:00
Topics and services available from `AP_DDS` are automatically mapped into ROS 2
2024-05-23 10:34:27 -03:00
provided a few rules are followed when defining the entries in the
topic and service tables.
2023-09-05 10:52:38 -03:00
#### ROS 2 message and service interface types
2023-10-11 04:41:52 -03:00
ROS 2 message and interface definitions are mangled by the `rosidl_adapter` when
2023-09-05 10:52:38 -03:00
mapping from ROS 2 to DDS to avoid naming conflicts in the C/C++ libraries.
The ROS 2 object `namespace::Struct` is mangled to `namespace::dds_::Struct_`
2024-09-20 02:55:16 -03:00
for DDS. The table below provides some example mappings:
2023-09-05 10:52:38 -03:00
| ROS 2 | DDS |
| --- | --- |
| `rosgraph_msgs::msg::Clock` | `rosgraph_msgs::msg::dds_::Clock_` |
| `sensor_msgs::msg::NavSatFix` | `sensor_msgs::msg::dds_::NavSatFix_` |
| `ardupilot_msgs::srv::ArmMotors_Request` | `ardupilot_msgs::srv::dds_::ArmMotors_Request_` |
| `ardupilot_msgs::srv::ArmMotors_Response` | `ardupilot_msgs::srv::dds_::ArmMotors_Response_` |
Note that a service interface always requires a Request / Response pair.
#### ROS 2 topic and service names
The ROS 2 design article: [Topic and Service name mapping to DDS ](https://design.ros2.org/articles/topic_and_service_names.html ) describes the mapping of ROS 2 topic and service
2023-11-17 22:20:28 -04:00
names to DDS. Each ROS 2 subsystem is provided a prefix when mapped to DDS.
2023-09-05 10:52:38 -03:00
The request / response pair for services require an additional suffix.
| ROS 2 subsystem | DDS Prefix | DDS Suffix |
| --- | --- | --- |
| topics | rt/ | |
| service request | rq/ | Request |
| service response | rr/ | Reply |
| service | rs/ | |
| parameter | rp/ | |
| action | ra/ | |
2024-09-20 02:55:16 -03:00
The table below provides example mappings for topics and services
2023-09-05 10:52:38 -03:00
| ROS 2 | DDS |
| --- | --- |
| ap/clock | rt/ap/clock |
2024-10-20 21:42:39 -03:00
| ap/navsat | rt/ap/navsat |
2023-09-05 10:52:38 -03:00
| ap/arm_motors | rq/ap/arm_motorsRequest, rr/ap/arm_motorsReply |
2024-05-23 10:34:27 -03:00
Refer to existing mappings in [`AP_DDS_Topic_Table` ](https://github.com/ArduPilot/ardupilot/blob/master/libraries/AP_DDS/AP_DDS_Topic_Table.h )
and [`AP_DDS_Service_Table` ](https://github.com/ArduPilot/ardupilot/blob/master/libraries/AP_DDS/AP_DDS_Service_Table.h )
for additional details.
2023-09-05 10:52:38 -03:00
2023-04-17 21:47:22 -03:00
### Development Requirements
Astyle is used to format the C++ code in AP_DDS. This is required for CI to pass the build.
2024-11-08 16:07:20 -04:00
To run the automated formatter, run:
2023-04-17 21:47:22 -03:00
2023-09-05 10:52:38 -03:00
```bash
2024-11-08 16:07:20 -04:00
./Tools/scripts/run_astyle.py
2023-04-17 21:47:22 -03:00
```
2023-05-23 12:54:29 -03:00
Pre-commit is used for other things like formatting python and XML code.
2023-04-17 21:47:22 -03:00
This will run the tools automatically when you commit. If there are changes, just add them back your staging index and commit again.
1. Install [pre-commit ](https://pre-commit.com/#installation ) python package.
1. Install ArduPilot's hooks in the root of the repo, then commit like normal
2023-09-05 10:52:38 -03:00
```bash
2023-04-17 21:47:22 -03:00
cd ardupilot
pre-commit install
git commit
```
2023-11-21 20:46:30 -04:00
## Testing DDS on Hardware
### With Serial
The easiest way to test DDS is to make use of some boards providing two serial interfaces over USB such as the Pixhawk 6X.
The [Pixhawk6X/hwdef.dat ](../AP_HAL_ChibiOS/hwdef/Pixhawk6X/hwdef.dat ) file has this info.
```
SERIAL_ORDER OTG1 UART7 UART5 USART1 UART8 USART2 UART4 USART3 OTG2
```
For example, build, flash, and set up OTG2 for DDS
```bash
./waf configure --board Pixhawk6X --enable-dds
./waf plane --upload
mavproxy.py --console
param set DDS_ENABLE 1
# Check the hwdef file for which port is OTG2
param set SERIAL8_PROTOCOL 45
param set SERIAL8_BAUD 115
reboot
```
Then run the Micro ROS agent
```bash
cd /path/to/ros2_ws
source install/setup.bash
cd src/ardupilot/libraries/AP_DDS
2024-05-23 10:34:27 -03:00
ros2 run micro_ros_agent micro_ros_agent serial -b 115200 -D /dev/serial/by-id/usb-ArduPilot_Pixhawk6X_210028000151323131373139-if02
2023-11-21 20:46:30 -04:00
```
If connection fails, instead of running the Micro ROS agent, debug the stream
```bash
python3 -m serial.tools.miniterm /dev/serial/by-id/usb-ArduPilot_Pixhawk6X_210028000151323131373139-if02 115200 --echo --encoding hexlify
```
The same steps can be done for physical serial ports once the above works to isolate software and hardware issues.