ROS2 入门指南

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 F42ED6FBAB17C654
sudo 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
# 清理所有 ROS 相关环境变量
for var in $(env | grep ROS | awk -F= '{print $1}'); do unset $var; done

# 再加载 ROS2
source /opt/ros/foxy/setup.bash

1
echo $ROS_DISTRO

即可查看环境变量是否转换


简单的代码运行

1
2
3
sudo apt update
sudo apt install python3-colcon-common-extensions

安装colcon用于编译,相当于ROS1的catkin_make

创建工作空间和包:

1
2
3
4
5
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws/src

ros2 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(1s)) {
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_ws
colcon build \
--packages-select cpp_srvcli \
--cmake-args \
-DPYTHON_EXECUTABLE=/usr/bin/python3

source install/setup.bash

注意,这里打开新终端的时候,还需要像上面那样转换到ROS2环境,如下所示:

1
2
3
4
5
6
7
# 清空所有 ROS 环境变量
for var in $(env | grep -E 'ROS|AMENT' | awk -F= '{print $1}'); do unset $var; done

# 切到 ROS2 环境
source /opt/ros/foxy/setup.bash
source ~/ros2_ws/install/setup.bash

运行

服务端运行:

1
2
3
4
# 开一个新终端
source /opt/ros/foxy/setup.bash
source ~/ros2_ws/install/setup.bash
ros2 run cpp_srvcli server

客户端运行:

1
2
3
4
5
# 再开一个新终端
source /opt/ros/foxy/setup.bash
source ~/ros2_ws/install/setup.bash
ros2 run cpp_srvcli client 3 5

作者

Gary

发布于

2025-08-14

更新于

2025-08-15

许可协议

评论

:D 一言句子获取中...

加载中,最新评论有1分钟缓存...