From 66b07d82196c8adc835eb1880bccfd16c4c40ea1 Mon Sep 17 00:00:00 2001 From: chfriedrich98 <125505139+chfriedrich98@users.noreply.github.com> Date: Fri, 26 Sep 2025 02:33:35 +0200 Subject: [PATCH] Docs: Rover API (#25499) * docs: add RoverSetpointTypes * docs: add rover api * docs: remove rover offboard mavlink support * docs: fix broken links * Apply suggestion from @hamishwillee --------- Co-authored-by: Hamish Willee --- .../mode_requirements_diagram.png | Bin 49198 -> 24541 bytes .../ros2_modes_overview.svg | 2 +- .../rover_control_structure.svg | 4 + docs/en/SUMMARY.md | 1 + docs/en/flight_modes/offboard.md | 127 ++++++++++++------ docs/en/flight_modes_rover/api.md | 29 ++++ docs/en/frames_rover/index.md | 3 +- docs/en/releases/main.md | 1 + docs/en/ros2/offboard_control.md | 4 +- docs/en/ros2/px4_ros2_control_interface.md | 37 +++++ 10 files changed, 165 insertions(+), 43 deletions(-) create mode 100644 docs/assets/middleware/ros2/px4_ros2_interface_lib/rover_control_structure.svg create mode 100644 docs/en/flight_modes_rover/api.md diff --git a/docs/assets/middleware/ros2/px4_ros2_interface_lib/mode_requirements_diagram.png b/docs/assets/middleware/ros2/px4_ros2_interface_lib/mode_requirements_diagram.png index 29f3b0333dc83d11e04ba962fab00b337c3b76e4..1875eb83b99627b581cc78256cf12cb60a844c45 100644 GIT binary patch delta 11620 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 + \ No newline at end of file diff --git a/docs/assets/middleware/ros2/px4_ros2_interface_lib/rover_control_structure.svg b/docs/assets/middleware/ros2/px4_ros2_interface_lib/rover_control_structure.svg new file mode 100644 index 0000000000..ca6af7498f --- /dev/null +++ b/docs/assets/middleware/ros2/px4_ros2_interface_lib/rover_control_structure.svg @@ -0,0 +1,4 @@ + + + +
Position Setpoint
Speed Setpoint
Throttle Setpoint
Attitude Setpoint
Rate Setpoint
Steering Setpoint
Actuator Setpoints
Position Controller
Speed Controller
Attitude Controller
Rate Controller
Actuator Controller
Position Setpoint
position_ned
(Optional) start_ned
(Optional) cruising_speed
(Optional) arrival_speed
(Optional) yaw (mecanum only)
Speed Setpoint
speed_body_x
speed_body_y (mecanum only)
Attitude Setpoint
yaw_setpoint
Throttle Setpoint
throttle_body_x
throttle_body_x (mecanum only)
Rate Setpoint
yaw_rate_setpoint
Steering Setpoint
normalized_steering_setpoint
Publish
Subscribe
\ No newline at end of file diff --git a/docs/en/SUMMARY.md b/docs/en/SUMMARY.md index bf0a3ee1e1..c1913bf6f2 100644 --- a/docs/en/SUMMARY.md +++ b/docs/en/SUMMARY.md @@ -416,6 +416,7 @@ - [Attitude Tuning](config_rover/attitude_tuning.md) - [Velocity Tuning](config_rover/velocity_tuning.md) - [Position Tuning](config_rover/position_tuning.md) + - [Apps & API](flight_modes_rover/api.md) - [Complete Vehicles](complete_vehicles_rover/index.md) - [Aion Robotics R1](complete_vehicles_rover/aion_r1.md) - [Submarines (experimental)](frames_sub/index.md) diff --git a/docs/en/flight_modes/offboard.md b/docs/en/flight_modes/offboard.md index 6a8b74953b..58143c0605 100644 --- a/docs/en/flight_modes/offboard.md +++ b/docs/en/flight_modes/offboard.md @@ -44,7 +44,7 @@ The following ROS 2 messages and their particular fields and field values are al In addition to providing heartbeat functionality, `OffboardControlMode` has two other main purposes: 1. Controls the level of the [PX4 control architecture](../flight_stack/controller_diagrams.md) at which offboard setpoints must be injected, and disables the bypassed controllers. -1. Determines which valid estimates (position or velocity) are required, and also which setpoint messages should be used. +2. Determines which valid estimates (position or velocity) are required, and also which setpoint messages should be used. The `OffboardControlMode` message is defined as shown. @@ -62,6 +62,11 @@ bool thrust_and_torque bool direct_actuator ``` +::: warning +The following list shows the `OffboardControlMode` options for copter, fixed-wing, and VTOL. +For rovers see the [rover section](#rover). +::: + The fields are ordered in terms of priority such that `position` takes precedence over `velocity` and later fields, `velocity` takes precedence over `acceleration`, and so on. The first field that has a non-zero value (from top to bottom) defines what valid estimate is required in order to use offboard mode, and the setpoint message(s) that can be used. For example, if the `acceleration` field is the first non-zero value, then PX4 requires a valid `velocity estimate`, and the setpoint must be specified using the `TrajectorySetpoint` message. @@ -90,20 +95,93 @@ Before using offboard mode with ROS 2, please spend a few minutes understanding - Velocity setpoint (`velocity` different from `NaN` and `position` set to `NaN`). Non-`NaN` values acceleration are used as feedforward terms for the inner loop controllers. - Acceleration setpoint (`acceleration` different from `NaN` and `position` and `velocity` set to `NaN`) - - All values are interpreted in NED (Nord, East, Down) coordinate system and the units are \[m\], \[m/s\] and \[m/s^2\] for position, velocity and acceleration, respectively. + - All values are interpreted in NED (Nord, East, Down) coordinate system and the units are `[m]`, `[m/s]` and `[m/s^2]` for position, velocity and acceleration, respectively. - [px4_msgs::msg::VehicleAttitudeSetpoint](https://github.com/PX4/PX4-Autopilot/blob/main/msg/versioned/VehicleAttitudeSetpoint.msg) - The following input combination is supported: - quaternion `q_d` + thrust setpoint `thrust_body`. - Non-`NaN` values of `yaw_sp_move_rate` are used as feedforward terms expressed in Earth frame and in \[rad/s\]. + Non-`NaN` values of `yaw_sp_move_rate` are used as feedforward terms expressed in Earth frame and in `[rad/s]`. - - The quaternion represents the rotation between the drone body FRD (front, right, down) frame and the NED frame. The thrust is in the drone body FRD frame and expressed in normalized \[-1, 1\] values. + - The quaternion represents the rotation between the drone body FRD (front, right, down) frame and the NED frame. + The thrust is in the drone body FRD frame and expressed in normalized \[-1, 1\] values. - [px4_msgs::msg::VehicleRatesSetpoint](https://github.com/PX4/PX4-Autopilot/blob/main/msg/versioned/VehicleRatesSetpoint.msg) - The following input combination is supported: - `roll`, `pitch`, `yaw` and `thrust_body`. - - All the values are in the drone body FRD frame. The rates are in \[rad/s\] while thrust_body is normalized in \[-1, 1\]. + - All the values are in the drone body FRD frame. + The rates are in `[rad/s]` while thrust_body is normalized in `[-1, 1]`. + +### Rover + +Rover modules must set the control mode using `OffboardControlMode` and use the appropriate messages to configure the corresponding setpoints. +The approach is similar to other vehicle types, but the allowed control mode combinations and setpoints are different: + +| Category | Usage | Setpoints | +| ------------------------------------------------------------------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| (Recommended) [Rover Setpoints](#rover-setpoints) | General rover control | [RoverPositionSetpoint](../msg_docs/RoverPositionSetpoint.md), [RoverSpeedSetpoint](../msg_docs/RoverSpeedSetpoint.md), [RoverAttitudeSetpoint](../msg_docs/RoverAttitudeSetpoint.md), [RoverRateSetpoint](../msg_docs/RoverRateSetpoint.md), [RoverThrottleSetpoint](../msg_docs/RoverThrottleSetpoint.md), [RoverSteeringSetpoint](../msg_docs/RoverSteeringSetpoint.md) | +| [Actuator Setpoints](#actuator-setpoints) | Direct actuator control | [ActuatorMotors](../msg_docs/ActuatorMotors.md), [ActuatorServos](../msg_docs/ActuatorServos.md) | +| (Deprecated) [Trajectory Setpoint](#deprecated-trajectory-setpoint) | General vehicle control | [TrajectorySetpoint](../msg_docs/TrajectorySetpoint.md) | + +#### Rover Setpoints + +The rover modules use a hierarchical structure to propagate setpoints: + +![Rover Control Structure](../../assets/middleware/ros2/px4_ros2_interface_lib/rover_control_structure.svg) + +The "highest" setpoint that is provided will be used within the PX4 rover modules to generate the setpoints that are below it (overriding them!). +With this hierarchy there are clear rules for providing a valid control input: + +- Provide a position setpoint **or** +- One of the setpoints on the "left" (speed **or** throttle) **and** one of the setpoints on the "right" (attitude, rate **or** steering). + All combinations of "left" and "right" setpoints are valid. + +The following are all valid setpoint combinations and their respective control flags that must be set through [OffboardControlMode](../msg_docs/OffboardControlMode.md) (set all others to _false_). +Additionally, for some combinations we require certain setpoints to be published with `NAN` values so that the setpoints of interest are not overridden by the rover module (due to the hierarchy above). +✓ are the relevant setpoints we publish, and ✗ are the setpoint that need to be published with `NAN` values. + +| Setpoint Combination | Control Flag | [RoverPositionSetpoint](../msg_docs/RoverPositionSetpoint.md) | [RoverSpeedSetpoint](../msg_docs/RoverSpeedSetpoint.md) | [RoverThrottleSetpoint](../msg_docs/RoverThrottleSetpoint.md) | [RoverAttitudeSetpoint](../msg_docs/RoverAttitudeSetpoint.md) | [RoverRateSetpoint](../msg_docs/RoverRateSetpoint.md) | [RoverSteeringSetpoint](../msg_docs/RoverSteeringSetpoint.md) | +| -------------------- | ----------------- | ------------------------------------------------------------- | ------------------------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------------------- | ----------------------------------------------------- | ------------------------------------------------------------- | +| Position | position | ✓ | | | | | | +| Speed + Attitude | velocity | | ✓ | | ✓ | | | +| Speed + Rate | velocity | | ✓ | | ✗ | ✓ | | +| Speed + Steering | velocity | | ✓ | | ✗ | ✗ | ✓ | +| Throttle + Attitude | attitude | | | ✓ | ✓ | | | +| Throttle + Rate | body_rate | | | ✓ | | ✓ | | +| Throttle + Steering | thrust_and_torque | | | ✓ | | | ✓ | + +::: info +If you intend to use the rover setpoints, we recommend using the [PX4 ROS 2 Interface Library](../ros2/px4_ros2_interface_lib.md) instead since it simplifies the publishing of these setpoints. +::: + +#### Actuator Setpoints + +Instead of controlling the vehicle using position, speed, rate and other setpoints, you can directly control the motors and actuators using [ActuatorMotors](../msg_docs/ActuatorMotors.md) and [ActuatorServos](../msg_docs/ActuatorServos.md). +In [OffboardControlMode](../msg_docs/OffboardControlMode.md) set `direct_actuator` to _true_ and all other flags to _false_. + +::: info +This bypasses the rover modules including any limits on steering rates or accelerations and the inverse kinematics step. +We recommend using [RoverSteeringSetpoint](../msg_docs/RoverSteeringSetpoint.md) and [RoverThrottleSetpoint](../msg_docs/RoverThrottleSetpoint.md) instead for low level control (see [Rover Setpoints](#rover-setpoints)). +::: + +#### (Deprecated) Trajectory Setpoint + +::: warning +The [Rover Setpoints](#rover-setpoints) are a replacement for the [TrajectorySetpoint](../msg_docs/TrajectorySetpoint.md) and we highly recommend using those instead as they have a well defined behaviour and offer more flexibility. +::: + +The rover modules support the _position_, _velocity_ and _yaw_ fields of the [TrajectorySetpoint](../msg_docs/TrajectorySetpoint.md). +However, only one of the fields is active at a time and is defined by the flags of [OffboardControlMode](../msg_docs/OffboardControlMode.md): + +| Control Mode Flag | Active Trajectory Setpoint Field | +| ----------------- | -------------------------------- | +| position | position | +| velocity | velocity | +| attitude | yaw | + +::: info +Ackermann rovers do not support the yaw setpoint. +::: ### Generic Vehicle @@ -116,8 +194,10 @@ The following offboard control modes bypass all internal PX4 control loops and s - [px4_msgs::msg::ActuatorMotors](https://github.com/PX4/PX4-Autopilot/blob/main/msg/versioned/ActuatorMotors.msg) + [px4_msgs::msg::ActuatorServos](https://github.com/PX4/PX4-Autopilot/blob/main/msg/versioned/ActuatorServos.msg) - You directly control the motor outputs and/or servo outputs. - - Currently works at lower level than then `control_allocator` module. Do not publish these messages when not in offboard mode. - - All the values normalized in \[-1, 1\]. For outputs that do not support negative values, negative entries map to `NaN`. + - Currently works at lower level than then `control_allocator` module. + Do not publish these messages when not in offboard mode. + - All the values normalized in `[-1, 1]`. + For outputs that do not support negative values, negative entries map to `NaN`. - `NaN` maps to disarmed. ## MAVLink Messages @@ -200,38 +280,7 @@ The following MAVLink messages and their particular fields and field values are ### Rover -- [SET_POSITION_TARGET_LOCAL_NED](https://mavlink.io/en/messages/common.html#SET_POSITION_TARGET_LOCAL_NED) - - The following input combinations are supported (in `type_mask`): - - Position setpoint (only `x`, `y`, `z`) - - Specify the _type_ of the setpoint in `type_mask`: - - ::: info - The _setpoint type_ values below are not part of the MAVLink standard for the `type_mask` field. - :: - - The values are: - - 12288: Loiter setpoint (vehicle stops when close enough to setpoint). - - - Velocity setpoint (only `vx`, `vy`, `vz`) - - - PX4 supports the coordinate frames (`coordinate_frame` field): [MAV_FRAME_LOCAL_NED](https://mavlink.io/en/messages/common.html#MAV_FRAME_LOCAL_NED) and [MAV_FRAME_BODY_NED](https://mavlink.io/en/messages/common.html#MAV_FRAME_BODY_NED). - -- [SET_POSITION_TARGET_GLOBAL_INT](https://mavlink.io/en/messages/common.html#SET_POSITION_TARGET_GLOBAL_INT) - - The following input combinations are supported (in `type_mask`): - - Position setpoint (only `lat_int`, `lon_int`, `alt`) - - Specify the _type_ of the setpoint in `type_mask` (not part of the MAVLink standard). - The values are: - - Following bits not set then normal behaviour. - - 12288: Loiter setpoint (vehicle stops when close enough to setpoint). - - - PX4 supports the coordinate frames (`coordinate_frame` field): [MAV_FRAME_GLOBAL](https://mavlink.io/en/messages/common.html#MAV_FRAME_GLOBAL). - -- [SET_ATTITUDE_TARGET](https://mavlink.io/en/messages/common.html#SET_ATTITUDE_TARGET) - - The following input combinations are supported: - - Attitude/orientation (`SET_ATTITUDE_TARGET.q`) with thrust setpoint (`SET_ATTITUDE_TARGET.thrust`). - ::: info - Only the yaw setting is actually used/extracted. - ::: +Rover does not support a MAVLink offboard API (ROS2 is supported). ## Offboard Parameters diff --git a/docs/en/flight_modes_rover/api.md b/docs/en/flight_modes_rover/api.md new file mode 100644 index 0000000000..828aacf879 --- /dev/null +++ b/docs/en/flight_modes_rover/api.md @@ -0,0 +1,29 @@ +# Apps & API + +The rover modules have been tested and integrated with a subset of the available [Apps & API](../middleware/index.md) methods. +We specifically provide guides for using [ROS 2](../ros2/index.md) to interface a companion computer with PX4 via [uXRCE-DDS](../middleware/uxrce_dds.md). + +| Method | Description | +| --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | +| [PX4 ROS 2 Interface](#px4-ros-2-interface) (Recommended) | Register a custom mode and publish [RoverSetpointTypes](../ros2/px4_ros2_control_interface.md#rover-setpoints). | +| [ROS 2 Offboard Control](#ros-2-offboard-control) | Use the PX4 internal [Offboard Mode](../flight_modes/offboard.md) and publish messages defined in [dds_topics.yaml](../middleware/dds_topics.md). | + +## PX4 ROS 2 Interface + +We recommend the use of the [PX4 ROS 2 Interface Library](../ros2/px4_ros2_interface_lib.md) which allows you to register a custom drive mode and exposes [RoverSetpointTypes](../ros2/px4_ros2_control_interface.md#rover-setpoints). + +By using these setpoints (instead of the PX4 internal rover setpoints), you are guaranteed to send valid control inputs to your vehicle and the control flags for the setpoints you are using are automatically set for you. +Registering a custom drive mode instead of using [ROS 2 Offboard Control](#ros-2-offboard-control) additionally provides the advantages listed [here](../concept/flight_modes.md#internal-vs-external-modes). + +To get familiar with this method, read through the guide for the [PX4 ROS 2 Interface Library](../ros2/px4_ros2_interface_lib.md) where we also provide an example app for rover. + +## ROS 2 Offboard Control + +[ROS 2 Offboard Control](../ros2/offboard_control.md) uses the PX4 internal [Offboard Mode](../flight_modes/offboard.md). + +While you can subscribe/publish to all topics specified in [dds_topics.yaml](../middleware/dds_topics.md), not all rover modules support all of these topics (see [Supported Setpoints](../flight_modes/offboard.md#rover)). +Unlike the [RoverSetpointTypes](../ros2/px4_ros2_control_interface.md#rover-setpoints) exposed through the [PX4 ROS 2 Interface](#px4-ros-2-interface), there is no guarantee that the published setpoints lead to a valid control input. + +In addition, the correct control mode flags must be set through [OffboardControlMode](../msg_docs/OffboardControlMode.md). +This requires a deeper understanding of PX4 and the structure of the rover modules. +For general information on setting up offboard mode read through [Offboard Mode](../flight_modes/offboard.md) and then consult [Supported Setpoints](../flight_modes/offboard.md#rover). diff --git a/docs/en/frames_rover/index.md b/docs/en/frames_rover/index.md index e805e1334b..8ba0751a0d 100644 --- a/docs/en/frames_rover/index.md +++ b/docs/en/frames_rover/index.md @@ -57,8 +57,9 @@ Each wheel is driven by its own motor, and by controlling the speed and directio ## See Also -- [Drive Modes](../flight_modes_rover/index.md). +- [Drive Modes](../flight_modes_rover/index.md) - [Configuration/Tuning](../config_rover/index.md) +- [Apps & API](../flight_modes_rover/api.md) - [Complete Vehicles](../complete_vehicles_rover/index.md) ## Simulation diff --git a/docs/en/releases/main.md b/docs/en/releases/main.md index 72c96d06dc..04fa799548 100644 --- a/docs/en/releases/main.md +++ b/docs/en/releases/main.md @@ -90,6 +90,7 @@ Please continue reading for [upgrade instructions](#upgrade-guide). ### Rover - Removed deprecated rover module ([PX4-Autopilot#25054](https://github.com/PX4/PX4-Autopilot/pull/25054)). +- Add support for [Apps & API](../flight_modes_rover/api.md) ([PX4-Autopilot#25074](https://github.com/PX4/PX4-Autopilot/pull/25074), [PX4-ROS2-Interface-Lib#140](https://github.com/Auterion/px4-ros2-interface-lib/pull/140)). ### ROS 2 diff --git a/docs/en/ros2/offboard_control.md b/docs/en/ros2/offboard_control.md index 56701bfe21..f16256cd4d 100644 --- a/docs/en/ros2/offboard_control.md +++ b/docs/en/ros2/offboard_control.md @@ -1,6 +1,6 @@ # ROS 2 Offboard Control Example -The following C++ example shows how to do position control in [offboard mode](../flight_modes/offboard.md) from a ROS 2 node. +The following C++ example shows how to do multicopter position control in [offboard mode](../flight_modes/offboard.md) from a ROS 2 node. The example starts sending setpoints, enters offboard mode, arms, ascends to 5 metres, and waits. While simple, it shows the main principles of how to use offboard control and how to send vehicle commands. @@ -22,7 +22,7 @@ To subscribe to data coming from nodes that publish in a different frame (for ex ## Trying it out -Follow the instructions in [ROS 2 User Guide](../ros2/user_guide.md) to install PX and run the simulator, install ROS 2, and start the XRCE-DDS Agent. +Follow the instructions in [ROS 2 User Guide](../ros2/user_guide.md) to install PX and run the multicopter simulator, install ROS 2, and start the XRCE-DDS Agent. After that we can follow a similar set of steps to those in [ROS 2 User Guide > Build ROS 2 Workspace](../ros2/user_guide.md#build-ros-2-workspace) to run the example. diff --git a/docs/en/ros2/px4_ros2_control_interface.md b/docs/en/ros2/px4_ros2_control_interface.md index 79866097af..ebb54be960 100644 --- a/docs/en/ros2/px4_ros2_control_interface.md +++ b/docs/en/ros2/px4_ros2_control_interface.md @@ -343,6 +343,7 @@ The following sections provide a list of supported setpoint types: - [MulticopterGotoSetpointType](#go-to-setpoint-multicoptergotosetpointtype): Smooth position and (optionally) heading control - [FwLateralLongitudinalSetpointType](#fixed-wing-lateral-and-longitudinal-setpoint-fwlaterallongitudinalsetpointtype): Direct control of lateral and longitudinal fixed wing dynamics - [DirectActuatorsSetpointType](#direct-actuator-control-setpoint-directactuatorssetpointtype): Direct control of motors and flight surface servo setpoints +- [Rover Setpoints](#rover-setpoints): Direct access to rover control setpoints (Position, Speed, Attitude, Rate, Throttle and Steering). :::tip The other setpoint types are currently experimental, and can be found in: [px4_ros2/control/setpoint_types/experimental](https://github.com/Auterion/px4-ros2-interface-lib/tree/main/px4_ros2_cpp/include/px4_ros2/control/setpoint_types/experimental). @@ -354,6 +355,8 @@ You can add your own setpoint types by adding a class that inherits from `px4_ro + + ::: info This setpoint type is currently only supported for multicopters. ::: @@ -547,6 +550,40 @@ For example to control a quadrotor, you need to set the first 4 motors according If you want to control an actuator that does not control the vehicle's motion, but for example a payload servo, see [below](#controlling-an-independent-actuator-servo). ::: +#### Rover Setpoints + + + +The rover modules use a hierarchical structure to propagate setpoints: + +![Rover Control Structure](../../assets/middleware/ros2/px4_ros2_interface_lib/rover_control_structure.svg) + +::: info +The "highest" setpoint that is provided will be used within the PX4 rover modules to generate the setpoints that are below it (Overriding them!). +With this hierarchy there are clear rules for providing a valid control input: + +- Provide a position setpoint, **or** +- One of the setpoints on the "left" (speed **or** throttle) **and** one of the setpoints on the "right" (attitude, rate **or** steering). All combinations of "left" and "right" setpoints are valid. + +For ease of use we expose these valid combinations as new SetpointTypes. +::: + +The RoverSetpointTypes exposed through the control interface are combinations of these setpoints that lead to a valid control input: + +| SetpointType | Position | Speed | Throttle | Attitude | Rate | Steering | Control Flags | +| ----------------------------------------------------------------------------------------------------------------------------------- | -------- | --------- | --------- | --------- | --------- | --------- | ------------------------------------------------------ | +| [RoverPosition](https://auterion.github.io/px4-ros2-interface-lib/classpx4__ros2_1_1RoverPositionSetpointType.html#details) | ✓ | (✓) | (✓) | (✓) | (✓) | (✓) | Position, Velocity, Attitude, Rate, Control Allocation | +| [RoverSpeedAttitude](https://auterion.github.io/px4-ros2-interface-lib/classpx4__ros2_1_1RoverSpeedAttitudeSetpointType.html) | | ✓ | (✓) | ✓ | (✓) | (✓) | Velocity, Attitude, Rate, Control Allocation | +| [RoverSpeedRate](https://auterion.github.io/px4-ros2-interface-lib/classpx4__ros2_1_1RoverSpeedRateSetpointType.html) | | ✓ | (✓) | | ✓ | (✓) | Velocity, Rate, Control Allocation | +| [RoverSpeedSteering](https://auterion.github.io/px4-ros2-interface-lib/classpx4__ros2_1_1RoverSpeedSteeringSetpointType.html) | | ✓ | (✓) | | | ✓ | Velocity, Control Allocation | +| [RoverThrottleAttitude](https://auterion.github.io/px4-ros2-interface-lib/classpx4__ros2_1_1RoverThrottleAttitudeSetpointType.html) | | | ✓ | ✓ | (✓) | (✓) | Attitude, Rate, Control Allocation | +| [RoverThrottleRate](https://auterion.github.io/px4-ros2-interface-lib/classpx4__ros2_1_1RoverThrottleRateSetpointType.html) | | | ✓ | | ✓ | (✓) | Rate, Control Allocation | +| [RoverThrottleSteering](https://auterion.github.io/px4-ros2-interface-lib/classpx4__ros2_1_1RoverThrottleSteeringSetpointType.html) | | | ✓ | | | ✓ | Control Allocation | + +✓ are the setpoints we publish, and (✓) are generated internally by the PX4 rover modules according to the hierarchy above. + +An example for a rover specific drive mode using the `RoverSpeedAttitudeSetpointType` is provided [here](https://github.com/Auterion/px4-ros2-interface-lib/tree/main/examples/cpp/modes/rover_velocity). + ### Controlling a VTOL