ros2入门教程-比较ros1和ros2的异同
ros2入门教程-比较ros1和ros2的异同
说明:
- 介绍通过比较ros1和ros2的异同,了解如何从ros1迁移到ros2
为什么 ROS2 而不是保留 ROS1
ROS1 最初由 Willow Garage 于 2007 年创建,在开源机器人社区中已经变得非常庞大。
ROS1 背后的团队已经学会了——凭借这些年的经验,缺少哪些重要功能,以及可以改进的地方。 不幸的是,将所有这些修改添加到 ROS1 中需要许多重大更改,并使 ROS1 非常不稳定。 所以,ROS2是从零开始开发的,是一个全新的ROS。
至于现在ROS在业界还不是很流行,缺乏一些最重要的要求,比如实时性、安全性、认证性。
ROS2 的目标之一是使其与工业应用兼容。
ROS1 和 ROS2 分布
这是 ROS1 的情况:ROS Noetic(发布日期:2020)是最后一个 ROS1 版本。 这个最终的 ROS1 版本主要目标是为需要继续使用 ROS1 一段时间的开发人员/组织提供 Python3 支持。
ROS Noetic 的 EOL(End of Life)定于 2025 年。在那之后,不再有 ROS1! 所以,如果你今天在 ROS1 中有很大的代码库,那完全没问题,但不要等到 2024 年才开始进行更改。
对于 ROS2,从 LTS(长期支持)版本 Foxy Fitzroy(发布日期:2020)开始,每年都会发布一个新的 ROS2 版本。 与之前对 ROS1 所做的相同。
你已经可以开始使用现在相当稳定的 ROS2——至少核心功能,一些 3rd 方插件仍然缺失。
现在让我们来探讨差异。 我将它们分成 3 个主要部分以形成某种结构,但可以随意跳到任何一点,它们都可以独立阅读。
ROS1 vs ROS2:编写节点
1.##ROS API – rclcpp, rclpy##
在 ROS1 中,对于 Cpp,您使用 roscpp,对于 Python,使用 rospy。这两个库都是完全独立的,并且是从头开始构建的。这意味着 roscpp 和 rospy 之间的 API 不一定相同,并且某些功能是针对其中一个开发的,而不是针对另一个开发的。
ROS2 有更多的层。只有一个名为 rcl 的基础库,用 C 语言实现。这是包含所有 ROS2 核心特性的基础。
您不会直接在程序中使用 rcl 库。您将使用构建在 rcl 之上的另一个客户端库。例如:rclcpp 用于 Cpp,rclpy 用于 Python。
它有什么好处?那么任何新功能只需要使用 rcl 来实现。然后,在 rcl 之上的客户端库只需要提供绑定。
对于作为开发人员的您来说,这意味着:
rclcpp 和 rclpy 之间的 API 将比 roscpp 和 rospy 之间的 API 更加相似。
创建和使用其他语言的客户端库会更容易,例如rclnodejs、rcljava等。不需要重新发明轮子,你只需要用rcl做一个C绑定。 - 所有语言的所有客户端都将具有类似的 API。
当一个新的核心功能发布时,它将更快地以不同的语言提供,因此您不必等待太多。
2.##Python 和 Cpp 版本##
您可能知道,不再支持 Python2。 事实上,为了提供更顺畅的过渡,它仍然支持 Ubuntu 18 和 ROS1 Melodic,直到它们的 EOL(2023 年)。
Python3针对ROS1 Noetic以及所有 ROS2 版本。
现在,对于 Cpp 来说,有一些很大的进展。 ROS1 的目标是 Cpp 98,您可以在以后的 ROS1 版本中使用 Cpp 11/14,前提是它不会破坏其他依赖项。
在 ROS2 中,您现在可以默认使用 Cpp 11 和 14。 Cpp 17 也在路线图上。 这很棒,因为新版本的 Cpp 引入了许多有用的功能,使开发更容易、更快、更安全。 此外,它使 Cpp 更有趣,也许这将有助于使这种强大而伟大的语言民主化
3.##编写节点(使用 OOP)##
在 ROS1 中,没有特定的结构告诉您应该如何编写节点功能。 您可以决定在程序的任何地方添加回调函数,或者如果您愿意,也可以使用 OOP,但每个实现都可能是独一无二的。
在 ROS2 中,情况有所不同。 关于如何编写节点有一个约定。 您必须创建一个继承自 Node 对象的类(例如:Cpp 中的 rclcpp::Node,Python 中的 rclpy.node.Node)。
这很棒,因为它将为每个人节省大量时间。 你已经有了一个很好的模块化结构来编写你的节点。 它将使您的程序更清洁,并且不同项目的开发人员之间的合作将更加容易。
在 ROS2 中为您的节点使用 OOP 还允许您将它们转换为组件,这是 ROS2 中的一项新功能。
4.##同一可执行文件中的多个节点 – ROS2 组件##
在 ROS1 中,节点与可执行文件紧密相关。 在 ROS1 中添加了一个名为 Nodelets 的新功能,以便能够在同一个可执行文件中编写多个节点,并进行进程内通信。 当您的硬件资源有限和/或您需要在节点之间发送大量消息时,这真的很棒。
在 ROS2 中,Nodelets 不再被称为 Nodelets。 该功能已直接包含在 ROS2 核心中,现在称为“组件”。
因此,使用 ROS2,您可以使用组件处理来自同一个可执行文件的多个节点。 组件只是一个稍微修改过的节点类(我们仍然在那里使用 OOP)。
然后,您可以从启动文件、终端或可执行文件启动组件。 您可以激活进程内通信以消除任何 ROS2 通信开销。
构建组件是创建高效 ROS2 应用程序的好习惯。
5.##生命周期节点##
ROS2 引入了生命周期节点的概念。 生命周期节点具有不同的状态:未配置、非活动、活动、已完成。 当您在实际运行节点的主要功能之前需要一个设置阶段时,这非常有用。
当您启动这样一个节点时,它最初是未配置的。 通过提供的接口(ROS2 服务),您可以请求转换到另一个状态。 当您这样做时,将在节点内触发预定义的回调。
假设您有一个传感器节点。 您首先需要确保检测到传感器,并且通信已成功启动。 然后您可以开始阅读循环并发布数据。
使用生命周期节点,您可以清楚地将其分开:首先,您为发布者、订阅者和其他实例化对象分配内存。 然后,您启动与传感器的通信。 最后你运行你的阅读循环来发布数据。
6.编写启动文件
启动文件允许您从一个文件启动所有节点。您可以启动标准节点、组件、生命周期节点。您可以添加自变量、参数和许多其他选项。
ROS1 中,您已经习惯使用 XML 编写启动文件。
在 ROS2 中,您现在将使用 Python 编写启动文件。有一个 API 允许您启动节点、检索配置文件、添加参数等。它将允许您比以前更多地自定义启动文件。
但是,用 Python 编写启动文件真的很新鲜吗?好吧事实上没有。在 ROS1 中还有一个 Python API。问题是:没有人知道它,关于它的文档几乎为零。所以,没有人使用它。用 XML 编写启动文件已成为一种常态,这很棒,但肯定不像 Python API 那样模块化。
而且……如果你愿意,你也可以用 XML 编写你的 ROS2 启动文件。但更喜欢使用 Python,因为它带来了更多的模块化、更多的文档,并且已经成为启动文件的 ROS2 约定。
ROS1 与 ROS2:通信
1.不再有 ROS master
您从 ROS1 中学到的一件事是:始终在运行节点之前启动 ROS 主节点。 ROS1 master 将充当您节点的 DNS 服务器,因此它们可以相互检索。
在 ROS2 中,没有更多的 ROS master 了! 这不再是一个集中式系统。 每个节点都有发现其他节点的能力。 您可以简单地启动一个节点,而不必担心是否有一个主节点正在运行。
这种变化很棒,因为它允许您创建一个完全分布式的系统。 每个节点都是独立的,不必关心全局主节点。
在创建多机 ROS2 应用程序时,您不必将一台机器定义为“主机”。 每台机器都将是独立的,并且能够自行启动、相互连接和断开连接,并且比 ROS1 中的设置更少。
2.参数
因此,在 ROS1 中,参数由参数服务器处理,而参数服务器本身由……ROS master 处理。
在 ROS2 中,没有更多的 ROS 主服务器 = 没有更多的(全局)参数服务器。
参数的概念已经完全改变。不再有全局参数。每个参数都特定于一个节点。
一个节点声明和管理自己的参数,这些参数在节点被杀死时被销毁。
就像每个节点都有自己的参数服务器一样。当您启动一个节点时,会创建一些 ROS2 服务。这些允许您从终端或其他节点与其参数进行交互。
此外,您可以在创建节点后使用参数回调轻松修改节点的参数。
如果您在 ROS1 中使用 dynamic_reconfigure 工具,那么,好消息,现在这是核心功能的一部分。无需额外配置,您只需将参数回调绑定到您的节点。
查看如何处理代码中的参数:rclcpp 参数和 rclpy 参数。
以及如何创建参数回调:rclpp 参数回调和 rclpy 参数回调。
3.服务
在 ROS1 中,服务是同步的。 当您的服务客户端向服务器请求请求时,它会一直卡住,直到服务器响应(或失败)。
在 ROS2 中,服务是异步的。
当您调用服务时,您可以添加一个回调函数,该回调函数将在服务器响应时触发。 与此同时,你的主线程没有卡住。
当然,如果你愿意,你也可以同步使用服务。
4. 动作
在 ROS1 中,动作从未出现在核心功能中。 这是几年后的一个补充,解决了服务不异步,没有反馈或取消机制的问题。
因此,ROS1 中的操作完全建立在 ROS1 话题之上。
在 ROS2 中,动作现在是 ROS2 核心的一部分。 Cpp 和 Python 的 API 与 ROS1 非常相似,因此代码没有问题。
在下面,动作仍然使用话题来提供反馈和目标状态,但也使用(异步)服务来设置目标、取消目标和请求结果。
现在,动作也有了自己的命令行工具! 正如您对服务所做的那样,您现在可以直接从终端将操作目标发送到服务器。
5. 消息、服务和动作定义
为消息、服务和动作创建定义的方式在 ROS1 和 ROS2 中非常相似。 您仍然将它们放入 msg/、srv/ 和 action/ 文件夹中。
但是在编译它们之后,会添加一个命名空间:
Message: msg/…
Services: srv/…
Actions: action/…
- 例如,假设您有一个名为 my_robot_msgs 的包,并且在此包中创建了一个名为 Temperature 的消息,以及一个名为 ActivateButton 的服务。 在您的节点代码中,您必须使用以下命令导入它们:
my_robot_msgs/msg/Temperature.
my_robot_msgs/srv/ActivateButton.
- 这很棒,因为它减少了混淆,并使所有 3 种通信类型之间的分离更加清晰。
6. 服务质量
ROS2 引入了 QoS,即服务质量。
使用该功能,您可以选择节点如何处理通信:您想确保收到所有消息吗?或者,只要数据经常更新,丢失几条消息就可以了?您是要保留消息队列以防节点没有时间处理所有消息,还是要在前一条消息的回调仍在运行时丢弃任何新消息?
好吧,如果您必须为您的应用程序提出此类问题,那么您将需要为您的节点调整 QoS。
默认情况下,已选择 ROS2 通信(主题、服务等)的 QoS,因此您可以期待与 ROS1 中相同的行为:
任何订阅主题的节点都不会收到之前的消息,只会收到订阅后发布的消息。
与 TCP 一样,消息保证被传递。
您可以为等待处理的已传递消息设置队列大小。
如果您必须处理有损耗的无线网络和/或较大的消息带宽,那么 QoS 是一个值得关注的设置。
但是,如果您刚刚开始使用 ROS,或者有一个非常简单的应用程序,请不要担心 QoS。有更重要的东西要先学习,当你需要的时候你会回到QoS。
ROS1 vs ROS2:包、工作区和环境
1. 构建你的节点
ROS1中的构建系统是catkin。 你使用“catkin_make”或“catkin build”来构建和安装你的包。
在 ROS2 中,没有更多的柳絮。 Ament 是新的构建系统,除此之外,您还可以获得 colcon 命令行工具。
要编译,您将在 ROS2 工作区中使用命令“colcon build”。
关于 ament 和 colcon 还有很多话要说,但只要有了这些信息,您就可以毫无问题地构建您的第一个节点。
2. 命令行工具
大多数命令行工具在 ROS1 和 ROS2 之间是相似的。 工具的名称和一些选项不同,但在使用时没有太大区别。
例如,要列出所有主题,在 ROS1 中您将执行“rostopic list”,在 ROS2 中您将执行“ros2 topic list”。 “rosservice” 变成 ros2 服务,“rosrun” 变成 ros2 run,“rosbag” 变成 ros2 bag,等等。
你只需要写“ros2”,然后是你想使用的工具的名称。
3. Cpp 和 Python 包
使用 ROS1,您可以创建一个包,然后添加您想要的任何 Cpp/Python 文件。
ROS2 区分了 Cpp 和 Python 包。从命令行创建包时,您必须指定一种构建类型:ament_cmake 或 ament_python。
根据该论点,包架构将不一样。
对于 Cpp 包,情况与 ROS1 非常相似。你还有一个 CMakeLists.txt。您只需要调整您的 cmake 指令以使用 ament 而不是 catkin。
对于 Python 包,情况有所不同:您有一些新文件,例如 setup.py 和 setup.cfg。 setup.py 替换了 CMakeLists.txt。您当然可以直接运行您的 Python 脚本,但如果您想从 ROS2 命令行工具或启动文件启动它们,您必须先安装它们(使用“colcon build”)。
如果你愿意,你也可以为 Python 和 Cpp 创建一个 ROS2 包,但这需要更多的设置。
总的来说,在 ROS2 中设置包比在 ROS1 中复杂一点,但它也更完整,更有条理。
4. 引入工作区和覆盖
在 ROS1 和 ROS2 之间引入 ROS 环境并没有太大的不同。 您首先获取您的全局 ROS 安装,然后是您的工作区,然后您可以使用您的自定义代码。
ROS2 带来了叠加层的概念。 您可以在彼此之上拥有多个工作区。
首先你获取你的全局 ROS 安装,然后是你的第一个工作空间(覆盖),你的第二个覆盖等等。如果一个包在较低级别的覆盖和较高级别的覆盖中具有相同的名称,那么只会使用较高级别的。
当您开发应用程序并且已经拥有一定数量的包时,您可以只为一个包创建覆盖。 这将允许您快速迭代它,同时为其他项目保持代码库不变。
使用这种技术,您还可以覆盖已经从二进制文件安装的包。 这是非常实用的,因此您可以保持安装包,同时为特定应用程序拥有自己的版本。
5. 操作系统支持
ROS1 的主要目标是 Ubuntu。
ROS2 的好消息:由于其新架构,您可以在 Ubuntu、MacOS 和 Windows 10(+其他操作系统,但这是 3 个主要操作系统)上安装和使用它。
这将使 ROS2 在许多应用程序中更易于访问和嵌入。
例如,您可以拥有一个带有 Raspberry Pi 和 Ubuntu 的移动机器人,以及另一台使用 Windows 的计算机作为 3D 模拟工具和一个驱动程序节点,用于扫描场景的相机。 所有这一切都顺利进行。
6. 何时从 ROS1 切换到 ROS2?
没那么简单,很多人会告诉你不同的答案。 ROS1 仍然很强大,有很多稳定的插件、更多的文档和 3rd 方插件。最终它会结束,但你还有几年的时间。
如果您是 ROS 新手(无论是 ROS1 还是 ROS2),那么您可能应该学习 ROS2 基础知识。但是,尝尝 ROS1 也很有趣。为什么?因为如果你也看到它在 ROS1 中是如何完成的,你可能会更好地理解 ROS2 中的一些东西。此外,您想要使用的某些工具/包可能尚未移植到 ROS2,因此您别无选择,只能使用 ROS1 版本的包。在这种情况下,ros1_bridge 包将很有用(见下一节)。
如果你已经了解 ROS 并且想要开始一个全新的项目,那么走 ROS2 的方式可能是你应该做的,所以这意味着未来的过渡工作更少。 ROS1 和 ROS2 的核心概念是相似的,所以你对 ROS1 的经验越多,你学习 ROS2 的时间就越少。您还可以使用 ROS1 和 ROS2,与 ros1_bridge 一起使用,以便使用缺少的工具和插件。
如果您的一个或多个机器人已经在 ROS1 中拥有代码库,或者对于拥有数十名开发人员的完整组织,切换到 ROS2 可能需要大量工作。代码库越大,ROS 对你的项目的影响越大,花费的时间就越长,也就越复杂。您可以选择继续使用 ROS1 处理遗留项目,并开始使用 ROS2 处理新项目。或者,您现在可以开始将所有代码移植到 ROS2,因为这涉及到很多工作(取决于您的代码编写得如何)。首先,在您决定进行完全切换之前,请确保您需要的大部分 ROS 功能都已移植到 ROS2。同样,ros1_bridge 可以在过渡期间为您提供帮助。
7. 将 ROS1 和 ROS2 与 ros1_bridge 包一起使用
如果您需要使用现有的 ROS1 代码库,但想使用 ROS2 开发新功能,那么您不一定会卡住。
您可以使用名为 ros1_bridge 的 ROS2 包,顾名思义,它将成为 ROS1 和 ROS2 通信之间的桥梁。
即使 ROS1 和 ROS2 的概念是一样的,但是底层的通信并不能直接兼容,需要一些适配。 ros1_bridge 包提供了这一点。
在过渡到 ROS2 时,您可以开始在 ROS2 中移植一些包,并使这些包与您的 ROS1 应用程序的其余部分进行通信。 然后,你移植越来越多的包,直到用 ROS1 写的东西都没有了。 在所有移植期间,您的应用程序仍然可以按预期工作。
ROS1 vs ROS2:结论
在本文中,您已经看到了 ROS1 和 ROS2 之间的一些主要区别。 我试图使该方法侧重于实用方面,因此当您使用 ROS 开发机器人应用程序时,您可以大致了解发生了什么变化。
要了解最新信息,您可以查看 ROS Discourse 论坛,在那里您会看到有关新概念、辩论和公告的有趣讨论。
现在,这里提供的列表肯定不是详尽无遗的,有些信息可能会发生变化,因为 ROS2 仍在不断发展。 但是,当您决定学习 ROS2 时,了解您需要关注什么是一个很好的起点。
参考:
获取最新文章: 扫一扫右上角的二维码加入“创客智造”公众号