1 简介
ROS2(Robot Operating System 2)是一个开源的机器人开发框架,旨在简化机器人软件的开发和集成。它提供了一系列工具、库和约定,帮助开发者在不同平台上构建复杂的机器人行为。相比 ROS1,ROS2 引入了改进的性能、更高的可靠性和更灵活的架构,广泛应用于机器人研究和工业应用。本教程为初学者设计,涵盖 ROS2 的安装、核心概念和简单程序开发,内容以 Markdown 格式呈现,易于阅读和实践。
1.1 主要特点
- 微内核架构:通过数据分发服务(DDS)提供高效的通信机制,支持分布式系统。
- 实时性能:支持实时任务调度,适合嵌入式和工业应用。
- 跨平台支持:可在 Linux、Windows 和 macOS 上运行。
- 模块化设计:通过节点、主题、服务等模块化组件实现灵活的系统架构。
- 社区支持:拥有活跃的开源社区,提供丰富的教程和包。
1.2 历史背景
ROS1 由 Willow Garage 于 2007 年推出,ROS2 则由 Open Robotics(现为 Intrinsic)于 2014 年开始开发。ROS2 的首个稳定版本(Ardent Apalone)于 2017 年发布,当前最新稳定版本为 Humble Hawksbill(2022 年发布,长期支持至 2027 年)。ROS2 解决了 ROS1 的单点故障问题,并支持更广泛的工业应用。
2 关键点
- ROS2 概述:ROS2 是一个强大的机器人开发框架,支持跨平台开发,适合初学者和专业开发者。
- 学习路径:从初始安装 ROS2 开始,逐步掌握节点、主题、服务等核心概念,并通过示例程序实践。
- 资源推荐:官方文档和 GitHub 仓库(如 MOGI-ROS)提供丰富的学习材料,部分以 Markdown 格式呈现。
- 实践重要性:ROS2 学习需要动手操作,建议在 Ubuntu 环境中安装 ROS2 并运行示例。
3 前置条件
- 编程基础:熟悉 Python 或 C++,Python 更适合初学者。
- 操作系统知识:了解 Linux(特别是 Ubuntu)命令行操作。
- 硬件准备:一台运行 Ubuntu 22.04 的计算机(物理机或虚拟机),建议 8 GB RAM 和 20 GB 磁盘空间。
- 网络环境:稳定的互联网连接,用于下载 ROS2 和依赖包。
4 设置 ROS2 开发环境
4.1 系统要求
- 操作系统:推荐使用 Ubuntu 22.04(Jammy Jellyfish),这是 ROS2 Humble 的主要支持平台。
- 硬件:至少 4GB 内存和 10GB 磁盘空间,建议使用虚拟机或物理机。
4.2 安装步骤
4.2.1 安装 Ubuntu 22.04
- 下载并安装 Ubuntu 22.04,可使用 VMware 或 VirtualBox 创建虚拟机。
- 更新系统:
sudo apt update && sudo apt upgrade -y
4.2.2 设置软件源
- 确保系统支持 UTF-8 编码:
locale
。 - 添加 ROS2 软件源:
sudo apt update && sudo apt install -y curl gnupg2 lsb-release sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null
4.2.3 安装 ROS2 Humble
- 更新软件包并安装桌面完整版:
sudo apt update sudo apt install -y ros-humble-desktop-full
- 安装开发工具:
sudo apt install -y python3-colcon-common-extensions python3-rosdep python3-vcstool
4.2.4 配置环境
- 将 ROS2 环境变量添加到
~/.bashrc
:echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc source ~/.bashrc
- 初始化 rosdep:
sudo rosdep init rosdep update
4.2.5 验证安装
- 检查 ROS2 版本:
ros2 --version
,应显示版本信息(如humble
)。 - 运行 turtlesim 示例:
应出现一个乌龟模拟器窗口。ros2 run turtlesim turtlesim_node
- 使用
ros2 doctor
检查安装是否完整。
5 ROS2 核心概念
5.1 核心组件
- 节点(Nodes):独立运行的进程,负责特定功能(如传感器数据采集或运动控制)。
- 主题(Topics):节点通过发布-订阅模型进行异步通信,适合连续数据流。
- 服务(Services):基于请求-响应的同步通信,适合一次性任务。
- 参数(Parameters):动态配置节点的运行时属性。
- 动作(Actions):支持长时间运行的任务,包含目标、反馈和结果。
- 工作空间(Workspace):使用 colcon 工具管理代码和依赖。
5.2 常用命令
命令 | 功能 |
---|---|
ros2 node list | 列出当前运行的节点 |
ros2 topic list | 列出当前活跃的主题 |
ros2 topic echo <topic> | 显示指定主题的消息内容 |
ros2 service list | 列出当前可用的服务 |
ros2 run <pkg> <node> | 运行指定包中的节点 |
6 开发简单 ROS2 应用程序
以下是基于 Python 和 C++ 的发布者-订阅者程序示例,展示 ROS2 的主题通信机制。
6.1 Python 实现
6.1.1 创建包
在工作空间中创建 Python 包:
cd ~/ros2_ws/src
ros2 pkg create --build-type ament_python my_python_package --dependencies rclpy std_msgs
6.1.2 发布者代码(publisher.py)
在 my_python_package/my_python_package/publisher.py
中添加以下代码:
import rclpy
from rclpy.node import Node
from std_msgs.msg import Stringclass MinimalPublisher(Node):def __init__(self):super().__init__('minimal_publisher')self.publisher_ = self.create_publisher(String, 'topic', 10)timer_period = 0.5 # secondsself.timer = self.create_timer(timer_period, self.timer_callback)self.i = 0def timer_callback(self):msg = String()msg.data = 'Hello, ROS2 from Python: %d' % self.iself.publisher_.publish(msg)self.get_logger().info('Publishing: "%s"' % msg.data)self.i += 1def main(args=None):rclpy.init(args=args)minimal_publisher = MinimalPublisher()rclpy.spin(minimal_publisher)minimal_publisher.destroy_node()rclpy.shutdown()if __name__ == '__main__':main()
6.1.3 订阅者代码(subscriber.py)
在 my_python_package/my_python_package/subscriber.py
中添加以下代码:
import rclpy
from rclpy.node import Node
from std_msgs.msg import Stringclass MinimalSubscriber(Node):def __init__(self):super().__init__('minimal_subscriber')self.subscription = self.create_subscription(String, 'topic', self.listener_callback, 10)self.subscription # prevent unused variable warningdef listener_callback(self, msg):self.get_logger().info('I heard: "%s"' % msg.data)def main(args=None):rclpy.init(args=args)minimal_subscriber = MinimalSubscriber()rclpy.spin(minimal_subscriber)minimal_subscriber.destroy_node()rclpy.shutdown()if __name__ == '__main__':main()
6.1.4 配置包
编辑 my_python_package/setup.py
,确保包含以下 entry_points
:
entry_points={'console_scripts': ['publisher = my_python_package.publisher:main','subscriber = my_python_package.subscriber:main',],
},
6.1.5 构建和运行
- 构建工作空间:
cd ~/ros2_ws colcon build source install/setup.bash
- 运行发布者:
ros2 run my_python_package publisher
- 在另一个终端运行订阅者:
ros2 run my_python_package subscriber
6.1.6 运行结果
订阅者将打印类似以下输出:
[INFO] [minimal_subscriber]: I heard: "Hello, ROS2 from Python: 0"
[INFO] [minimal_subscriber]: I heard: "Hello, ROS2 from Python: 1"
6.2 C++ 实现
6.2.1 创建包
在工作空间中创建 C++ 包:
cd ~/ros2_ws/src
ros2 pkg create --build-type ament_cmake my_cpp_package --dependencies rclcpp std_msgs
6.2.2 发布者代码(publisher.cpp)
在 my_cpp_package/src/publisher.cpp
中添加以下代码:
#include <chrono>
#include <memory>
#include <rclcpp/rclcpp.hpp>
#include <std_msgs/msg/string.hpp>using namespace std::chrono_literals;class MinimalPublisher : public rclcpp::Node
{
public:MinimalPublisher(): Node("minimal_publisher"), count_(0){publisher_ = this->create_publisher<std_msgs::msg::String>("topic", 10);timer_ = this->create_wall_timer(500ms, std::bind(&MinimalPublisher::timer_callback, this));}private:void timer_callback(){auto message = std_msgs::msg::String();message.data = "Hello, ROS2 from C++: " + std::to_string(count_++);RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str());publisher_->publish(message);}rclcpp::TimerBase::SharedPtr timer_;rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;size_t count_;
};int main(int argc, char * argv[])
{rclcpp::init(argc, argv);rcpp::spin(std::make_shared<MinimalPublisher>());rclcpp::shutdown();return 0;
}
6.2.3 订阅者代码(subscriber.cpp)
在 my_cpp_package/src/subscriber.cpp
中添加以下代码:
#include <memory>
#include <rclcpp/rclcpp.hpp>
#include <std_msgs/msg/string.hpp>class MinimalSubscriber : public rclcpp::Node
{
public:MinimalSubscriber(): Node("minimal_subscriber"){subscription_ = this->create_subscription<std_msgs::msg::String>("topic", 10, std::bind(&MinimalSubscriber::topic_callback, this, std::placeholders::_1));}private:void topic_callback(const std_msgs::msg::String::SharedPtr msg) const{RCLCPP_INFO(this->get_logger(), "I heard: '%s'", msg->data.c_str());}rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscription_;
};int main(int argc, char * argv[])
{rclcpp::init(argc, argv);rclcpp::spin(std::make_shared<MinimalSubscriber>());rclcpp::shutdown();return 0;
}
6.2.4 配置包
编辑 my_cpp_package/CMakeLists.txt
,添加以下内容以编译节点:
# 查找依赖
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)# 添加可执行文件
add_executable(publisher src/publisher.cpp)
ament_target_dependencies(publisher rclcpp std_msgs)add_executable(subscriber src/subscriber.cpp)
ament_target_dependencies(subscriber rclcpp std_msgs)# 安装可执行文件
install(TARGETSpublishersubscriberDESTINATION lib/${PROJECT_NAME}
)# 安装其他文件(如果需要)
ament_package()
6.2.5 构建和运行
- 构建工作空间:
cd ~/ros2_ws colcon build source install/setup.bash
- 运行发布者:
ros2 run my_cpp_package publisher
- 在另一个终端运行订阅者:
ros2 run my_cpp_package subscriber
6.2.6 运行结果
订阅者将打印类似以下输出:
[INFO] [minimal_subscriber]: I heard: "Hello, ROS2 from C++: 0"
[INFO] [minimal_subscriber]: I heard: "Hello, ROS2 from C++: 1"
7 高级主题
7.1 启动文件(Launchfiles)
启动文件用于同时启动多个节点。示例(Python 包):
from launch import LaunchDescription
from launch_ros.actions import Nodedef generate_launch_description():return LaunchDescription([Node(package='my_python_package',executable='publisher',name='minimal_publisher'),Node(package='my_python_package',executable='subscriber',name='minimal_subscriber'),])
保存为 my_python_package/launch/my_launch.py
,然后运行:
ros2 launch my_python_package my_launch.py
7.2 参数(Parameters)
节点可以通过参数动态配置。修改 Python 发布者代码以支持参数:
self.declare_parameter('message', 'Hello, ROS2')
msg.data = '%s: %d' % (self.get_parameter('message').value, self.i)
通过命令行设置参数:
ros2 run my_python_package publisher --ros-args -p message:="Custom Message"
7.3 服务(Services)
服务用于请求-响应通信。参考 ROS2 服务教程 学习服务开发。
参考资料
-
官方教程:参考 ROS2 Humble 教程,学习更高级的主题,如动作、参数和自定义消息。
-
实践项目:尝试使用 turtlesim 或 Gazebo 模拟器开发简单的机器人控制程序。
-
社区支持:加入 ROS 社区论坛,获取帮助和分享经验。
-
GitHub 教程:MOGI-ROS 提供的 ROS2 入门教程 涵盖基础到高级内容,适合初学者。
-
官方文档:ROS2 Humble 教程 提供全面的学习路径。
-
社区论坛:ROS 社区 是获取帮助和交流经验的平台。
-
实践平台:The Construct 提供在线模拟环境。
-
硬件教程:Husarion ROS2 教程 结合 ROSbot 硬件。
-
ROS2 Humble Tutorials Documentation
-
MOGI-ROS Week-1-2-Introduction-to-ROS2 GitHub
-
The Construct ROS2 Tutorials
-
Husarion ROS2 Tutorials
-
ROS Community Discourse
-
ROS2 Service Tutorial