☰
C++ 第 35 课:Service——“我问你,你回答我”
2026/10/5 8:57:09 网站建设 项目流程

两条不同的“因果链”:

Publisher → Topic → Subscriber → callback → 处理消息

描述的是:

一条消息怎么从发送端走到接收端。

而:

spin / timer

描述的是:

ROS2 节点什么时候去处理事件、什么事件会触发 callback。

把这两层分开,就清楚了。


一、先看 Publisher → Topic → Subscriber 这条链

假设 Publisher 发布:

msg.data = 100; publisher_->publish(msg);

数据流是:

Publisher │ │ 发送 data=100 ▼ Topic: /number │ ▼ Subscriber

到这里,意思只是:

Subscriber 对应的 Topic 上有一条新消息可以处理了。

但还差一步:

谁真正让 callback 执行?

这时候才轮到spin()。


二、spin()像“事件处理总管”

执行:

rclcpp::spin(node);

之后,可以粗略理解成:

一直检查这个 Node 有没有待处理事件

例如 Node 里可能同时有:

Subscriber Timer Service Action

spin()大概做:

有没有Subscriber消息? 有没有Timer到期? 有没有Service请求? 有没有其他事件?

如果发现:

/number 有新消息

它就去调用:

这个 Subscriber 对应的 callback

所以完整链应该是:

Publisher ↓ Topic ↓ Subscriber收到新消息 ↓ 消息成为“待处理事件” ↓ spin发现这个事件 ↓ 调用Subscriber callback ↓ 处理消息 ↓ callback结束 ↓ 回到spin继续等待

这个版本更完整。


三、所以spin()不在 Publisher 和 Topic 中间

不要理解成:

Publisher ↓ spin ↓ Topic

不对。

spin()主要是在:

接收端/节点内部负责调度事件。

可以画成:

Publisher │ ▼ Topic │ ▼ Subscriber │ │ 新消息等待处理 ▼ ┌─────────────────┐ │ spin │ │ 发现Subscriber事件│ └────────┬────────┘ ▼ callback ▼ 处理消息

四、那 Timer 又在哪里?

Timer 和 Topic 没有直接上下级关系。

Timer 是:

另外一种能够产生 callback 的事件源。

Subscriber 的触发来源是:

消息到了

Timer 的触发来源是:

时间到了

所以一个 Node 可能这样:

Node │ spin │ ┌─────────┴─────────┐ │ │ Subscriber有消息 Timer到时间 │ │ ▼ ▼ subscriberCallback timerCallback

这张图建议你记住。


五、举一个具体例子

假设一个 ROS2 节点同时有:

Subscriber: 监听 /vla_action Timer: 每100ms执行一次

程序进入:

rclcpp::spin(node);

然后真实运行可能是:

0 ms ↓ spin等待 50 ms ↓ /vla_action来了一条消息 ↓ spin发现Subscriber事件 ↓ actionCallback() ↓ 处理VLA动作 ↓ 回到spin 100 ms ↓ Timer到期 ↓ spin发现Timer事件 ↓ timerCallback() ↓ 发布机器人状态 ↓ 回到spin 180 ms ↓ 又来一条VLA Action ↓ actionCallback() 200 ms ↓ Timer再次到期 ↓ timerCallback()

所以:

spin()是总的事件调度循环;Subscriber 和 Timer 都是在给spin()提供“待处理事件”。


六、把三者关系压缩成一句话

Subscriber

消息来了 → 产生事件 → spin调callback

Timer

时间到了 → 产生事件 → spin调callback

spin

持续等待和处理这些事件

这就是三者的关系。


七、再看 Publisher,它又是什么角色?

Publisher 通常是:

callback 执行以后可能使用的一个“发消息工具”。

例如 Timer callback:

[this]() { publishNumber(); }

然后:

void publishNumber() { std_msgs::msg::Int32 msg; msg.data = 100; publisher_->publish(msg); }

完整链:

spin ↓ Timer到时间 ↓ timer callback ↓ publishNumber() ↓ Publisher发消息 ↓ Topic ↓ 另一个Node的Subscriber ↓ 另一个Node的spin发现事件 ↓ Subscriber callback ↓ 处理消息

现在你应该能看出:

一个节点里的 Timer callback,完全可以触发 Publisher,然后这个 Publisher 又让另一个节点产生 Subscriber 事件。

这就是 ROS2 节点之间真正“动起来”的样子。


八、VLA 场景再串一次

以后非常可能是:

VLA Node │ │ 模型推理完成 │ ▼ Publisher │ ▼ /vla_action │ ▼ RobotController Node 的 Subscriber │ ▼ 这个Node的spin发现新消息 │ ▼ actionCallback() │ ▼ 更新机械臂目标

同时 RobotController 还有:

Timer:每20ms ↓ spin发现Timer事件 ↓ controlCallback() ↓ 把最新目标发给机械臂

于是:

VLA Action 只是“更新目标” Timer 负责“周期执行控制”

这个结构以后非常常见。


上一课答案

  1. Timer 和 Subscriber 的触发条件:
Timer → 时间到了 Subscriber → 消息到了
    std::chrono::seconds(1)

    表示:

    1 秒的时间长度。

    在 Timer 中就是周期为 1 秒。

      [this]() { publishNumber(); }

      是:

      Timer 到期后执行的 callback。

      [this]允许 lambda 使用当前 Node 对象的成员,比如publishNumber()。

      1. 10 ms:
      1秒 = 1000ms 1000 / 10 = 100

      理想情况下约:

      100 Hz,也就是每秒执行 100 次。

      1. 补全:
      spin ↓ Timer到时间 ↓ Timer callback ↓ publishNumber() ↓ Publisher发消息

      第 35 课:Service——“我问你,你回答我”

      到现在我们学的 Topic 是:

      Publisher → 不断发消息 Subscriber → 监听消息

      这是:

      单向、持续的数据流。

      但有些事情不是“广播消息”,而是:

      我要明确问你一个问题,然后等你给我答案。

      例如机械臂:

      客户端: “机械臂准备好了吗?” 服务端: “准备好了。”

      这种通信更适合:

      Service


      1. Topic 和 Service 的直觉区别

      Topic 像:

      电台广播。

      Publisher:

      “当前关节角度30°” “当前关节角度31°” “当前关节角度32°”

      一直发。

      Subscriber:

      谁想听谁听。


      Service 更像:

      打客服电话。

      你主动:

      “请帮我查询一次机器人状态。”

      对方处理后明确返回:

      “当前状态:Ready。”

      也就是:

      Request ↓ 处理 ↓ Response

      2. Service 里有两个角色

      Server

      服务提供者:

      我能处理某种请求。

      例如:

      Robot Server: 可以处理“是否Ready”的查询

      Client

      请求方:

      我需要调用这个服务。

      例如:

      VLA节点: 询问机器人是否Ready

      所以:

      Client ↓ Request Server ↓ Response Client

      3. 和 Topic 对比

      Topic:

      Publisher ↓ Topic ↓ Subscriber

      Service:

      Client ↓ Request Service Server ↓ Response Client

      最大的不同:

      Topic 没有天然的“一问一答”;Service 天生就是请求—响应。


      4. 一个最简单的例子

      假设请求:

      a = 3 b = 5

      Service Server 负责:

      a + b

      返回:

      8

      流程:

      Client 发送 Request: a=3, b=5 ↓ Server callback ↓ 计算 3+5 ↓ Response: sum=8 ↓ Client收到结果

      5. Server 仍然使用 callback

      注意:

      Service 仍然没有抛弃我们前面学的事件机制。

      Server 通常会注册一个:

      Service callback

      然后:

      Client请求到达 ↓ 产生Service事件 ↓ spin发现事件 ↓ 执行Service callback ↓ 填Response

      所以你会发现:

      spin + callback是 ROS2 很统一的核心思维。


      6. 和 Subscriber 的区别

      Subscriber callback:

      收到消息 ↓ 处理消息

      Service callback:

      收到请求 ↓ 处理请求 ↓ 还要给对方准备一个Response

      Service 多了一步:

      回答。


      7. VLA/机器人什么时候适合 Service?

      例如:

      很适合 Service

      “机械臂是否初始化完成?” “请执行一次复位。” “请获取一次设备状态。” “请清除错误。”

      因为这些像:

      一次请求 → 一个明确结果。


      不适合 Service

      例如:

      相机连续图像 JointState连续反馈 VLA不断输出动作

      这些是连续数据流,更适合:

      Topic。


      8. 一个简单判断法

      问自己:

      “我是想持续接收数据,还是想主动问一次并得到回答?”

      持续数据:

      Topic

      一问一答:

      Service

      9. Service 和 spin 的关系

      完整流程:

      rclcpp::spin(node) ↓ 持续等待事件 ↓ Client发来Request ↓ Service事件出现 ↓ spin发现 ↓ 调用Service callback ↓ 生成Response ↓ 返回给Client ↓ 继续spin

      所以:

      Service 同样依赖事件循环。


      10. 一个 ROS2 Node 可以同时拥有

      RobotController Node │ ├── Subscriber │ /vla_action │ ├── Publisher │ /joint_command │ ├── Timer │ 每20ms控制 │ └── Service /reset_robot

      也就是:

      一个 Node 不是只能干一种事。

      这点以后一定要习惯。


      本课核心对比

      机制典型用途触发
      Topic连续数据流消息到达
      Timer周期任务时间到达
      Service一次请求/响应请求到达
      spin统一等待、调度这些事件持续运行

      本课小练习

      1. /joint_states连续发布关节状态,更适合 Topic 还是 Service?

      2. “机械臂是否已经初始化完成?”更适合 Topic 还是 Service?

      3. Service 中两个角色分别叫什么?

      4. Service Server 的 callback 一般比 Subscriber callback 多做什么?

      5. 补全:

      Client ↓ ______ ↓ Server callback ↓ ______ ↓ Client

      需要专业的网站建设服务?

      联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

      立即咨询