ROS2 机器人 少年创客营:Day 5

🤖 ROS2 机器人 少年创客营:Day 5

主题:动作 (Action) ------ 可中断的长时任务与实时反馈

👋 欢迎回来,指挥官!

昨天回顾 :我们学会了 Service (服务)。它像"打电话",有问必答。但是,如果任务很长怎么办?

  • 场景:你命令海龟:"请走到坐标 (9, 9)!"或者"请旋转 360 度!"
  • 问题 :海龟执行这些动作需要时间。如果用 Service,你的程序会卡住(阻塞)直到任务结束,期间什么都做不了!更糟糕的是,如果海龟半路被墙挡住了,你想让它立刻停下,Service 却做不到,因为它必须等到海龟到了(或失败)才能回复。

今天挑战

  1. 突破阻塞 :学习 Action (动作) 通信机制。
  2. 实时反馈:让海龟在行走/旋转过程中不断汇报:"我已走了 50%..."、"还剩 30 度"。
  3. 随时取消:实现"紧急制动",在海龟走到一半时强行叫停。

今日核心 :掌握 ROS 2 中最强大的通信方式 ------ Action,它是控制机器人长时任务(如导航、机械臂抓取)的终极武器!


🗺️ 今日探险地图 (Checklist)

  • 🆚 概念对决:Topic vs Service vs Action,到底什么时候用哪个?
  • 🔍 现场侦查 :使用命令行查看现有的 Action 服务器(就像刚才看到的 rotate_absolute)。
  • 📦 消息结构:拆解 Action 的三大件:Goal, Feedback, Result。
  • 🛠️ 命令行实战 :向 /turtle1/rotate_absolute 发送目标并监控进度。
  • 🧠 代码进阶 :编写 Action Client,实现自动发送目标并在中途取消。
  • 🏆 终极任务:指挥海龟进行"长途奔袭",并在中途实施"紧急制动"!

🆚 第一关:通信三巨头大比拼

在 ROS 2 中,我们有三种通信方式,它们各司其职:

特性 Topic (话题) Service (服务) Action (动作)
模式 发布/订阅 (广播) 请求/响应 (同步) 目标/反馈/结果 (异步)
数据流 单向 (One-way) 双向 (一次请求,一次回复) 双向持续流 (请求 -> 多次反馈 -> 最终结果)
阻塞性 非阻塞 (发完就跑) 阻塞 (等待回复) 非阻塞 (发送后可继续做别的事)
可取消性 ❌ 不可取消 ❌ 不可取消 可随时取消
典型场景 传感器数据 (激光雷达)高频控制指令 开关机、重置、查询状态短任务 导航、机械臂抓取任何耗时长的任务
比喻 📻 收音机 📞 打电话 🚀 发射导弹 + 遥测(发射后实时监控,可随时自毁)

💡 为什么需要 Action?

想象你在下载一个大文件:

  • Service:点击下载 -> 屏幕黑屏等待 -> 下载完成显示"成功"。(体验极差!)
  • Action:点击下载 -> 显示进度条 10%...50%...90% -> 完成。而且你可以在 50% 时点击"取消"。(完美!)

🔍 第二关:现场侦查 (命令行实战)

在你动手写代码之前,我们先看看系统中已经有哪些 Action 准备好了。
(这正是你刚才截图中展示的内容!)

1. 列出所有 Action

打开终端,输入:

bash 复制代码
ros2 action list

👀 观察现象

你应该能看到:

text 复制代码
/turtle1/rotate_absolute

这说明 turtlesim 节点已经作为一个 Action Server 启动好了,它在等待我们发送"旋转目标"。

2. 查看 Action 详情

输入:

bash 复制代码
ros2 action info /turtle1/rotate_absolute

👀 观察现象(参考你的截图):

text 复制代码
Action: /turtle1/rotate_absolute
Action clients: 0
Action servers: 1
    /turtlesim
  • Action servers: 1 (/turtlesim):有一个服务器(海龟)在监听。
  • Action clients: 0:目前还没有人(客户端)给它发指令。

🎯 任务 :这就是我们的靶子!接下来我们要成为那个 Client,把 clients 的数量变成 1!


📦 第三关:解剖 Action 消息

Action 的消息定义比 Service 复杂,它包含三个部分(以 RotateAbsolute 为例):

plaintext 复制代码
# 1. Goal (目标):你要它做什么?
float32 theta  # 目标角度(弧度),例如 1.57 (90 度)

---
# 2. Feedback (反馈):做得怎么样了?(周期性发送)
float32 remaining  # 还需要转多少度

---
# 3. Result (结果):最终做完了吗?(只发送一次)
bool success     # 是否成功
string message   # 结果描述
  • Goal: 客户端发给服务器(例如:转到 1.57 弧度)。
  • Feedback: 服务器不断发给客户端(例如:还剩 1.0 弧度...还剩 0.5 弧度...)。
  • Result: 任务结束时,服务器发给客户端(例如:成功到达)。

🛠️ 第四关:命令行操控 Action

现在,让我们不写代码,直接用命令行体验 Action 的强大功能:实时反馈

1. 发送旋转目标

在终端输入以下命令(注意 --feedback 参数,这是灵魂!):

bash 复制代码
ros2 action send_goal /turtle1/rotate_absolute turtlesim/action/RotateAbsolute "{theta: 1.57}" --feedback

🔍 命令拆解

  • send_goal:发送一个行动目标。
  • /turtle1/rotate_absolute:目标 Action 的名字。
  • turtlesim/action/RotateAbsolute:消息类型。
  • "{theta: 1.57}":具体的参数(转 90 度)。
  • --feedback关键参数! 加上它,你才能在终端看到实时的进度更新。

👀 观察现象

  1. 海龟开始旋转。

  2. 终端不会卡住,而是疯狂刷屏:

    text 复制代码
    Sending goal...
    Goal accepted with ID: ...
    Feedback: {remaining: 1.4}
    Feedback: {remaining: 1.2}
    Feedback: {remaining: 0.8}
    ...
    Result: {success: true, message: 'Target reached'}
  3. 这就是 Action 的魅力:你在等待结果的同时,能清楚知道过程!

2. 尝试"紧急制动" (取消任务)

这次我们发一个大一点的目标,比如转两圈 (6.28 弧度),然后在它转的时候按下 Ctrl + C

bash 复制代码
ros2 action send_goal /turtle1/rotate_absolute turtlesim/action/RotateAbsolute "{theta: 6.28}" --feedback
  • 当看到 Feedback 开始滚动时,迅速按下 Ctrl + C
  • 现象 :终端会显示 Canceling goal...,海龟会立刻停止旋转
  • 这就是 可取消性,Service 做不到这一点。

💻 第五关:代码实战 ------ 编写智能指挥官

现在,我们要用 Python 编写一个 Action Client,让它自动执行以下逻辑:

  1. 发送目标:让海龟旋转 360 度 (6.28 弧度)。
  2. 监听反馈:打印剩余角度。
  3. 自动取消 :当剩余角度小于 2.0 弧度(还没转完)时,主动取消任务,测试"紧急制动"功能。

📝 代码文件:action_client_turtle.py

python 复制代码
#!/usr/bin/env python3
import rclpy
from rclpy.action import ActionClient
from rclpy.node import Node
from turtlesim.action import RotateAbsolute

class SmartTurtleCommander(Node):
    def __init__(self):
        super().__init__('smart_turtle_commander')
        
        # 1. 创建 Action Client
        # 参数:节点本身,Action 类型,Action 名称
        self._action_client = ActionClient(self, RotateAbsolute, '/turtle1/rotate_absolute')
        
        self.goal_handle = None
        self.cancel_triggered = False

        self.get_logger().info('⏳ 等待 Action 服务器启动...')
        
        # 等待服务器上线 (最多等 10 秒)
        if not self._action_client.wait_for_server(timeout_sec=10.0):
            self.get_logger().error('❌ 未找到 Action 服务器!请确保 turtlesim_node 已运行。')
            return

        self.get_logger().info('✅ 服务器已连接!准备发射目标...')
        
        # 2. 构造目标消息
        goal_msg = RotateAbsolute.Goal()
        goal_msg.theta = 6.28  # 目标:旋转 360 度 (2 * pi)
        
        self.get_logger().info(f'🎯 发送目标:旋转 {goal_msg.theta} 弧度 (约 360 度)')
        
        # 3. 异步发送目标
        self._send_goal_future = self._action_client.send_goal_async(
            goal_msg,
            feedback_callback=self.feedback_callback
        )
        
        # 注册回调:当服务器回应"收到目标"时触发
        self._send_goal_future.add_done_callback(self.goal_response_callback)

    def goal_response_callback(self, future):
        """处理服务器对目标的响应"""
        self.goal_handle = future.result()
        
        if not self.goal_handle.accepted:
            self.get_logger().info('❌ 目标被服务器拒绝')
            rclpy.shutdown()
            return
        
        self.get_logger().info('✅ 目标已接受,海龟开始旋转!监控中...')
        
        # 注册回调:当任务最终结束时触发
        self._get_result_future = self.goal_handle.get_result_async()
        self._get_result_future.add_done_callback(self.get_result_callback)

    def feedback_callback(self, feedback_msg):
        """处理实时反馈"""
        feedback = feedback_msg.feedback
        remaining = feedback.remaining
        
        # 打印进度
        self.get_logger().info(f'📈 [进度] 剩余角度:{remaining:.2f} 弧度')
        
        # 🚨 核心逻辑:自动取消!
        # 如果剩余角度小于 1.0 弧度 (还没转完),且尚未触发过取消
        if remaining < 1.0 and not self.cancel_triggered:
            self.cancel_triggered = True
            self.get_logger().warn('⚠️ 触发条件:剩余 < 1.0 rad! 执行紧急取消!')
            
            # 发送取消请求
            self.goal_handle.cancel_goal_async()

    def get_result_callback(self, future):
        """处理最终结果"""
        result = future.result().result
        status = future.result().status
        
        # 状态码说明:1=SUCCEEDED, 2=CANCELED, 3=ABORTED
        if status == 2: 
            self.get_logger().info('🛑 任务已被成功取消!海龟停下了。')
        elif status == 1 and result.success:
            self.get_logger().info('✅ 任务圆满完成!')
        else:
            self.get_logger().info('❌ 任务失败或被中止')
        
        # 任务结束,关闭节点
        rclpy.shutdown()

def main(args=None):
    rclpy.init(args=args)
    node = SmartTurtleCommander()
    
    try:
        rclpy.spin(node)
    except KeyboardInterrupt:
        pass
    finally:
        node.destroy_node()

if __name__ == '__main__':
    main()

🚀 第四关:编译与运行

1. 更新 setup.py

添加新的入口点:

python 复制代码
'start_action = my_turtle_bot.action_client_turtle:main',

2. 构建与运行

bash 复制代码
cd ~/ros2_ws
colcon build
source install/setup.bash

# 终端 1: 启动仿真器
ros2 run turtlesim turtlesim_node

# 终端 2: 启动 Action 客户端
ros2 run my_turtle_bot start_action

👀 预期结果

  • 海龟开始旋转。
  • 终端显示剩余角度不断减小。
  • 当剩余角度小于 3.0 时,脚本自动发送取消指令。
  • 海龟立刻停止
  • 终端打印:"任务已被成功取消!"

🏆 终极挑战:画个"未完成"的正方形

结合 Day 1 的手动控制和今天的 Action 知识:

任务

  1. 编写一个脚本,让海龟使用 Action (rotate_absolute) 依次旋转 90 度,共 4 次(理论上画正方形)。
  2. 特殊规则:在第 3 次旋转时,强制在旋转到一半(剩余 0.5 弧度)时取消任务。
  3. 观察海龟的轨迹:它应该画出三条完整的边,和一条只有半条边的残缺正方形。

这证明了你可以精确控制任务的生命周期,这是高级机器人控制的基础!


📝 Day 5 总结清单

概念 关键词 作用
Action Goal, Feedback, Result 处理长时、可监控、可取消的任务
非阻塞 Async (异步) 发送任务后不卡死程序,可并行处理其他事
反馈机制 feedback_callback 实时了解任务进度(如导航剩余距离)
取消机制 cancel_goal_async() 遇到危险或需求变更时,立即停止任务
命令行工具 ros2 action list/info/send_goal 调试和测试 Action 的神器

🔮 明日预告 (Day 6)

海龟现在能执行长任务了,也能随时叫停。但是,每次都要手动敲命令启动 Server、Client、Rviz 太麻烦了!

明天,我们将学习 "一键启动" 的魔法:

  • Launch Files :编写 .launch.py 文件,一行命令同时启动仿真器、你的 Python 脚本和可视化工具。
  • Parameters:在不改代码的情况下,动态修改海龟的颜色、速度上限、背景色。
  • 系统集成:将之前几天的碎片拼成一个完整的、可交付的机器人系统!

准备好让你的机器人项目变得专业且高效了吗?明天见!


© 2026 ROS2 机器人 少年创客营 | 从单步指令到智能长时任务,Action 让机器人更懂人性

相关推荐
TE-茶叶蛋3 小时前
AI聊天机器人 / 轻量级对话系统(调用闭源API)
人工智能·机器人
无心水3 小时前
【OpenClaw:赚钱】案例9、模拟盘ROI+1560%:跨平台加密预测市场套利机器人全栈开发指南
机器人·区块链·金融科技·roi·openclaw·openclaw 变现
逻辑君5 小时前
Research in Brain-inspired Computing [9]-球机器人研究【2】
人工智能·深度学习·神经网络·机器人
沫儿笙5 小时前
机器人焊接气体自适应调节
机器人
maxmaxma5 小时前
ROS2 机器人 少年创客营:Day 4
机器人·ros2
鲁邦通物联网6 小时前
智慧园区物流无人车跨层架构:自主乘梯流程与边缘状态机解析
机器人·巡检机器人·机器人梯控·agv梯控·非侵入式采集·机器人乘梯·机器人自主乘梯
自动化智库7 小时前
库卡机器人外部轴配置
机器人
自动化智库7 小时前
KUKA机器人外部IO配置
机器人
破无差17 小时前
01春晚舞蹈机器人复刻_跟做记录
机器人