跳转至

控制器链式连接 / 串级控制(Controller Chaining / Cascade Control)

本文档提出了对《控制器链式连接设计文档》中描述的串行控制器链式连接(serial controller chaining)的一种最小可行实现(MVI)。串级控制(Cascade Control)是控制器链式连接的一种特定形式。


文档范围与背景知识

本方案仅关注控制器的串行链式连接,并尽可能复用现有机制。重点在于控制器的输入与输出,以及 Controller Manager 对这些接口的管理。

本文引入“控制器组”(controller groups)这一概念仅用于表述清晰,其唯一含义是:组内的控制器可以以任意顺序更新

这并不意味着未来不会实现设计文档中描述的完整“控制器组”机制。作者认为,在当前阶段引入完整控制器组会带来不必要的复杂性,尽管从长远来看,它们可能提供更清晰的结构和接口。


动机、目的与用途

为阐明本文意图,我们聚焦于《controllers_chaining》设计文档中的 示例 2(Example 2)

示例 2

在此例中,我们希望将以下控制器进行链式连接: - position_tracking 控制器 - diff_drive_controller(差速驱动控制器) - 两个 PID 控制器 - robot_localization(机器人定位)控制器

设想一个更灵活的使用场景:我们不仅希望将这些控制器作为一组运行,还希望动态地添加前置步骤。具体流程如下:

  1. 机器人启动时
    仅激活两个 PID 控制器,以验证电机速度控制是否正常。此时,PID 控制器的输入可通过外部话题(如 /pid_reference)控制。同时,这些控制器也提供虚拟接口,可用于后续链式连接。

  2. 激活 diff_drive_controller
    它连接到 PID 控制器的虚拟输入接口。此时,PID 控制器检测到自己处于“链式模式”(chained mode),自动禁用其外部话题订阅者。随后,验证差速机器人的运动学是否正常。

  3. diff_drive_controller 激活后
    它暴露 odom 状态接口(state interfaces),供以下控制器使用:

  4. odom_publisher:订阅 odom 状态接口并发布里程计消息
  5. sensor_fusion(传感器融合):同时使用 diff_drive_controllerodom 接口和 IMU 的状态接口

  6. sensor_fusion 激活后
    它暴露自己的 odom 状态接口,供 robot_localization 控制器使用。

  7. robot_localization 激活后
    它暴露 actual_pose 状态接口,供 position_tracking 控制器使用。

  8. 最后激活 position_tracking

  9. 它连接到 diff_drive_controller 的命令接口(使其禁用外部话题)
  10. 同时使用 robot_localization 提供的 actual_pose 状态接口

关键规则:若链中任一控制器被停用,则其所有前置控制器也必须被停用


注意事项

  • 参考接口(reference interfaces)只有在被其他控制器使用时,才进入“链式模式”;否则,控制器从话题订阅者获取参考值。
  • 状态接口(state interfaces)被其他控制器使用时,不会触发链式模式
  • 术语说明
  • 前置控制器(preceding controller):其输出连接到另一控制器的输入(参考接口)
  • 后置控制器(following controller):其输入由另一控制器提供

    例如:diff_drive_controller 是前置控制器,PID 控制器是后置控制器。


实现方案

控制器基类:ChainableController

ChainableController 继承自 ControllerInterface,并新增两个纯虚方法:

virtual std::vector<hardware_interface::CommandInterface> export_reference_interfaces() = 0;
virtual std::vector<hardware_interface::StateInterface> export_state_interfaces() = 0;
  • export_reference_interfaces():导出供其他控制器作为命令输入的虚拟命令接口(即本控制器的“参考输入”来源)。
  • export_state_interfaces():导出供其他控制器读取的虚拟状态接口。

简化假设:当前假设控制器的所有参考接口要么全被使用,要么全不被使用。状态接口可被多个控制器同时、任意组合使用。若需排他性,应拆分为多个控制器。

此外,ChainableController 提供:

void set_chained_mode(bool activate);  // 设置链式模式标志
virtual void on_set_chained_mode(bool activate) = 0;  // 子类实现具体行为

示例

  • PID 控制器
  • 导出虚拟接口:pid_reference
  • 链式模式下:停用 /pid_reference 话题订阅者
  • diff_drive_controller
  • 导出虚拟接口:v_x, v_y, w_z
  • 链式模式下:停用 /cmd_vel/cmd_vel_unstamped 订阅者,但发布者照常运行

术语定义(Nomenclature)

ros2_control 中,有两种核心接口:

接口类型 访问权限 典型用途
CommandInterface 读写 向硬件(或链式控制器)发送命令
StateInterface 只读 从硬件(或链式控制器)读取状态

控制器接口配置方法

方法 作用
command_interface_configuration()ControllerInterface 声明本控制器所需的命令接口(来自硬件或其他控制器的参考接口)
state_interface_configuration()ControllerInterface 声明本控制器所需的状态接口(来自硬件或其他控制器的状态接口)
export_reference_interfaces()ChainableController 声明本控制器对外提供的参考接口(供其他控制器作为命令输入)
export_state_interfaces()ChainableController 声明本控制器对外提供的状态接口(供其他控制器读取)

Controller Manager 使用这些信息向 ResourceManager 申请(claim)所需接口。


内部资源管理(Inner Resource Management)

  • 当链式控制器被配置(configured)后,Controller Manager 调用其 export_reference_interfaces()export_state_interfaces() 方法。
  • Controller Manager 接管这些导出接口的所有权(类似于 ResourceManager 管理硬件接口)。
  • 接口的“已申请”(claimed)状态由 Controller Manager 维护(使用与 ResourceManager 相同的数据结构)。

链式控制器的激活与停用

链式控制器的启停必须遵循严格顺序

  • 激活顺序:必须先激活所有后置控制器,才能激活前置控制器。
  • 停用顺序:必须先停用所有前置控制器,才能停用后置控制器。

可类比为“链条”:不能从中间断开或插入链节。

实用方法

  • 使用 switch_controllers 服务时,在 activate_controllers / deactivate_controllers 列表中一次性传入整个链
  • 使用 spawner 脚本时,添加 --activate-as-group 参数,可一次性激活整条链

调试输出状态说明

控制器状态 参考接口状态 说明
未激活(inactive) 不可用、未申请 接口未导出
激活但未链式连接 可用、未申请 从话题订阅者获取参考值
激活且链式连接 可用、已申请 从链式前置控制器获取参考值

结语(Closing Remarks)

或许无需引入新的 ChainableController 类型
也可以直接在 ControllerInterface 中添加 export_reference_interfaces()export_state_interfaces() 方法,并默认返回 interface_configuration_type::NONE

这种方式可避免新增基类,保持接口简洁,同时通过默认实现兼容非链式控制器。