ARTICLE DETAIL

资讯详情

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

PX4+Gazebo+ROS2无人机轨迹跟踪仿真环境搭建指南

PX4+Gazebo+ROS2无人机轨迹跟踪仿真环境搭建指南 先把话放前面这套环境看着就三个词——PX4、Gazebo、ROS2但真正从零开始把它们拼起来跑通一个轨迹跟踪仿真中间踩的坑比想象中多得多。这篇东西我按自己实际搭环境的顺序写从系统准备到编译固件再到把ROS2节点、仿真器、飞控三端连通最后给你一个能直接改的圆形轨迹跟踪示例。全程基于Ubuntu 22.04 ROS2 Humble PX4 v1.14.x Gazebo Classic这也目前兼容性最稳、教程最多的一套组合。一个背景交代我做这个环境目标不是飞个悬停或者随便绕圈而是为了后续验证轨迹跟踪算法——就是在仿真里给无人机一条期望航线让它按照控制律去逼近这条线并实时观察位置误差和姿态变化。所以这套环境里头仿真器、飞控、控制器这三层是缺一不可的。仿真器负责“假装有个物理世界”飞控负责“真的在跑姿态和位置控制”外层的ROS2节点负责“告诉飞控该往哪飞”。三层之间怎么通信、怎么配消息格式是整篇文章的核心。如果你想跑通整个流程最好对Linux基本命令行有概念知道cd、vim这些是干嘛的就能跟下来。你要是纯零基础那也没关系我把每一步都写细了你照着敲就行。1. 环境选型为什么是Ubuntu 22.04 Humble PX4 v1.141.1 版本搭配的逻辑很多人上来就卡在版本问题上这太正常了。PX4、ROS2、Gazebo三者的版本兼容关系非常严格尤其是ROS2的中间件实现——DDS——和PX4的microdds客户端之间是有版本绑定的。乱配版本轻则编译报错重则仿真器里无人机根本不动。我最终的版本组合是这个组件版本说明操作系统Ubuntu 22.04.3 LTSLTS版本生态最全ROS2Humble Hawksbill对应Ubuntu 22.04的正式版本PX4固件v1.14.3稳定配套教程多接口成熟GazeboGazebo Classic 11ROS2 Humble自带兼容性较好QGroundControl最新稳定版地面站用于监控和日志分析为什么不直接上Ubuntu 24.04因为ROS2 Jazzy虽然出来了但PX4官方对Jazzy的支持在2024年下半年才逐步完善很多第三方节点还没跟上。对于“从零到一”的教程稳定性大于新特性。Ubuntu 22.04 Humble这套组合是网上教程最多、踩坑记录最全、第三方依赖最不缺的出了问题Google一下基本都能找到答案。1.2 三个核心组件的分工这三者的分工我用一句话就能讲清楚Gazebo负责“物理世界”PX4负责“飞控大脑”ROS2负责“外部指挥”。更具体一点Gazebo一个开源机器人仿真器。它给你模拟重力、空气阻力虽然很简化、地面碰撞、传感器数据。你不需要真飞机就能看到一架四旋翼在虚拟世界里受到物理规律约束。它也是“屠宰场”一样的存在——你的控制代码如果写得有问题在仿真里炸机也就是重启一下的事成本极低。PX4这是一个开源的飞行控制软件栈。它运行在STM32这类单片机上时控制真实飞机运行在普通PC上时控制仿真飞机。在仿真模式下PX4把自己编译成了一个叫px4的进程监听来自仿真器的传感器数据然后跑姿态估计和控制算法最后把电机指令回传。它完成了自稳、姿态控制、位置控制这些底层逻辑。从某种程度上说PX4代表的是“飞机本体”。ROS2机器人操作系统但它其实不是操作系统而是一套分布式通信框架。在轨迹跟踪场景里ROS2是“地面指挥官”——它从PX4拿状态信息位置、速度等然后计算期望轨迹再把期望轨迹发给PX4。注意控制器不一定非得跑在ROS2里也可以直接在PX4内部做但用ROS2的好处是逻辑清晰、便于调试、可以随时换算法、方便和视觉等其他模块集成。这套组合的本质就是把“飞行控制”这摊子事拆成了两半底层快速响应、实时性要求高的部分交给PX4上层任务规划、轨迹生成的灵活性交给ROS2。你只要搞清楚这个分层逻辑后面理解数据流的时候就非常顺畅。2. 基础环境准备把地基打牢2.1 Ubuntu 22.04安装与基础配置如果你电脑上还没装Ubuntu我建议直接装双系统不要用虚拟机。虚拟机的USB透传和图形加速问题在Gazebo里会非常痛苦尤其是界面刷新和GPU渲染卡到你怀疑人生。如果你用的是Windows去官网下Ubuntu 22.04的ISO镜像用Rufus做个启动盘装系统的时候网上教程非常多这步我就不展开细说了。装完系统以后第一件事换软件源。Ubuntu默认源在国外不换源的话你装软件会慢到崩溃。换成国内镜像源清华源、阿里源都行然后更新系统sudo apt update sudo apt upgrade -y第二件事装一些基础工具。后面编译PX4和ROS2都会用到提前装好能少踩很多坑sudo apt install -y \ git zip cmake build-essential genromfs ninja-build exiftool \ python3-pip python3-dev python3-venu python3-setuptools \ astyle libxml2-utils \ g-12 gcc-12如果你不装g-12PX4 v1.14在Ubuntu 22.04上编译可能会遇到编译器版本不匹配的报错。这个坑我踩过编译到最后突然报一堆“internal compiler error”最后发现是GCC 11的问题换了GCC 12就好了。所以这一步别省。2.2 ROS2 Humble安装别偷懒按官方流程来ROS2的安装方式有两种一种是官网的一行命令脚本一种是手动添加软件源一步步装。我强烈推荐手动装因为一行命令的脚本在国内网络环境下经常卡在repo服务器上。虽然网上有个“鱼香ROS一键安装”的脚本很火也确实很省事但我遇到过它默认装出来的ROS2版本和我后面PX4要的版本对不上的情况所以还是建议手动走一遍。手动安装步骤一共四步# 1. 设置编码 sudo apt update sudo apt install locales sudo locale-gen en_US en_US.UTF-8 sudo update-locale LC_ALLen_US.UTF-8 LANGen_US.UTF-8 export LANGen_US.UTF-8 # 2. 添加ROS2软件源 sudo apt install software-properties-common curl sudo add-apt-repository universe sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg echo deb [arch$(dpkg --print-architecture) signed-by/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(. /etc/os-release echo $UBUNTU_CODENAME) main | sudo tee /etc/apt/sources.list.d/ros2.list /dev/null # 3. 安装ROS2 Humble完整版 sudo apt update sudo apt install ros-humble-desktop # 4. 配置环境变量 echo source /opt/ros/humble/setup.bash ~/.bashrc source ~/.bashrc如果你在添加ros.key这一步遇到网络问题raw.githubusercontent.com有时在国内不太稳定可以多试几次或者先配一下代理再拉。反正别用那些不靠谱的第三方源安全性没法保证还行装出来的包经常缺依赖后面排查起来更麻烦。装完之后验证一下ros2 --help ros2 topic list只要命令能正常输出说明ROS2核心组件已经装好了。这里说一下为什么装了ros-humble-desktop而不是ros-humble-ros-base因为desktop版本包含了rviz2和Gazebo。rviz2后面用来可视化无人机状态和轨迹Gazebo直接作为仿真器一举两得省得后面再单独装。2.3 QGroundControl地面站安装QGroundControl简称QGC是PX4最常用的地面站用来启动仿真、监控飞行数据、看日志。装QGC之前需要先装一些串口和图形库sudo usermod -a -G dialout $USER sudo apt-get remove modemmanager -y sudo apt install libqt5gui5 libqt5core5t64 libqt5widgets5t64 libqt5dbus5t64 -y然后从QGC官网下载AppImage文件下载完成后给它加执行权限chmod x qgroundcontrol.AppImage ./qgroundcontrol.AppImageQGC第一次启动会提示你选择“地面站”或“开发者”模式正常选“地面站”就行。面板里的“Airframe”分类如果能看到PX4的机型列表说明QGC已经正确识别到了PX4固件。不过QGC这一步后面仿真跑通再确认就行现在能打开界面就算装好了。3. PX4固件获取与编译仿真环境的核心3.1 源码下载与子模块同步PX4的源码需要用git从GitHub拉取这里有个非常关键的细节——PX4的仓库包含了很多子模块submodule如果不用--recursive参数或者同步子模块的时候出问题编译过程会找不到依赖然后中断。我推荐的拉取命令是这样的cd ~ mkdir -p workspace cd workspace git clone --recursive https://github.com/PX4/PX4-Autopilot.git -b v1.14.3 cd PX4-Autopilot-b v1.14.3是指定分支。我之前用main分支编译过虽然能通过但后面跟ROS2配合的时候经常遇到消息定义对不上的问题。指定版本号稳定压倒一切。源码拉下来之后先更新子模块git submodule update --init --recursive这是一个漫长的过程因为很多子模块托管在GitHub上。国内网络不好的话这步可能反复失败。我的经验是多试几次或者用一些加速方式实在不行就把子模块的git地址改成镜像。这种操作比较脏但不影响最终结果。如果你拉了好几次都不行可以考虑等网络好的时候再拉或者找一个国内做过PX4镜像的仓库来拉源码。3.2 自动化环境配置脚本PX4官方提供了一个自动配置脚本在Tools/setup/目录下cd PX4-Autopilot bash ./Tools/setup/ubuntu.sh这个脚本会帮你装好PX4编译所需要的所有依赖包括arm交叉编译器、Python库、Gazebo的依赖包等等。脚本执行时间比较长中间可能会提示你输入密码看着点终端别走开。脚本执行完以后一定记得关掉终端重新开一个让PATH环境变量重新加载。否则你敲arm-none-eabi-gcc --version可能还是找不到命令。补充提醒如果你前面用了我给的g-12安装命令ubuntu.sh脚本通常也能识别并处理好。如果编译的时候提示GCC版本问题你可以在~/.bashrc里加一行export CCgcc-12和export CXXg-12来强制指定版本。3.3 编译PX4 SITL仿真固件PX4可以交叉编译成真机固件也可以编译成**SITLSoftware In The Loop软件在环**模式下运行的PC版本。轨迹跟踪仿真用的是SITL版本因为整个飞控逻辑都在电脑上跑不需要任何硬件。编译命令cd ~/workspace/PX4-Autopilot make px4_sitl gazebo-classic这步第一次编译会很久十几分钟到半小时都有可能看机器性能。期间屏幕上会刷大量编译日志别慌只要不是红色的error就是正常的。编译成功的标志是最后出现类似[100%] Built target px4然后自动启动一个Gazebo Classic界面里面有一架四旋翼停在跑道中央。这里插一句Gazebo Classic和Gazebo Sim的选择问题。在PX4 v1.14里默认的gazebo参数是gazebo-classic对应的就是Gazebo 11。PX4 v1.15及以上版本开始全面转向新版的Gazebo Sim也就是Ignition。如果你装的是PX4 v1.14.3就用gazebo-classic不要手动去装新版的Gazebo Sim不然会有SIM_MASTER和DDS接口不同导致通信连不上的问题。跑起来以后Gazebo里能看到一架四旋翼这叫iris无人机模型是PX4自带的成熟模型。如果你能在这个界面上看到无人机并且没有crash或者陷入地里的情况恭喜你PX4 Gazebo的底层已经通了。在继续往下走之前我们再启动一个终端测试一下PX4的SITL进程是否正常输出数据cd ~/workspace/PX4-Autopilot source Tools/simulation/gazebo-classic/setup_gazebo.bash source build/px4_sitl_default/px4/ # 确认这个路径下的可执行文件存在只要进程没崩就说明PX4的SITL正在跑。这也意味着第一个大节点——仿真环境已经就绪。4. Gazebo仿真环境场景操控与自定义4.1 默认世界与模型加载机制当你执行make px4_sitl gazebo-classic的时候PX4会自动加载一个名为empty_world的默认世界里面只有一块地面和简单的光照。但你在界面上看到的跑道模型是在/worlds里定义的和在PX4模型数据库里的runway等模型一起组成的。Gazebo的模型加载机制是通过环境变量来指定的。PX4在setup_gazebo.bash脚本里设置了GAZEBO_MODEL_PATH、GAZEBO_PLUGIN_PATH这些变量这样Gazebo才能在启动时找到PX4无人机模型和传感器插件。如果你想加载不同的环境比如一个带有障碍物的城区或者一个开阔的草地可以修改PX4的启动脚本。最直接的方法是在启动命令里指定世界文件名make px4_sitl gazebo-classic_iris_ctrlalloc # 不同机型或者更常见的是直接改launch文件在PX4-Autopilot/launch/目录下有对应不同场景的配置文件。你如果想省事可以复制默认的gazebo-classic_iris的启动脚本把world参数改成你想要的export PX4_HOME_LAT47.397742 export PX4_HOME_LON8.545593 export PX4_HOME_ALT550.0这三个环境变量是设置起飞机场的经纬度和海拔用Tools/simulation/run.sh启动仿真时生效。改这些值无人机在仿真世界里的初始位置就会对应改变。4.2 解决Gazebo界面闪烁和卡顿问题这个事必须单独开一小节说因为网上问“为什么gazebo界面一直在闪”的人太多了。我之前也被这个折磨过最后总结了三个主要原因第一显卡驱动问题。Gazebo默认使用的OGRE渲染引擎在部分NVIDIA显卡上存在兼容性问题表现就是界面闪烁、刷新异常。解决办法是手动指定渲染引擎export SVGA_VGPU100 export LIBGL_ALWAYS_SOFTWARE1第二段命令会强制Gazebo使用CPU软渲染虽然画面质量会下降一些但是稳定性会大幅提升。如果你的电脑有NVIDIA独显也可以试一下在Gazebo启动前设置__GLX_VENDOR_LIBRARY_NAMEnvidia这个变量能协助解决部分闪烁问题。第二虚拟机用户。如果你是在虚拟机里跑Gazebo界面闪烁大概率是3D加速没开。虚拟机设置里把“图形控制器”改成VMSVGA开启3D加速能大幅改善。但说实话虚拟机跑复杂仿真仍然会卡想要顺畅体验还是双系统吧。第三版本冲突。如果你apt源里同时存在多个Gazebo版本启动时可能加载两个版本的库文件导致冲突闪烁。检查一下你当前加载的版本gazebo --version如果是8.x或者9.x很可能你的系统里有个旧版本的Gazebo残留。把旧的通过apt autoremove清理掉确保加载的是Gazebo Classic 11。4.3 编写自定义世界文件入门级默认的empty_world太简陋了如果你想要一个更接近实际测试的环境可以自己写一个简单的世界文件。在任意目录创建my_ground.world?xml version1.0 ? sdf version1.6 world nametracking_world include urimodel://sun/uri /include include urimodel://ground_plane/uri /include include urimodel://iris/uri pose0 0 0.3 0 0 0/pose /include /world /sdf保存后在启动PX4 SITL之前先设置环境变量export GAZEBO_MODEL_PATH$HOME/workspace/PX4-Autopilot/Tools/simulation/gazebo-classic/sitl_gazebo-classic/models gazebo my_ground.world这里说明一下最简世界其实没有太多必写的内容sun模型提供光照ground_plane提供地面碰撞iris是无人机模型。如果你只是想调整初始位置改pose里的xyz就行。当然这是非常初级的写法后续如果想放障碍物、建筑物各种模型网上都有但是先把这个机制理解清楚后面扩展会顺手很多。我实际测试中的感受是在拿到轨迹跟踪demo之前先在自定义世界里飞几次手动起降能帮你快速确认PX4的姿态控制是否正常响应。如果飞控本身就不稳后面上层算法再对也没用。5. ROS2与PX4通信链路打通数据通路5.1 三个进程之间如何通信现在你已经有了两个进程在跑Gazebo仿真物理世界和PX4 SITL飞控逻辑。ROS2这边是第三进程要控制飞机就必须和PX4建立通信。这里有几个通信通道我用最通俗的方式给你捋清楚PX4与Gazebo之间通过MAVLink协议经UDP端口通信。PX4的SITL默认监听127.0.0.1:14540端口Gazebo里的传感器数据IMU、GPS通过这个端口发给PX4PX4算好的电机指令也发回Gazebo。这个通道PX4已经自动配好了你不需要操作。PX4与QGC之间通过MAVLink经UDP的14550端口。QGC默认监听这个端口所以打开QGC就能看到仿真飞机的状态。PX4与ROS2之间这是最需要你手动配置的一环。PX4使用了**microdds也就是XRCE-DDS**中间件把MAVLink消息转化成DDS消息从而让ROS2节点可以直接订阅/发布PX4的话题。PX4的SITL启动后会开启一个UDP端口8889一个叫Micro XRCE-DDS Agent的进程负责把DDS数据桥接到这个端口上。简单一句话ROS2要想跟PX4通信必须在系统里跑一个Micro XRCE-DDS Agent作为“翻译官”。这个Agent把ROS2的DDS消息转成MicroDDS消息再通过UDP发给PX4进程。5.2 安装Micro XRCE-DDS Agentcd ~/workspace git clone https://github.com/eProsima/Micro-XRCE-DDS-Agent.git cd Micro-XRCE-DDS-Agent mkdir build cd build cmake .. make sudo make install装完之后每次启动PX4仿真之前先启动AgentMicroXRCEAgent udp4 -p 8889看到控制台输出[Info] [UDPv4Agent] ... Added client之类的日志说明Agent已经在UDP 8889端口监听了。有一种情况需要注意如果先启动PX4后启动AgentPX4会不断重试连接倒不影响最终结果只是日志里会有大量timeout记录。所以规范操作是先启动Agent再启动PX4 SITL。5.3 编译px4_msgsROS2与PX4之间的消息协议有了通信Agent还不够ROS2节点要读懂PX4发来的数据必须知道消息的结构。PX4的ROS2消息定义在px4_msgs包里。这个包需要放在你的ROS2工作空间里编译。创建一个ROS2工作空间mkdir -p ~/ws_ros2/src cd ~/ws_ros2/src git clone https://github.com/PX4/px4_msgs.git cd ~/ws_ros2 colcon build source install/setup.bash注意px4_msgs的版本要和PX4固件版本匹配。我在v1.14.3上用的px4_msgs就是main分支最新版本基本没出过兼容性问题。但你如果升级了PX4固件必须同步更新px4_msgs否则消息字段对不上订阅起来全是零值。5.4 用命令行验证通信是否通在Agent已经启动、PX4 SITL已经跑起来、ROS2环境已经source的情况下新开一个终端ros2 topic list正常情况下你会看到一大堆以/fmu/out/开头的topic比如/fmu/out/vehicle_attitude姿态四元数/fmu/out/vehicle_local_position本地位置NED坐标系/fmu/out/vehicle_odometry里程计信息/fmu/out/vehicle_status飞行状态/fmu/in/offboard_control_modeoffboard控制模式指令/fmu/in/trajectory_setpoint轨迹设定点这些topic就是ROS2和PX4之间的“官方语言”。验证一下ros2 topic echo /fmu/out/vehicle_local_position如果你能看到持续刷新的位置数据说明整条链路已经打通。这相当于你已经可以在ROS2里实时获取无人机状态了。这一步非常有成就感因为从这之后你已经不是在看两个独立的软件而是在看一个完整的飞控系统了。6. 轨迹跟踪控制器实现核心数据流与代码解析6.1 Offboard模式与控制流PX4有几种飞行模式其中对轨迹跟踪最重要是Offboard模式。在这个模式下PX4不再自己决定飞行目标而是完全听从外部指令——也就是我们ROS2节点发过来的设定点。可以理解为自动驾驶的车里PX4是司机但你ROS2节点是坐在副驾拿着地图指挥的人。控制流是这样的ROS2节点轨迹发生器 ↓ 发布期望位置/速度/fmu/in/trajectory_setpoint PX4位置控制器 ↓ 计算姿态和油门期望 PX4姿态控制器 ↓ 计算电机指令 Gazebo仿真模型也就是说你在ROS2里只需要告诉PX4“你期望无人机到哪个位置、以什么速度飞”剩下的姿态控制、电机控制PX4自己搞定。你不需要管电机的PWM值也不需要自己写姿态环PID。这极大地简化了轨迹跟踪的实现——你只需要写好“轨迹生成器”和“期望设定点发布器”剩下的交给PX4。6.2 关键消息解析TrajectorySetpoint和OffboardControlMode在px4_msgs里有两个消息对轨迹跟踪至关重要。第一个是TrajectorySetpoint.msgstd_msgs/Header header bool valid int8 type float32[3] position # NED坐标系下的期望位置单位m float32[3] velocity # NED坐标系下的期望速度单位m/s float32[3] acceleration float32[3] yaw # 期望偏航单位rad float32[3] yaw_speed我们最常用的就是position和yaw两个字段。注意坐标系是NED北东地也就是X轴朝北、Y轴朝东、Z轴朝下。这个坐标系和Gazebo的世界坐标ENU东北天不一样容易搞混。记住一个转换关系NED的Z轴向下所以想让无人机上升position.z要设成负数。反过来如果你从Gazebo里读到的位置z是正数向上发到PX4的时候要取反。第二个是OffboardControlMode.msgstd_msgs/Header header bool position bool velocity bool acceleration bool attitude bool body_rate bool thrust_and_torque bool direct_actuator这个消息的作用是告诉PX4“我现在要用什么控制量来指挥你”。我们做位置轨迹跟踪就把position字段置为true其他全false。这两个消息需要在每个控制循环里都发。PX4对Offboard模式有一个超时机制如果超过一定时间默认0.5秒没收到设定点它会自动退出Offboard模式或者触发降落保护。所以你的ROS2节点里发布频率至少要在10Hz以上我习惯用20Hz稳妥又不会太占CPU。6.3 最简单的圆形轨迹跟踪节点下面给出一个可以直接用的Python节点它让无人机在10米半径的圆上以恒定高度飞行。这个代码参考了PX4官方offboard示例的结构但是我加了轨迹生成函数和误差打印更贴合轨迹跟踪场景。在工作空间里创建节点cd ~/ws_ros2/src ros2 pkg create --build-type ament_python px4_circle_tracking cd px4_circle_tracking编辑px4_circle_tracking/px4_circle_tracking_node.py#!/usr/bin/env python3 import math import rclpy from rclpy.node import Node from px4_msgs.msg import OffboardControlMode, TrajectorySetpoint from px4_msgs.msg import VehicleLocalPosition class CircleTracker(Node): def __init__(self): super().__init__(circle_tracker) # 发布Offboard模式指令和轨迹设定点 self.offboard_pub self.create_publisher(OffboardControlMode, /fmu/in/offboard_control_mode, 10) self.traj_pub self.create_publisher(TrajectorySetpoint, /fmu/in/trajectory_setpoint, 10) # 订阅本地位置用于监控当前状态 self.sub self.create_subscription(VehicleLocalPosition, /fmu/out/vehicle_local_position, self.pos_callback, 10) self.current_pos [0.0, 0.0, 0.0] self.timer self.create_timer(0.05, self.timer_callback) # 20Hz self.start_time self.get_clock().now() def pos_callback(self, msg): self.current_pos [msg.x, msg.y, msg.z] def timer_callback(self): # 1. 发布offboard控制模式 offboard OffboardControlMode() offboard.timestamp int(self.get_clock().now().nanoseconds / 1000) offboard.position True # 其他类型全默认False self.offboard_pub.publish(offboard) # 2. 生成圆形轨迹 elapsed (self.get_clock().now() - self.start_time).nanoseconds * 1e-9 radius 10.0 angular_vel 0.3 # 弧度每秒 x radius * math.cos(angular_vel * elapsed) y radius * math.sin(angular_vel * elapsed) z -5.0 # NED坐标系下负值表示上升5米高度 yaw 0.0 # 3. 发布期望轨迹 traj TrajectorySetpoint() traj.timestamp int(self.get_clock().now().nanoseconds / 1000) traj.position [float(x), float(y), float(z)] traj.yaw float(yaw) self.traj_pub.publish(traj) # 4. 打印当前位置和期望位置方便观察误差 self.get_logger().info( fcur: ({self.current_pos[0]:.2f}, {self.current_pos[1]:.2f}, {self.current_pos[2]:.2f}) | fdes: ({x:.2f}, {y:.2f}, {z:.2f}) ) def main(argsNone): rclpy.init(argsargs) node CircleTracker() rclpy.spin(node) node.destroy_node() rclpy.shutdown() if __name__ __main__: main()把setup.py里的entry_points改成entry_points{ console_scripts: [ circle_tracker px4_circle_tracking.px4_circle_tracking_node:main, ], },然后在工作空间编译并sourcecd ~/ws_ros2 colcon build source install/setup.bash6.4 如何切换到Offboard模式有了节点还不够PX4默认不在Offboard模式你得手动切换。三种方式任选第一种用QGC地面站。在飞行模式的设置面板里把飞行模式映射到Offboard。QGC右侧的“飞行模式”窗口里通常可以设置一个遥控器开关位或者直接在状态面板切换到Offboard。仿真里没有遥控器也可以直接在QGC里切就行。第二种在PX4 shell里执行命令。如果你在PX4 SITL的终端哪能看到nsh提示符输入commander mode offboard第三种只要你的ROS2节点持续发送设定点你也可以在QGC里手动点击模式切换这个方式最直观。但无论哪种我强烈建议先让无人机稳定悬停再切Offboard也就是起点位置就在飞机当前附近。如果你一上来就让飞机从悬停状态跳到10米外它会用最大速度飞过去姿态会很剧烈搞不好直接翻滚炸机。6.5 节点运行观察跟踪过程启动顺序总结# 终端1启动MicroXRCEAgent MicroXRCEAgent udp4 -p 8889 # 终端2启动PX4 SITL Gazebo cd ~/workspace/PX4-Autopilot make px4_sitl gazebo-classic # 终端3启动轨迹跟踪节点 cd ~/ws_ros2 source install/setup.bash ros2 run px4_circle_tracking circle_tracker在QGC里切换到Offboard模式后你会看到无人机缓慢起飞然后进入圆周运动。你可以用ros2 topic echo /fmu/out/vehicle_local_position实时观察位置变化也可以用rviz2配合可视化。rviz2如果对轨迹可视化有需求可以订阅/fmu/out/vehicle_odometry并在rviz2里添加好Odometry显示添加一个Axes和Path就能看到飞机的轨迹线条。这样比单纯看数值直观很多。6.6 从圆形轨迹到自定义轨迹圆形只是验证实际项目里肯定要跑更复杂的轨迹比如8字轨迹、螺旋上升轨迹。改轨迹本质上就是改timer_callback里x、y、z的生成逻辑。8字轨迹lemniscate的参数方程x radius * math.sin(angular_vel * elapsed) y radius * math.sin(angular_vel * elapsed / 2) * math.cos(angular_vel * elapsed)螺旋上升就是在原来圆形轨迹基础上让z随着时间线性减小NED下z -5.0 - 0.2 * elapsed # 每秒上升0.2米记住一点轨迹的位置和速度要连续不要突然跳变否则PX4的位置控制器会输出很大的姿态角飞机可能沿着一个很怪异的角度猛冲。理想轨迹生成器会在每个时间步输出期望位置的同时也计算期望速度并填充到TrajectorySetpoint的velocity字段里。不过对于初学者先只发position也完全够用。7. 轨迹跟踪调试误差分析与问题排查实录7.1 我踩过的最典型的三个坑调试过程中我遇到过不少问题整理一下最典型的三个这些都是那种“不亲自动手根本不会注意”的坑。第一个坑坐标系搞反。我把Gazebo的ENU坐标数据直接用在了PX4设定点上导致无人机拼命往后飞。这个问题最大的迷惑性在于飞行器离得很近的时候你根本看不出来它飞反了只有轨迹半径拉大以后才明显。检查方法很简单通过QGC的姿势仪表盘观察机头朝向或者在Gazebo里对比飞机位置和期望位置方向一目了然。第二个坑超时保护导致无人机坠落。代码里我一开始只发了TrajectorySetpoint忘了发OffboardControlMode。PX4虽然收到了轨迹点但offboard模式被判定为无效几秒钟后触发了降落保护飞机直接落地。解决方法是把这两个消息都放到timer_callback里同时发布保证两个topic的数据流同步到达。第三个坑启动顺序不对导致连不上。经常有朋友问我为什么ros2 topic list里看不到PX4的topic。一排查Agent忘了启动或者先启动了PX4后启动Agent。PX4的microdds会因为连接不上而不断重试这种情况我试过等它自动恢复但偶尔会卡住。最好还是干脆重启一遍PX4 SITL重来也就几十秒的事。7.2 如何判断跟踪效果是否合格轨迹跟踪好不好不能光看飞机在不在飞要用数据说话。在QGC的“Analyze Tools”里打开日志分析可以看到无人机实际轨迹和期望轨迹的偏差。但我更推荐用的是ROS2的方式——你的节点里已经打印了当前坐标可以自己粗略算一下距离误差error math.sqrt( (self.current_pos[0] - x) ** 2 (self.current_pos[1] - y) ** 2 (self.current_pos[2] - z) ** 2 )一个经验数据圆形轨迹跟踪在仿真环境里稳态误差通常在0.2~0.5米以内这取决于你选的半径和角速度。如果你发现误差明显偏大优先怀疑这几个原因轨迹的期望速度给得太快PX4的位置控制器跟不上了TrajectorySetpoint里只发了位置没发速度PX4内部估算的速度和你期望的轨迹不匹配没有给足飞机一个“预热”时间直接从悬停跳到飞行轨迹初始误差太大循环频率太低PX4在两个设定点之间用了线性插值但插值间隔太长导致轨迹不平滑。7.3 参数调整建议PX4的位置控制器的相关参数在MC_POS_CTRL_前缀下可以通过QGC的参数面板在线修改。但我要提醒一句仿真里的默认参数就够用了除非你要追求极致的跟踪性能否则不要轻易动PID参数。如果你确实想调最简单有效的是调这两个参数MPC_XY_P水平位置控制P增益增大它可以让位置跟踪误差更快收敛但是太大会引起震荡。MPC_Z_P高度控制P增益同理。MPC_XY_VEL_P水平速度环的P增益这个参数影响的是响应速度的“手感”别调太大容易震荡。我的做法是先不改参数把轨迹的角速度调低从0.3降到0.1看飞机是否能正常跟踪。如果正常再逐步提高角速度找到能接受的误差上限再决定要不要动PID。7.4 QGC和仿真日志分析一旦出现炸机、飞丢、振荡别急着重启先看日志。QGC里点顶部的“应用”菜单选择“Analyze Tools”点击“Log Download”可以把PX4的ULog文件下载下来。用PX4官方工具ulog2csv转换一下cd ~/workspace/PX4-Autopilot python3 Tools/ulog/ulog2csv.py 你的日志文件.ulg转换出来的csv文件里重点看vehicle_local_position和vehicle_attitude两个topic的数据可以定位到炸机前的几十个控制周期内飞控在做什么。有些时候你会发现控制器指令是正常的但仿真物理引擎出了问题比如模型陷进地面这时候就不是代码问题而是仿真环境问题了。8. 常见问题速查表与避坑经验问题现象可能原因排查与解决ros2 topic list里没有PX4的topicMicro XRCE-DDS Agent未启动先启动Agent再启动PX4 SITLGazebo界面一直闪烁显卡驱动不兼容或虚拟机3D加速未开设置LIBGL_ALWAYS_SOFTWARE1或用独显启动无人机起飞后迅速侧翻轨迹设定点的位置突变太大从当前悬停位置开始生成轨迹不要从原点直接跳远切Offboard模式后飞机不动没有同时发布OffboardControlMode在timer_callback里同时发布两个消息编译PX4报GCC错误系统默认编译器版本过旧或过新安装g-12并设置CC/CXX环境变量期望位置方向反了ENU和NED坐标系混淆Gazebo中z轴向上PX4中z轴向下注意取反无人机在Gazebo里陷入地面初始高度设成0设置PX4_HOME_ALT或把spawn高度设为0.3米以上px4_msgs和固件消息对不上版本不匹配升级PX4固件时同步更新px4_msgs仿真一段时间后越来越卡日志过多或模型复杂减小QGC的日志采样率或更换轻量级worldros2 run找不到命令没有source环境source install/setup.bash并确认在workspace目录下还有一个很隐蔽的问题我放在最后说。如果你在启动PX4 SITL时终端输出很多[error]信息但同时QGC又显示飞机状态正常那多半是因为你前后启动的PX4实例都占了同一个14540端口。也就是说你上一个PX4进程没关干净新的又起了。用ps aux | grep px4关掉旧进程再重来就行了。端口冲突这种事看似是小事但排查起来非常耗费时间。9. 扩展建议这套环境还能做些什么既然PX4GazeboROS2已经跑通后面的路就很宽了。如果你对视觉感兴趣可以让Gazebo里的无人机模型挂载一个虚拟摄像头然后用ros2话题读取图像数据做视觉目标跟踪。PX4的iris_fpv_cam模型就是带摄像头的启动命令是make px4_sitl gazebo-classic_iris_fpv_cam。有了图像流以后你可以用OpenCV做目标识别再用我们刚才写的轨迹设定点节点把目标位置的误差转换成飞行指令这就是一个完整的视觉伺服项目框架。如果你对多机编队感兴趣PX4支持在同一个仿真里启动多架无人机每个都需要自己的microdds连接端口。控制逻辑大同小异但要在话题命名上做区分比如/uav1/fmu/in/trajectory_setpoint和/uav2/fmu/in/trajectory_setpoint。编队的核心难点在协同控制算法但环境层面只需把每架飞机当作独立的PX4进程处理。如果你对仿真和真机的一致性有要求建议后面把代码迁移到ROS2的控制框架中比如用control_toolbox或mavros。不过我这里用的是PX4官方原生的px4_msgs接口它和mavros在消息延迟和实时性上有差异但胜在消息定义简洁、和控制律对接方便。我个人在实际操作中的习惯是任何新算法先在这套环境里跑通再考虑上真机。仿真环境的价值不在于“像真机”而在于把一个复杂系统的风险提前暴露出来。这套环境搭好以后它就是你后续所有飞行算法开发的“实验田”。后面用起来会越来越顺手因为它的每一层你都知道是怎么转起来的出了问题定位到具体组件心里不慌。
返回列表