ROS2 入门指南
本文是我学习 ROS2(Robot Operating System 2)的入门操作的笔记与总结。
1. ROS2 简介以及与 ROS1 的区别 1.1 ROS2 简介 ROS2(Robot Operating System 2)是一个开源的机器人软件开发框架,继承并改进了 ROS1 的设计理念。 它并不是一个操作系统,而是一个运行在多种平台上的中间件框架 ,提供了机器人软件开发所需的通信、工具和生态支持。 ROS2 旨在解决 ROS1 在工业化、实时性、多平台适配等方面的不足,支持在嵌入式设备、桌面计算机以及云端运行。
ROS2 的主要特点:
跨平台 :支持 Linux、Windows、macOS 以及嵌入式系统。
实时性支持 :适合需要严格延迟控制的机器人应用。
更安全和可扩展 :引入 DDS(Data Distribution Service)作为底层通信中间件,支持安全加密与认证。
活跃的社区与生态 :持续更新与维护,提供大量功能包和工具。
1.2 ROS1 与 ROS2 的区别
对比项
ROS1
ROS2
发布年份
2010 年左右
2017 年左右(Alpha 发布,之后逐步稳定)
底层通信
TCPROS、UDPROS
DDS(Data Distribution Service)
实时性
基本不支持
原生支持实时系统和实时调度
平台支持
主要是 Linux(Ubuntu)
Linux、Windows、macOS、RTOS 等
多机器人
需要额外配置或依赖外部工具
内置多主机、多机器人支持
安全性
无内置安全机制
内置安全认证与加密(基于 DDS Security)
生命周期管理
节点生命周期缺乏标准化
支持节点生命周期管理
社区状态
维护中(推荐迁移至 ROS2)
正在快速发展与更新
2. ROS2 安装 2.1 ubuntu20.04下安装
推荐操作系统
依赖工具(colcon、python3 等)
2.2 安装步骤(以 Ubuntu 为例) 添加清华源 1 sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
编辑 ROS2 软件源列表: 1 sudo nano /etc/apt/sources.list.d/ros2.list
根据不同的ubuntu版本安装 Ubuntu 20.04 (ROS2 Foxy)
1 deb [arch =amd64] https://mirrors.tuna.tsinghua.edu.cn/ros2/ubuntu focal main
Ubuntu 22.04 (ROS2 Humble)
1 2 deb [arch =amd64] https://mirrors.tuna.tsinghua.edu.cn/ros2/ubuntu jammy main
保存并退出(Ctrl+O → 回车 → Ctrl+X)
导入清华 ROS2 公钥 1 2 sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys F42ED6FBAB17C654sudo apt update
安装 ROS2 桌面版 Ubuntu 20.04 (ROS2 Foxy)
1 sudo apt install ros-foxy-desktop
Ubuntu 22.04 (ROS2 Humble)
1 sudo apt install ros-humble-desktop
配置环境变量 这里由于我在环境里面安装了ROS1和ROS2,所以需要在终端清除环境变量
1 2 3 4 5 6 for var in $(env | grep ROS | awk -F= '{print $1}' ); do unset $var ; done source /opt/ros/foxy/setup.bash
即可查看环境变量是否转换
简单的代码运行 1 2 3 sudo apt updatesudo apt install python3-colcon-common-extensions
安装colcon用于编译,相当于ROS1的catkin_make
创建工作空间和包:
1 2 3 4 5 mkdir -p ~/ros2_ws/srccd ~/ros2_ws/srcros2 pkg create --build-type ament_cmake cpp_srvcli --dependencies rclcpp example_interfaces
写服务端节点(server):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include "rclcpp/rclcpp.hpp" #include "example_interfaces/srv/add_two_ints.hpp" #include <memory> void add ( const std::shared_ptr<example_interfaces::srv::AddTwoInts::Request> request, std::shared_ptr<example_interfaces::srv::AddTwoInts::Response> response) { response->sum = request->a + request->b; RCLCPP_INFO (rclcpp::get_logger ("rclcpp" ), "Incoming request: a=%ld, b=%ld" , request->a, request->b); RCLCPP_INFO (rclcpp::get_logger ("rclcpp" ), "Sending back response: sum=%ld" , response->sum); } int main (int argc, char **argv) { rclcpp::init (argc, argv); auto node = rclcpp::Node::make_shared ("add_two_ints_server" ); auto service = node->create_service <example_interfaces::srv::AddTwoInts>("add_two_ints" , &add); RCLCPP_INFO (rclcpp::get_logger ("rclcpp" ), "Ready to add two ints." ); rclcpp::spin (node); rclcpp::shutdown (); return 0 ; }
写客户端节点(client):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #include "rclcpp/rclcpp.hpp" #include "example_interfaces/srv/add_two_ints.hpp" #include <chrono> #include <cstdlib> #include <memory> using namespace std::chrono_literals;int main (int argc, char **argv) { rclcpp::init (argc, argv); if (argc != 3 ) { RCLCPP_INFO (rclcpp::get_logger ("rclcpp" ), "Usage: add_two_ints_client X Y" ); return 1 ; } auto node = rclcpp::Node::make_shared ("add_two_ints_client" ); auto client = node->create_client <example_interfaces::srv::AddTwoInts>("add_two_ints" ); while (!client->wait_for_service (1 s)) { if (!rclcpp::ok ()) { RCLCPP_ERROR (rclcpp::get_logger ("rclcpp" ), "Interrupted while waiting for the service." ); return 0 ; } RCLCPP_INFO (rclcpp::get_logger ("rclcpp" ), "Waiting for service to appear..." ); } auto request = std::make_shared <example_interfaces::srv::AddTwoInts::Request>(); request->a = atoll (argv[1 ]); request->b = atoll (argv[2 ]); auto result = client->async_send_request (request); if (rclcpp::spin_until_future_complete (node, result) == rclcpp::FutureReturnCode::SUCCESS) { RCLCPP_INFO (rclcpp::get_logger ("rclcpp" ), "Sum: %ld" , result.get ()->sum); } else { RCLCPP_ERROR (rclcpp::get_logger ("rclcpp" ), "Failed to call service" ); } rclcpp::shutdown (); return 0 ; }
修改 CMakeLists.txt,在 cpp_srvcli/CMakeLists.txt 添加:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 find_package(rclcpp REQUIRED) find_package(example_interfaces REQUIRED) add_executable(server src/add_two_ints_server.cpp) ament_target_dependencies(server rclcpp example_interfaces) add_executable(client src/add_two_ints_client.cpp) ament_target_dependencies(client rclcpp example_interfaces) install(TARGETS server client DESTINATION lib/${PROJECT_NAME} )
编译:
1 2 3 4 5 6 7 8 cd ~/ros2_wscolcon build \ --packages-select cpp_srvcli \ --cmake-args \ -DPYTHON_EXECUTABLE=/usr/bin/python3 source install/setup.bash
注意,这里打开新终端的时候,还需要像上面那样转换到ROS2环境,如下所示:
1 2 3 4 5 6 7 for var in $(env | grep -E 'ROS|AMENT' | awk -F= '{print $1}' ); do unset $var ; done source /opt/ros/foxy/setup.bashsource ~/ros2_ws/install/setup.bash
运行 服务端运行:
1 2 3 4 source /opt/ros/foxy/setup.bashsource ~/ros2_ws/install/setup.bashros2 run cpp_srvcli server
客户端运行:
1 2 3 4 5 source /opt/ros/foxy/setup.bashsource ~/ros2_ws/install/setup.bashros2 run cpp_srvcli client 3 5