文章目录
ROS(Robot Operating System)分为两个版本:ROS1 和 ROS2。它们之间有很多不同,特别是在架构、通信机制和操作系统支持等方面。
- ROS1的架构较为简单,但缺乏实时性支持和分布式系统的灵活性。
- ROS2在设计上更为现代,采用DDS协议来实现去中心化通信,增强了实时性、跨平台性、分布式能力和安全性。
- 示例场景:假设用ROS1控制扫地机器人,若主节点崩溃,机器人会“僵住”;用ROS2则各模块(传感器、电机)仍能自主通信,继续工作。
特性 | ROS1 | ROS2 |
---|---|---|
通信机制 | 基于 ROS Master | 使用 DDS(去中心化,支持分布式) |
实时性支持 | 不支持实时性 | 支持实时性,适合实时系统 |
平台支持 | 主要支持 Linux,有限的 Windows/macOS 支持 | 跨平台支持(Linux, Windows, macOS, RTOS) |
节点生命周期 | 无生命周期管理 | 引入了节点生命周期管理 |
构建系统 | catkin | ament/colcon |
多机支持 | 支持有限 | 原生支持分布式、跨机器通信 |
消息序列化 | ROS1 自定义序列化 | 使用 DDS 高效序列化 |
ROS2 相比 ROS1 更加注重实时性、跨平台支持、分布式系统以及工业级别的可靠性和性能。如果你正在开发一个新的系统,特别是对于需要实时性和更高性能的系统,ROS2 是更好的选择。对于许多现有的机器人应用,尤其是在传统工业应用中,ROS1 仍然是非常成熟的解决方案,但随着 ROS2 生态系统的逐渐成熟,ROS2 会成为未来的主要发展方向。
推荐论文《Exploring the Performance of ROS》
ROS1 melodic 使用介绍-https://blog.csdn.net/weixin_41469272/article/details/105289174
ROS1与ROS2的核心区别及原理机制
1. 架构设计:从“电话交换机”到“点对点通信”
- ROS1:依赖单一主节点(ROS Master),ROS1使用
Master
节点来协调通信,所有的节点都需要连接到Master,Master管理各个节点之间的通信信息。Master是中心化的系统。类似电话交换机,一旦主节点崩溃,整个系统瘫痪。 - ROS2:采用去中心化的DDS(数据分发服务
Data Distribution Service
)协议作为底层通信机制,DDS是一种面向分布式系统的协议,支持实时、可扩展和多平台的通信。ROS2的通信是去中心化的,不再依赖中央的Master节点,而是节点直接通信。DDS是工业级通信标准,支持自动发现节点,系统更健壮,适合分布式多机器人场景。
DDS的核心是一个以数据为中心的发布-订阅(Data-Centric Publish-Subscribe,DCPS)模型,该模型旨在为分布式异构平台上的进程间提供高效的数据传输。DCPS模型创建了一个可供任何独立应用程序访问的"全局数据空间",通过类型化接口实现高效数据分发。在DDS架构中,每个发布或订阅数据的进程称为参与者(Participant),这对应到ROS中的一个节点。参与者可以通过类型化接口对全局数据空间进行读写操作。
上图简要说明了ROS1和ROS2的系统模型。图中左侧,ROS1的实现包括通信系统TCPROS/UDPROS。由于ROS1的实现,这种通信需要一个主进程(在分布式系统中是唯一的)。相比之下,如右侧图所示,ROS2基于DDS,并包含一个DDS抽象层。由于这个抽象层,用户不需要了解DDS的API。这个层次使得ROS2可以拥有更高层次的配置,并优化DDS的利用。此外,由于使用DDS,ROS2不需要主进程。这在容错性方面是一个重要的点。
2. 通信机制:从“固定线路”到“智能物流”
ROS应用程序由独立的计算进程组成,这些进程称为节点(nodes),它们促进了故障隔离、开发速度的提升、模块化和代码复用。节点之间的通信基于发布/订阅模型。在这种模型中,节点通过主题(topic)传递消息进行通信。消息有一个简单的数据结构(类似于C语言中的结构体),由.msg文件定义。节点通过主题名称来识别消息的内容。当一个节点向一个主题发布消息时,另一个节点订阅该主题并利用消息。例如,如下图所示,“Camera”节点将消息发送到“Images”主题。主题中的消息被“Car Detection”节点和“Pedestrian Detection”节点接收。发布/订阅模型被设计为在细粒度的尺度上模块化,适合分布式系统。
在ROS1中,上述通信系统作为基于TCPROS和UDPROS的中间件实现,使用TCP和UDP套接字。当订阅节点和发布节点启动时,它们会与主节点交互,主节点收集信息并管理主题,类似于服务器。通过与主节点的XML/远程过程调用(RPC)事务后,订阅节点请求与发布节点的连接,使用约定的连接协议。实际数据(即消息)直接在节点之间传输,不通过主节点。ROS1实现了节点之间的点对点数据传输。
ROS1可选地提供了nodelets,这些nodelets提供了优化数据传输的高效节点组合,避免了TCPROS和UDPROS的使用。nodelet通过传递指针在同一进程中的节点之间实现非序列化的数据传输。ROS2继承了这个选项作为进程内通信,解决了nodelets的一些基本问题(例如,安全内存访问问题)。
ROS2采用DDS作为其通信系统。然而,进程内通信是在没有DDS的情况下执行的。DDS由许多供应商提供,具有多种实现类型。开发人员可以从各种DDS供应商中选择合适的DDS实现。
-
ROS1:使用自定义协议(TCPROS/UDPROS),实时性和可靠性有限。例如,网络不稳定时可能丢数据。-
-
ROS2:基于DDS,支持QoS(服务质量)配置,开发者可调整传输策略(如保证数据必达、容忍延迟)。类似物流公司,可根据需求选择“次日达”或“经济件”。
DCPS模型通信机制:
DCPS模型由DCPS实体组成:DomainParticipant(域参与者)、Publisher(发布者)、Subscriber(订阅者)、DataWriter(数据写入器)、DataReader(数据读取器)和Topic(主题)。各进程之间的数据传输是根据服务质量(QoS)策略执行的。
-
DomainParticipant(域参与者):DomainParticipant是其他实体的容器,也是服务的入口点。在DDS中,所有应用程序都在一个域内进行通信,这有助于隔离和优化通信。
-
Publisher(发布者):Publisher是负责数据发布的对象。Publisher管理一个或多个DataWriter,向一个或多个Topic发布数据。
-
Subscriber(订阅者):Subscriber负责接收已发布的数据并使数据可用。Subscriber代表一个或多个DataReader。根据Subscriber,DomainParticipant可以接收并分发不同类型的数据。
-
DataWriter(数据写入器):DataWriter是DomainParticipant必须通过Publisher发布数据的对象。DataWriter发布特定类型的数据。
-
DataReader(数据读取器):DataReader是附加到Subscriber的对象。通过DataReader,DomainParticipant可以接收和访问数据,其类型必须与DataWriter的类型一致。
-
Topic(主题):Topic用于在DataWriter和DataReader之间标识每个数据对象。每个Topic由名称和数据类型定义。
-
QoS Policy(服务质量策略):所有DCPS实体都有QoS策略,表示它们的数据传输行为。每个数据传输可以通过许多QoS策略选项,在不同的粒度级别进行配置。下图显示了一个遵循QoS策略的DDS数据传输示例。QoS策略配置了截止时间、历史深度和通信可靠性。
在DCPS模型中,给定类型的数据从一个或多个DataWriter发布到一个Topic(其名称在域内唯一)。一个或多个DataReader通过主题名称识别数据对象,从而订阅该主题。完成此事务后,DataWriter使用实时发布/订阅(RTPS)协议[20]在分布式系统中与DataReader连接。RTPS协议是DDS标准协议,允许来自多个供应商的DDS实现通过抽象和优化传输(如TCP/UDP/IP)进行互操作。RTPS协议灵活,并被定义为利用QoS策略。多个供应商使用UDP和共享内存传输进行通信。然而,在某些情况下,可能需要TCP协议用于发现和数据交换。
在RTPS协议中,DataWriter和DataReader之间的数据传输根据QoS策略执行。每个DCPS实体根据用户指定的唯一QoS策略管理数据样本。DCPS中间件负责基于QoS策略的数据传输。在不考虑详细的传输实现的情况下,DDS用户通过DDS API生成代码作为DomainParticipant,包括QoS策略。这样,用户可以专注于他们的目的,并轻松地确定如何满足实时约束。
3. 实时性
- ROS1:实时性差(如机械臂控制难精准同步)。尽管可以通过第三方的实时操作系统来改进,但ROS1本身并不适合进行严格的实时控制。
- ROS2:ROS2为实时系统设计,支持更高效的实时性要求。它能够通过一些实时操作系统(RTOS)和特定的DDS配置来提供更高精度的时序控制。
4. 跨平台支持
- ROS1:ROS1主要支持Linux操作系统,虽然有一些对Windows和Mac的支持,但并不完美。
- ROS2:ROS2增加了对Windows、macOS和Linux的原生支持。它的跨平台能力比ROS1更强,特别是在不同操作系统间的兼容性和部署上有很大改进。
5. 开发与维护
- ROS1:ROS1在设计时使用了一些当前已经过时的工具和库,使得它的开发和维护变得复杂。
- ROS2:ROS2采用了现代的开发工具和更简洁的设计,使得开发者能够更轻松地进行扩展和维护。ROS2的架构相较于ROS1来说更为模块化和灵活。
6. 多机器人系统与依赖管理
- ROS1:在面对多机器人系统和分布式系统时,配置复杂,依赖管理(如第三方库)较麻烦。
- ROS2:ROS2在设计上更适合分布式应用,支持多机器人协同工作。并且它提供了更强的安全性(如加密和认证)和更好的网络可靠性。原生支持多机器人通信,依赖管理更规范(类似Python的
requirements.txt
),构建工具从catkin
升级为ament/colcon
。
其他:ROS 1 通常使用 Python 2(根据发行版不同),而 ROS 2 使用 Python 3。
ROS2基础使用命令
创建工作区与包
mkdir -p ros2_ws/src
cd ros2_ws/src
ros2 pkg create my_pkg --dependencies rclcpp std_msgs # 创建包,依赖ROS2库
ros2 pkg create --build-type ament_python <package_name> #可以生成setup.py package.xml
#注意python版本改动也需要编译才能生效,`setup.py `用来设置node运行入口`entry_points`,以及package name
colcon build --symlink-install
#使用 --symlink-install 参数可以确保 Python 脚本在开发过程中可以直接更新而无需重新安装。
安装colcon
#安装colcon用于管理ros2工作空间
sudo apt install python3-colcon-common-extensions
编译代码
cd ros2_ws
colcon build # 编译整个工作区
source install/setup.bash # 激活环境
colcon build --packages-select <package_name> #编译指定node
source bashfile
和bash bashfile
的区别- 使用 source(或 .)执行脚本时,脚本会在 当前 shell 中执行,而不是在子 shell 中。
- 使用 bash 执行脚本时,脚本会在 子 shell 中运行。这意味着,所有在脚本中设置的环境变量或其他设置(如 export 的变量、函数等)仅会影响子 shell,并不会影响父 shell(即当前终端会话)。执行完成后,子 shell 会退出,脚本中的更改不会继续影响当前的终端环境。
安装包依赖
#自动安装工作空间下的pkg需要的包:
rosdep install --from-paths src --ignore-src -r -y
#通过apt安装对应包
sudo apt-get install ros-$ROS_DISTRO-<pac_name>
#eg:
sudo apt-get install ros-$ROS_DISTRO-rqt-tf-tree
sudo apt-get install ros-$ROS_DISTRO-rqt-tf-tool
#注意有些包 ros-$ROS_DISTRO-<pac_name>只能安装cpp版本,python包需要额外安装
sudo apt-get install python3-<pac_name>
#可用apt list查看包名
#eg:
apt list |grep sensors-msg
sudo apt-get install python3-sensor-msgs
运行节点
ros2 run my_pkg my_node # 运行名为my_node的节点
ros2 run your_package your_node --ros-args --log-level DEBUG #设置log级别
编译清除
清除编译内容,以及cmake文件
sudo apt install python3-colcon-clean #需要安装colcon clean 工具
colcon clean {packages,workspace}
话题管理
ros2 topic list # 查看所有话题
ros2 topic echo /chatter # 订阅话题并打印消息
ros2 topic pub /chatter std_msgs/String "data: 'Hello'" # 发布消息
服务与参数
ros2 service list # 列出所有服务
ros2 param get <node_name> <param_name> # 获取某个参数的值
ros2 param set /my_node param_name value # 修改节点参数
启动多个节点(Launch文件)
创建launch.py
文件,使用Python编写启动配置:
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package='my_pkg',
executable='talker',
name='my_talker'
),
Node(
package='my_pkg',
executable='listener',
name='my_listener'
)
])
运行命令:
ros2 launch my_pkg launch.py
查找包及安装地址
- 查找包的安装位置:
ros2 pkg prefix <包>
#eg:
ros2 pkg prefix tf2_sensor_msgs
- 查找包是否安装
ros2 pkg list | grep <包>
#eg:
ros2 pkg list | grep tf2_sensor_msgs
- 查找包的python版本安装或绑定
find /opt/ros/humble/lib/python3.10/site-packages -name "<包名>*"
- 查找包的安装位置
dpkg -L <包名>
#eg:
dpkg-query -L python3-sensor-msgs
- python包的安装地址
/opt/ros//lib/python3.x/site-packages:标准的 ROS 2 Python 包安装路径。ros-${ROS_DISTRO}-pkgxxx 安装路径
/opt/ros//local/lib/python3.x/dist-packages:某些 ROS 2 包或额外的 Python 依赖被安装到的地方。尤其是在使用系统级的 apt 安装时,Python 包可能安装到 dist-packages,而不是默认的 site-packages 路径。
/usr/lib/python3/dist-packages:系统级的 Python 包,通常与 ROS 1 一起使用。pythonx-pkgxxx安装路径,有些ros-${ROS_DISTRO}-pkgxxx不提供python版本(仅与cpp相关包)
tf信息输出
使用 tf2_tools 生成 TF Tree 图形:
#安装工具包:
sudo apt install ros-${ROS_DISTRO}-tf2-tools
#生成tf tree pdf:
ros2 run tf2_tools view_frames
可视化查看tf tree:
#安装工具包:
sudo apt install ros-${ROS_DISTRO}-rqt-tf-tree
#使用`rqt`打开可视化界面,Plugins -> Visualization -> TF Tree 打开tf_tree
通过topic输出tf信息:
ros2 topic echo /tf # 查看动态 TF 变换,固定的坐标系关系,仅需要广播一次
ros2 topic echo /tf_static # 查看静态 TF 变换,动态坐标关系,
ros2 run tf2_ros tf2_echo [父坐标系] [子坐标系] # 输出两坐标系间的变换关系
python 相关
python 包环境变量:PYTHONPATH
python代码中打印:
import sys
print(sys.path)
查看指定包的位置:
pip show 包名
import site
print(site.getsitepackages())
import pkg_resources
print(pkg_resources.get_distribution("包名").location)
__name__
变量的特性:分离脚本与模块功能,允许同一文件兼具脚本及模块两种角色。
Python 每个模块均包含内置变量 __name__
,其值取决于模块运行方式:
- 直接运行脚本时,
__name__
被自动赋值为 ‘main’; - 作为模块被导入时,
__name__
值为模块文件名(不含.py
后缀)