ros笔记02--从零体验ros2中的服务通信方式

ros笔记02--从零体验ros2中的服务通信方式

介绍

在ROS 2中,服务指的是远程过程调用,client调用server,server节点收到数据后计算出结果并返回给client.
服务通常期望能快速返回,因此不应当用于处理长时间的任务; 若有长时间的任务可以考虑使用 ros2 中的行为 act.
在ros2中,服务的请求和响应结构通常被定义到一个 .srv 的文件中。本文基于python案例,从零开始创建一个计算 a + b 的服务。

创建步骤

  1. 新建 dev_ws 并初始化依赖信息

    $ mkdir -p dev_ws/src
    $ cd dev_ws
    $ rosdep install -i --from-path src --rosdistro jazzy -y
    输出: #All required rosdeps installed successfully
    
  2. 创建 interfaces, 新增 AddTwoInts.srv
    2.1 创建 pkg 并新增 srv/AddTwoInts.srv

    $ cd dev_ws/src
    $ ros2 pkg create --build-type ament_cmake --license Apache-2.0 example_interfaces
    cd dev_ws/src/example_interfaces
    $ mkdir srv
    $ vim srv/AddTwoInts.srv
    int64 a
    int64 b
    ---
    int64 sum
    

    2.2 在CMakeLists中新增依赖

    $ cd dev_ws/src/example_interfaces
    $ vim CMakeLists.txt
    # 新增如下内容
    find_package(rosidl_default_generators REQUIRED)
    rosidl_generate_interfaces(${PROJECT_NAME}
      "srv/AddTwoInts.srv"
     )
    

    2.3 在package.xml下新增如下内容

    <buildtool_depend>rosidl_default_generators</buildtool_depend>
    <exec_depend>rosidl_default_runtime</exec_depend>
    <member_of_group>rosidl_interface_packages</member_of_group>
    
  3. 创建service包
    在 src目录创建包

    $ cd dev_ws/src
    $ ros2 pkg create --build-type ament_python --license Apache-2.0 py_srvcli --dependencies rclpy example_interfaces
    

    3.1 新增 service_member_function.py
    vim py_srvcli/py_srvcli/service_member_function.py

    from example_interfaces.srv import AddTwoInts
    
    import rclpy
    from rclpy.node import Node
    
    
    class MinimalService(Node):
    
        def __init__(self):
            super().__init__('minimal_service')
            self.srv = self.create_service(AddTwoInts, 'add_two_ints', self.add_two_ints_callback)
    
        def add_two_ints_callback(self, request, response):
            response.sum = request.a + request.b
            self.get_logger().info('Incoming request\na: %d b: %d' % (request.a, request.b))
    
            return response
    
    
    def main():
        rclpy.init()
    
        minimal_service = MinimalService()
    
        rclpy.spin(minimal_service)
    
        rclpy.shutdown()
    
    
    if __name__ == '__main__':
        main()
    

    3.2 新增 client_member_function.py
    vim py_srvcli/py_srvcli/client_member_function.py

    import sys
    
    from example_interfaces.srv import AddTwoInts
    import rclpy
    from rclpy.node import Node
    
    
    class MinimalClientAsync(Node):
    
        def __init__(self):
            super().__init__('minimal_client_async')
            self.cli = self.create_client(AddTwoInts, 'add_two_ints')
            while not self.cli.wait_for_service(timeout_sec=1.0):
                self.get_logger().info('service not available, waiting again...')
            self.req = AddTwoInts.Request()
    
        def send_request(self, a, b):
            self.req.a = a
            self.req.b = b
            return self.cli.call_async(self.req)
    
    
    def main():
        rclpy.init()
    
        minimal_client = MinimalClientAsync()
        future = minimal_client.send_request(int(sys.argv[1]), int(sys.argv[2]))
        rclpy.spin_until_future_complete(minimal_client, future)
        response = future.result()
        minimal_client.get_logger().info(
            'Result of add_two_ints: for %d + %d = %d' %
            (int(sys.argv[1]), int(sys.argv[2]), response.sum))
    
        minimal_client.destroy_node()
        rclpy.shutdown()
    
    
    if __name__ == '__main__':
        main()
    

    3.3 在 setup.py的console_scripts 新增如下内容

      'service = py_srvcli.service_member_function:main',
      'client = py_srvcli.client_member_function:main',
    
  4. 编译运行

    $ cd dev_ws
    $ colcon build
    # 输出
    ...
    This may be promoted to an error in a future release of colcon-override-check.
    Starting >>> example_interfaces
    Finished <<< example_interfaces [4.11s]                     
    Starting >>> py_srvcli
    Finished <<< py_srvcli [1.01s]          
    
    Summary: 2 packages finished [5.21s]
    $ source install/setup.bash
    $ ros2 run py_srvcli service
    $ ros2 run py_srvcli client 2 3
    

    输出结果如下,service收到 2 和 3, client得到结果 5 在这里插入图片描述

注意事项

  1. 安装ros2的python版本最好和编译使用使用的python版本一致,否则会出现类似 Assertion `PyUnicode_IS_READY(name_attr)’ failed. 的错误
    笔者安装ros2的时候使用的python3.12 , 最初系统conda中python为3.10, 编译成功后运行client报错
    
    $ ros2 run py_srvcli client 2 3
    python3: /home/xg/files/code/gitee/learn-ros/dev_ws/build/example_interfaces/rosidl_generator_py/example_interfaces/srv/_add_two_ints_s.c:34: example_interfaces__srv__add_two_ints__request__convert_from_py: Assertion `PyUnicode_IS_READY(name_attr)' failed.
    [ros2run]: Aborted
    
    经过多次测试发现是由于编译的时候python版本和和安装时候不一致导致的,重新使用conda准备python3.12后恢复正常
    
  2. colcon build 常见报错
    对于指定权限版本的python可能会出现多种依赖缺失的情况,此时按需安装对应的pip包即可,以下为常见缺失包对应的报错和处理方法
    报错1:ModuleNotFoundError: No module named 'em'
    解决方法: pip3 install empy==3.3.2 -i https://mirrors.aliyun.com/pypi/simple/
    
    报错2: ModuleNotFoundError: No module named 'catkin_pkg'
    解决方法: pip3 install catkin_pkg -i https://mirrors.aliyun.com/pypi/simple
    
    报错3: Could NOT find Python3 (missing: Python3_NumPy_INCLUDE_DIRS NumPy) (found  version "3.12.4")
    解决方法:pip3 install numpy -i https://mirrors.aliyun.com/pypi/simple
    
    报错4: ModuleNotFoundError: No module named 'lark'
    解决方法: pip3 install lark-parser
    

说明

软件系统:
ubuntu24.04 Desktop
ros2 jazzy
python 3.12.4(conda)
参考文档:
Writing a simple service and client (Python)
Concepts/Basic/About-Services.html
理解 ROS2 服务

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

昕光xg

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

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

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

打赏作者

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

抵扣说明:

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

余额充值