简介:本资源是一个面向机器人仿真开发者的Gazebo动态仓库环境实战项目,适用于ROS初学者及自动化物流算法验证人员,解决真实仓储场景中机器人协同、动态交互与物理仿真建模等核心问题。压缩包共104个文件,含13个SDF世界与模型定义文件、24个DAE三维模型、41张PNG材质贴图、13个CONFIG配置项、1个WORLD主场景、1个LAUNCH启动脚本及RVIZ可视化配置等,完整覆盖建模、仿真、插件开发与构建全流程;包体大小9.52MB,结构清晰分为model/、worlds/、plugins/、launch/等标准目录。已有350人学习下载,提供可直接编译运行的CMakeLists.txt、预置动态行为插件源码(C++)、多货架+AGV+输送带联合仿真世界,以及配套README说明与LICENSE授权文件,助开发者快速部署、调试并二次扩展动态物流仿真系统。

1. 项目背景与拆包初印象

最近手里拿到一个工程压缩包,名字很直白: Gazebo模拟仓库中的动态环境。_CMake_下载.zip 。拆开之后其实就能明白,这是一个把仿真场景和构建脚本打在一起的ROS2工程包:用Gazebo搭一个仓库环境,在里面布置动态障碍物,再用CMake管理整个工程,最后跑起来一个差速轮机器人,前后或斜对角挂两颗RGBD传感器,通过话题做数据收发。这类工程很适合作为SLAM和导航算法测试的“靶场”——你不需要把真实AGV搬到仓库里,也不需要担心撞坏货架,Gazebo里什么都能重复复现。

这个项目解决的核心问题是:如何快速得到一个带动态干扰的室内结构化环境。对做slam_toolbox、nav2或者感知算法的人来说,动态环境是绕不开的坎:在静态地图里SLAM跑得再好,一旦有移动的叉车、行人、货架上的传送带,算法往往就开始飘。而Gazebo恰恰能提供物理上可信的动态元素,还不会烧掉一辆真实底盘的钱。合适的使用者包括刚学Gazebo的学生、要评估导航算法在动态场景中表现的工程师,以及想给机器人测试环境加一点“活物”的爱好者。

整个技术链路并不复杂:Gazebo负责物理和传感器仿真,URDF/SDF负责建模,CMake和ament_cmake负责把ROS2节点组织起来,差速轮插件负责让机器人动起来,RGBD相机插件负责出图像和深度数据。你可以直接用现成的模型,也可以自己改参数,比如轮距、相机高度、障碍物运动速度。下面我把这个工程的搭建思路、关键参数和常见坑都过一遍,照着做基本能跑通。

2. 环境准备:从系统到Gazebo和CMake

2.1 操作系统与ROS2版本选择

我在实际搭建时用的是Ubuntu 22.04虚拟机加ROS2 Humble,Gazebo版本是Gazebo Classic 11。这套组合在目前ROS2社区里资料最多,很多教程都是基于这个版本写的,遇到问题也好搜。如果你用的是Ubuntu 24.04虚拟机,那对应的是ROS2 Jazzy,默认的Gazebo变成了新版本的Gazebo Harmonic(也叫gz sim),使用方式和Classic差别比较大,插件接口、命令行工具都不一样,不建议新手直接跳到这套组合。

如果只是做仓库环境仿真和传感器数据收发,优先选Humble。理由有三个:第一, gazebo_ros_pkgs 在Humble下是二进制的,安装方便;第二,slam_toolbox和nav2在Humble下都有现成版本,可以直接跑;第三,旧版Gazebo对显卡要求相对低,在虚拟机里也跑得动。别一上来就追求最新版本,扎扎实实用成熟组合解决核心问题,比折腾版本更划算。

2.2 Gazebo安装与验证

Ubuntu 22.04环境下的安装步骤很简单,先装ROS2 Humble,再装Gazebo相关套件:

sudo apt update
sudo apt install ros-humble-gazebo-ros-pkgs

这个包会替你装好Gazebo本体、ROS2桥接插件和标准模型库。安装完成后先验证一下:

gazebo --version

能输出版本号就说明核心组件没问题。接着启动一个空世界:

gazebo

如果窗口能正常打开,编译不报缺库,环境就OK了。我在虚拟机上遇到过双击启动后黑屏的问题,后来发现是3D加速没打开。在VMware或VirtualBox设置里把“加速3D图形”打开,或者设置环境变量 LIBGL_ALWAYS_SOFTWARE=1 强制软渲染,都能缓解。注意,软渲染下Gazebo会卡,但跑一个不算大的仓库场景还是能接受的。

2.3 CMake版本管理与常见坑

做ROS2工程绕不开CMake,因为ROS2的ament_cmake构建系统本质上就是在CMake之上扩展的。很多人看到工程名里带“CMake_下载”,其实就是在提醒你:先把CMake版本弄对。

Ubuntu 22.04自带的CMake通常是3.22.x,ROS2 Humble要求最低CMake 3.16以上,所以系统自带的就够用。不要看到搜到“如何将Ubuntu中cmake降到3.16.3”就动手降级。只有在交叉编译、老版本第三方库、或者某些特殊生成器指定版本的情况下才需要折腾版本。降级CMake很容易把系统依赖搞坏,因为很多系统组件在编译时会用到新版本CMake。

检查当前版本:

cmake --version

如果确实需要自定义版本,我推荐用源码编译到独立目录,而不是覆盖系统路径。比如:

wget https://cmake.org/files/v3.16/cmake-3.16.3.tar.gz
tar xzf cmake-3.16.3.tar.gz
cd cmake-3.16.3
./bootstrap --prefix=$HOME/.local
make -j$(nproc)
make install

然后通过 export PATH=$HOME/.local/bin:$PATH 把它放到用户环境里。这样不影响系统其他软件,用起来也安全。

2.4 解压zip并规划目录

拿到工程压缩包后,先把它放到工作区解压:

unzip Gazebo模拟仓库中的动态环境。_CMake_下载.zip -d my_warehouse
cd my_warehouse

我建议你顺手整理一下目录,别把所有文件堆在根目录。一个典型的工程结构大概是:

my_warehouse/
├── CMakeLists.txt
├── package.xml
├── world/
│   └── warehouse_warehouse.world
├── models/
│   ├── shelf/
│   ├── agv/
│   └── robot/
├── launch/
│   └── warehouse_sim.launch.py
├── src/
│   └── min_distance_node.cpp
└── config/
    └── slam_params.yaml

目录清晰之后,编译、启动、加模型都要省心很多。很多新手在Gazebo里加载不到模型,就是 GAZEBO_MODEL_PATH 环境变量没指到 models/ 目录。后面我会专门讲。

3. 仓库动态环境建模:让场景“活”起来

3.1 静态仓库地图的搭建思路

仓库动态环境的基础是静态场景。你要先有一个像样的仓库地图:平整的地面、墙面、货架、柱子和通道。不要一上来就用复杂的CAD图,先用SDF或URDF描述几个箱子组合起来就够用了。

比如一个简单货架,用SDF模型描述长1.8米、宽0.6米、高1.5米,四根柱子加三块层板。 <visual> 标签管显示, <collision> 标签管碰撞。视觉和碰撞形状不要做得太细,否则仿真会卡。

<model name="shelf_01">
  <static>true</static>
  <link name="base">
    <pose>0 0 0.75 0 0 0</pose>
    <visual name="vis">
      <geometry>
        <box><size>1.8 0.6 1.5</size></box>
      </geometry>
    </visual>
    <collision name="col">
      <geometry>
        <box><size>1.8 0.6 1.5</size></box>
      </geometry>
    </collision>
  </link>
</model>

然后把这个模型放到世界文件里,沿通道两侧摆,留出中间2米宽的过道。这种结构化布局是仓库环境的灵魂:货架遮挡激光雷达,柱子造成视觉盲区,过道限制运动空间,算法很容易在这种场景里暴露问题。

3.2 动态障碍物的三种常用实现方式

要让环境“动”起来,在Gazebo里有三种常见做法,我按推荐程度排个序。

第一种是用Gazebo内置的Actor,适合模拟行人、自动导引叉车这类不需要物理碰撞交互的移动物体。一个Actor本质上是一个自带动画模型的实体,可以设定运动轨迹,路径点用 <waypoint> 指定,循环走。缺点是不遵守物理碰撞,会穿过物体,但做一些巡逻路线就够。

第二种是用差速轮驱动插件,比如 libgazebo_ros_diff_drive.so 。这种适合模拟真实的AGV,可以接收 /cmd_vel 话题控制,发布里程计。你要做多机协同或者动态障碍物避让测试,用这个方式最灵活,因为它完全由ROS2话题驱动。

第三种是直接用ROS2节点周期性地修改模型位姿,通过Gazebo的 set_model_state 服务或者 ros_gz_bridge 把话题转成 gz 命令。这个适合做传送带之类规则运动的物体,控制粒度更细。

我在实际工程里建议这样组合:仓库里放一两个Actor作为来回移动的“人员”,再放一台差速轮AGV作为可灵活控制的动态障碍物。这样既省事,又能覆盖大多数动态SLAM测试需求。

3.3 差速轮机器人模型与双RGBD传感器的挂载

下面要重点说机器人本体。差速轮机器人模型建议用URDF写,因为要挂传感器和插件,URDF和xacro用起来比SDF顺手。

底盘可以先做一个长方体,两个驱动轮放在左右两侧,再加两个万向支撑轮。接着挂上两个RGBD传感器,一个前置,一个后置,高度在0.5米到0.8米之间。RGBD在Gazebo里不是单独的一个实体,而是通过 gazebo_ros_camera 插件实现,它同时发布彩色图像和深度图像话题。

URDF里传感器的关键部分大概是:

<link name="front_rgbd_link">
  <pose>0.35 0 0.55 0 0 0</pose>
  <visual name="vis">
    <geometry><mesh filename="package://my_robot/meshes/rgbd.dae"/></geometry>
  </visual>
</link>

<gazebo reference="front_rgbd_link">
  <sensor type="depth" name="front_depth">
    <always_on>true</always_on>
    <update_rate>10</update_rate>
    <camera>
      <horizontal_fov>1.396</horizontal_fov>
      <image>
        <width>640</width>
        <height>480</height>
        <format>R8G8B8</format>
      </image>
      <clip>
        <near>0.1</near>
        <far>10.0</far>
      </clip>
    </camera>
    <plugin name="front_depth_camera" filename="libgazebo_ros_camera.so">
      <ros>
        <namespace>front</namespace>
        <remapping>image_raw:=depth/image_raw</remapping>
        <remapping>camera_info:=depth/camera_info</remapping>
      </ros>
      <camera_name>front_depth</camera_name>
      <frame_name>front_rgbd_link</frame_name>
    </plugin>
  </sensor>
</gazebo>

两个RGBD传感器建议别放在完全相同的水平面,最好在高度或角度上错开一点,这样能采集到更丰富的环境信息,也方便后续做数据融合。参数方面,深度相机的 <update_rate> 设成10到15Hz就够了,设太高会让CPU飙升。分辨率640x480比1080p更适合跑SLAM和后续算法。

3.4 世界文件与模型加载细节

世界文件用 .world 后缀,包含光照、物理引擎参数和已加载的模型。你可以在里面直接写多个 sdf 模型,也可以留空让launch文件动态加载机器人模型。

比较推荐的做法是:把货架、墙壁、地面这些静态物体直接写进 .world ,机器人则通过launch文件里spawn加载。这样更换机器人模型时不用改地图文件。

launch文件里加载机器人的关键步骤是:

# spawn robot
spawn_entity = Node(
    package='gazebo_ros',
    executable='spawn_entity.py',
    arguments=['-entity', 'my_robot',
               '-topic', 'robot_description',
               '-x', '0.0', '-y', '0.0', '-z', '0.1'],
    output='screen'
)

动态障碍物的Actor写在世界文件里即可,会随着世界加载自动出现。注意要把模型路径设置好,否则Gazebo找不到货架或机器人模型。在启动仿真前,最好先 echo $GAZEBO_MODEL_PATH ,确认已指向 models/ 目录。如果没设置,就在 ~/.bashrc 里加一行:

export GAZEBO_MODEL_PATH=$GAZEBO_MODEL_PATH:$PWD/models

这一步能避免大量“Unknown model”的报错。

4. 用CMake组织ROS2工程:从编译到运行

4.1 CMakeLists.txt怎么写得顺手

ROS2的工程包虽然推荐用 colcon build 编译,但底层调用的还是CMake。工程包里的 CMakeLists.txt 决定了这个包怎么被编译、依赖哪里来、生成的节点装到哪里。

一个基础但完整的 CMakeLists.txt 大概是这样的:

cmake_minimum_required(VERSION 3.16)
project(warehouse_sim)

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()

find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(sensor_msgs REQUIRED)
find_package(std_msgs REQUIRED)

add_executable(min_distance_node src/min_distance_node.cpp)
target_compile_features(min_distance_node PUBLIC c_std_17)
target_include_directories(min_distance_node PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  $<INSTALL_INTERFACE:include>)
target_link_libraries(min_distance_node
  rclcpp::rclcpp
  sensor_msgs::sensor_msgs
  std_msgs::std_msgs
)

install(TARGETS min_distance_node
  DESTINATION lib/${PROJECT_NAME}
)

ament_package()

注意三点。第一, cmake_minimum_required 版本不要写太高,3.16是个稳的值,能覆盖大多数发行版。第二, project 名字别带中文和空格,后面编译和运行都会有麻烦。第三, ament_package() 必须在最后,否则安装过程会不完整。

对应的 package.xml 也要写清楚依赖:

<package format="3">
  <name>warehouse_sim</name>
  <version>0.0.1</version>
  <description>Warehouse dynamic environment simulation</description>
  <maintainer email="you@example.com">you</maintainer>
  <license>Apache-2.0</license>

  <depend>rclcpp</depend>
  <depend>sensor_msgs</depend>
  <depend>std_msgs</depend>
  <depend>gazebo_ros</depend>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>

4.2 一个能收发话题的ROS2节点实例

现在写一个核心节点,它做的事情是:接收两颗RGBD深度相机发出的图像话题,计算图像中心点附近的深度值,再把结果作为消息发送出去。这个过程完整覆盖了“话题接受与发送”,也是动态环境感知里非常小的一个切面。

节点代码 src/min_distance_node.cpp :

#include <rclcpp/rclcpp.hpp>
#include <sensor_msgs/msg/image.hpp>
#include <std_msgs/msg/float32.hpp>

class MinDistanceNode : public rclcpp::Node
{
public:
  MinDistanceNode() : Node("min_distance_node")
  {
    sub_front_ = create_subscription<sensor_msgs::msg::Image>(
      "/front/depth/image_raw", rclcpp::SensorDataQoS(),
      [this](sensor_msgs::msg::Image::SharedPtr msg) {
        process(msg, front_pub_, "front");
      });
    sub_back_ = create_subscription<sensor_msgs::msg::Image>(
      "/back/depth/image_raw", rclcpp::SensorDataQoS(),
      [this](sensor_msgs::msg::Image::SharedPtr msg) {
        process(msg, back_pub_, "back");
      });

    front_pub_ = create_publisher<std_msgs::msg::Float32>("/front/min_distance", 10);
    back_pub_ = create_publisher<std_msgs::msg::Float32>("/back/min_distance", 10);
  }

private:
  void process(sensor_msgs::msg::Image::SharedPtr msg,
               rclcpp::Publisher<std_msgs::msg::Float32>::SharedPtr pub,
               const std::string &label)
  {
    if (msg->encoding != "32FC1")
    {
      RCLCPP_WARN_THROTTLE(get_logger(), *get_clock(), 5000,
        "%s encoding is %s, want 32FC1", label.c_str(), msg->encoding.c_str());
      return;
    }
    size_t h = msg->height;
    size_t w = msg->width;
    size_t idx = h / 2 * w + w / 2;
    const float *data = reinterpret_cast<const float *>(msg->data.data());
    float center_depth = data[idx];

    if (!std::isfinite(center_depth))
    {
      center_depth = 0.0;
    }

    std_msgs::msg::Float32 out;
    out.data = center_depth;
    pub->publish(out);
  }

  rclcpp::Subscription<sensor_msgs::msg::Image>::SharedPtr sub_front_;
  rclcpp::Subscription<sensor_msgs::msg::Image>::SharedPtr sub_back_;
  rclcpp::Publisher<std_msgs::msg::Float32>::SharedPtr front_pub_;
  rclcpp::Publisher<std_msgs::msg::Float32>::SharedPtr back_pub_;
};

int main(int argc, char** argv)
{
  rclcpp::init(argc, argv);
  rclcpp::spin(std::make_shared<MinDistanceNode>());
  rclcpp::shutdown();
  return 0;
}

这个节点用了 rclcpp::SensorDataQoS() ,这点很关键。Gazebo相机插件发布图像时默认QoS是 SensorDataQoS (类似Best Effort),如果订阅端用普通的 QoS(10) ,两端兼容性可能出问题,导致你订阅不到数据。很多新手遇到这个话题没数据,第一个想的就是名字打错了,其实QoS不匹配才是高发原因。

4.3 编译并运行仿真

确认 /opt/ros/humble/setup.bash 已经source之后,直接在工作区根目录编译:

colcon build --packages-select warehouse_sim

colcon build 内部会调用CMake、make,然后把安装产物放到 install/ 目录。编译输出里能看到CMake的 -- Configuring done 和 -- Generating done ,这就说明CMake配置没问题。

编译成功之后,source一下:

source install/setup.bash
ros2 launch warehouse_sim warehouse_sim.launch.py

启动完成后,可以打开几个终端验证:

ros2 topic list
ros2 topic echo /front/min_distance
ros2 topic hz /front/depth/image_raw

如果一切正常, hz 会稳定在10Hz左右, /front/min_distance 会输出一个不断变化的深度数值。这说明Gazebo里的深度相机数据成功通过话题发送到了节点,节点处理后又把结果发了出去。

5. 实操过程实录与关键参数

5.1 拉取依赖并生成构建文件

第一次拿到工程包,最容易漏的就是依赖。直接用 rosdep 检查并安装所有缺失依赖:

sudo apt install python3-rosdep python3-colcon-common-extensions
rosdep init
rosdep update
rosdep install -i --from-path src --rosdistro humble -y

如果 rosdep init 报错说已经存在,直接跳过,用 rosdep update 更新即可。依赖装完后,在工程根目录执行:

colcon build

这里有个细节:第一次编译前确保 build/ 和 install/ 目录是干净的。如果你之前用过别的ROS2版本或改过CMake选项,残留的CMakeCache会干扰新配置。这时直接删掉重新来:

rm -rf build install log
colcon build --cmake-args -DCMAKE_BUILD_TYPE=Release

加 --cmake-args 可以给底层CMake传参数,比如指定Release模式。Debug模式会让Gazebo插件很卡,不建议仿真时用。

5.2 动态环境的运动控制参数

差速轮机器人的运动参数集中在URDF的gazebo插件里。我用的是 libgazebo_ros_diff_drive.so ,核心参数如下:

<gazebo>
  <plugin name="diff_drive" filename="libgazebo_ros_diff_drive.so">
    <ros>
      <namespace>/</namespace>
      <remapping>cmd_vel:=cmd_vel</remapping>
      <remapping>odom:=odom</remapping>
    </ros>
    <left_joint>left_wheel_joint</left_joint>
    <right_joint>right_wheel_joint</right_joint>
    <wheel_separation>0.35</wheel_separation>
    <wheel_diameter>0.2</wheel_diameter>
    <max_wheel_torque>20</max_wheel_torque>
    <max_wheel_acceleration>1.0</max_wheel_acceleration>
    <publish_odom>true</publish_odom>
    <publish_odom_tf>true</publish_odom_tf>
  </plugin>
</gazebo>

wheel_separation 和 wheel_diameter 必须和URDF里的实际尺寸严格一致,否则里程计会偏,SLAM出来的地图会飘。调试时我建议先把机器人模型放到一张只有一个地面和一个货架的场景里,发一条速度指令,看它是否直线走、转弯半径是否符合预期,再放进复杂仓库。

动态障碍物用的Actor,参数大概是这样的:

<actor name="moving_forklift">
  <pose>2.0 1.0 0.0 0 0 0</pose>
  <skin>
    <filename>meshes/forklift.dae</filename>
  </skin>
  <animation name="movement">
    <filename>meshes/forklift.dae</filename>
    <scale>1.0</scale>
    <interpolate_x>true</interpolate_x>
  </animation>
  <script>
    <loop>true</loop>
    <auto_start>true</auto_start>
    <waypoint>
      <time>0</time><pose>2.0 1.0 0 0 0 0</pose>
    </waypoint>
    <waypoint>
      <time>10</time><pose>2.0 -2.0 0 0 0 0</pose>
    </waypoint>
    <waypoint>
      <time>20</time><pose>2.0 1.0 0 0 0 0</pose>
    </waypoint>
  </script>
</actor>

这个Actor会在两个点之间往返,模拟一台叉车在仓库通道里来回开。注意它的路径最好避开机器人主赛道,不然你的导航规划永远找不到一条无碰撞路径。

5.3 传感器话题与SLAM工具链的对接

动态环境建好之后,最直接的用法就是测试slam_toolbox和nav2。slam_toolbox需要一个稳定的激光或深度数据来源,你可以用RGBD的深度图转成激光,也可以通过 lidar_simulator 插件直接输出激光话题。如果没有装激光雷达,可以在URDF里加一个二维激光插件,这样SLAM的输入会更稳定。

slam_toolbox的关键参数文件 config/slam_params.yaml :

slam_toolbox:
  ros__parameters:
    use_sim_time: true
    odom_frame: odom
    base_frame: base_link
    scan_topic: /scan
    laser_min_range: 0.2
    laser_max_range: 8.0
    minimum_time_interval: 0.5
    mode: mapping

然后运行:

ros2 launch slam_toolbox online_async_launch.py

在建图和nav2定位跑起来之后,你就能看到动态环境为什么会给算法带来麻烦:货架后面突然开出来的Actor会把新的观测帧拉出一个小漂移,nav2的代价地图上会不断出现“幽灵障碍物”。这个问题恰好就是做动态环境仿真想复现的。如果你想让算法在动态环境中表现更好,后续可以考虑加入动态障碍物检测、过滤或者使用带动态剔除的SLAM方法。

6. 常见问题与排查技巧

6.1 CMake相关报错速查

我在运行这个工程时遇到过几个典型的CMake报错,整理成一个速查表:

现象 可能原因 解决办法
CMake Error: Generator ... does not match ... build目录里有旧的CMake缓存,或者CMake版本差异过大 删除build目录重新构建
Could not find a package configuration file ... 没setup ROS2环境,或某个apt包没装 source /opt/ros/humble/setup.bash ,再检查 rosdep
The current CMake version is lower than required 系统CMake版本太低 用源码编译新版CMake,放到 ~/.local ,或安装较新的发行版
ament_cmake not found 缺少ament_cmake包或未正确source sudo apt install ros-humble-ament-cmake

特别提一下Visual Studio 16 2019的报错,这个常出现在Windows上使用CMake生成器不匹配的时候。Linux平台下一般不会遇到,但在虚拟机里如果直接拷贝了Windows生成的构建目录,也可能出现。最简单的处理就是完全删除build目录,重新用 colcon build 生成。

6.2 Gazebo启动与模型加载问题

Gazebo启动黑屏或加载模型失败是我遇到最多的问题。黑屏大概率是显卡渲染问题,尤其是虚拟机环境。可以在启动Gazebo前设置:

export LIBGL_ALWAYS_SOFTWARE=1

这样会强制用软件渲染。代价是帧率低,但至少能打开。

模型加载不出来分两种情况:一种是Gazebo找不到模型路径,表现为日志里出现 [Err] [ModelDatabase.cc] ... not found 。这时把 GAZEBO_MODEL_PATH 指到工程目录下的 models 再重启。另一种是URDF中的mesh文件路径不对,表现为机器人一部分是灰白色方块。这时检查URDF里 <mesh filename> 是否用了 package:// ,且 package.xml 中正确声明了对应包。

另外要提醒的是,动态环境里如果模型太多,Gazebo的仿真步长会拖慢。可以把物理引擎的实时因子打开看一下,确保 <max_step_size> 和 <real_time_update_rate> 匹配。比如:

<physics type="ode">
  <max_step_size>0.001</max_step_size>
  <real_time_factor>1</real_time_factor>
  <real_time_update_rate>1000</real_time_update_rate>
</physics>

设为 real_time_factor=1 能让仿真速度和现实时间基本同步,SLAM测试的timestamps才不会乱。

6.3 传感器无数据/话题不通的排查思路

RGBD传感器话题没数据,按这个顺序排查,基本能定位问题。

第一步,确认插件加载成功。启动Gazebo时,终端里如果出现类似 Could not load plugin [libgazebo_ros_camera.so] ,说明插件没装上。检查是否安装了 gazebo_ros_pkgs 。

第二步,查看话题列表:

ros2 topic list | grep depth

如果没有看到 /front/depth/image_raw ,大概率是命名空间和remapping没配对。检查插件里 <namespace>front</namespace> 和 <remapping> 是否匹配,然后重启Gazebo。

第三步,检查QoS。用 ros2 topic echo /front/depth/image_raw --qos-reliability best_effort 测试。如果这样能收到,而代码里收不到,就是QoS不匹配。像我上面写的节点,需要用 rclcpp::SensorDataQoS() 订阅,而不是 QoS(10) 。

第四步,检查 <always_on> 设置。很多传感器插件默认不是常开,只有模型被选中或场景刷新时才发布一帧。给传感器加上 <always_on>true</always_on> ,确保持续发布。

还有一个小技巧:在Gazebo里选中机器人模型,旁边会有绿色坐标系,如果连RGBD传感器模型本身都没出来,那问题在URDF的mesh加载,而不是插件。先解决模型显示,再查话题。

7. 项目扩展与个人经验

7.1 从仿真到slam_toolbox+nav2的完整测试平台

这个工程包最值得扩展的方向就是变成一套持续的SLAM和导航测试平台。我在实际使用中是这样做的:先把所有动态障碍物关掉,启动robot和静态仓库地图,用slam_toolbox建一张“静态基准地图”,保存好。之后把动态Actor打开,启动nav2导航,让机器人自动导航到某个目标点。然后观察同一张地图下,动态障碍物对全局路径规划和局部代价地图的影响。

再进一步,可以在launch文件里加一个脚本节点,周期性地把机器人当前位置和目标点记录下来,自动跑几十遍测试,统计规划失败率。这个做法的价值在于:你算法改动后是否引入回归,只需要跑一遍测试集就能看出来。动态环境的随机性让测试结果更接近真实部署。

7.2 仿真器选择的思考:Gazebo和MuJoCo怎么选

有段时间我也在Gazebo和MuJoCo之间犹豫。说实话,MuJoCo在接触动力学、数值稳定性、训练速度上确实有优势,很多人拿它做强化学习和机械臂控制。但如果你要的是“一个完整的机器人带传感器跑在仓库环境里,还要和SLAM、nav2、RGBD图像有完整交互”,那Gazebo的生态更合适。Gazebo有ROS2原生的摄像头、激光雷达、RGBD插件,有Actor、差速轮驱动插件,还有sdf/world这样方便描述场景的文件格式,这些在MuJoCo里都要自己拼。不是说MuJoCo不好,而是工具选型要匹配场景。做算法控制的,MuJoCo真香;做室内机器人和SLAM的,Gazebo依旧是省力选项。

7.3 几个工程化建议

最后分享几个我一直沿用的习惯。第一,工程从第一天就放进Git仓库,每次改CMakeLists、URDF或者world文件都提交一次,出问题能快速回滚。第二,launch文件里尽量用Python形式,比XML灵活,比如我可以根据参数动态决定要不要加载Actor。第三,不要随便降级系统CMake,一定要用自己编译的CMake时放到用户目录,避免污染系统。第四,Gazebo的世界文件和模型文件别用中文名,ROS2包名和可执行文件名也全用英文小写加下划线,能避开很多编码和路径问题。

这个仓库动态环境工程的实际意义,不在于它有多炫酷,而在于它给了你一个可以反复折腾的测试场。我第一次跑通两颗RGBD数据收发的时候,发现一个深度话题的QoS没对上,折腾了一下午才查出来。后来把这类问题都记到排查清单里,再遇到就顺手解掉。做仿真就是这样,越熟悉这些细枝末节的坑,你后面真正调试机器人算法的时候就越轻松。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

Logo

聚焦RDK与具身智能,汇集机器人开发教程、开源案例和技术交流

更多推荐