ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

PX4 Gazebo仿真:给Iris无人机挂载D435i深度相机完整指南

PX4 Gazebo仿真:给Iris无人机挂载D435i深度相机完整指南 1. 为什么偏偏是D435i关于这颗相机的选型思路很多刚接触PX4 Gazebo仿真的朋友上来就问怎么给Iris挂个相机但很少有人问为什么要挂D435i。这个问题其实比操作步骤更重要因为你的选择直接决定了后续能做哪些实验、用哪个ROS版本、跑什么感知算法。先说结论Intel RealSense D435i是当前视觉SLAM、目标检测、深度估计这类实验里性价比最高、资料最全的入门级深度相机在仿真环境里挂载它最大的价值不是好看而是传感器数据流完全对齐真实硬件。D435i本质上是一颗双目红外结构光相机它输出三种数据流左/右红外图、RGB彩色图、对齐后的深度图。Gazebo里挂载它意味着你可以在完全虚拟的世界里得到接近真实的深度数据用来测试PX4的避障逻辑、SLAM建图、或者是基于深度图的物体识别。而Iris无人机作为PX4官方钦定的测试机体动力学模型稳定、机架参数公开、可用的固件版本覆盖广两者结合就是一套标准视觉避障开发平台。我在实际配置中踩过的坑主要集中在三个地方模型坐标系偏移、D435i的ROS插件参数、以及Gazebo和ROS之间的TF树关系。这三个问题网上说法很多但大多只给了结论没给排查思路这次我把完整的配置流程和排错链路一起写出来保证你照着做完能跑通而且出了问题知道去哪查。适合看这篇教程的人有三类刚搭好PX4开发环境想往机体上加传感器的初学者已经在跑仿真但发现相机挂在模型上不生效的老手以及准备把自己的算法从仿真迁移到真机、想提前验证传感器数据格式的研究者。2. 开工前的环境准备哪套PX4和Gazebo能省掉一半的坑在动任何模型文件之前先把环境捋清楚。我见过太多人卡在编译阶段就放弃了其实大部分都是版本不对齐导致的。2.1 我使用的环境搭配清单组件版本说明Ubuntu20.04 / 22.0420.04更稳22.04也能跑ROSNoetic20.04/ Foxy或Humble22.04取决于PX4固件版本PX4-Autopilotv1.13.3或v1.14.3两个版本我都试过均可用GazeboGazebo 11随PX4工具链自动安装不要手动乱装其他版本realsense-ros2.3.2及以上提供D435i的URDF和plugin核心建议如果你是新装环境直接选Ubuntu 20.04 ROS Noetic PX4 v1.14.3。这条组合是目前社区里讨论最多、踩坑记录最全的路线遇到问题随便搜都能找到解决方案。Ubuntu 22.04 Gazebo Classic11也能跑但ROS 2版本下PX4的MAVROS通信配置会多几步不适合新手。PX4的官方工具链脚本会自动安装Gazebo和MAVROS相关依赖git clone https://github.com/PX4/PX4-Autopilot.git --recursive cd PX4-Autopilot make px4_sitl gazebo-classic这一条命令如果顺利完成说明Gazebo 11已经就位。验证方法gazebo --version如果输出的是Gazebo multi-robot simulator version 11.x.x就对了。2.2 环境里最容易忽略的一个依赖realsense-ros很多人忽略了realsense-ros这个驱动包。在Gazebo仿真中D435i并不是靠Gazebo自带的传感器模型变出来的而是通过ROS的URDF模型文件加载到无人机机体上的这个URDF里使用的相机插件来自realsense-ros包。安装方式sudo apt install ros-$ROS_DISTRO-realsense2-camera或者从源码编译mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone https://github.com/IntelRealSense/realsense-ros.git cd ~/catkin_ws catkin_make source ~/catkin_ws/devel/setup.bash提示如果你用Ubuntu 22.04的ROS 2环境需要编译的是realsense-ros的ROS 2分支。我给新手一个简化建议暂时用ROS 1一条路走到黑把算法流程跑通之后再考虑迁移ROS 2。2.3 验证环境的最终手段先跑一架裸Iris在挂载相机之前先确认裸Iris能飞起来。这一步相当于仪器校准以后所有问题都要回到这个基准来判断。cd ~/PX4-Autopilot make px4_sitl gazebo-classic看到Gazebo窗口里出现一架Iris四旋翼终端里出现[INFO] [px4] Startup script returned successfully之类的日志就说明环境OK。这一步非常重要因为后续相机加载失败时你需要能区分是PX4的问题还是模型文件的问题。如果裸机都起不来先去解决PX4的编译问题不要急着加相机。3. 核心操作在Iris模型上挂载D435i的完整配置流程环境确认无误后下面进入正题。整个过程分三块准备模型插件、修改机体模型文件、启动验证。我会把文件路径和关键代码都列出来。3.1 把D435i模型文件放进Iris的sdf目录PX4中Iris的机体模型文件在PX4-Autopilot/Tools/sitl_gazebo/models/iris/目录下核心文件是iris.sdf。我们的任务就是往这个SDF文件里加一个相机传感器的描述。Intel官方其实提供了一个专门用于Gazebo仿真的D435i SDF模型文件文件名通常叫d435i.sdf放在Tools/sitl_gazebo/models/下。但这个文件不一定在你clone的PX4版本里自带需要手动放入。如果你用的是我推荐的v1.14.3先检查ls ~/PX4-Autopilot/Tools/sitl_gazebo/models/ | grep d435正常情况下应该能看到d435i目录。如果没有就去realsense-ros的GitHub仓库里找或者直接创建mkdir -p ~/PX4-Autopilot/Tools/sitl_gazebo/models/d435i然后创建一个d435i.sdf文件。这个文件的核心结构包含两个部分实体的视觉/碰撞属性和传感器插件定义。下面是一个最小可用的D435i SDF模型文件我裁剪掉了大部分重复参数保留了关键项?xml version1.0 ? sdf version1.6 model named435i link namelink inertial mass0.072/mass inertia ixx0.0001/ixx iyy0.0001/iyy izz0.0001/izz /inertia /inertial visual namevisual geometry box size0.09 0.025 0.025/size /box /geometry material ambient0.4 0.4 0.4/ambient diffuse0.4 0.4 0.4/diffuse /material /visual collision namecollision geometry box size0.09 0.025 0.025/size /box /geometry /collision sensor namecamera_depth typedepth always_on1/always_on update_rate30/update_rate camera horizontal_fov1.5708/horizontal_fov image width640/width height480/height formatR8G8B8/format /image clip near0.1/near far10/far /clip /camera plugin namecamera_plugin filenamelibgazebo_ros_camera.so ros namespaced435i/namespace remapping~/camera_link/remapping /ros camera_namecamera/camera_name image_topic_nameimage_raw/image_topic_name camera_info_topic_namecamera_info/camera_info_topic_name distortion_topic_namedistortion/distortion_topic_name /plugin /sensor sensor namecamera_rgb typecamera always_on1/always_on update_rate30/update_rate camera horizontal_fov1.5708/horizontal_fov image width640/width height480/height formatR8G8B8/format /image clip near0.1/near far10/far /clip /camera plugin namergb_camera_plugin filenamelibgazebo_ros_camera.so ros namespaced435i/namespace remapping~/camera_link/remapping /ros camera_namergb/camera_name image_topic_nameimage_raw/image_topic_name camera_info_topic_namecamera_info/camera_info_topic_name /plugin /sensor /link /model /sdf注意上面的SDF文件是简化演示版本实际realsense-ros里提供的d435i.sdf会更复杂包含imu传感器、多个光学坐标系。但在Gazebo仿真里我们真正关心的是深度图和RGB图是否能发布出来所以简化版完全够用。你甚至可以在此基础上自己加imu插件。3.2 修改Iris的SDF文件把d435i作为子模型include进来接下来修改iris.sdf让四旋翼模型挂载这个相机。用文本编辑器打开gedit ~/PX4-Autopilot/Tools/sitl_gazebo/models/iris/iris.sdf在model nameiris标签内部、link namebase_link的/link之后加入include块include urimodel://d435i/uri pose0.05 0 0.05 0 0 0/pose /include这里的pose是相机在Iris机体坐标系下的位置前方0.05米、上方0.05米无旋转。D435i朝前挂默认x轴方向是相机朝向。如果你希望相机稍微向下倾斜比如后续做地面检测可以改成pose0.05 0 0.05 0 0.4363 0/pose0.4363弧度等于25度下俯角。一个很容易踩的坑在这里include块的位置放错会导致Gazebo加载模型失败。SDF的include应该放在model根元素内不能放在world层。我见过有人把include放在world下结果相机和机体成了两个独立模型飞起来相机原地不动TF树完全错乱。3.3 编译并确认D435i插件被加载修改完SDF后重新编译启动cd ~/PX4-Autopilot make px4_sitl gazebo-classic启动后注意观察终端输出。正常情况下会出现类似这样的日志[INFO] [gazebo] Loading model d435i [INFO] [gazebo] Spawning model d435i named d435i_0 [INFO] [gazebo] Camera plugin loaded (libgazebo_ros_camera.so)如果日志里没有任何d435i相关内容有几种可能include路径写错、模型文件没放对目录、或者模型名和文件名不一致。技巧你可以用gz model --info -m iris来列出Gazebo中加载的模型信息确认d435i是否作为子模型挂在了iris下。这一步很实用能在不重启仿真的情况下检查模型树。4. 验证仿真是否真的看到了深度图话题、TF和数据流一条龙模型加载完成只是第一步。真正决定你能不能做视觉实验的是ROS话题里有没有数据、数据格式对不对、TF树是否完整。这一节讲讲验证链路。4.1 查看话题列表确认相机数据在发布另开一个终端在ROS环境下查看话题source ~/catkin_ws/devel/setup.bash rostopic list如果一切正常应该能看到以下话题/d435i/camera/image_raw /d435i/camera/camera_info /d435i/camera_depth/image_raw /d435i/camera_depth/depth_image这里稍微解释一下如果你用的是我上面提到的简化SDF话题是自定义的如果你用了realsense-ros官方提供的完整d435i模型话题名会是/camera/color/image_raw和/camera/depth/image_rect_raw因为它们遵循的是realsense-ros的标准命名规则。我实测下来在PX4 Gazebo仿真里使用自定义SDF更可控因为你可以根据自己的YOLO检测节点、SLAM算法来定制话题名而不用去适配官方命名。4.2 用rqt_image_view可视化深度图查看图像话题最方便的工具是rqt_image_viewsudo apt install ros-$ROS_DISTRO-rqt-image-view rosrun rqt_image_view rqt_image_view在界面左上角的话题下拉菜单里选择/d435i/camera_depth/image_raw你应该能看到一张与场景中障碍物对应的灰度深度图。距离越近的物体越亮越远越暗。如果你看到的是一片纯黑或者纯白说明深度数据处理有问题。常见原因相机传感器的far距离设置过大近距离物体占比太小整体偏暗话题选择错误选成了RGB图而不是深度图相机朝向没有对准场景中的物体视野里一片天空我建议你在Gazebo场景里放几个大小不一的方块作为参照物这样深度图的变化更直观gz model --spawn-file/path/to/box.sdf --model-nametest_box -x 2 -y 1 -z 04.3 TF树检查相机坐标系有没有挂上机体坐标系这一项容易被忽视但对后续做SLAM或视觉定位非常关键。用以下命令看TF树rosrun tf view_frames或者直接看坐标系列表rostopic echo /tf | grep frame_id一个健康的TF树应该能看到类似frame_id: d435i_link parent_frame_id: base_link如果在TF树里找不到相机坐标系或者相机坐标系的原点在很远的地方几乎可以确定是pose设置出了问题回到iris.sdf检查include里的坐标。经验之谈TF树对于单目相机实验影响不大但一旦你做的是RGB-D SLAM比如ORB-SLAM3的RGB-D模式相机和机体之间的外参标定是直接靠TF拿的这一步不对后续的算法全废。所以养成习惯加任何外设都先看一眼TF。5. 完整排错链路我在这套配置里遇到过的6个坑及排查过程写这一节的时候我把自己从零开始配置这个环境时踩过的坑按现象→排查→解决的逻辑整理了一遍。这些坑不是我凭空想象的每一件都是我或者身边朋友真实遇到过的。5.1 坑一Gazebo启动后相机模型是红色的、且没有图像话题现象Iris正常显示但相机是一个红色半透明框rostopic list里看不到任何相机话题。排查过程我用gz model --info发现d435i的link在Gazebo里加载失败原因是SDF文件里的inertial标签里缺少ixx/iyy/izz。Gazebo在加载模型时需要完整的惯性矩阵如果缺失或值非法它不会报错而是直接不加载传感器。解决方法检查SDF文件的inertial部分补全惯性张量。上面我给的简化版已经包含了如果你是从网上抄的旧代码特别注意这一点。5.2 坑二深度图一直在闪动或变成马赛克现象深度图话题有数据但图像不稳定界面一直闪烁像信号干扰。排查过程这个问题我一开始以为是显卡驱动问题折腾半天发现和Gazebo无关。看输出的位图数据发现depth的格式设置成了R8G8B8但深度数据本质上是单通道的这个格式把它当三通道解析就会错乱。解决方法深度相机的sensor类型设置为typedepth时format应设为L8或者R8G8B8配合合理的plugin解析。最简单稳妥的方案是直接用Gazebo的libgazebo_ros_camera.so插件默认处理不要自定义深度格式。5.3 坑三相机抖动画面有高频细碎噪声现象相机画面能显示但无人机在悬停时机身有微小高频抖动导致图像像果冻一样晃动。排查过程开始时我以为是PX4的PID参数没调好后来逐个检查才发现问题出在inertial质量设置太小。D435i真实质量约72克这是只算相机本体的。如果为了省事写成了0.01整个机体的转动惯量会变得极不真实PX4的姿态控制器就会产生细微的极限环振荡。解决方法把这个质量改成真实值同时把D435i挂载位置尽量靠近机体重心减少转动惯量变化。这一点也和真机一致真机挂点远离重心会导致飞行品质下降。5.4 坑四编译报错找不到libgazebo_ros_camera.so现象模型能加载但Gazebo启动时日志显示plugin加载失败Failed to load plugin libgazebo_ros_camera.so : ... cannot open shared object file。排查过程这是典型的环境变量问题。PX4的SITL工具链和你自己catkin_ws的库路径冲突。如果你先source了PX4的setup脚本可能会把GAZEBO_PLUGIN_PATH指向PX4自带的build目录但那个目录里的gazebo插件只包含了PX4自己的不一定包含gazebo_ros的plugin。解决方法export GAZEBO_PLUGIN_PATH$GAZEBO_PLUGIN_PATH:/opt/ros/noetic/lib把/opt/ros/noetic/lib加进去确保能搜到ROS的gazebo插件库。如果你用ROS 2路径改为/opt/ros/$ROS_DISTRO/lib。5.5 坑五相机挂载后Iris起飞即翻转现象相机模型加进了SDF界面一切正常但PX4一解锁起飞飞机直接侧翻。排查过程这个问题非常隐秘。检查SDF才发现inertial的三轴惯量值严重偏离真实值——我是从别的模型文件复制出来的没有改。D435i的惯量虽然小但挂载位置在机体前方0.05米处改变了质心位置。如果相机惯量数值不写对PX4的动力学模型计算出的机体质心和转动惯量就会出现偏差。解决方法把SDF里的惯量改成真实估算值。我当时用SolidWorks的估算值ixx0.000031/ixx iyy0.000043/iyy izz0.000057/izz改完后恢复正常。这个坑很少人提但危害极大尤其在后期模拟货物抓取或投放时外挂物的惯量会影响整个动力学解算。5.6 坑六改了SDF但Gazebo里没变化现象明明改了iris.sdf重新启动后相机还是没有出现或者还是旧参数。排查过程PX4的SITL不直接读取Tools/sitl_gazebo/models/iris/iris.sdf文件本身。它会把模型文件复制到build/px4_sitl_default/tmp_models/iris/目录下编译缓存。所以如果你修改的是源目录但启动时用的是build缓存修改就不会生效。解决方法cd ~/PX4-Autopilot make clean make px4_sitl gazebo-classic强制重新拷贝模型文件。或者手动删除build里的模型缓存目录再编译。这个坑我自己反复踩了三次后来养成了习惯凡是改了任何模型文件至少删掉build下对应的tmp_models目录。6. 进阶操作把D435i模型加入人群检测实战场景前面所有配置跑通之后你可以开始做一些真正有价值的实验。这里以人群检测为例讲一下如何把这套仿真传感器接入实际算法闭环。6.1 在Gazebo场景中放置多个行人模型Gazebo的模型库里有人形模型或者你可以在网上找一些简单的3D人形模型转成SDF。放入场景gz model --spawn-file/usr/share/gazebo-11/models/person/person.sdf --model-nameperson1 -x 5 -y 2 -z 0person模型自带行走动画在Gazebo 11自带的模型库里就有。你可以放三到五个人形模拟地面上的人群。6.2 编写一个简单的YOLO检测节点在Simulink或ROS节点里订阅深度话题转成OpenCV的Mat格式送入YOLO推理。我这里给一个极简的Python节点框架#!/usr/bin/env python3 import cv2 import rospy import numpy as np from sensor_msgs.msg import Image from cv_bridge import CvBridge class DepthDetector: def __init__(self): rospy.init_node(depth_detector, anonymousTrue) self.bridge CvBridge() self.depth_sub rospy.Subscriber( /d435i/camera_depth/image_raw, Image, self.depth_callback ) self.rgb_sub rospy.Subscriber( /d435i/camera/image_raw, Image, self.rgb_callback ) self.depth_image None self.rgb_image None def depth_callback(self, msg): self.depth_image self.bridge.imgmsg_to_cv2(msg, desired_encodingpassthrough) def rgb_callback(self, msg): self.rgb_image self.bridge.imgmsg_to_cv2(msg, desired_encodingbgr8) if self.depth_image is not None: h, w self.depth_image.shape depth_colored cv2.normalize(self.depth_image, None, 0, 255, cv2.NORM_MINMAX) depth_colored depth_colored.astype(np.uint8) # 这里接入你的YOLO检测模型 # results model(self.rgb_image) cv2.imshow(RGB Depth Aligned, np.hstack([self.rgb_image, cv2.cvtColor(depth_colored, cv2.COLOR_GRAY2BGR)])) cv2.waitKey(1) if __name__ __main__: d DepthDetector() rospy.spin()别忘了在CMakeLists或pip install里装好cv_bridge依赖——如果直接跑from cv_bridge import CvBridge在ROS 1环境通常没问题。6.3 用MAVROS控制Iris飞到人群上空这就用到了PX4的offboard控制。下面是一个用MAVROS发送位置设定点的最小示例roslaunch mavros px4.launch fcu_url:udp://:14540127.0.0.1:14557然后在另一个终端里#!/usr/bin/env python3 import rospy from geometry_msgs.msg import PoseStamped from mavros_msgs.msg import State from mavros_msgs.srv import CommandBool, SetMode import time rospy.init_node(offboard_node) state State() def state_cb(msg): global state state msg rospy.Subscriber(/mavros/state, State, state_cb) pose_pub rospy.Publisher(/mavros/setpoint_position/local, PoseStamped, queue_size10) arming rospy.ServiceProxy(/mavros/cmd/arming, CommandBool) set_mode rospy.ServiceProxy(/mavros/set_mode, SetMode) for i in range(100): pose PoseStamped() pose.pose.position.x 5 pose.pose.position.y 2 pose.pose.position.z 3 pose_pub.publish(pose) rate rospy.Rate(20) rate.sleep() if not state.armed: arming(True) set_mode(custom_modeOFFBOARD)起飞后飞机飞到(5, 2, 3)这个点上空深度相机朝下对准地面人群你的检测节点就能实时看到深度信息。提示OFFBOARD模式是PX4仿真的灵魂。务必搞懂它的逻辑——持续以20Hz以上频率发送位置设定点否则PX4会在半秒内退回自稳模式。这是很多初学者容易困惑的点。7. 这组配置还能怎么扩展从仿真到真机的数据通路一致性配置完这套仿真环境很多人的疑问是仿真里跑的东东迁到真机能直接用吗答案是代码可以复用但话题名和参数要微调而D435i恰好是这两者差异最小的传感器。真实D435i通过realsense-ros驱动发布的话题是/camera/color/image_raw、/camera/depth/image_rect_raw、/camera/imu。如果你在仿真里把话题命名成跟它完全一致那么你的视觉SLAM、目标检测节点几乎可以无缝切换。这是我强烈推荐在仿真里不要随意改话题名的原因——保持和真机一致省得后期算法层到处改。另外仿真里的D435i如果带了imu插件它发布的IMU数据也可以用于PX4的视觉惯性导航VINS实验。PX4本身支持外部视觉姿态估计通过MAVROS的/mavros/vision_pose/pose话题可以把D435i仿真数据注入姿态估计器。我个人在实际操作中的体会是这套配置真正难的不是加相机而是把相机数据、机体动力学、飞控状态三者打通。很多人做完前四步看到深度图就停下来了但其实后面的数据闭环才是最有价值的部分。建议你按这套流程跑通之后试着做一个小项目——比如深度相机避障或者目标跟随把整个链路串一遍收获会大得多。最后再分享一个经验如果你未来要频繁改相机位置、调内参建议把d435i的SDF参数单独拆成一个可以被多个机体复用的include文件不要每次复制到iris的SDF里。这样后期维护模型库会轻松很多也方便团队其他人直接使用统一标准。
返回列表