4. Cyber RT核心概念

Apollo Cyber RT 是面向自动驾驶场景的高性能运行时框架。它把“谁在运行、数据如何流动、模块如何被调度、参数如何被管理”抽象为一组稳定的核心术语。理解这些术语及其通信模型,是后续进行模块治理、性能调优和故障排查的基础。本节将围绕 Node、Channel、Reader、Writer、Service、Client、Component、Timer 与参数服务展开,并给出它们之间的协作关系。

一、核心术语与职责边界

Cyber RT 的通信模型可以概括为“节点承载参与者,通道承载数据流,读写器完成收发,服务/客户端完成请求响应,组件与定时器负责调度,参数服务负责配置”。各术语的职责如下:

  • Node(节点):通信的基本参与单元,是创建 Reader、Writer、Service、Client 的入口。一个进程可以创建多个 Node,通常按功能域划分,例如感知节点、规划节点、控制节点。
  • Channel(通道):具名的数据管道,是发布/订阅的中间抽象。通道名全局唯一,例如 /apollo/perception/obstacles,消息类型在通道上固定。
  • Writer(写者):向某个 Channel 发布消息的句柄,一个 Writer 对应一个通道,可被多个 Reader 订阅。
  • Reader(读者):从某个 Channel 订阅消息的句柄,支持回调触发或主动轮询,可配置历史缓存与 QoS 策略。
  • Service(服务端):提供请求-响应式通信的服务对象,注册服务名并处理 Client 请求。
  • Client(客户端):向 Service 发起请求并等待响应的调用方,适合低频、需确认结果的交互。
  • Component(组件):Cyber RT 的模块封装单元,内部可声明 Reader、Writer、Service、Client 与 Timer,由框架统一加载和调度。
  • Timer(定时器):按周期或定时触发回调的调度工具,常用于周期控制、状态上报与心跳检测。
  • 参数服务(Parameter Service):集中管理运行期参数的键值服务,支持参数设置、查询与变更通知。

二、通信模型:发布/订阅与请求/响应

Cyber RT 主要提供两类通信模型。第一类是发布/订阅模型,由 Channel + Writer + Reader 构成,适合高频、异步、一对多的数据流,例如传感器数据、障碍物列表、规划轨迹。第二类是请求/响应模型,由 Service + Client 构成,适合低频、需要明确返回结果的交互,例如查询地图、请求标定、触发诊断。

发布/订阅模型中,Writer 将消息写入 Channel,框架根据订阅关系把消息分发给所有 Reader。Reader 可以注册回调函数,消息到达时自动触发;也可以主动轮询。Channel 是解耦的关键:发布者不需要知道订阅者是谁,订阅者也不需要知道发布者是谁,从而降低模块间耦合。

请求/响应模型中,Client 发起请求后会阻塞或异步等待 Service 返回响应。Service 通常由某个 Component 提供,服务名全局唯一。与发布/订阅相比,请求/响应有明确的调用边界和结果确认,但吞吐量较低,不适合高频数据流。

通信选型原则:高频、连续、一对多数据流优先使用 Channel + Writer/Reader;低频、需确认结果、点对点交互优先使用 Service + Client。

三、Component 与 Timer:模块化与调度

Component 是 Cyber RT 推荐的模块封装方式。一个 Component 继承自框架基类,在初始化阶段声明自己需要的 Reader、Writer、Service、Client 和 Timer。框架根据配置加载 Component,并为其分配线程资源。Component 内部通常包含一个或多个数据处理回调,由 Reader 或 Timer 触发。

Timer 是周期任务的核心工具。例如控制模块需要以 100 Hz 运行,可以创建一个周期为 10 ms 的 Timer,在回调中读取最新规划轨迹、计算控制指令并通过 Writer 发布。Timer 的周期、回调执行时间与线程池配置直接影响实时性,是运行时调优的重要参数。

// 伪代码:Component 中声明 Reader、Writer 与 Timer
class ControlComponent : public cyber::Component<ControlCommand> {
 public:
  bool Init() override {
    reader_ = node_->CreateReader<PlanningTrajectory>(
        "/apollo/planning/trajectory",
        [this](const std::shared_ptr<PlanningTrajectory>& msg) {
          latest_trajectory_ = msg;
        });
    writer_ = node_->CreateWriter<ControlCommand>(
        "/apollo/control/command");
    timer_ = node_->CreateTimer(10, [this]() { OnTimer(); });
    return true;
  }
 private:
  void OnTimer() {
    // 以 100 Hz 计算并发布控制指令
    writer_->Write(ComputeCommand(latest_trajectory_));
  }
};

四、参数服务:运行期配置管理

参数服务用于集中管理运行期可调参数,例如控制增益、滤波系数、阈值和开关。参数以键值形式存储,支持设置、查询和变更通知。模块可以在启动时读取参数,也可以在运行中监听参数变化并动态调整行为。相比硬编码或重启生效的配置文件,参数服务更适合需要在线调优的场景。

使用参数服务时需要注意:参数名应具备命名空间,避免冲突;参数变更通知应轻量,避免在回调中执行耗时操作;关键参数变更应记录日志,便于复盘。参数服务不是高频数据通道,不应承载传感器数据或控制指令。

五、核心对象对照与协作关系

核心对象 通信角色 典型使用场景 关键配置/注意点
Node 参与者入口 按功能域创建节点 命名清晰,避免单节点承载过多职责
Channel 数据管道 障碍物、轨迹、点云传输 通道名与消息类型需全局约定
Writer / Reader 发布 / 订阅 高频异步数据流 关注缓存深度、回调耗时与线程模型
Service / Client 请求 / 响应 查询地图、触发标定 避免高频调用,注意超时与重试
Component 模块封装 感知、规划、控制模块 Init 中集中声明资源,便于治理
Timer 周期调度 控制周期、状态上报 周期与回调耗时需匹配实时性要求
参数服务 配置管理 在线调参、阈值切换 命名空间隔离,变更需记录日志
Cyber RT 核心对象与通信模型 Node A(感知) Component Writer Channel /apollo/perception/obstacles 消息类型固定 · 全局唯一 Node B(规划) Component Reader Write Subscribe Client 请求 / 响应 Service 名全局唯一 适合低频、需确认结果 Service 处理请求并返回响应 查询地图 / 触发标定 避免高频调用 Request / Response Timer 周期触发 · 控制/上报/心跳 参数服务 键值管理 · 变更通知 · 在线调参 调度 配置 发布/订阅用于高频数据流,请求/响应用于低频确认交互,Component 统一封装,Timer 与参数服务提供调度与配置支撑

六、常见误区与复盘要点

误区一:把 Channel 当成普通队列,忽略消息类型与通道名的全局约定,导致订阅失败或类型不匹配。误区二:在 Reader 回调中执行耗时计算,阻塞通信线程,造成数据积压。误区三:用 Service/Client 传输高频数据,导致请求堆积和延迟升高。误区四:参数服务中存放大量动态数据,混淆配置与数据通道的边界。

复盘时建议检查:Node 与 Component 的职责是否清晰;Channel 命名与消息类型是否统一;Reader 回调是否轻量;Timer 周期与回调耗时是否匹配;Service 调用是否设置了超时与重试;参数变更是否有日志与回滚机制。通过这些检查,可以把 Cyber RT 的核心术语真正落到工程治理中,而不是停留在概念记忆层面。