2. ROS2基础与AUV软件架构
ROS2 是 AUV 水下仿真与控制系统的软件骨架。理解它,关键不是记住几个术语,而是弄清楚“一个节点如何通过话题、服务、参数与 Launch 文件,与其他节点协同完成一次推进、一次姿态调整或一次任务下发”。本节围绕这五个基础概念展开,并落到 AUV 控制系统的典型 ROS2 架构上。
节点:功能的最小运行单元
节点(Node)是 ROS2 中可独立启动、独立通信的进程单元。在 AUV 系统中,通常按“职责单一”原则拆分节点:一个节点负责读取仿真中的 IMU 与深度计,一个节点负责推进器分配,一个节点负责航向/深度控制律计算,一个节点负责任务调度。每个节点通过 rclcpp(C++)或 rclpy(Python)创建,拥有唯一名称,例如 /auv/imu_driver、/auv/thruster_allocator、/auv/depth_controller。节点名是后续话题、服务、参数寻址的基础,命名应体现设备与功能层级。
一个最小节点示例(Python)如下,它发布深度数据:
import rclpy
from rclpy.node import Node
from std_msgs.msg import Float64
class DepthSensor(Node):
def __init__(self):
super().__init__('depth_sensor')
self.pub = self.create_publisher(Float64, '/auv/depth', 10)
self.timer = self.create_timer(0.05, self.tick) # 20 Hz
def tick(self):
msg = Float64()
msg.data = 12.5 # 示例:来自仿真模型的深度值
self.pub.publish(msg)
rclpy.init()
rclpy.spin(DepthSensor())
话题:持续数据流的发布与订阅
话题(Topic)是异步、多对多的数据通道,适合传感器流、控制指令流这类高频、持续的数据。发布者与订阅者通过话题名和消息类型匹配,彼此不感知对方存在。AUV 中典型话题包括:/auv/imu(sensor_msgs/Imu)、/auv/depth(std_msgs/Float64)、/auv/cmd_vel(geometry_msgs/Twist)、/auv/thruster_cmd(自定义 Float64MultiArray)。
设计话题时要关注三点:一是频率与队列深度,传感器流用 10~50 Hz、队列 10 较常见;二是QoS 策略,仿真中传感器数据可用 SensorDataQoS(best effort),控制指令宜用 reliable;三是坐标系约定,AUV 的 cmd_vel 通常约定为机体坐标系:x 向前、y 向右、z 向下,线速度与角速度均在该系下表达,全文与图示保持一致。
服务:请求—响应的同步交互
服务(Service)用于“发一次请求、等一次响应”的场景,如切换控制模式、请求上浮、查询电池状态。与话题不同,服务是同步的、一对一的。AUV 中可定义 /auv/set_mode(请求字段 mode: "manual"|"auto"|"hold",响应字段 success: bool),或 /auv/calibrate_imu。服务不宜承载高频数据,也不宜在控制回路中阻塞调用,否则会拖慢实时性。
参数:运行时可调的配置
参数(Parameter)是节点的配置项,可在启动时声明、运行时查询与修改。AUV 控制器的 PID 增益、限幅、采样周期都适合做成参数。例如深度控制器声明 kp、ki、kd、max_thrust,通过 ros2 param set /auv/depth_controller kp 1.8 在线调整。参数修改后节点需读取新值并生效,这为水下调试提供了不必重启节点的便利。
Launch 文件:多节点的统一编排
Launch 文件把节点启动、参数注入、话题重映射、命名空间组织在一起。一个 AUV 仿真启动文件通常同时拉起 Gazebo、机器人状态发布、传感器桥接、控制器与任务节点。示例(Python Launch):
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(package='auv_control', executable='depth_controller',
name='depth_controller', namespace='auv',
parameters=[{'kp': 1.5, 'ki': 0.2, 'kd': 0.05,
'max_thrust': 40.0}]),
Node(package='auv_control', executable='thruster_allocator',
name='thruster_allocator', namespace='auv'),
Node(package='auv_bringup', executable='mission_manager',
name='mission_manager', namespace='auv'),
])
AUV 控制系统的典型 ROS2 架构
把上述概念串起来,AUV 控制系统可划分为四层:感知层(IMU、深度计、DVL 驱动节点,发布传感器话题)、估计层(状态估计节点,融合出位姿与速度)、控制层(航向/深度/速度控制器,订阅设定值与估计状态,输出推力指令)、执行层(推力分配节点,把合力/力矩映射到各推进器转速)。任务管理层通过服务与参数对控制层下发模式与目标。下图给出这一数据流与调用关系。
这张架构图对应到实际调试:启动后先用 ros2 node list 确认各节点在线,用 ros2 topic hz /auv/imu 检查传感器频率是否达到 20 Hz,用 ros2 topic echo /auv/odom 观察估计位姿是否随仿真运动更新。若深度控制器输出异常,先确认它订阅的 /auv/depth 与 /auv/odom 是否有数据,再检查参数 kp 是否被 Launch 文件覆盖。任务管理层通过服务切换模式时,若响应 success=false,应检查当前状态是否允许切换(例如手动模式下不允许直接进入自动定深)。
/auv 统一了所有节点与话题前缀,便于多机器人或多仿真实例并存;Launch 文件中用 namespace='auv' 即可批量生效,避免逐个重映射。