ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

从零搭建水下机器人仿真环境:ROS2、Gazebo与ArduSub集成指南

2026/8/7 7:26:31 拓冰建站 浏览量
从零搭建水下机器人仿真环境:ROS2、Gazebo与ArduSub集成指南

在实际机器人开发中,仿真环境是验证算法、测试硬件接口、进行安全训练的关键环节。对于水下机器人这类复杂且昂贵的系统,直接在真实水域中进行算法调试和功能测试不仅成本高昂,也伴随着巨大的风险。因此,一个能够逼真模拟水下动力学、传感器数据流和控制指令交互的仿真平台,对于研发团队来说至关重要。ROS2 提供了现代化的机器人软件框架,Gazebo 是强大的物理仿真引擎,而 ArduSub 则是经过实战检验的无人潜航器(UUV)自动驾驶仪固件。将三者结合,意味着我们可以在一个高保真的虚拟海洋环境中,使用真实的自动驾驶仪软件栈来驱动一个虚拟的机器人模型,从而完成从底层控制到上层自主决策的完整开发与测试闭环。

本文旨在为机器人开发者,特别是对水下机器人或复杂系统仿真感兴趣的工程师和学生,提供一个从零搭建 ROS2 + Gazebo + ArduSub 集成仿真环境的详细指南。我们将一步步完成环境配置、模型构建、软件桥接和自主控制逻辑验证。通过本文,你将能够搭建一个可运行的水下机器人仿真场景,理解三者之间的数据流,并在此基础上进行自主导航、任务规划等算法的开发与测试。

1. 理解 ROS2、Gazebo 与 ArduSub 的协同工作流

在开始动手之前,必须厘清这三个核心组件各自的角色以及它们如何协同工作。这决定了后续所有配置和代码编写的逻辑。

1.1 核心组件角色定义

  • ROS2 (Robot Operating System 2): 扮演“神经系统”“消息总线”的角色。它不负责具体的物理计算或底层控制,而是提供了一套基于节点(Node)的分布式通信框架。在仿真中,ROS2 节点用于:
    • 发布传感器数据(如 IMU、深度计、相机图像)。
    • 订阅控制指令(如目标深度、航向、速度)。
    • 运行高级算法(如 SLAM、路径规划)。
    • 管理整个系统的启动和配置。
  • Gazebo: 扮演“物理世界模拟器”“传感器模拟器”的角色。它基于物理引擎(如 ODE、Bullet)计算机器人模型在水下的运动(浮力、阻力、推进器推力),并生成逼真的传感器输出。Gazebo 通过其插件系统与外部世界交互。
  • ArduSub: 扮演“机器人大脑(自动驾驶仪)”的角色。它是一套专为无人潜航器设计的固件,运行在 Pixhawk 系列或类似的飞控硬件上。在仿真中,我们并不运行在真实硬件上,而是运行其SITL (Software In The Loop)版本。ArduSub SITL 接收来自 Gazebo(通过 MAVLink)的传感器数据,运行其内部的控制律(PID 控制器等),并计算出推进器指令,再发送回 Gazebo 驱动模型运动。

1.2 数据流与集成架构

三者集成的核心在于MAVLink协议。MAVLink 是一种轻量级的消息传递协议,专为无人机/无人车通信设计,也是 ArduPilot/ArduSub 生态的通用语言。

整个仿真系统的数据流如下:

  1. Gazebo加载一个水下机器人模型(包含推进器、传感器等插件)。
  2. Gazebo内部的一个插件(如libgazebo_mavlink_interface.so)充当MAVLink 网关。它将 Gazebo 中的模型姿态、IMU 数据等封装成 MAVLink 消息发送出去;同时,它也接收外部的 MAVLink 控制指令,并转化为 Gazebo 中模型的力和力矩。
  3. ArduSub SITL作为一个独立进程运行。它通过 UDP 端口与 Gazebo 的 MAVLink 插件进行通信。它接收传感器数据,运行控制算法,并发出执行器(舵机、电机)控制指令。
  4. ROS2如何介入?有两种主要方式:
    • 方式一(直接): 通过ros2mavrosmavlink相关包,直接与 ArduSub SITL 的 MAVLink 端口通信,从而实现 ROS2 话题与服务到 MAVLink 消息的转换。这是最接近真实硬件的模式。
    • 方式二(通过 Gazebo): 利用 Gazebo-ROS2 的桥接功能。Gazebo 中的传感器插件(如相机、IMU)可以直接将数据发布到 ROS2 话题上;同时,也可以编写 ROS2 节点来订阅 Gazebo 中的模型状态,或通过服务调用控制模型。这种方式更侧重于利用 ROS2 进行感知和高级规划,而底层控制仍由 ArduSub 处理。

本文将重点介绍方式一,因为它更完整地复现了真实系统中 ROS2 与飞控的交互模式,是进行自主控制算法开发的更佳起点。

2. 基础环境搭建与依赖安装

一个稳定、版本匹配的基础环境是成功的第一步。以下步骤在 Ubuntu 22.04 LTS 上进行验证,这是目前 ROS2 Humble Hawksbill 的推荐系统。

2.1 安装 ROS2 Humble

如果系统已安装 ROS2,请跳过此步。确保安装的是桌面完整版(Desktop-Full),以包含 Gazebo 和 RViz 等可视化工具。

# 1. 设置语言环境 sudo apt update && sudo apt install locales sudo locale-gen en_US en_US.UTF-8 sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 export LANG=en_US.UTF-8 # 2. 添加 ROS2 软件源 sudo apt install software-properties-common sudo add-apt-repository universe sudo apt update && sudo apt install curl -y 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 $(. /etc/os-release && echo $UBUNTU_CODENAME) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null # 3. 安装 ROS2 Humble 桌面完整版 sudo apt update sudo apt install ros-humble-desktop-full # 4. 设置环境变量(建议写入 ~/.bashrc) echo “source /opt/ros/humble/setup.bash” >> ~/.bashrc source ~/.bashrc

2.2 安装 Gazebo Harmonic 与 ROS2 桥接

Ubuntu 22.04 默认的 Gazebo 版本可能较旧。我们安装较新的 Gazebo Harmonic,并通过源码编译其 ROS2 桥接包。

# 1. 安装 Gazebo Harmonic sudo apt install wget sudo wget https://packages.osrfoundation.org/gazebo.gpg -O /usr/share/keyrings/pkgs-osrf-archive-keyring.gpg echo “deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/pkgs-osrf-archive-keyring.gpg] http://packages.osrfoundation.org/gazebo/ubuntu-stable $(lsb_release -cs) main” | sudo tee /etc/apt/sources.list.d/gazebo-stable.list > /dev/null sudo apt update sudo apt install gazebo-harmonic libgazebo-harmonic-dev # 2. 创建工作空间并下载 gazebo_ros_pkgs 源码 mkdir -p ~/underwater_ws/src cd ~/underwater_ws/src git clone -b humble https://github.com/ros/gazebo_ros_pkgs.git # 3. 安装依赖并编译 cd ~/underwater_ws sudo apt install python3-rosdep2 sudo rosdep init rosdep update rosdep install -i --from-path src --rosdistro humble -y colcon build --symlink-install # 4. 将工作空间加入环境变量 echo “source ~/underwater_ws/install/setup.bash” >> ~/.bashrc source ~/.bashrc

2.3 安装 ArduSub SITL 及相关工具

ArduSub 是 ArduPilot 项目的一部分。我们通过其官方工具ardupilot-gazeboardupilot源码来搭建 SITL 环境。

# 1. 安装通用依赖 sudo apt install git cmake build-essential genromfs ninja-build libgsl-dev libeigen3-dev libxml2-dev libblas-dev liblapack-dev libopenblas-dev libarmadillo-dev python3-dev python3-pip python3-matplotlib python3-lxml python3-future python3-pexpect python3-serial # 2. 克隆 ArduPilot 源码(包含 ArduSub) cd ~ git clone https://github.com/ArduPilot/ardupilot.git cd ardupilot git submodule update --init --recursive # 3. 安装 ardupilot-gazebo 插件(用于 Gazebo 与 SITL 通信) cd ~ git clone https://github.com/ArduPilot/ardupilot_gazebo.git cd ardupilot_gazebo mkdir build && cd build cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo make -j4 sudo make install # 4. 设置环境变量(非常重要!) echo ‘export PATH=$PATH:$HOME/ardupilot/Tools/autotest’ >> ~/.bashrc echo ‘export PATH=/usr/lib/ccache:$PATH’ >> ~/.bashrc echo ‘export ARDUPILOT_GAZEBO_PATH=$HOME/ardupilot_gazebo’ >> ~/.bashrc # 假设插件安装在此 source ~/.bashrc

2.4 安装 MAVROS 与 MAVLink 工具

MAVROS 是 ROS 与 MAVLink 设备(如 ArduSub)通信的官方节点。

# 安装 MAVROS 及相关包 sudo apt install ros-humble-mavros ros-humble-mavros-extras ros-humble-mavros-msgs # 安装地理围栏数据(MAVROS 需要) wget https://raw.githubusercontent.com/mavlink/mavros/master/mavros/scripts/install_geographiclib_datasets.sh sudo bash ./install_geographiclib_datasets.sh

3. 构建仿真场景与启动完整系统

环境就绪后,我们需要准备一个水下机器人模型,并编写启动文件将三者串联起来。

3.1 获取或创建水下机器人模型

我们可以使用ardupilot_gazebo中自带的蓝鳍金枪鱼(BlueROV2)模型,这是一个经典且配置完善的水下机器人模型。

# 检查模型是否已安装 ls /usr/share/gazebo-*/models/ | grep -i bluerov2 # 如果未找到,可以手动从 ardupilot_gazebo 仓库复制(假设你克隆在 ~/ardupilot_gazebo) # 模型通常位于 ~/ardupilot_gazebo/models

模型目录通常包含.sdf(模型描述文件)、meshes/(模型网格文件)和materials/(材质文件)。关键是要确保模型中的推进器(<plugin name=”thruster”>)和 IMU 等传感器的命名与 ArduSub 的期望相匹配。

3.2 编写集成启动文件

我们将创建一个 ROS2 包来管理启动配置。在~/underwater_ws/src下:

cd ~/underwater_ws/src ros2 pkg create underwater_simulation --build-type ament_python --dependencies rclpy launch_ros cd underwater_simulation mkdir launch

launch/目录下创建bluerov2_ardusub.launch.py文件:

# launch/bluerov2_ardusub.launch.py import os from ament_index_python.packages import get_package_share_directory from launch import LaunchDescription from launch.actions import ExecuteProcess, IncludeLaunchDescription, RegisterEventHandler from launch.event_handlers import OnProcessExit from launch.launch_description_sources import PythonLaunchDescriptionSource from launch.substitutions import FindExecutable, PathJoinSubstitution from launch_ros.actions import Node def generate_launch_description(): # 定义路径和命令 ardupilot_dir = os.path.expanduser(‘~/ardupilot’) model_name = ‘bluerov2_heavy’ world_name = ‘underwater.world’ # 可以自定义或使用默认的 empty.world # 1. 启动 Gazebo 服务器和客户端,并加载水下世界和机器人模型 # 这里我们使用 ardupilot_gazebo 提供的启动文件(如果存在) # 或者直接使用 gazebo_ros 启动一个空世界,然后通过服务调用生成模型 gazebo_launch = IncludeLaunchDescription( PythonLaunchDescriptionSource([ PathJoinSubstitution([ get_package_share_directory(‘gazebo_ros’), ‘launch’, ‘gazebo.launch.py’ ]) ]), launch_arguments={ ‘world’: [‘worlds/’, world_name], ‘verbose’: ‘true’, # 有助于调试 }.items() ) # 2. 在 Gazebo 中生成 BlueROV2 模型 spawn_entity = Node( package=‘gazebo_ros’, executable=‘spawn_entity.py’, arguments=[‘-entity’, model_name, ‘-file’, f‘/usr/share/gazebo-11/models/{model_name}/model.sdf’, ‘-x’, ‘0’, ‘-y’, ‘0’, ‘-z’, ‘-5’, ‘-R’, ‘0’, ‘-P’, ‘0’, ‘-Y’, ‘0’], output=‘screen’ ) # 3. 启动 ArduSub SITL # 注意:ardupilot 的 sitl 需要在其目录下运行,并指定车型和参数 sitl_cmd = ExecuteProcess( cmd=[ ‘bash’, ‘-c’, f‘cd {ardupilot_dir} && sim_vehicle.py -v ArduSub -f gazebo-{model_name} --model=JSON --console --map’ ], cwd=ardupilot_dir, output=‘screen’, shell=True ) # 4. 启动 MAVROS 节点,连接 SITL # SITL 默认在 UDP 端口 14550 和 14551 监听 mavros_node = Node( package=‘mavros’, executable=‘mavros_node’, name=‘mavros’, output=‘screen’, parameters=[{ ‘fcu_url’: ‘udp://:14550@localhost:14557’, ‘gcs_url’: ‘’, ‘target_system_id’: 1, ‘target_component_id’: 1, ‘fcu_protocol’: ‘v2.0’, }] ) # 5. (可选) 启动一个简单的 ROS2 控制节点,用于发送测试指令 test_controller_node = Node( package=‘underwater_simulation’, executable=‘simple_controller’, name=‘simple_controller’, output=‘screen’ ) return LaunchDescription([ gazebo_launch, spawn_entity, sitl_cmd, mavros_node, # test_controller_node, # 初始测试时可先注释掉 RegisterEventHandler( event_handler=OnProcessExit( target_action=spawn_entity, on_exit=[sitl_cmd], # 确保模型生成后再启动 SITL,但顺序可能需调整 ) ), ])

注意:上述启动文件是一个概念框架,实际路径(如模型文件路径、SITL 命令)需要根据你的具体安装和模型进行调整。ardupilot_gazebo项目可能提供了更集成的启动方式。

3.3 编写一个简单的测试控制器

underwater_simulation包中创建节点脚本simple_controller.py,用于通过 MAVROS 向 ArduSub 发送指令。

# underwater_simulation/underwater_simulation/simple_controller.py import rclpy from rclpy.node import Node from geometry_msgs.msg import TwistStamped from mavros_msgs.msg import OverrideRCIn import time class SimpleController(Node): def __init__(self): super().__init__(‘simple_controller’) # 方式1:通过 MAVROS 的 /mavros/rc/override 话题直接发送 RC 通道值 # 这是最底层、最直接的控制方式,对应飞控的 RC 输入 self.rc_override_pub = self.create_publisher(OverrideRCIn, ‘/mavros/rc/override’, 10) # 方式2:通过 /mavros/setpoint_velocity/cmd_vel 发送速度指令(需要飞控在相应模式) # self.vel_pub = self.create_publisher(TwistStamped, ‘/mavros/setpoint_velocity/cmd_vel’, 10) self.timer = self.create_timer(0.1, self.timer_callback) # 10Hz self.get_logger().info(‘Simple controller node started’) def timer_callback(self): msg = OverrideRCIn() # 假设通道映射:1- Roll, 2- Pitch, 3- Throttle, 4- Yaw, 5- Forward, 6- Lateral, 7- Camera Pan, 8- Camera Tilt # PWM 值通常在 1100-1900 之间,1500 为中立点。 # 例如:设置油门(通道3)为 1600,使机器人缓慢上浮。 msg.channels[0] = 1500 # Ch1 msg.channels[1] = 1500 # Ch2 msg.channels[2] = 1600 # Ch3 - Throttle (上浮) msg.channels[3] = 1500 # Ch4 msg.channels[4] = 1500 # Ch5 msg.channels[5] = 1500 # Ch6 msg.channels[6] = 1500 # Ch7 msg.channels[7] = 1500 # Ch8 self.rc_override_pub.publish(msg) self.get_logger().info(‘Publishing RC override: Throttle=1600’) def main(args=None): rclpy.init(args=args) controller = SimpleController() rclpy.spin(controller) controller.destroy_node() rclpy.shutdown() if __name__ == ‘__main__’: main()

别忘了在setup.py中配置入口点:

# setup.py 片段 entry_points={ ‘console_scripts’: [ ‘simple_controller = underwater_simulation.simple_controller:main’, ], },

编译工作空间:

cd ~/underwater_ws colcon build --packages-select underwater_simulation source install/setup.bash

4. 运行验证与数据流分析

现在,我们可以启动整个系统并观察其运行状态。

4.1 启动仿真系统

cd ~/underwater_ws source install/setup.bash ros2 launch underwater_simulation bluerov2_ardusub.launch.py

如果一切顺利,你应该会看到:

  1. Gazebo 客户端界面打开,一个水下世界中出现 BlueROV2 模型。
  2. 一个终端窗口运行 ArduSub SITL,显示初始化信息,最后出现ArduSub>提示符。
  3. 另一个终端运行 MAVROS 节点,显示连接状态。
  4. 机器人模型可能开始运动(取决于你的控制器指令或默认参数)。

4.2 关键数据流检查点

使用ros2 topic listros2 topic echo命令来验证数据流是否畅通。

检查点ROS2 话题预期内容说明
Gazebo -> ArduSub(非 ROS 话题,通过 MAVLink UDP)模型姿态、IMU 数据在 SITL 终端查看是否有传感器数据输入。
ArduSub -> Gazebo(非 ROS 话题,通过 MAVLink UDP)执行器(电机)指令在 Gazebo 中观察机器人是否按指令运动。
MAVROS 连接状态/mavros/stateconnected: True,armed: True/False确认 MAVROS 已连接到 SITL。
飞控状态/mavros/global_position/globalGPS 坐标(仿真中可能为 0)确认定位数据流。
IMU 数据/mavros/imu/data加速度、角速度、姿态四元数确认 IMU 数据已从仿真环境通过 SITL 转发到 ROS2。
RC 指令覆盖/mavros/rc/override8个通道的 PWM 值这是我们控制器发布的话题,用于手动控制。
本地位置/mavros/local_position/pose相对于 Home 点的位置和姿态这是进行自主导航(如 OFFBOARD 模式)的关键反馈。

4.3 发送第一个自主任务:定深

在 ArduSub SITL 的控制台中,我们可以切换模式并发送指令。更符合 ROS2 集成的方式是使用 MAVROS 服务。

  1. 解锁并切换模式(通过 MAVROS 服务):
    # 在新的终端中 source ~/underwater_ws/install/setup.bash # 解锁(Arm)飞控 ros2 service call /mavros/cmd/arming mavros_msgs/srv/CommandBool “{value: true}” # 将模式切换为 “ALT_HOLD” (定深模式) ros2 service call /mavros/set_mode mavros_msgs/srv/SetMode “{base_mode: 0, custom_mode: ‘ALT_HOLD’}”
  2. 发送目标深度(通过 MAVROS 话题):
    # 发布一个目标深度消息(例如:-2米,水面为0,水下为负) ros2 topic pub /mavros/setpoint_position/global geographic_msgs/msg/GeoPoseStamped “{header: {stamp: {sec: 0, nanosec: 0}, frame_id: ‘’}, pose: {position: {latitude: 0.0, longitude: 0.0, altitude: -2.0}, orientation: {x: 0.0, y: 0.0, z: 0.0, w: 1.0}}}” -1
    在 ALT_HOLD 模式下,飞控会尝试维持当前深度。通过发布目标位置(包含深度),可以指令机器人下潜或上浮到指定深度。观察 Gazebo 中的机器人是否开始向目标深度运动。

5. 常见问题排查与调试

集成过程复杂,遇到问题是常态。以下是按优先级排序的排查清单。

5.1 Gazebo 相关问题

问题现象可能原因检查与解决
Gazebo 无法启动或黑屏显卡驱动、渲染器问题1. 尝试gazebo --verbose查看详细日志。
2. 使用软件渲染:export LIBGL_ALWAYS_SOFTWARE=1后再启动。
3. 检查是否安装了gazebo-harmoniclibgazebo-harmonic-dev
模型无法生成(spawn失败)模型文件路径错误、模型依赖缺失1. 检查spawn_entity.py命令中的-file参数路径是否正确。
2. 在 Gazebo 中手动插入模型测试:Edit -> Model Editor -> 保存为.sdf,再在终端中检查路径。
模型加载后沉底或飞上天模型物理参数(质量、浮力)错误1. 检查模型.sdf文件中的<mass><inertia><buoyancy>插件配置。
2. 参考ardupilot_gazebo中已有模型的配置进行对比。
推进器不工作推进器插件配置错误,或与 SITL 通道映射不匹配1. 在 Gazebo 中选中模型,查看左侧 “World” 面板,检查关节(Joint)是否有力/速度输出。
2. 检查模型.sdf<plugin name=”thruster”><jointName><topicName>。确保 SITL 输出的通道号与 Gazebo 插件订阅的关节名对应。

5.2 ArduSub SITL 相关问题

问题现象可能原因检查与解决
sim_vehicle.py命令找不到环境变量PATH未设置正确1. 确认已执行source ~/.bashrc
2. 检查$HOME/ardupilot/Tools/autotest是否在 PATH 中:echo $PATH
3. 尝试在ardupilot目录下直接运行./Tools/autotest/sim_vehicle.py
SITL 启动失败,提示 JSON 解析错误模型参数文件缺失或路径错误1. 检查-f gazebo-bluerov2对应的参数文件(如gazebo-bluerov2.param)是否存在于ardupilot/Tools/autotest/default_params/或相关目录。
2. 可以尝试使用-f vehicle而不指定 gazebo 前缀,使用默认参数启动。
SITL 无法连接到 GazeboUDP 端口冲突或 Gazebo 插件未加载1. 确认 Gazebo 模型加载时,其 MAVLink 插件已正确初始化(查看 Gazebo 终端输出)。
2. 检查 SITL 启动时指定的--model=JSON-I(实例号)参数。默认通信端口为1455014551
3. 使用netstat -uap查看 UDP 端口监听情况。

5.3 MAVROS 与 ROS2 通信问题

问题现象可能原因检查与解决
/mavros/state显示connected: FalseMAVROS 无法连接到 SITL 的 MAVLink 端点1. 检查mavros_node启动参数中的fcu_url。SITL 默认在14550端口发送,在14551端口接收。常见配置为udp://:14550@localhost:14557,其中14557是 MAVROS 本地监听端口。
2. 确认 SITL 已成功启动并开始输出数据。
3. 尝试使用mavlink-routerQGroundControl连接 SITL,先确认 MAVLink 链路本身是通的。
话题列表中没有预期的 MAVROS 话题MAVROS 节点未启动或命名空间错误1. 使用ros2 node list查看mavros节点是否存在。
2. 使用ros2 node info /mavros查看其发布和订阅的话题。
3. 检查启动文件中mavros_nodenamenamespace参数。
发送服务调用(如解锁)失败飞控未准备就绪(未校准、模式不对)1. 在 SITL 控制台输入arm throttle尝试直接解锁,查看反馈信息。
2. 检查status话题,确认传感器(如罗盘)是否已校准。在 SITL 中,通常需要运行calibrate命令。
3. 确保飞行模式不是INITIALISING

5.4 综合调试建议

  1. 分步启动:不要一次性启动所有组件。先单独启动 Gazebo 并加载模型,确认模型物理表现正常。再单独启动 ArduSub SITL,看其是否能独立运行。最后启动 MAVROS 进行桥接。
  2. 善用日志:为每个启动命令添加--verboseoutput=‘screen’参数,仔细阅读终端输出。错误信息通常就在前几行。
  3. 检查版本兼容性:这是最隐蔽的问题。确保ardupilot_gazebo插件版本与你的 Gazebo 版本(Harmonic)兼容。必要时,从源码编译指定分支的插件。
  4. 简化测试:初次集成时,使用最简单的模型(如一个立方体)和最基础的通信测试(如只发送 RC 指令看模型是否动),逐步增加复杂性。

6. 进阶应用与最佳实践

当基础仿真链路跑通后,可以在此基础上构建更复杂的应用。

6.1 开发自主导航节点

利用 ROS2 的导航栈(Nav2)或自定义的规划算法,结合/mavros/local_position/pose(位姿)和/mavros/setpoint_position/local(目标点)话题,实现水下路径跟踪。

  1. 获取定位信息:融合来自 Gazebo(通过 SITL)的 IMU、深度计、DVL(多普勒计程仪)数据,在 ROS2 中运行扩展卡尔曼滤波(EKF)节点,提供更平滑的odometry
  2. 路径规划:使用nav2或自定义的全局/局部规划器,生成从 A 点到 B 点的路径(一系列位姿点)。
  3. 控制接口:将规划出的路径点,通过/mavros/setpoint_position/local话题发送给飞控。需要将飞控模式设置为OFFBOARD,并确保位姿估计源已设置正确。

6.2 集成自定义传感器与执行器

Gazebo 允许你为模型添加各种传感器插件(如相机、声呐、机械臂)。

  1. 添加传感器:在模型的.sdf文件中添加<sensor>标签,例如一个前视相机。Gazebo 的 ROS2 插件会自动将其数据发布到类似/camera/image_raw的 ROS2 话题上。
  2. 处理传感器数据:编写 ROS2 节点订阅这些话题,进行图像处理、目标检测或点云处理。
  3. 控制执行器:例如控制一个机械爪。可以在模型中添加一个夹持器关节,并通过<plugin>使其可被 ROS2 服务控制。你的自主任务节点可以在到达目标点后,调用该服务执行抓取动作。

6.3 仿真环境配置优化

  1. 水下环境模拟:Gazebo 的默认世界是空气。需要修改世界文件(.world),设置流体的密度、粘度来模拟水。ardupilot_gazeboworlds目录下可能有现成的underwater.world
  2. 添加海流与扰动:在水下世界中添加匀速或随机的海流,测试控制器的鲁棒性。这可以通过 Gazebo 的wind插件或自定义的力场插件实现。
  3. 多机器人仿真:复制机器人模型,为每个实例分配不同的 MAVLink 系统 ID(sysid),并在启动时指定不同的 UDP 端口,可以实现多水下机器人协同仿真。

6.4 迈向真实部署的检查清单

仿真通过后,若计划部署到真实机器人,需注意:

  • 硬件在环(HITL)测试:将 SITL 替换为真实的 Pixhawk 硬件,通过 USB/UART 连接,在 Gazebo 中测试真实飞控的响应。这是验证参数和逻辑的关键一步。
  • 参数迁移与校准:仿真中调试好的 PID 等控制参数,需要谨慎地迁移到真实飞控。真实环境必须进行完整的传感器(罗盘、加速度计、水平仪)校准。
  • 通信链路可靠性:仿真中使用的是本地 UDP 回环,延迟极低。真实系统中需考虑数传电台的带宽、延迟和丢包,并在 ROS2 节点中增加相应的超时和重试机制。
  • 安全机制:在真实系统中,必须实现心跳监测、失控保护(Return-to-Launch)、紧急上浮等安全逻辑,这些在仿真阶段就应设计并测试。

通过 ROS2 + Gazebo + ArduSub 的集成,我们构建了一个从算法仿真到硬件在环的完整水下机器人研发管道。这个管道极大地降低了开发风险与成本,使得复杂的自主水下任务开发变得可迭代、可测试。接下来的方向,是根据你的具体任务需求,在 Gazebo 中构建更逼真的水下场景,在 ROS2 中开发更智能的感知与决策节点,并利用 ArduSub 稳定的底层控制,最终将代码安全地部署到真实的海洋探索者身上。