PX4 + ROS2 Humble + Gazebo 视觉仿真环境搭建与排错指南

为了防止以后换电脑或者重装系统再踩一遍这些天坑,特此记录核心步骤和 Debug 方案。

一、 核心组件与命令速查

  • 操作系统: Ubuntu 22.04
  • ROS 版本: ROS 2 Humble
  • 飞控版本: PX4-Autopilot (支持 Gazebo Classic 版)

1. 启动仓库环境下的深度相机无人机:

cd ~/px4/PX4-Autopilot
PX4_SITL_WORLD=warehouse make px4_sitl gazebo-classic_iris_depth_camera

2. 启动 DDS 通信代理 (必须):

MicroXRCEAgent udp4 -p 8888

二、 史诗级天坑排雷记录

坑 1:Gazebo 中有无人机,但 ROS 2 找不到图像话题

  • 原因: SDF 模型文件里用的是 ROS 1 的老插件,或者启动 Gazebo 的终端没有 source ROS 2 环境变量。
  • 解决:
  1. 找到模型文件:~/px4/PX4-Autopilot/Tools/simulation/gazebo-classic/sitl_gazebo-classic/models/depth_camera/depth_camera.sdf
  2. <plugin> 部分替换为 ROS 2 的 libgazebo_ros_camera.so
<plugin name="gazebo_ros_camera" filename="libgazebo_ros_camera.so">
  <ros><namespace>camera</namespace></ros>
  <camera_name>camera</camera_name>
  <frame_name>camera_link</frame_name>
</plugin>

  1. 注意重名陷阱: 如果 namespace 设置了 camera,camera_name 也是 camera,最终输出的话题会叠加成 /camera/camera/image_raw

坑 2:编译 C++ 视觉节点时报错 已杀死 signal terminated program cc1plus

  • 原因: 虚拟机内存不足(OOM),colcon build 多线程编译 OpenCV 时把内存撑爆了。
  • 解决: 编译前先关掉 Gazebo 等吃内存的软件,并使用严格单线程编译命令:
export MAKEFLAGS="-j1"
export CMAKE_BUILD_PARALLEL_LEVEL=1
colcon build --packages-select cv_test_pkg

坑 3:rqt 里能看到画面,但自己写的 C++ 节点一直卡在“正在等待图像”

  • 原因: ROS 2 的 QoS (服务质量) 不匹配。Gazebo 相机发图是“尽力而为 (Best Effort)”,而普通订阅节点默认是“可靠 (Reliable)”。两者无法建立连接。
  • 解决: 在 C++ 源码 create_subscription 时,必须将队列长度参数替换为 rclcpp::SensorDataQoS()

三、 最终可运行的 ORB 节点 C++ 源码

文件路径参考:~/px4_ros_ws/src/cv_test_pkg/src/cv_test_pkg_node.cpp

#include "rclcpp/rclcpp.hpp"
#include "sensor_msgs/msg/image.hpp"
#include "cv_bridge/cv_bridge.h"
#include <opencv2/opencv.hpp>

class OrbNode : public rclcpp::Node {
public:
    OrbNode() : Node("orb_feature_node") {
        // 关键点:使用 SensorDataQoS 适配 Gazebo,注意确认话题全名是否带两个 camera
        subscription_ = this->create_subscription<sensor_msgs::msg::Image>(
            "/camera/camera/image_raw", rclcpp::SensorDataQoS(), 
            std::bind(&OrbNode::image_callback, this, std::placeholders::_1));
        
        orb_detector_ = cv::ORB::create(500);
        RCLCPP_INFO(this->get_logger(), "ORB 节点已启动,正在监听...");
    }

private:
    void image_callback(const sensor_msgs::msg::Image::SharedPtr msg) const {
        try {
            cv_bridge::CvImagePtr cv_ptr = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::BGR8);
            std::vector<cv::KeyPoint> keypoints;
            cv::Mat descriptors;
            orb_detector_->detectAndCompute(cv_ptr->image, cv::noArray(), keypoints, descriptors);
            
            cv::Mat image_with_keypoints;
            cv::drawKeypoints(cv_ptr->image, keypoints, image_with_keypoints, 
                              cv::Scalar(0, 255, 0), cv::DrawMatchesFlags::DEFAULT);
            
            cv::imshow("ORB Features", image_with_keypoints);
            cv::waitKey(1); 
        } catch (cv_bridge::Exception& e) {
            RCLCPP_ERROR(this->get_logger(), "cv_bridge 异常: %s", e.what());
        }
    }

    rclcpp::Subscription<sensor_msgs::msg::Image>::SharedPtr subscription_;
    cv::Ptr<cv::ORB> orb_detector_;
};

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

请添加图片描述

请添加图片描述
请添加图片描述
请添加图片描述

请添加图片描述
请添加图片描述

Logo

立足具身智能前沿赛道,致力于搭建全球化、开源化、全栈式技术交流与实践共创平台。

更多推荐