ROS2学习(1)—核心概念

注:本文根据古月居老师视频整理而成

1. ROS2为何会替代ROS1?

  1. 要在资源有限的嵌入式系统中运行——>资源有限
  2. 要在有干扰的地方保证通信的可靠性——>易受到干扰
  3. 要做成产品走向市场——>成本昂贵,无法走向市场

2. ROS2的命令行工具——>基本与ROS1相同

1.ros2 topic

  1. ros2 topic list:显示所有话题
  2. ros2 topic info <话题名称>:显示节点信息,包含消息类型、发布者数量、订阅数量
  3. ros2 topic echo <话题名称>:打印某个话题中的消息数据——>相比于之前更加方便
  4. ros2 topic pub -rate 10 <话题> <消息> <tab补全>:向某个话题循环发送10次消息——>跟ROS1相同

2. ros2 service call <service_name> <service_type> <service_data> # 发送服务请求

3.动作指令

  1. ros2 action

4.录制

  1. ros2 record <话题>
  2. ros2 play <录制文件>

3. 工作空间

概念:实现机器人某项功能的所使用的文件夹

  1. 工作空间内会存在四个子空间
    1. src:源码空间,源代码之类
    2. install:安装空间,编译得到的可执行文件和脚本
    3. build:编译的中间文件
    4. log:日志空间

创建工作空间:自动初始化

$ mkdir -p ~/dev_ws/src    #-p代表递归文件夹
$ cd ~/dev_ws/src
$ git clone https://gitee.com/guyuehome/ros2_21_tutorials.git #下载课程所用源码

自动安装各种依赖

#初次使用ROS2需要安装的依赖
$ sudo apt install -y python3-pip
$ sudo pip3 install rosdepc
$ sudo rosdepc init
$ rosdepc update


$ cd ..  #返回主目录,cd ~/dev_ws
$ rosdepc install -i --from-path src --rosdistro humble -y   #查看src空间中所需要的源码

编译工作空间

$ sudo apt install python3-colcon-ros   #初次安装,colcon

#返回主目录进行编译
$ cd ~/dev_ws/
$ colcon build

设置环境变量

$ source install/local_setup.sh # 仅在当前终端生效
$ echo " source ~/dev_ws/install/local_setup.sh" >> ~/.bashrc # 所有终端均生效

总结

创建工作空间
安装依赖
编译工作空间
设置环境
mkdir
rosdepc
colcon
source

4. 功能包

创建功能包

$ ros2 pkg create --build-type <build-type> <package_name>

$ cd ~/dev_ws/src
$ ros2 pkg create --build-type ament_cmake learning_pkg_c               # C++
$ ros2 pkg create --build-type ament_python learning_pkg_python         # Python
  • build-type:创建类型
    • C/C++:ament_cmake
    • python: ament_python

编译功能包:可以在功能包编写完成代码之后,再进行编译

$ cd ~/dev_ws/src
$ colcon build   # 编译工作空间所有功能包
$ source install/local_setup.bash

5. 节点

职责

  1. 节点在机器人系统中的职责就是执行某些具体的任务
  2. 节点都是一个独立运行的可执行文件
  3. 节点可以在不同设备上,称之为分布式
  4. 每个节点都要有唯一的命名

节点流程:打开节点阀门->创建节点->实现节点->关闭节点阀门

编程接口初始化
创建节点并初始化
实现节点功能
销毁节点并关闭接口

注意

  1. 当修改功能包中代码后,需要重新编译运行——>(1)colcon build (2)source install/local_setup.bash

6.话题:节点间传输数据的桥梁

  1. 发布者和订阅者要统一数据的描述格式
  2. 消息是ROS中的一种接口定义方式

发布者代码解析

编程接口初始化
创建节点并初始化
创建发布者对象
创建并填充话题消息
发布话题消息
销毁节点并关闭接口
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
@作者: 古月居(www.guyuehome.com)
@说明: ROS2话题示例-发布“Hello World”话题
"""

import rclpy                                     # ROS2 Python接口库
from rclpy.node import Node                      # ROS2 节点类
from std_msgs.msg import String                  # 字符串消息类型

"""
创建一个发布者节点
"""
class PublisherNode(Node):

    def __init__(self, name):
        super().__init__(name)                                    # ROS2节点父类初始化
        self.pub = self.create_publisher(String, "chatter", 10)   # 创建发布者对象(消息类型、话题名、队列长度)
        self.timer = self.create_timer(0.5, self.timer_callback)  # 创建一个定时器(单位为秒的周期,定时执行的回调函数)

    def timer_callback(self):                                     # 创建定时器周期执行的回调函数
        msg = String()                                            # 创建一个String类型的消息对象
        msg.data = 'Hello World'                                  # 填充消息对象中的消息数据
        self.pub.publish(msg)                                     # 发布话题消息
        self.get_logger().info('Publishing: "%s"' % msg.data)     # 输出日志信息,提示已经完成话题发布

def main(args=None):                                 # ROS2节点主入口main函数
    rclpy.init(args=args)                            # ROS2 Python接口初始化
    node = PublisherNode("topic_helloworld_pub")     # 创建ROS2节点对象并进行初始化
    rclpy.spin(node)                                 # 循环等待ROS2退出
    node.destroy_node()                              # 销毁节点对象
    rclpy.shutdown()                                 # 关闭ROS2 Python接口

订阅者代码解析

编程接口初始化
创建节点对象并初始化
创建订阅者对象
回调函数并处理数据
销毁节点并关闭接口
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
@作者: 古月居(www.guyuehome.com)
@说明: ROS2话题示例-订阅“Hello World”话题消息
"""

import rclpy                      # ROS2 Python接口库
from rclpy.node   import Node     # ROS2 节点类
from std_msgs.msg import String   # ROS2标准定义的String消息

"""
创建一个订阅者节点
"""
class SubscriberNode(Node):

    def __init__(self, name):
        super().__init__(name)                             # ROS2节点父类初始化
        self.sub = self.create_subscription(\
            String, "chatter", self.listener_callback, 10) # 创建订阅者对象(消息类型、话题名、订阅者回调函数、队列长度)

    def listener_callback(self, msg):                      # 创建回调函数,执行收到话题消息后对数据的处理
        self.get_logger().info('I heard: "%s"' % msg.data) # 输出日志信息,提示订阅收到的话题消息

def main(args=None):                               # ROS2节点主入口main函数
    rclpy.init(args=args)                          # ROS2 Python接口初始化
    node = SubscriberNode("topic_helloworld_sub")  # 创建ROS2节点对象并进行初始化
    rclpy.spin(node)                               # 循环等待ROS2退出
    node.destroy_node()                            # 销毁节点对象
    rclpy.shutdown()                               # 关闭ROS2 Python接口

话题命令行常用操作

$ ros2 topic list                # 查看话题列表
$ ros2 topic info <topic_name>   # 查看话题信息
$ ros2 topic hz <topic_name>     # 查看话题发布频率
$ ros2 topic bw <topic_name>     # 查看话题传输带宽
$ ros2 topic echo <topic_name>   # 查看话题内消息数据
$ ros2 topic pub <topic_name> <msg_type> <msg_data>   # 发布话题消息

7.服务:你问我答的模式

  1. 如果服务器不存在,客户端会一直发送请求,直到服务器存在

客户端代码解析

编程接口初始化
创建节点对象并初始化
创建客户端
创建并发送请求
等待服务器响应
销毁节点并关闭接口
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
@作者: 古月居(www.guyuehome.com)
@说明: ROS2服务示例-发送两个加数,请求加法器计算
"""

import sys

import rclpy                                  # ROS2 Python接口库
from rclpy.node   import Node                 # ROS2 节点类
from learning_interface.srv import AddTwoInts # 自定义的服务接口

class adderClient(Node):
    def __init__(self, name):
        super().__init__(name)                                       # ROS2节点父类初始化
        self.client = self.create_client(AddTwoInts, 'add_two_ints') # 创建服务客户端对象(服务接口类型,服务名)
        while not self.client.wait_for_service(timeout_sec=1.0):     # 循环等待服务器端成功启动
            self.get_logger().info('service not available, waiting again...') 
        self.request = AddTwoInts.Request()                          # 创建服务请求的数据对象

    def send_request(self):                                          # 创建一个发送服务请求的函数
        self.request.a = int(sys.argv[1])
        self.request.b = int(sys.argv[2])
        self.future = self.client.call_async(self.request)           # 异步方式发送服务请求

def main(args=None):
    rclpy.init(args=args)                        # ROS2 Python接口初始化
    node = adderClient("service_adder_client")   # 创建ROS2节点对象并进行初始化
    node.send_request()                          # 发送服务请求

    while rclpy.ok():                            # ROS2系统正常运行
        rclpy.spin_once(node)                    # 循环执行一次节点

        if node.future.done():                   # 数据是否处理完成
            try:
                response = node.future.result()  # 接收服务器端的反馈数据
            except Exception as e:
                node.get_logger().info(
                    'Service call failed %r' % (e,))
            else:
                node.get_logger().info(          # 将收到的反馈信息打印输出
                    'Result of add_two_ints: for %d + %d = %d' % 
                    (node.request.a, node.request.b, response.sum))
            break

    node.destroy_node()                          # 销毁节点对象
    rclpy.shutdown()                             # 关闭ROS2 Python接口

服务器代码解析

编译接口代码
创建节点对象
创建服务器对象
创建回调函数进行服务
向客户端反馈结果
销毁节点并关闭接口
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
@作者: 古月居(www.guyuehome.com)
@说明: ROS2服务示例-提供加法器的服务器处理功能
"""

import rclpy                                     # ROS2 Python接口库
from rclpy.node   import Node                    # ROS2 节点类
from learning_interface.srv import AddTwoInts    # 自定义的服务接口

class adderServer(Node):
    def __init__(self, name):
        super().__init__(name)                                                           # ROS2节点父类初始化
        self.srv = self.create_service(AddTwoInts, 'add_two_ints', self.adder_callback)  # 创建服务器对象(接口类型、服务名、服务器回调函数)

    def adder_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(args=None):                             # ROS2节点主入口main函数
    rclpy.init(args=args)                        # ROS2 Python接口初始化
    node = adderServer("service_adder_server")   # 创建ROS2节点对象并进行初始化
    rclpy.spin(node)                             # 循环等待ROS2退出
    node.destroy_node()                          # 销毁节点对象
    rclpy.shutdown()                             # 关闭ROS2 Python接口

服务命令行操作

$ ros2 service list                  # 查看服务列表
$ ros2 service type <service_name>   # 查看服务数据类型
$ ros2 service call <service_name> <service_type> <service_data>   # 发送服务请求

8.总结

工作空间和功能包

  1. 工作空间和功能包创建过程

    创建工作空间
    安装依赖
    编译
    设置环境变量
    创建功能包
  2. 共同部分:当源码或其他地方发生变化时,需要重新编译和设置环境变量

    • 编译:clocon build
      • 工作空间是在主目录下编译
      • 功能包是在src空间下编译
    • 设置环境变量:source install/local_setup.bash
  3. 不同部分:

    • 创建:
      • 工作空间:mkdir ——>创建文件夹即可
      • 功能包(src文件夹下):ros2 pkg --build-type <build-type> <build-name>
        • C/C++:ros2 pkg --build-type ament_cmake <pkg_name>
        • Python:ros2 pkg --build-type ament_python<pkg_name>
    • 安装依赖:工作空间特有
      • rosdepc install -i --from-path src --rosdistro humble -y

节点、话题、服务

  1. 总体流程:

    编译接口初始化
    创建并初始化节点
    实现功能
    销毁节点并关闭接口
    • 实现功能部分:
      • 话题:发布、订阅
      • 服务:客户端、服务器
  2. 话题:发布——服务:客户端

    创建发布者
    创建并填充话题消息/请求数据
    发布话题消息
    创建客户端
    发送请求数据
    等待服务器响应
    • 共同部分:创建

      • 创建发布者/客户端:一行代码,略

      • 创建并填充话题消息/请求数据

        1. 创建话题消息/请求数据对象

        2. 向对象中填充数据

    • 不同部分:

      • 发布/发送
        • 发布者:直接发送(一行代码),略
        • 客户端:
          1. 选择发送方式,比如上文中的异步发送
          2. 发送
      • 等待服务器响应
        • 因为服务是实时的情况,所以需要不断的问答,等待服务器响应
  3. 话题:订阅——服务:服务端

    创建订阅者
    创建回调函数并处理数据/进行服务
    结束
    创建服务端
    向客户端反馈结果
    • 共同部分:创建回调函数并处理数据/进行服务
      • 回调函数:对接受到的数据进行处理
    • 不同部分:
      • 服务端需要将处理后的数据反馈回客户端
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值