- 嵌入式
- 物联网
- 机器人
- 自动驾驶
- 智能硬件
【免费下载链接】PX4-Autopilot
PX4 Autopilot Software
PX4 ROS 2 控制接口(Control Interface)是 PX4 ROS 2 接口库提供的核心能力:开发者可以用 C++(或 Python 绑定)在 ROS 2 侧编写自定义飞行模式(Mode)与模式执行器(Mode Executor),将其动态注册到 PX4 中,让地面站把它当作 PX4 原生模式来显示、选择与失效保护联动,甚至可以直接替换 PX4 内置的 Return 等模式。读完本文,你将掌握自定义模式的类结构、四类已稳定的 setpoint 类型(多旋翼 Go-to、固定翼横侧/纵向、直接舵机、Rover 层级 setpoint)、VTOL 过渡控制、遥测封装、失效保护与模式需求配置,以及把模式绑定到 RC 开关的完整流程。
适用版本提示:本文基于 PX4 v1.15 及更新的仓库代码(固定翼与 Rover 相关 setpoint 标注为 PX4 v1.17)。截至编写时,控制接口仍有部分内容处于实验阶段——模式的架构与核心接口已基本稳定并在 CI 中测试,但仅少数 setpoint 类型已定型,其余仍可能变动;API 尚未完全文档化。若需要用到未定型的 setpoint,可能需要直接使用 PX4 内部话题,这些话题不保证向后兼容。
控制接口的工作模式:Mode、Mode Executor 与配置覆盖
下图给出了控制接口模式与模式执行器如何与 PX4 交互的整体概念:
Mode(模式)
使用接口库定义的模式具有如下性质:
- 模式是一个可以向飞行器发送 setpoint(如速度或直接舵机指令)以控制其运动的组件;
- 模式选择一种 setpoint 类型并在激活期间持续发送;它可以在多种 setpoint 类型之间切换;
- 模式不能激活其他模式,必须由用户(通过 RC/GCS)、飞控在失效保护场景中、模式执行器或其他外部系统激活;
- 拥有一个由地面站显示的名称;
- 可以配置其模式需求(例如要求有效的位姿估计);
- 可以执行多种任务,例如飞向目标、放下绞盘、释放载荷再飞回;
- 可以替换 PX4 中定义的某个内置模式。
Mode Executor(模式执行器)
模式执行器是可选的、用于调度模式的组件。例如,一个自定义载荷投递或巡线模式的执行器,可能先触发起飞,再切换到自定义模式,等任务完成后触发 Return。
具体性质如下:
- 模式执行器是比模式高一级的可选组件,本质是一个状态机,可以激活模式并等待其完成;
- 它只有在“掌权”期间才能这么做:每个执行器恰好拥有一个被拥有的模式(owned mode)(一个模式最多被一个执行器拥有)。该模式作为执行器的激活入口:当用户选中该模式时,拥有它的执行器被激活,并可以选用任意模式;它一直掌权,直到用户切换模式(RC 或 GCS)或失效保护触发模式切换;失效保护解除后执行器会被重新激活;
- 这种设计允许多个执行器共存;
- 执行器不能激活其他执行器;
- 在库内,模式执行器总是与某个自定义模式组合实现。
这两条定义保证了:用户可以在任何时刻通过 RC 或 GCS 发出模式切换命令,从自定义模式或执行器手中夺回控制权;模式执行器对用户是透明的——它通过被拥有的模式被间接选中与激活,因此该模式应当被恰当地命名。
Configuration Overrides(配置覆盖)
模式与执行器都可以定义配置覆盖,用于在模式或执行器激活期间定制某些行为。当前已实现两类:
- 禁用自动上锁(Disabling auto-disarm):允许着陆后再次起飞(例如用于释放载荷);
- 推迟非必需失效保护(Deferring non-essential failsafes):允许执行器在不被非关键失效保护打断的情况下执行动作,例如忽略低电量失效保护以完成绞盘操作。
与 Offboard 控制对比
相比传统的 offboard 控制,上述概念带来如下优势:
- 多个节点或应用可以共存甚至同时运行;但同一时刻只有一个节点能控制飞行器,且该节点是明确界定的;
- 模式拥有独立名称,可在地面站显示/选择;
- 模式与失效保护状态机和上锁检查(arming checks)深度集成;
- 可发送的 setpoint 类型被明确界定;
- ROS 2 模式可以替换飞控内置模式(如 Return 模式)。
PX4 ROS 2 模式比 PX4 内置模式更易实现与维护,且为开发者提供更充足的处理能力与现成库资源。除非该模式属于安全关键(safety-critical)、需要严格时序或极高更新率,或你的飞行器没有配套计算机,否则应优先考虑使用 PX4 ROS 2 模式而非内置模式(可参考 内部模式 vs 外部模式 的讨论)。
安装与首次测试
按以下步骤完成环境准备并跑通第一个示例模式:
确认你已有可用的 ROS 2 环境,且工作区中包含了
px4_msgs消息包;将接口库克隆到工作区:
cd $ros_workspace/src git clone --recursive https://github.com/Auterion/px4-ros2-interface-lib为保证兼容性,请使用最新的
main分支:PX4、px4_msgs与接口库三者需相互匹配(详见该库的 compatibility 说明)。构建工作区:
cd .. colcon build source install/setup.bash在另一个 shell 中启动 PX4 SITL:
cd $px4-autopilot make px4_sitl gazebo-classic(此处使用 Gazebo-Classic,也可以用任意机型或模拟器)
再开一个 shell 启动 Micro XRCE Agent(之后可保持运行):
MicroXRCEAgent udp4 -p 8888启动 QGroundControl(建议使用QGroundControl Daily版本,它支持动态更新模式列表);
回到 ROS 2 终端,运行示例模式:
ros2 run example_mode_manual_cpp example_mode_manual应看到类似如下的输出,表明
My Manual Mode正在注册:[DEBUG] [example_mode_manual]: Checking message compatibility... [DEBUG] [example_mode_manual]: Subscriber found, continuing [DEBUG] [example_mode_manual]: Publisher found, continuing [DEBUG] [example_mode_manual]: Registering 'My Manual Mode' (arming check: 1, mode: 1, mode executor: 0) [DEBUG] [example_mode_manual]: Subscriber found, continuing [DEBUG] [example_mode_manual]: Publisher found, continuing [DEBUG] [example_mode_manual]: Got RegisterExtComponentReply [DEBUG] [example_mode_manual]: Arming check request (id=1, only printed once)在 PX4 shell 中验证新模式是否注册成功:
commander status输出中应包含:
INFO [commander] Disarmed INFO [commander] navigation mode: Position INFO [commander] user intended navigation mode: Position INFO [commander] in failsafe: no INFO [commander] External Mode 1: nav_state: 23, name: My Manual Mode此时在 QGroundControl 中也能看到该模式:
选择该模式,确保存在手动控制源(物理或虚拟摇杆),然后上锁(arm)飞行器。模式被激活后应打印:
[DEBUG] [example_mode_manual]: Mode 'My Manual Mode' activated现在你就可以着手创建自己的模式了。
源码侧的注册链路:commander status中出现的External Mode由 PX4 的 模式管理模块 维护——外部模式共占用NAVIGATION_STATE_EXTERNAL1到NAVIGATION_STATE_EXTERNAL8共 8 个导航状态(见 ModeManagement.hpp),本示例注册后即占用了 nav_state 23(即 EXTERNAL1)。注册请求与应答、上锁检查、setpoint 配置、模式完成等消息,通过 uXRCE-DDS 客户端的 dds_topics.yaml(/fmu/in/register_ext_component_request、/fmu/out/register_ext_component_reply、/fmu/out/arming_check_request、/fmu/in/setpoint_config等)在 PX4 与 ROS 2 之间桥接;基于 Zenoh 的传输则对应 src/modules/zenoh/dds_topics.yaml 中的同名映射。
使用接口库:模式类定义
本节逐步演示如何为自定义模式创建类。完整的可运行示例位于Auterion/px4-ros2-interface-lib仓库的examples/cpp/modes/manual目录(参考include/mode.hpp)。
class MyMode : public px4_ros2::ModeBase // [1] { public: explicit MyMode(rclcpp::Node & node) : ModeBase(node, Settings{"My Mode"}) // [2] { // [3] _manual_control_input = std::make_shared<px4_ros2::ManualControlInput>(*this); _rates_setpoint = std::make_shared<px4_ros2::RatesSetpointType>(*this); } void onActivate() override { // Called whenever our mode gets selected } void onDeactivate() override { // Called when our mode gets deactivated } void updateSetpoint(const rclcpp::Duration & dt) override { // [4] const Eigen::Vector3f thrust_sp{0.F, 0.F, -_manual_control_input->throttle()}; const Eigen::Vector3f rates_sp{ _manual_control_input->roll() * 150.F * M_PI / 180.F, -_manual_control_input->pitch() * 150.F * M_PI / 180.F, _manual_control_input->yaw() * 100.F * M_PI / 180.F }; _rates_setpoint->update(rates_sp, thrust_sp); } private: std::shared_ptr<px4_ros2::ManualControlInput> _manual_control_input; std::shared_ptr<px4_ros2::RatesSetpointType> _rates_setpoint; };逐条解读:
[1]:创建一个继承自px4_ros2::ModeBase的类;[2]:构造函数中传入模式名称。此处还可以配置其他选项,例如替换飞控内置模式(见下文“替换内部模式”);[3]:在此创建后续要使用的所有对象,可以是 RC 输入、setpoint 类型或遥测。*this作为Context传入每个对象,将对象与当前模式关联;[4]:每当模式处于激活状态时,该方法会被周期性调用(更新率取决于 setpoint 类型)。在这里完成业务逻辑并生成新的 setpoint。
创建模式实例后,必须调用mode->doRegister()完成与飞控的实际注册;若注册失败会返回false。如果使用了模式执行器,则应改为在执行器上调用doRegister()。
模式执行器类定义
下面逐步演示模式执行器类的创建:
class MyModeExecutor : public px4_ros2::ModeExecutorBase // [1] { public: MyModeExecutor(px4_ros2::ModeBase & owned_mode) // [2] : ModeExecutorBase(px4_ros2::ModeExecutorBase::Settings{}, owned_mode), _node(owned_mode.node()) { } enum class State // [3] { Reset, TakingOff, MyMode, RTL, WaitUntilDisarmed, }; void onActivate() override { runState(State::TakingOff, px4_ros2::Result::Success); // [4] } void onDeactivate(DeactivateReason reason) override { } void runState(State state, px4_ros2::Result previous_result) { if (previous_result != px4_ros2::Result::Success) { RCLCPP_ERROR(_node.get_logger(), "State %i: previous state failed: %s", (int)state, resultToString(previous_result)); return; } switch (state) { // [5] case State::Reset: break; case State::TakingOff: takeoff(this {runState(State::MyMode, result);}); break; case State::MyMode: // [6] scheduleMode( ownedMode().id(), this { runState(State::RTL, result); }); break; case State::RTL: rtl(this {runState(State::WaitUntilDisarmed, result);}); break; case State::WaitUntilDisarmed: waitUntilDisarmed(this { RCLCPP_INFO(_node.get_logger(), "All states complete (%s)", resultToString(result)); }); break; } } private: rclcpp::Node & _node; };[1]:创建继承自px4_ros2::ModeExecutorBase的类;[2]:构造函数接收与该执行器关联的自定义模式,并把它传给ModeExecutorBase的构造函数;[3]:定义一个枚举描述要依次执行的状态;[4]:onActivate在执行器被激活时调用,此时可以开始运行状态序列。具体实现方式由你决定,本示例用runState方法推进下一个状态;[5]:切换到某状态时,调用ModeExecutorBase提供的异步方法来启动目标模式:run、takeoff、rtl等。这些方法接收一个完成回调,回调提供Result参数告知操作是否成功;成功时回调会继续运行下一个状态;[6]:使用scheduleMode()启动执行器“被拥有的模式”,模式与其他状态处理保持一致。
Setpoint 类型
模式可以选择自己用于控制飞行器的 setpoint 类型;所选类型同时决定了它与不同机型的兼容性。目前已支持的(相对稳定)setpoint 类型:
- MulticopterGotoSetpointType(Go-to):仅多旋翼。平滑的位置与(可选)航向控制;
- FwLateralLongitudinalSetpointType(固定翼横侧/纵向):仅固定翼,PX4 v1.17 起。直接控制固定翼横侧与纵向动力学;
- DirectActuatorsSetpointType:直接控制电机与舵面伺服 setpoint;
- Rover 系列 setpoint:PX4 v1.17 起。直接访问 Rover 控制 setpoint(Position、Speed、Attitude、Rate、Throttle 与 Steering)。
其余 setpoint 类型目前仍处于实验阶段,位于接口库的
px4_ros2_cpp/include/px4_ros2/control/setpoint_types/experimental目录。你也可以添加自己的 setpoint 类型:新增一个继承自px4_ros2::SetpointBase的类,按 setpoint 需要设置配置标志,然后发布任意包含 setpoint 的话题即可。
Go-to Setpoint(MulticopterGotoSetpointType)
该 setpoint 类型目前仅支持多旋翼。
使用px4_ros2::MulticopterGotoSetpointType平滑地控制位置与(可选)航向 setpoint。该 setpoint 被流式传输到 FMU 侧基于**时间最优、最大加加速度(jerk)**轨迹公式化的位置与航向平滑器,并带有速度与加速度约束。
此外还有px4_ros2::MulticopterGotoGlobalSetpointType类,允许在全局坐标系中发送 setpoint。
最简用法是只把三维位置传入 update 方法:
const Eigen::Vector3f target_position_m{-10.F, 0.F, 3.F}; _goto_setpoint->update(target_position_m);此时航向将保持不受控制。若要同时控制航向,将其作为第二个参数传入:
const Eigen::Vector3f target_position_m{-10.F, 0.F, 3.F}; const float heading_rad = 3.14F; _goto_setpoint->update( target_position_m, heading_rad);Go-to setpoint 的另一个特性是动态控制底层平滑器的速度上限(即最大水平/垂直平动速度以及航向角速度)。若像上面一样不指定,平滑器默认使用飞行器的默认最大值(通常设置为物理限制)。注意:平滑器只会降低速度上限,绝不会提高。
_goto_setpoint->update( target_position_m, heading_rad, max_horizontal_velocity_m_s, max_vertical_velocity_m_s, max_heading_rate_rad_s);update 方法中除位置外的所有参数都以std::optional<float>模板化——如果只想约束航向角速度而不约束平动速度,可以传std::nullopt:
_goto_setpoint->update( target_position_m, heading_rad, std::nullopt, std::nullopt, max_heading_rate_rad_s);固定翼横侧与纵向 Setpoint(FwLateralLongitudinalSetpointType)
该 setpoint 类型支持固定翼飞行器以及处于固定翼模式的 VTOL。
使用px4_ros2::FwLateralLongitudinalSetpointType直接控制固定翼的横侧动力学(左右运动:转弯/压坡)与纵向动力学(前后/垂直运动:加速与爬升/下降)。该 setpoint 被流式传输到 PX4 的 FwLateralLongitudinalControl 模块,该模块解耦横侧与纵向输入,同时保证飞行器极限被尊重。
要控制飞行器,至少需要提供横侧和纵向各一个 setpoint:
- 纵向输入中:
altitude或height_rate必须有一个有限(finite)才能控制垂直运动;若两者都为NAN,飞行器保持当前高度; - 横侧输入中:
course、airspeed_direction、lateral_acceleration至少有一个有限。
各可控参数的详细说明请参考消息定义:FixedWingLateralSetpoint 与 FixedWingLongitudinalSetpoint。
基本用法
该类型提供多个 update 方法,每个方法允许指定越来越多的 setpoint。
最简单的是updateWithAltitude(),可指定course与altitude目标:
const float altitude_msl = 500.F; const float course = 0.F; // due North _fw_lateral_longitudinal_setpoint->updateWithAltitude(altitude_msl, course);PX4 使用这些 setpoint 计算发送给底层控制器的滚转角、俯仰角与油门setpoint。注意:使用本方法时,指令的飞行预计相对平缓/不激进。其计算链路如下:
横侧控制输出:
course setpoint(用户设定)→ airspeed direction(航向)setpoint → lateral acceleration setpoint → 滚转角 setpoint;
纵向控制输出:
altitude setpoint(用户设定)→ height rate setpoint → 俯仰角 setpoint 与油门设置。
updateWithHeightRate()允许设置目标course与height_rate(当爬升/下降速率很重要或需要动态控制时很有用):
const float height_rate = 2.F; const float course = 0.F; // due North _fw_lateral_longitudinal_setpoint->updateWithHeightRate(height_rate, course);updateWithAltitude()与updateWithHeightRate()还允许通过第三、第四个参数额外控制等效空速或横侧加速度:
const float altitude_msl = 500.F; const float course = 0.F; // due North const float equivalent_aspd = 15.F; // m/s const float lateral_acceleration = 2.F; // FRD, used as feedforward _fw_lateral_longitudinal_setpoint->updateWithAltitude(altitude_msl, course, equivalent_aspd, lateral_acceleration);等效空速与横侧加速度参数以std::optional<float>定义,因此可以通过传std::nullopt省略其中任意一个。
若同时提供横侧加速度与 course setpoint,横侧加速度 setpoint 将作为前馈(feedforward)使用。
使用 Setpoint 结构体进行全量控制
为获得最大灵活性,可以创建并传入FwLateralLongitudinalSetpoint结构体,每个字段都以std::optional<float>模板化:
优先级规则:若同时设置 course 与 airspeed direction,airspeed direction 优先,course 不被控制;若 course 或 airspeed direction 任一有限,横侧加速度作为前馈;若同时设置 altitude 与 height rate,height rate 优先,altitude 不被控制。
px4_ros2::FwLateralLongitudinalSetpoint setpoint_s; setpoint_s.withCourse(0.F); // setpoint_s.withAirspeedDirection(0.2F); // uncontrolled setpoint_s.withLateralAcceleration(2.F); // feedforward //setpoint_s.withAltitude(500.F); // uncontrolled setpoint_s.withHeightRate(2.F); setpoint_s.withEquivalentAirspeed(15.F); _fw_lateral_longitudinal_setpoint->update(setpoint_s);下图展示了所有输入均被设置时FwLateralLongitudinalSetpointType与 PX4 之间的交互:
高级配置(可选)
还可以随 setpoint 一起传入FwControlConfiguration结构体,覆盖默认控制器设置与约束,例如俯仰限制、油门限制以及目标下沉/爬升速率。这面向高级用户:
px4_ros2::FwLateralLongitudinalSetpoint setpoint_s; setpoint_s.withAirspeedDirection(0.F); setpoint_s.withLateralAcceleration(2.F); // feedforward setpoint_s.withAltitude(500.F); setpoint_s.withEquivalentAirspeed(15.F); px4_ros2::FwControlConfiguration config_s; config_s.withTargetClimbRate(3.F); config_s.withMaxAcceleration(5.F); config_s.withThrottleLimits(0.4F, 0.6F); _fw_lateral_longitudinal_setpoint->update(setpoint_s, config_s);所有配置字段均定义为std::optional<float>,未设置的值将默认采用 PX4 配置。更多配置选项参见 LateralControlConfiguration 与 FixedWingLongitudinalConfiguration 消息文档。
出于安全考虑,PX4 会自动将配置值限制在飞行器约束范围内。例如油门覆盖会被钳制在
FW_THR_MIN与FW_THR_MAX之间。
直接执行机构控制 Setpoint(DirectActuatorsSetpointType)
使用px4_ros2::DirectActuatorsSetpointType可以直接控制执行机构,电机与舵机可独立设置。请注意,执行机构编号是机型与安装配置相关的:例如要控制四旋翼,需要按照其输出/控制分配配置设置前 4 个电机。
若想控制的执行机构并不影响飞行器运动(例如载荷舵机),请参考下面的“控制独立执行机构/舵机”一节。
Rover Setpoints
Rover 模块使用层级结构传播 setpoint:
在 PX4 的 Rover 模块中,所提供的“最高层”setpoint 会被用来生成其下方的 setpoint(并覆盖它们!)。该层级给出明确的合法控制输入规则:
- 提供一个位置 setpoint,或
- 提供“左侧”(speed或throttle)的某个 setpoint和“右侧”(attitude、rate或steering)的某个 setpoint。左右组合全部合法。
为便于使用,接口库将这些合法组合暴露为新的 SetpointType:
| SetpointType | Position | Speed | Throttle | Attitude | Rate | Steering | Control Flags |
|---|---|---|---|---|---|---|---|
| RoverPosition | ✓ | (✓) | (✓) | (✓) | (✓) | (✓) | Position, Velocity, Attitude, Rate, Control Allocation |
| RoverSpeedAttitude | ✓ | (✓) | ✓ | (✓) | (✓) | Velocity, Attitude, Rate, Control Allocation | |
| RoverSpeedRate | ✓ | (✓) | ✓ | (✓) | Velocity, Rate, Control Allocation | ||
| RoverSpeedSteering | ✓ | (✓) | ✓ | Velocity, Control Allocation | |||
| RoverThrottleAttitude | ✓ | ✓ | (✓) | (✓) | Attitude, Rate, Control Allocation | ||
| RoverThrottleRate | ✓ | ✓ | (✓) | Rate, Control Allocation | |||
| RoverThrottleSteering | ✓ | ✓ | Control Allocation |
其中 ✓ 表示该 setpoint 由接口库发布,(✓) 表示由 PX4 Rover 模块根据上述层级在内部生成。Rover 专用驱动模式示例(使用RoverSpeedAttitudeSetpointType)见接口库的examples/cpp/modes/rover_velocity目录。
上述 7 类 Rover setpoint 在 PX4 侧对应
/fmu/in/rover_position_setpoint、/fmu/in/rover_speed_setpoint、/fmu/in/rover_attitude_setpoint、/fmu/in/rover_rate_setpoint、/fmu/in/rover_throttle_setpoint、/fmu/in/rover_steering_setpoint等话题,均已在 dds_topics.yaml 中完成映射。
控制 VTOL
要在外部飞行模式中控制 VTOL,请根据当前飞行配置返回正确的 setpoint 类型:
- 多旋翼模式:使用与多旋翼控制兼容的 setpoint 类型,例如
MulticopterGotoSetpointType或TrajectorySetpointType; - 固定翼模式:使用
FwLateralLongitudinalSetpointType。
只要 VTOL 在整个外部模式期间保持在多旋翼或固定翼模式,就无需额外处理。
如果要在外部模式中指令 VTOL 过渡(transition),需要使用VTOL API(px4_ros2::VTOL)。该 API 提供指令过渡与查询飞行器当前状态的能力。
请谨慎使用该 API!与机上过渡(如通过 RC 开关,由 PX4 处理完整流程)不同,外部指令过渡会使用户部分负责确保平滑与安全行为:
确保你的模式同时具备
TrajectorySetpointType与FwLateralLongitudinalSetpointType;在模式构造函数中创建
px4_ros2::VTOL实例;指令过渡时,在 VTOL 对象上使用
toMulticopter()或toFixedwing()方法设置期望状态;过渡期间发送如下 setpoint 组合:
// Assuming the instance of the px4_ros2::VTOL object is called vtol // Send TrajectorySetpointType as follows: Eigen::Vector3f acceleration_sp = vtol.computeAccelerationSetpointDuringTransition(); Eigen::Vector3f velocity_sp{NAN, NAN, 0.f}; _trajectory_setpoint->update(velocity_sp, acceleration_sp); // Send FwLateralLongitudinalSetpointType with lateral input to realign vehicle as desired float course_sp = 0.F; // North _fw_lateral_longitudinal_setpoint->updateWithAltitude(NAN, course_sp)这将确保过渡在 PX4 内被正确处理。可选地,可以向
computeAccelerationSetpointDuringTransition()传入一个减速 setpoint,用于反向过渡(back-transition)。
查询飞行器当前状态,使用 VTOL 对象上的getCurrentState()方法。实际使用示例见接口库的examples/cpp/modes/vtol目录。
控制独立执行机构/舵机
若需要控制独立执行机构(舵机),按以下步骤:
- 先配置输出(基于 MAVLink 的通用执行机构控制);
- 在模式构造函数中创建
px4_ros2::PeripheralActuatorControls实例; - 调用
set()方法控制执行机构,这可以独立于任何激活的 setpoint 进行。
遥测
可以通过以下类直接访问 PX4 遥测话题:
OdometryGlobalPosition:全局位置;OdometryLocalPosition:本地位置、速度、加速度与航向;OdometryAttitude:飞行器姿态;OdometryAirspeed:空速。
例如,查询飞行器当前位姿估计:
std::shared_ptr<px4_ros2::OdometryLocalPosition> _vehicle_local_position; ... // Get vehicle's last local position _vehicle_local_position->positionNed(); // Check last horizontal position is valid _vehicle_local_position->positionXYValid();这些类是对 PX4 内部话题的封装,当内部话题变更时,库可以借此维持兼容性。新话题可参考接口库的
px4_ros2_cpp/include/px4_ros2/odometry目录;当然你也可以直接使用 PX4 发布的任何 ROS 2 话题。
失效保护与模式需求
每个模式都有一组需求标志(requirement flags),通常会根据模式上下文中使用的对象自动设置。例如,添加手动控制输入时,手动控制需求标志被自动设置:
_manual_control_input = std::make_shared<px4_ros2::ManualControlInput>(*this);具体而言,当条件不满足时,设置某个标志会在 PX4 中产生以下后果:
- 模式被选中期间不允许上锁(arming);
- 已上锁时,该模式无法被选中;
- 已上锁且模式被选中时,会触发相应失效保护(例如手动控制需求对应 RC 丢失)。失效保护行为可参考安全配置页面进行配置;此外,当模式崩溃或失去响应时也会触发失效保护。
手动控制标志对应的流程如下图所示:
模式注册后也可以手动更新任何模式需求,例如添加“需要家点(home position)”:
modeRequirements().home_position = true;完整标志列表见接口库的px4_ros2_cpp/include/px4_ros2/common/requirement_flags.hpp。
从源码看,PX4 侧的上锁检查与失效保护通过
/fmu/out/arming_check_request与/fmu/in/arming_check_reply话题与外部模式交互(见 dds_topics.yaml);ModeManagement还会在检测到外部模式无响应时执行回退(例如解除注册或回落到内部模式,见 ModeManagement.cpp)。
推迟失效保护(Deferring Failsafes)
模式或模式执行器可以通过调用deferFailsafesSync()方法临时推迟非必需失效保护。若希望在失效保护即将被触发时得到通知,可重写void onFailsafeDeferred()方法。
参考集成测试示例:接口库的px4_ros2_cpp/test/integration/overrides.cpp。
将模式绑定到 RC 开关或摇杆动作
外部模式可以绑定到 RC 开关或摇杆动作。将模式绑定到 RC 开关时,你需要知道其索引(因为参数元数据中不包含动态模式名)。在模式运行期间使用commander status获取该信息。
例如:
INFO [commander] External Mode 1: nav_state: 23, name: My Manual Mode表示你应在 QGC 中选择External Mode 1:
PX4 通过存储模式名的哈希值,保证同一模式始终分配到同一索引。这样在存在多个外部模式时,结果与启动顺序无关。
替换内置模式
外部模式可以替换某个现有内置模式,例如 Return 模式。一旦替换,无论何时该模式被选中(用户选择或失效保护场景),都会使用外部模式;仅当外部模式失去响应或崩溃时,内置模式作为回退被使用。
替换模式在ModeBase构造函数的 Settings 中指定:
Settings{kName, false, ModeBase::kModeIDRtl}从源码看,PX4 在ModeManagement中通过RegisterExtComponentRequest的replace_internal_mode字段记录替换关系(见 ModeManagement.cpp),并在地面站/用户选中被替换模式时,先检查外部模式是否有效且响应正常,否则才回落到内置模式(getNavStateReplacementIfValid与getReplacedModeIfAny逻辑)。模式替换相关的注册/注销消息同样经由 dds_topics.yaml 中的/fmu/in/register_ext_component_request与/fmu/in/unregister_ext_component话题传递。
小结
PX4 ROS 2 控制接口把“外部模式”从零散的 offboard 指令提升为与飞控深度集成的第一等公民:模式拥有名称、需求标志与失效保护联动,可被 GCS 显示选择、可绑定 RC 开关、可替换内置模式;模式执行器则提供了起飞→任务→RTL 的完整状态机编排能力。配合已定型的 Go-to、固定翼横侧/纵向、直接执行机构与 Rover 系列 setpoint 类型,大多数非安全关键的导航与控制需求都可以在 ROS 2 侧以更高开发效率实现。若要深入源码,可从 src/modules/commander/ModeManagement.cpp 与 src/modules/uxrce_dds_client/dds_topics.yaml 继续探索其 PX4 侧实现。
- 嵌入式
- 物联网
- 机器人
- 自动驾驶
- 智能硬件
【免费下载链接】PX4-Autopilot
PX4 Autopilot Software
相关推荐
PX4 无人车(Rover)外部控制 API 指南:PX4 ROS 2 接口与 ROS 2 Offboard 两种方案详解
PX4 无人车(Rover)外部控制 API 指南:PX4 ROS 2 接口与 ROS 2 Offboard 两种方案详解 本篇技术指南以 PX4 Autopi
嵌入式物联网机器人自动驾驶智能硬件PX4 Offboard 模式(Offboard Mode)完全指南:MAVLink 与 ROS 2 外部控制详解
PX4 Offboard 模式(Offboard Mode)完全指南:MAVLink 与 ROS 2 外部控制详解 Offboard 模式是 PX4 自动飞行栈
嵌入式物联网机器人自动驾驶智能硬件PX4 Offboard 控制实战指南:通过 MAVLink 与 ROS 2 让外部软件接管飞控
PX4 Offboard 控制实战指南:通过 MAVLink 与 ROS 2 让外部软件接管飞控 Offboard(机外)控制是 PX4 最重要的开发能力之一:
嵌入式物联网机器人自动驾驶智能硬件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考