1. 为什么要在Ubuntu 20.04上折腾ROS1与PX4这套组合
如果你刚拿到一台装了Ubuntu 20.04的机器,想跑无人机仿真、做二次开发,或者单纯想把PX4飞控的代码从编译到起飞全流程走一遍,那ROS1加PX4加MAVROS这套组合基本是绕不开的起点。我前后在虚拟机、双系统、物理机上装过不下十遍,踩过的坑从依赖冲突到环境变量污染,从Gazebo黑屏到MAVROS连不上,几乎每一类问题都遇到过。这篇内容就是把这些经验整理出来,给准备入坑或者正在坑里的朋友一份可以直接抄的作业。
先说清楚这套环境到底能干什么。PX4是飞控固件,负责底层姿态控制、传感器融合、电机输出;ROS1是机器人操作系统,负责上层任务调度、感知、规划;MAVROS是两者之间的翻译官,把PX4的uORB消息转成ROS话题,反过来也一样。三者打通之后,你可以在ROS里写一个节点,发一个目标位置,PX4就能控制无人机飞过去。这就是无人机二次开发最核心的链路。
适合谁来参考?如果你已经装好了Ubuntu 20.04,会基本的终端操作,知道cd、ls、sudo是什么意思,那就可以直接往下看。如果你连Ubuntu都还没装,建议先搞定系统安装,再回来折腾这套环境。另外,这套流程在虚拟机里也能跑,但Gazebo仿真对显卡有要求,虚拟机里可能会卡,物理机体验会好很多。
我选择Ubuntu 20.04而不是22.04,原因很直接:ROS1 Noetic的官方支持到20.04为止,22.04原生只支持ROS2。虽然22.04也能通过一些手段装ROS1,但依赖问题会多很多。PX4这边对20.04的支持也最成熟,社区里大部分教程和问题解答都是基于这个版本。所以如果你不是非要用新系统,20.04是最省心的选择。
2. 系统准备与基础环境配置
2.1 安装Ubuntu 20.04的几种方式和选择建议
装系统这一步,我试过三种方式:VMware虚拟机、双系统、纯物理机。虚拟机最安全,不影响原有系统,适合先试水;双系统性能好,但分区操作有风险;纯物理机最省事,但需要一台专门的机器。如果你只是学习仿真,VMware虚拟机足够了,分配4核CPU、8G内存、50G硬盘,跑Gazebo基本流畅。如果你要做硬件在环或者实际飞行,建议物理机。
安装的时候有个细节要注意:语言选英文,不要选中文。中文环境下很多路径会变成中文,后面编译PX4的时候容易出问题。时区选上海,键盘布局默认就行。分区的时候,如果是虚拟机,直接自动分区;如果是双系统,建议给/至少50G,/home单独分,swap给8G左右。
装完之后第一件事是换源。默认的源在国内下载速度很慢,换成清华或者阿里的镜像源,后面装ROS和PX4依赖会快很多。命令如下:
sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak sudo sed -i 's/archive.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list sudo sed -i 's/security.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list sudo apt update sudo apt upgrade换源之后更新一下系统,确保所有包都是最新的。这一步可能要几分钟,取决于网速。
2.2 中文输入法和常用工具的安装
虽然前面说系统语言选英文,但中文输入法还是要装的,不然写注释或者查资料的时候很麻烦。我习惯用搜狗输入法,安装步骤如下:
sudo apt install fcitx fcitx-config-gtk fcitx-googlepinyin然后在系统设置里把输入法框架切换成fcitx,重启之后在fcitx配置里添加Google拼音。搜狗输入法也可以,但需要去官网下载deb包,安装后还要处理依赖问题,稍微麻烦一点。如果你不想折腾,Google拼音够用了。
另外几个常用工具建议一起装上:terminator(多窗口终端)、git、curl、wget、vim、htop。这些在后面编译和调试的时候都会用到。
sudo apt install terminator git curl wget vim htop net-tools注意:如果你在虚拟机里,建议装一下VMware Tools或者open-vm-tools,这样剪贴板共享和文件拖拽会方便很多。命令是
sudo apt install open-vm-tools-desktop。
2.3 环境变量配置的坑与正确做法
环境变量是这套环境里最容易出问题的地方。ROS、PX4、MAVROS都有自己的环境变量脚本,如果顺序不对或者重复source,会导致各种奇怪的错误。我的做法是:把所有环境变量配置都写进~/.bashrc,但要注意顺序。
ROS的环境变量要在PX4之前source,MAVROS的要在ROS之后。具体来说,~/.bashrc里应该有这样的顺序:
source /opt/ros/noetic/setup.bash source ~/catkin_ws/devel/setup.bash source ~/PX4-Autopilot/Tools/setup_gazebo.bash ~/PX4-Autopilot ~/PX4-Autopilot/build/px4_sitl_default export ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:~/PX4-Autopilot export ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:~/PX4-Autopilot/Tools/sitl_gazebo这里有个细节:setup_gazebo.bash这个脚本在PX4 1.14之后的版本里路径可能变了,有些版本是Tools/simulation/gazebo-classic/setup_gazebo.bash。如果你source的时候提示文件不存在,先去Tools目录下找一下实际路径。
提示:每次修改
~/.bashrc之后,记得source ~/.bashrc或者重新开一个终端。如果改错了导致终端打不开,可以用Ctrl+Alt+F3进入tty,用vim改回来。
3. ROS1 Noetic的安装与验证
3.1 添加ROS源和密钥的完整流程
ROS1 Noetic在Ubuntu 20.04上的安装不算复杂,但网络问题经常导致失败。我建议按下面的步骤来,每一步都确认成功再继续。
首先添加ROS的软件源和密钥:
sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list' sudo apt install curl curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add - sudo apt update如果curl那一步卡住或者报错,说明网络有问题,可以换成国内的ROS镜像源。比如清华的源:
sudo sh -c '. /etc/lsb-release && echo "deb http://mirrors.tuna.tsinghua.edu.cn/ros/ubuntu/ `lsb_release -cs` main" > /etc/apt/sources.list.d/ros-latest.list'密钥那一步如果失败,可以手动下载ros.asc文件然后sudo apt-key add ros.asc。总之这一步的目标是让sudo apt update不报错。
3.2 安装ROS桌面完整版和依赖
源配置好之后,安装ROS桌面完整版:
sudo apt install ros-noetic-desktop-full这个包比较大,下载加安装可能要十几分钟。装完之后初始化rosdep:
sudo rosdep init rosdep updaterosdep init如果报错说文件已存在,说明之前装过,可以跳过。rosdep update如果超时,可以多试几次,或者配置一下rosdep的源。
然后安装一些常用的ROS包和编译工具:
sudo apt install python3-rosinstall python3-rosinstall-generator python3-wstool build-essential最后在~/.bashrc里source ROS的环境:
echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc source ~/.bashrc验证安装是否成功,开一个终端运行roscore,如果看到started core service [/rosout]就说明ROS装好了。再开一个终端运行rosrun turtlesim turtlesim_node,如果弹出一个小乌龟的窗口,说明ROS桌面版也正常。
3.3 创建catkin工作空间和MAVROS的安装
MAVROS是ROS和PX4之间的桥梁,必须装在catkin工作空间里。先创建空间:
mkdir -p ~/catkin_ws/src cd ~/catkin_ws catkin_make source devel/setup.bash然后安装MAVROS:
sudo apt install ros-noetic-mavros ros-noetic-mavros-extras装完之后还要安装GeographicLib的数据集,否则MAVROS启动时会报错:
wget https://raw.githubusercontent.com/mavlink/mavros/master/mavros/scripts/install_geographiclib_datasets.sh sudo bash ./install_geographiclib_datasets.sh这个脚本会下载一些地理数据,如果网络不好可能会失败,多试几次或者手动下载。
注意:MAVROS的版本要和ROS版本对应,Noetic对应的是
ros-noetic-mavros。如果你用的是其他ROS版本,包名要相应调整。
4. PX4源码编译与仿真环境搭建
4.1 克隆PX4源码和子模块更新
PX4的源码在GitHub上,国内克隆速度可能很慢。我一般先用git clone,如果太慢就换成Gitee的镜像。命令如下:
cd ~ git clone https://github.com/PX4/PX4-Autopilot.git --recursive--recursive会同时克隆子模块,这一步很关键,因为PX4依赖很多子模块。如果克隆过程中断了,可以进入目录后运行:
cd PX4-Autopilot git submodule update --init --recursive如果你想要特定版本,比如1.14.3,可以先git tag看一下有哪些标签,然后git checkout v1.14.3。不过新手建议直接用master分支,社区支持最好。
4.2 安装PX4编译依赖和工具链
PX4提供了一个脚本来自动安装依赖:
cd ~/PX4-Autopilot bash ./Tools/setup/ubuntu.sh这个脚本会安装gcc-arm-none-eabi、cmake、python3依赖等。运行完之后建议重启一下,确保所有环境变量生效。
如果脚本执行过程中报错,常见的原因是网络问题或者apt锁被占用。可以等一会儿再试,或者手动安装缺失的包。比如cmake版本不够,可以:
sudo apt install cmake cmake --versionUbuntu 20.04自带的cmake是3.16,PX4要求3.10以上,所以够用。如果提示gcc-arm-none-eabi安装失败,可以单独装:
sudo apt install gcc-arm-none-eabi4.3 编译PX4固件和启动Gazebo仿真
依赖装好之后,编译PX4的SITL版本:
cd ~/PX4-Autopilot make px4_sitl_default gazebo第一次编译会比较久,大概十几分钟到半小时,取决于机器性能。编译成功后会启动Gazebo,里面有一架四旋翼模型。这时候你可以在PX4的终端里输入commander takeoff,无人机就会起飞。
如果Gazebo启动黑屏或者报错,常见原因是显卡驱动问题。虚拟机里可以试试export LIBGL_ALWAYS_SOFTWARE=1,用软件渲染。物理机的话,确保装了正确的NVIDIA或者AMD驱动。
提示:编译的时候如果报错说某个子模块缺失,运行
git submodule update --init --recursive补上。如果报错说Python包缺失,用pip3 install装上。
5. MAVROS与PX4的联调与验证
5.1 启动MAVROS并连接PX4仿真
PX4仿真启动后,MAVROS可以通过UDP连接。先启动PX4的Gazebo仿真:
cd ~/PX4-Autopilot make px4_sitl_default gazebo然后在另一个终端启动MAVROS:
roslaunch mavros px4.launch fcu_url:="udp://:14540@127.0.0.1:14557"如果连接成功,你会看到MAVROS输出一些状态信息,比如FCU: PX4。这时候可以用rostopic list看一下有哪些话题,应该能看到/mavros/state、/mavros/local_position/pose等。
验证连接是否正常:
rostopic echo /mavros/state如果看到connected: true,说明MAVROS和PX4已经通了。
5.2 用ROS话题控制无人机起飞和移动
连接成功之后,可以通过ROS话题发送指令。比如解锁电机:
rosservice call /mavros/cmd/arming "value: true"然后切换到OFFBOARD模式:
rosservice call /mavros/set_mode "custom_mode: 'OFFBOARD'"接着发布位置指令:
rostopic pub /mavros/setpoint_position/local geometry_msgs/PoseStamped "header: seq: 0 stamp: secs: 0 nsecs: 0 frame_id: '' pose: position: x: 0.0 y: 0.0 z: 2.0 orientation: x: 0.0 y: 0.0 z: 0.0 w: 1.0" -r 20这个指令会让无人机飞到2米高度。注意-r 20是发布频率,OFFBOARD模式要求至少2Hz,20Hz比较稳。
5.3 常见连接失败的原因和排查方法
MAVROS连不上PX4是最常见的问题,我遇到过几次,原因各不相同。最常见的是端口不对。PX4默认的UDP端口是14540,MAVROS的fcu_url要写成udp://:14540@127.0.0.1:14557。如果你改了PX4的启动参数,端口可能不一样。
第二个原因是PX4还没完全启动。Gazebo启动后要等几秒钟,PX4的终端里出现INFO [commander] Ready for takeoff!之后再启动MAVROS。
第三个原因是环境变量没source。确保~/.bashrc里source了ROS和PX4的环境,并且新开的终端都生效了。
如果还是连不上,可以检查一下防火墙:
sudo ufw status如果防火墙开着,临时关掉试试:sudo ufw disable。
6. 实操中踩过的坑和独家避坑技巧
6.1 环境变量污染导致的编译失败
我遇到过最头疼的问题是环境变量污染。有一次我在~/.bashrc里同时source了ROS和PX4的环境,结果编译PX4的时候报错说找不到某个ROS的库。原因是PX4的编译系统检测到了ROS的环境变量,误以为要编译ROS相关的模块。
解决办法是:编译PX4的时候,开一个干净的终端,不source ROS的环境。或者用env -i bash启动一个干净的环境。具体来说:
env -i HOME=$HOME DISPLAY=$DISPLAY PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin bash然后在这个终端里编译PX4。这样虽然麻烦一点,但能避免很多奇怪的问题。
6.2 Gazebo模型下载慢和黑屏问题
Gazebo第一次启动时会下载很多模型,国内下载很慢,有时候会卡住。解决办法是提前下载模型库:
git clone https://github.com/osrf/gazebo_models.git ~/.gazebo/models如果GitHub太慢,可以找国内的镜像。另外,Gazebo黑屏通常是显卡问题。虚拟机里可以试试:
export LIBGL_ALWAYS_SOFTWARE=1然后重新启动Gazebo。物理机的话,确保装了正确的显卡驱动。NVIDIA显卡可以装nvidia-driver-470或者更新的版本。
6.3 MAVROS时间同步和消息频率问题
MAVROS连接PX4之后,有时候会报时间同步的警告。这是因为PX4和ROS的时间源不一致。可以在MAVROS的launch文件里加上<param name="time_sync" value="true"/>,或者忽略这个警告,一般不影响使用。
另一个问题是消息频率。OFFBOARD模式要求位置指令至少2Hz,如果发布频率太低,无人机会自动退出OFFBOARD模式。我一般用20Hz,比较稳。如果你用Python写节点,可以用rospy.Rate(20)来控制频率。
提示:如果你在仿真里测试,建议把
/mavros/setpoint_position/local的发布频率设成20Hz以上,并且持续发布,不要停。一旦停止发布,无人机可能会掉高或者退出OFFBOARD。
6.4 虚拟机性能优化和USB设备直通
如果你在虚拟机里跑这套环境,性能优化很重要。首先给虚拟机分配足够的资源:4核CPU、8G内存、50G硬盘。其次,关闭虚拟机的3D加速,有时候反而更稳定。如果要用真实的飞控硬件,需要把USB设备直通给虚拟机。VMware里可以在虚拟机设置里添加USB控制器,然后把飞控插上,选择连接到虚拟机。
不过说实话,虚拟机里跑仿真可以,做硬件在环或者实际飞行还是建议物理机。USB直通有时候不稳定,飞控会掉线。
7. 后续扩展和二次开发方向
7.1 用Python写一个简单的Offboard控制节点
环境搭好之后,下一步就是写自己的控制节点。我一般用Python,因为开发快。下面是一个最简单的Offboard控制节点,让无人机起飞到2米然后悬停:
import rospy from geometry_msgs.msg import PoseStamped from mavros_msgs.msg import State from mavros_msgs.srv import CommandBool, SetMode current_state = State() def state_cb(msg): global current_state current_state = msg rospy.init_node('offboard_node', anonymous=True) state_sub = rospy.Subscriber('/mavros/state', State, state_cb) local_pos_pub = rospy.Publisher('/mavros/setpoint_position/local', PoseStamped, queue_size=10) arming_client = rospy.ServiceProxy('/mavros/cmd/arming', CommandBool) set_mode_client = rospy.ServiceProxy('/mavros/set_mode', SetMode) pose = PoseStamped() pose.pose.position.x = 0 pose.pose.position.y = 0 pose.pose.position.z = 2 rate = rospy.Rate(20) for i in range(100): local_pos_pub.publish(pose) rate.sleep() rospy.wait_for_service('/mavros/cmd/arming') rospy.wait_for_service('/mavros/set_mode') last_request = rospy.Time.now() while not rospy.is_shutdown(): if current_state.mode != "OFFBOARD" and (rospy.Time.now() - last_request > rospy.Duration(5.0)): set_mode_client(custom_mode="OFFBOARD") last_request = rospy.Time.now() else: if not current_state.armed and (rospy.Time.now() - last_request > rospy.Duration(5.0)): arming_client(True) last_request = rospy.Time.now() local_pos_pub.publish(pose) rate.sleep()这个节点先发布100次位置指令,然后切换OFFBOARD模式并解锁。注意要先启动PX4仿真和MAVROS,再运行这个节点。
7.2 接入自己的控制算法和传感器数据
环境跑通之后,你可以接入自己的控制算法。比如用卡尔曼滤波做状态估计,或者用PID做位置控制。PX4本身有EKF2做状态估计,但如果你想用自己的算法,可以通过MAVROS订阅/mavros/local_position/pose和/mavros/imu/data,然后发布/mavros/setpoint_position/local或者/mavros/setpoint_raw/attitude。
如果你要做视觉导航,可以接入摄像头,用ROS的image_transport订阅图像,跑SLAM或者光流算法,然后把位置估计发给PX4。这部分内容比较多,后面可以单独写一篇。
7.3 从仿真到实飞的过渡注意事项
仿真跑通之后,下一步就是实飞。实飞之前有几个事情必须确认:第一,飞控的固件版本和仿真一致;第二,遥控器已经校准,并且设置了失控保护;第三,GPS和罗盘已经校准;第四,飞行场地开阔,没有干扰。
实飞的时候,先用遥控器手动飞一下,确认姿态控制正常。然后切换到Position模式,测试定点悬停。最后再测试OFFBOARD模式。OFFBOARD模式下,如果ROS节点挂了,飞控会自动切换到Position模式,所以不用担心失控。
注意:实飞有风险,第一次飞建议在空旷场地,并且有经验的人在场。不要一上来就测试OFFBOARD,先用遥控器飞几个起落,确认飞机状态正常。
8. 一些实用脚本和配置备份
8.1 一键启动仿真和MAVROS的脚本
每次开终端手动敲命令太麻烦,我写了一个脚本start_sim.sh:
#!/bin/bash cd ~/PX4-Autopilot make px4_sitl_default gazebo & sleep 10 cd ~/catkin_ws source devel/setup.bash roslaunch mavros px4.launch fcu_url:="udp://:14540@127.0.0.1:14557" & wait保存后chmod +x start_sim.sh,以后直接运行这个脚本就行。注意sleep 10是等PX4启动,如果你的机器慢,可以改成15秒。
8.2 环境变量备份和恢复
环境变量改多了容易乱,我习惯把~/.bashrc备份一份:
cp ~/.bashrc ~/.bashrc.bak如果改坏了,直接cp ~/.bashrc.bak ~/.bashrc恢复。另外,可以把ROS和PX4的环境变量单独写在一个文件里,比如~/.ros_px4_env,然后在~/.bashrc里source这个文件。这样管理起来更清晰。
8.3 常用调试命令速查表
| 命令 | 作用 |
|---|---|
rostopic list | 列出所有ROS话题 |
rostopic echo /mavros/state | 查看MAVROS连接状态 |
rosservice call /mavros/cmd/arming "value: true" | 解锁电机 |
rosservice call /mavros/set_mode "custom_mode: 'OFFBOARD'" | 切换OFFBOARD模式 |
rosrun rqt_graph rqt_graph | 查看节点和话题关系图 |
gz topic -l | 列出Gazebo话题 |
make px4_sitl_default gazebo | 编译并启动PX4仿真 |
这些命令我几乎每天都会用到,建议收藏。
9. 个人经验总结和最后几句
这套环境我从第一次装到现在,前后折腾了大概两周,中间重装过三次系统。最大的体会是:环境变量一定要干净,不要什么都往~/.bashrc里塞。另外,PX4的版本更新很快,不同版本的目录结构可能不一样,遇到问题先看官方文档和GitHub issue,大部分问题都有人遇到过。
如果你在虚拟机里跑,建议给足资源,不然Gazebo会很卡。如果要做实飞,一定要先仿真验证,不要直接上真机。最后,ROS1虽然现在逐渐被ROS2取代,但PX4的ROS1生态还是很成熟,短期内不会过时。先把这套跑通,后面转ROS2也会容易很多。
我在实际使用中发现,MAVROS的px4.launch文件里有很多参数可以调,比如fcu_url、gcs_url、target_system等。如果你有多架无人机,可以通过修改这些参数来区分。另外,PX4的日志文件在~/PX4-Autopilot/build/px4_sitl_default/rootfs/log下面,分析飞行数据的时候很有用。
最后再分享一个小技巧:如果你在编译PX4的时候遇到ccache相关的错误,可以sudo apt install ccache,然后make clean再重新编译。ccache可以加速重复编译,省很多时间。