ros笔记04--从零体验ros2行为通信方式

介绍

行为是ros2中的一种通信方式,其多被用于一些长时间运行的任务,它包含了目标、反馈、结果三部分。
行为建立在主题和服务之上,其功能类似于服务,但它可以取消操作。行为通信方式还提供了稳定的反馈,而服务通信返回单个响应。
行为通行方式使用客户-服务模型,类似于发布者-订阅者模型。行为客户端节点向行为服务端节点发送目标,服务端节点确认目标并返回反馈流和执行结果。
如下图所示,图中可清晰的体现行为通信的数据流向。
在这里插入图片描述

创建步骤

体验官方案例

我们以官网小海龟为例子,打开小海龟节点和键盘终端遥控节点。

打开小海龟仿真节点
$ ros2 run turtlesim turtlesim_node
打开遥控节点
$ ros2 run turtlesim turtle_teleop_key

从终端输出的结果可以看到,若无打断的话目标可以正常完成,我们也可以通过F来中断一个行为目标。

初始状态完成目标和取消
在这里插入图片描述在这里插入图片描述

我们也可以进一步通过 ros2 node info /node-name 来查看节点中包含的Action Servers 和 Clients。

$ ros2 node info /
...
  Action Servers:
    /turtle1/rotate_absolute: turtlesim/action/RotateAbsolute

$ ros2 node info /teleop_turtle
  Action Clients:
    /turtle1/rotate_absolute: turtlesim/action/RotateAbsolute

通过 ros2 action send_goal 让小海龟移动,通过 --feedback 来查看本次目标执行的反馈信息

小海龟旋转180度
$ ros2 action send_goal /turtle1/rotate_absolute turtlesim/action/RotateAbsolute "{theta: 3.14}"
Waiting for an action server to become available...
Sending goal:
     theta: 3.14

Goal accepted with ID: 5e97b4ca2592488282727bbb36f2d90c

Result:
    delta: -3.119999885559082

Goal finished with status: SUCCEEDED

输出旋转过程中的反馈信息
$ ros2 action send_goal /turtle1/rotate_absolute turtlesim/action/RotateAbsolute "{theta: 3.14}"

基于python开发行为案例

创建action接口

  1. 创建接口包
    继续前几篇ros2博文,当前工作目录依旧为dev_ws
    $ cd dev_ws/src
    $ ros2 pkg create --license Apache-2.0 custom_action_interfaces
    
  2. 定义action文件
    $ cd custom_action_interfaces
    $ mkdir action
    $ vim action/Fibonacci.action
    int32 order
    ---
    int32[] sequence
    ---
    int32[] partial_sequence
    
  3. 在CMakeLists中新增依赖
    find_package(rosidl_default_generators REQUIRED)
    rosidl_generate_interfaces(${PROJECT_NAME}
      "action/Fibonacci.action"
    )
    
  4. 在package.xml下新增如下内容
    <buildtool_depend>rosidl_default_generators</buildtool_depend>
    <member_of_group>rosidl_interface_packages</member_of_group>
    
  5. 构建并测试接口
    # Change to the root of the workspace
    
    $ cd dev_ws
    # Build
    $ colcon build --packages-select custom_action_interfaces
    输出:
    Starting >>> custom_action_interfaces
    Finished <<< custom_action_interfaces [0.65s]                     
    
    Summary: 1 package finished [0.86s]
    
    输出接口信息:
    $ source install/local_setup.bash
    $ ros2 interface show custom_action_interfaces/action/Fibonacci
    
    在这里插入图片描述

创建action sever和client

  1. 创建保 action_tutorials_py
    $ cd dev_ws/src
    $ ros2 pkg create --build-type ament_python --license Apache-2.0 action_tutorials_py
    
  2. 创建 action server
    vim action_tutorials_py/action_tutorials_py/fibonacci_action_server.py
    import time
    
    import rclpy
    from rclpy.action import ActionServer
    from rclpy.node import Node
    
    from custom_action_interfaces.action import Fibonacci
    
    
    class FibonacciActionServer(Node):
    
        def __init__(self):
            super().__init__('fibonacci_action_server')
            self._action_server = ActionServer(
                self,
                Fibonacci,
                'fibonacci',
                self.execute_callback)
    
        def execute_callback(self, goal_handle):
            self.get_logger().info('Executing goal...')
    
            feedback_msg = Fibonacci.Feedback()
            feedback_msg.partial_sequence = [0, 1]
    
            for i in range(1, goal_handle.request.order):
                feedback_msg.partial_sequence.append(
                    feedback_msg.partial_sequence[i] + feedback_msg.partial_sequence[i-1])
                self.get_logger().info('Feedback: {0}'.format(feedback_msg.partial_sequence))
                goal_handle.publish_feedback(feedback_msg)
                time.sleep(1)
    
            goal_handle.succeed()
    
            result = Fibonacci.Result()
            result.sequence = feedback_msg.partial_sequence
            return result
    
    
    def main(args=None):
        rclpy.init(args=args)
        fibonacci_action_server = FibonacciActionServer()
        rclpy.spin(fibonacci_action_server)
    
    
    if __name__ == '__main__':
        main()
    
  3. 创建 action client
    vim action_tutorials_py/action_tutorials_py/fibonacci_action_client.py
    import rclpy
    from rclpy.action import ActionClient
    from rclpy.node import Node
    
    from custom_action_interfaces.action import Fibonacci
    
    
    class FibonacciActionClient(Node):
    
        def __init__(self):
            super().__init__('fibonacci_action_client')
            self._action_client = ActionClient(self, Fibonacci, 'fibonacci')
    
        def send_goal(self, order):
            goal_msg = Fibonacci.Goal()
            goal_msg.order = order
    
            self._action_client.wait_for_server()
    
            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):
            goal_handle = future.result()
            if not goal_handle.accepted:
                self.get_logger().info('Goal rejected :(')
                return
    
            self.get_logger().info('Goal accepted :)')
    
            self._get_result_future = goal_handle.get_result_async()
            self._get_result_future.add_done_callback(self.get_result_callback)
    
        def get_result_callback(self, future):
            result = future.result().result
            self.get_logger().info('Result: {0}'.format(result.sequence))
            rclpy.shutdown()
    
        def feedback_callback(self, feedback_msg):
            feedback = feedback_msg.feedback
            self.get_logger().info('Received feedback: {0}'.format(feedback.partial_sequence))
    
    
    def main(args=None):
        rclpy.init(args=args)
        action_client = FibonacciActionClient()
        action_client.send_goal(10)
        rclpy.spin(action_client)
    
    
    if __name__ == '__main__':
        main()
    
  4. 在 package.xml 中新增依赖项
      <depend>action_tutorials_interfaces</depend>
      <exec_depend>rclpy</exec_depend>
    
  5. 在 setup.py中新增 entry point
        entry_points={
            'console_scripts': [
                'fibonacci_action_server = action_tutorials_py.fibonacci_action_server:main',
                'fibonacci_action_client = action_tutorials_py.fibonacci_action_client:main',
            ],
        },
    
  6. 构建 & 运行
    构建
    $ cd dev_ws
    $ colcon build --packages-select action_tutorials_py
    运行
    $ source install/setup.bash
    $ ros2 run action_tutorials_py fibonacci_action_server
    $ ros2 run action_tutorials_py fibonacci_action_client
    $ ros2 action send_goal fibonacci custom_action_interfaces/action/Fibonacci "{order: 5}"
    
    输出结果如下:
    在这里插入图片描述
    直接通过 ros2 action send_goal 来发送action请求
    在这里插入图片描述

注意事项

  1. 官方文档直接使用 python3 fibonacci_action_server.py 和 python3 fibonacci_action_client.py 来执行验证,此处为了保持python项目的统一,直接设置了 entry point 并进行了编译构建。

说明

软件版本
ubuntu24.04 Desktop
ros2 jazzy
python 3.12.4(conda)
参考文档
ros2 jazzy 官方文档 Understanding actions
ros2 jazzy 官方文档 Writing an action server and client
ros2官网demos jazzy/action_tutorials/action_tutorials_py

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

昕光xg

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值