一、ROS2 架构概览

通信方式 方向 适用场景
Topic 单向,发布/订阅 传感器数据、速度指令
Service 双向,请求/响应 参数配置、触发操作
Action 双向,带反馈 导航、长耗时任务

二、工作空间创建

1
2
3
4
5
6
7
8
9
10
11
12
# 1. 创建工作空间
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws

# 2. 编译(空工作空间)
colcon build

# 3. 加载环境
source install/setup.bash

# 4. 加入 ~/.bashrc(可选)
echo "source ~/ros2_ws/install/setup.bash" >> ~/.bashrc

三、Python 节点

第一个节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# src/my_pkg/my_pkg/simple_node.py
import rclpy
from rclpy.node import Node

class MyNode(Node):
def __init__(self):
super().__init__('my_node') # 节点名称
self.get_logger().info('节点已启动!')
self.timer = self.create_timer(1.0, self.timer_callback)

def timer_callback(self):
self.get_logger().info('Hello ROS2')

def main():
rclpy.init()
node = MyNode()
rclpy.spin(node) # 阻塞,保持节点运行
node.destroy_node()
rclpy.shutdown()

setup.py 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# src/my_pkg/setup.py
from setuptools import setup

setup(
name='my_pkg',
version='0.0.1',
packages=['my_pkg'],
install_requires=['setuptools'],
entry_points={
'console_scripts': [
'simple_node = my_pkg.simple_node:main',
],
},
)
1
2
3
4
# 编译运行
cd ~/ros2_ws && colcon build --packages-select my_pkg
source install/setup.bash
ros2 run my_pkg simple_node

四、Topic 话题通信

4.1 发布者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# talker.py
import rclpy
from rclpy.node import Node
from std_msgs.msg import String

class Talker(Node):
def __init__(self):
super().__init__('talker')
self.pub = self.create_publisher(String, 'chatter', 10)
self.timer = self.create_timer(0.5, self.callback)
self.count = 0

def callback(self):
msg = String()
msg.data = f'Hello {self.count}'
self.pub.publish(msg)
self.get_logger().info(f'发布: {msg.data}')
self.count += 1

4.2 订阅者

1
2
3
4
5
6
7
8
9
10
11
12
13
# listener.py
import rclpy
from rclpy.node import Node
from std_msgs.msg import String

class Listener(Node):
def __init__(self):
super().__init__('listener')
self.sub = self.create_subscription(
String, 'chatter', self.callback, 10)

def callback(self, msg):
self.get_logger().info(f'收到: {msg.data}')

4.3 常用消息类型

消息类型 用途 字段
std_msgs/String 字符串 data: string
std_msgs/Int32 整数 data: int32
std_msgs/Float32 浮点 data: float32
geometry_msgs/Twist 速度指令 linear.x/y/z, angular.x/y/z
sensor_msgs/Image 图像 header, height, width, data
sensor_msgs/LaserScan 激光 ranges[], angle_min/max
nav_msgs/Odometry 里程计 pose, twist

4.4 自定义消息

1
2
3
4
# msg/MyData.msg
string name
int32 value
float32[] data
1
2
3
4
# CMakeLists.txt
rosidl_generate_interfaces(${PROJECT_NAME}
"msg/MyData.msg"
)

五、Service 服务通信

1
2
3
4
5
6
7
8
9
10
11
12
13
# add_two_ints_server.py
from example_interfaces.srv import AddTwoInts

class AddServer(Node):
def __init__(self):
super().__init__('add_server')
self.srv = self.create_service(
AddTwoInts, 'add_two_ints', self.callback)

def callback(self, request, response):
response.sum = request.a + request.b
self.get_logger().info(f'{request.a} + {request.b} = {response.sum}')
return response
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# add_two_ints_client.py
class AddClient(Node):
def __init__(self):
super().__init__('add_client')
self.cli = self.create_client(AddTwoInts, 'add_two_ints')
while not self.cli.wait_for_service(timeout_sec=1.0):
self.get_logger().info('等待服务...')

def send_request(self, a, b):
req = AddTwoInts.Request()
req.a = a; req.b = b
future = self.cli.call_async(req)
rclpy.spin_until_future_complete(self, future)
return future.result().sum

六、常用调试命令

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
# 节点
ros2 node list # 列出所有节点
ros2 node info /talker # 查看节点详情

# 话题
ros2 topic list # 列出所有话题
ros2 topic echo /chatter # 监听话题消息
ros2 topic info /chatter # 查看话题类型
ros2 topic hz /chatter # 查看发布频率

# 发布测试消息
ros2 topic pub /chatter std_msgs/msg/String "data: 'hi'"

# 服务
ros2 service list # 列出所有服务
ros2 service call /add_two_ints example_interfaces/srv/AddTwoInts "{a: 3, b: 5}"

# 参数
ros2 param list /talker
ros2 param get /talker param_name
ros2 param set /talker param_name value

# 可视化
rqt_graph # 节点关系图
ros2 run rqt_plot rqt_plot # 数据曲线
ros2 topic echo /cmd_vel | ros2 run rqt_plot rqt_plot /cmd_vel/linear/x

七、launch 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# launch/demo.launch.py
from launch import LaunchDescription
from launch_ros.actions import Node

def generate_launch_description():
return LaunchDescription([
Node(
package='my_pkg',
executable='talker',
name='talker_1',
parameters=[{'rate': 1.0}]
),
Node(
package='my_pkg',
executable='listener',
name='listener_1',
),
])
1
ros2 launch my_pkg demo.launch.py

八、话题 vs 服务 vs Action

Topic Service Action
通信模式 发布-订阅 请求-响应 目标-结果-反馈
方向 单向 双向 双向 + 进度
持续性 持续发布 一次调用 长时间执行
多对多 ❌(一服务一请求)
适用 传感器流、控制指令 参数配置、计算 导航、抓取
接口 .msg .srv .action

九、ROS1 vs ROS2 速查

ROS1 ROS2
构建工具 catkin_make colcon
通信 XML-RPC TCPROS DDS
主节点 roscore(单点故障) 无(去中心化)
Python 2.7 3.6+
启动 roslaunch ros2 launch
编译 package.xml + CMakeLists 同,但支持纯 Python
跨平台 仅 Linux Linux / Windows / macOS