ROS 2 and ArduPilot speak different languages: ROS 2 uses DDS pub/sub with topic names and ROS message types; ArduPilot uses MAVLink, a binary protocol with numbered message IDs. The bridge between them is MAVROS — a ROS 2 node that subscribes to MAVLink streams on one side and publishes/subscribes ROS 2 topics on the other. Every command from the ROS 2 stack hits MAVROS first, gets translated to a MAVLink message, and arrives at ArduPilot. Every status update from ArduPilot makes the same trip in reverse.
This page is a placeholder for the synchronization-and-reliability details. The conceptual underpinning is on MAVROS theory, which covers what MAVLink is, how the translation layer works, and which topics exist on the ROS 2 side. The rules you actually have to follow to avoid getting yourself disarmed are on setpoint vs takeoff. And for the latency picture, ROS 2 latency tuning has the QoS tables that govern how reliably each topic actually arrives.
The two non-obvious sync issues we’ve hit:
- Stream rates. ArduPilot streams MAVLink messages at configurable rates (
SR0_*parameters). Default rates are conservative; if you want 10 Hz/mavros/stateyou have to bumpSR0_EXTRA1or accept ~2 Hz default. If your FSM polls at a rate that exceeds the stream rate, every read returns the same stale data. - Service vs topic for commands. Arming is a service call (
/mavros/cmd/arming); position setpoints are a topic publish (/mavros/setpoint_position/local). Mixing these up — publishing arm-as-a-topic, calling setpoint-as-a-service — silently fails with no error.
Where to go next
- MAVROS theory — the conceptual foundation
- Setpoint vs takeoff rules — the four hard-earned rules
- Takeoff node v7 — event-driven FSM that handles real-world sync failures