简介这份资源面向无人机飞控开发、机器人方向的学生与研究人员提供一套基于PX4与ROS2的完整仿真环境用于在实飞前验证控制算法、开展毕业设计与课程实践。压缩包共154个文件约46.62MB以99个png贴图、11个sdf场景模型、9个config参数配置、6个py脚本及obj、mtl、dae等三维模型资源为主另含Dockerfile、Readme说明与build、run、entrypoint等shell脚本以及launch_files启动配置覆盖环境构建、场景加载与节点启动全流程。资源通过话题、服务、动作等机制打通ROS2与PX4的通信可实现飞行模式切换、姿态与位置控制、导航控制等功能的仿真测试并借助容器化保证环境一致复现。目前已有132人学习适合希望低成本搭建可控实验平台、理解自主飞行机制的开发者参考。1. 从零搭一套 PX4 ROS2 无人机仿真这套环境到底解决什么问题很多人第一次接触无人机开发卡住的地方不是算法而是环境。飞控固件编译不过、ROS2 话题对不上、Gazebo 里飞机一解锁就翻、MAVROS 连不上……这些琐碎问题消耗的精力远超写控制律本身。基于 PX4 和 ROS2 的无人机仿真环境本质是把飞控、通信中间件、物理引擎和可视化工具打包成一条可复现的链路让你在没有真机的情况下完成从起飞到路径跟踪的全流程验证。它适合三类人想入门无人机软件栈的学生、需要快速验证算法的研究者、以及做硬件在环之前想先把软件跑通的工程师。这套环境的核心价值在于——把“炸机成本”换成“重启成本”调参、改代码、重跑几分钟一轮。下面我从选型、安装、联调、避坑到进阶把这条链路拆开讲清楚。2. 环境选型与依赖关系为什么是 PX4 ROS2 Gazebo 这个组合2.1 三个组件各自负责什么PX4 是飞控固件跑在仿真里时它扮演“虚拟飞控”的角色负责姿态控制、位置估计、混控输出。ROS2 是通信框架负责把传感器数据、控制指令、状态信息以话题和服务的形式暴露出来。Gazebo 是物理引擎提供刚体动力学、传感器噪声模型和三维场景。三者之间的关系是Gazebo 算出飞机当前状态 → PX4 读取并解算 → 通过 MAVLink 发给 ROS2 → ROS2 里的算法处理后把指令发回 PX4 → PX4 输出电机转速 → Gazebo 更新状态。这个闭环里任何一环版本不匹配都会出现“能起飞但飘”“话题有数据但不动”这类玄学问题。常见做法是锁定 Ubuntu 22.04 ROS2 Humble PX4 v1.14 以上 Gazebo Classic 11。不要混用 Gazebo SimIgnition和 Gazebo Classic两者的插件接口不同PX4 的gz_bridge只认其中一种。我一般会先确认系统版本再按官方文档顺序装 ROS2、装 Gazebo、最后编译 PX4顺序反了容易出依赖冲突。2.2 版本对应关系与安装顺序组件推荐版本安装方式备注Ubuntu22.04 LTS系统镜像不要用 24.04ROS2 Humble 官方支持到 22.04ROS2Humbleapt 源装桌面版包含 rviz2 和 demo 节点GazeboClassic 11apt与 PX4 的sitl_gazebo插件匹配PX4v1.14 或 v1.15git clone 子模块编译前先make distcleanMAVROSros-humble-mavrosapt需要额外装 geographiclib 数据集安装顺序建议系统更新 → 装 ROS2 → 装 Gazebo → 装 MAVROS → 编译 PX4。每一步做完都跑一个最小验证比如 ROS2 装完跑ros2 run demo_nodes_cpp talkerGazebo 装完跑gz sim看能不能出界面PX4 编译完跑make px4_sitl gazebo看能不能出飞机。不要等全部装完再一起调那样出问题很难定位。2.3 工作空间与包结构规划ROS2 的工作空间用 colcon 管理建议单独建一个px4_ros2_ws里面放你自己的功能包不要和 PX4 源码混在一起。PX4 源码单独放PX4-Autopilot目录编译产物在build/下。MAVROS 通过 apt 安装不需要放进工作空间。这样分层的好处是PX4 升级不影响你的算法包ROS2 重装也不用重新编译飞控。# 创建工作空间 mkdir -p ~/px4_ros2_ws/src cd ~/px4_ros2_ws colcon build source install/setup.bash # 克隆 PX4 源码单独目录 cd ~ git clone https://github.com/PX4/PX4-Autopilot.git --recursive cd PX4-Autopilot make px4_sitl gazebo上面命令的逻辑先建 ROS2 工作空间并编译空空间确认 colcon 可用再克隆 PX4 并递归拉子模块最后编译 SITL Gazebo 目标。参数说明--recursive必须加否则子模块缺失会导致编译报错make px4_sitl gazebo里的gazebo是机型目标换成gazebo_iris可以指定具体机型。如果编译卡在子模块下载检查网络或改用make px4_sitl gazebo前先git submodule update --init --recursive。3. 从编译到起飞PX4 SITL 与 ROS2 联调的最小闭环3.1 启动仿真并验证 MAVLink 链路PX4 编译成功后启动 SITL 仿真会同时拉起 Gazebo 和飞控进程。默认的 MAVLink 端口是 14550UDPMAVROS 通过这个端口连接。启动命令有两种一种是在 PX4 目录下直接make px4_sitl gazebo另一种是用ros2 launch拉起 MAVROS 和 PX4。我一般先手动启动 PX4确认 Gazebo 里飞机能解锁再启动 MAVROS这样出问题容易判断是哪一层。# 终端 1启动 PX4 SITL Gazebo cd ~/PX4-Autopilot make px4_sitl gazebo # 终端 2启动 MAVROS 连接 PX4 ros2 launch mavros px4.launch fcu_url:udp://:14540127.0.0.1:14557逻辑说明PX4 启动后会监听 14540 端口等待 MAVROS 连接同时把 Gazebo 的传感器数据通过gz_bridge送入飞控。MAVROS 的fcu_url参数格式是udp://绑定地址目标地址:目标端口这里绑定本地 14540目标指向 PX4 的 14557。参数怎么改如果 PX4 启动时提示端口占用改fcu_url里的端口如果 MAVROS 连不上先用netstat -anu | grep 14540确认 PX4 在监听。3.2 用 ROS2 话题读取飞控状态MAVROS 连上后ROS2 里会出现一批话题比如/mavros/state、/mavros/local_position/pose、/mavros/imu/data。用ros2 topic list能看到完整列表。验证链路是否通最直接的方法是看/mavros/state里的connected字段是否为true以及armed是否随解锁指令变化。# 查看话题列表 ros2 topic list | grep mavros # 读取飞控状态 ros2 topic echo /mavros/state # 读取本地位置 ros2 topic echo /mavros/local_position/pose --once逻辑说明/mavros/state是 MAVROS 从飞控心跳包里解析出来的状态包含连接状态、解锁状态、飞行模式。/mavros/local_position/pose是飞控估计的本地位置仿真里由 Gazebo 的真值加噪声生成。参数说明--once表示只打印一条消息就退出适合脚本里做检查。如果connected一直是false检查fcu_url和防火墙如果armed不变化检查解锁指令是否发到了正确的话题。3.3 发送起飞与位置指令解锁和起飞通过 MAVROS 的服务和话题完成。常见做法是先用/mavros/cmd/arming服务解锁再用/mavros/set_mode切到OFFBOARD模式最后往/mavros/setpoint_position/local发位置设定点。注意 OFFBOARD 模式要求设定点以不低于 2Hz 的频率持续发送否则飞控会自动切回其他模式。import rclpy from rclpy.node import Node from geometry_msgs.msg import PoseStamped from mavros_msgs.srv import CommandBool, SetMode class OffboardControl(Node): def __init__(self): super().__init__(offboard_control) self.pub self.create_publisher(PoseStamped, /mavros/setpoint_position/local, 10) self.arm_client self.create_client(CommandBool, /mavros/cmd/arming) self.mode_client self.create_client(SetMode, /mavros/set_mode) self.timer self.create_timer(0.1, self.send_setpoint) # 10Hz def send_setpoint(self): msg PoseStamped() msg.pose.position.x 0.0 msg.pose.position.y 0.0 msg.pose.position.z 2.0 # 目标高度 2 米 self.pub.publish(msg) def arm_and_offboard(self): arm_req CommandBool.Request() arm_req.value True self.arm_client.call_async(arm_req) mode_req SetMode.Request() mode_req.custom_mode OFFBOARD self.mode_client.call_async(mode_req) def main(): rclpy.init() node OffboardControl() node.arm_and_offboard() rclpy.spin(node) rclpy.shutdown() if __name__ __main__: main()逻辑说明节点以 10Hz 发布位置设定点满足 OFFBOARD 模式的最低频率要求。arm_and_offboard先发解锁请求再切模式。参数说明msg.pose.position.z 2.0是目标高度单位米create_timer(0.1, ...)里的 0.1 是周期秒数改成 0.05 就是 20Hz。注意解锁和切模式之间最好留 1 到 2 秒否则飞控可能拒绝切换。如果飞机不起飞先看/mavros/state的mode是否变成OFFBOARD再看设定点话题有没有数据。4. 避坑与排查仿真环境里最容易翻车的五个地方4.1 现象Gazebo 里飞机能解锁但原地打转原因PX4 的磁力计模型被 Gazebo 的环境磁场干扰或者gz_bridge没有正确转发 IMU 数据。仿真里磁力计噪声默认偏大导致偏航估计漂移。解决在 PX4 参数里把EKF2_MAG_TYPE设为1关闭磁力计融合或者用make px4_sitl gazebo时加PX4_SIM_MODELiris指定机型不同机型的传感器配置不同。我一般先在 QGroundControl 里看偏航角是否乱跳再决定要不要关磁力计。4.2 现象MAVROS 显示 connected 但话题没有数据原因MAVROS 的plugin_allowlist没有加载对应插件或者 PX4 端的 MAVLink 流没有开启。解决检查px4.launch里的plugin_allowlist参数确保local_position、imu、setpoint_position都在列表里。另外在 PX4 控制台用mavlink status看流速率如果某个流是 0用mavlink stream -u 14540 -s LOCAL_POSITION_NED -r 10手动开。4.3 现象OFFBOARD 模式切不过去原因设定点发布频率不够或者解锁和切模式之间没有等待。PX4 要求 OFFBOARD 切换前必须已经收到一段时间的设定点流。解决先以 10Hz 发 2 秒设定点再发解锁请求等 1 秒后再切模式。代码里可以把arm_and_offboard拆成三步用定时器控制顺序。如果还是不行检查/mavros/state里的mode字段看飞控是否报了COM_RC_IN_MODE相关错误。4.4 现象编译 PX4 时子模块报错原因git clone时没有加--recursive或者子模块更新到一半断网。解决进入 PX4 目录执行git submodule update --init --recursive如果某个子模块卡住删掉.git/modules下对应目录重试。国内网络环境下可以配置 git 代理或者用镜像源但不要混用多个源否则版本对不上。4.5 现象ROS2 节点收不到 Gazebo 的传感器数据原因Gazebo 的传感器插件没有在 SDF 文件里启用或者 ROS2 的gz_bridge配置里话题名不匹配。解决检查PX4-Autopilot/Tools/sitl_gazebo/models/iris/iris.sdf里是否有libgazebo_ros_camera.so之类的插件确认rosnamespace和 ROS2 节点订阅的话题一致。如果用的是 Gazebo Classic桥接是通过gazebo_ros包做的不是ros_gz_bridge两者配置方式不同。5. 进阶技巧用 ROS2 记录数据并做硬件在环前的验证仿真跑通之后下一步通常是记录飞行数据做分析或者把算法从仿真迁移到真机。ROS2 自带的ros2 bag record可以录下所有 MAVROS 话题回放时用ros2 bag play复现飞行过程。我一般会录/mavros/local_position/pose、/mavros/imu/data、/mavros/setpoint_position/local这三个话题足够做控制效果评估。# 录制关键话题 ros2 bag record /mavros/local_position/pose /mavros/imu/data /mavros/setpoint_position/local -o flight_test_01 # 回放并查看信息 ros2 bag info flight_test_01 ros2 bag play flight_test_01逻辑说明-o指定输出目录名回放时ros2 bag play会按时间戳重新发布消息。参数说明如果只想录一段时间加--duration 60表示录 60 秒。回放时注意时间同步仿真里的时间戳和系统时间可能不一致用--clock参数配合/clock话题。硬件在环之前建议先在仿真里做三件事一是把控制频率从 10Hz 逐步提到 50Hz看飞控是否稳定二是注入传感器噪声在 Gazebo 的 IMU 插件里加noise标签三是模拟通信延迟用tc命令在回环接口上加延迟。这三步做完再上真机心里有底。我自己的习惯是每次改完控制参数先跑一遍自动起飞降落的脚本确认没有回归问题再去做更复杂的路径跟踪。仿真环境最大的好处就是让你可以反复试错而不心疼但前提是你要把仿真和真机的差异摸清楚——比如仿真里没有风扰、没有电机振动、没有 GPS 多径这些在真机上都是翻车点。希望帮到你。本文还有配套的精品资源点击获取