PX4 + ROS2 Humble + Gazebo 视觉仿真环境搭建与排错指南
本文记录了在Ubuntu 22.04下搭建PX4+ROS2 Humble+Gazebo视觉仿真环境的关键步骤和常见问题解决方案。主要内容包括:1) 核心组件版本和启动命令;2) 三个典型问题的排错方法(ROS2找不到图像话题、编译内存不足、QoS不匹配);3) 最终可运行的ORB特征检测节点C++源码。重点解决了Gazebo与ROS2的通信配置、虚拟机内存优化和图像话题订阅等关键问题,为无人机视觉
·
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 的终端没有
sourceROS 2 环境变量。 - 解决:
- 找到模型文件:
~/px4/PX4-Autopilot/Tools/simulation/gazebo-classic/sitl_gazebo-classic/models/depth_camera/depth_camera.sdf - 将
<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>
- 注意重名陷阱: 如果 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;
}






更多推荐

所有评论(0)