ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

无人机飞控仿真三件套:SITL+MAVProxy+QGC从环境搭建到航线规划实战

无人机飞控仿真三件套:SITL+MAVProxy+QGC从环境搭建到航线规划实战 做无人机飞控二次开发这一年多我最大的体会是真机调试不是第一选择能在地面上把逻辑跑通就别急着上天。DRONEKIT-SITL、MAVPROXY、QGroundControl这三件套就是我用得最顺手的仿真组合。简单说DRONEKIT-SITL让我的笔记本变成一架虚拟无人机MAVPROXY在后台搬运和翻译MAVLink数据流QGroundControl把这架虚拟飞机的姿态、高度、航点实时投到屏幕上操作起来和真机几乎没差别。这篇文章就把这套模拟飞行环境从安装到自动航线跑通的完整过程记录下来适合刚接触无人机二次开发、或者想先调通算法再碰真机的朋友参考。1. 用软件在环模拟飞行为什么是这套组合1.1 三个工具各自扮演什么角色很多朋友第一次接触仿真时容易懵因为这三个名词听起来都有点“专业”但把它们拆开看就简单了。DRONEKIT-SITL是Software In The Loop的缩写软件在环仿真。它把ArduPilot飞控固件直接编译成电脑上可运行的程序用软件模拟出GPS信号、气压计、加速度计、陀螺仪这些传感器数据同时虚拟出一架飞机的动力学模型。也就是说你运行它的时候电脑里真的“飞”着一架虚拟无人机可以通过MAVLink协议读出它的姿态、位置、速度也可以向它发送解锁、起飞、转向等指令。MAVPROXY是一个MAVLink通信网关。它的核心价值是“转发”和“拆包”。无人机端产生的是MAVLink二进制数据流地面站需要这些数据来做显示和控制。MAVPROXY可以同时接收多个MAVLink源再转发给多个终端而且能在转发过程中记录日志、修改参数、注入指令。你可以把它理解成一个“中间路由器”让数据在多个软件之间顺畅流动。QGroundControl是地面站英文简称QGC。它负责把MAVLink数据翻译成人能看懂的画面——地图、航点、姿态仪表、电池电压、飞行模式全部图形化显示。同时它也承担航线规划任务你可以在地图上直接拖动航点生成一条航线然后一键上传给无人机。 QGroundControl是目前开源飞控领域最主流的图形化地面站之一对ArduPilot和PX4都支持得很好。这三者的关系其实是一条数据链路DRONEKIT-SITL用软件生成一架虚拟飞机MAVPROXY把飞机的数据流转发给外部端口QGroundControl在这个端口上接收数据并做可视化显示。命令行工具、图形界面和通信网关各管一段但组合起来就是一个完整的闭环仿真系统。1.2 脱离真机调试收益和边界在哪有人会问为什么不直接用真机测试成本和安全是最重要的两个原因。一套稍微像样点的四旋翼加上电池、数传、遥控器少说也要几千块万一飞控逻辑写错炸机就是瞬间的事。而软件仿真里把无人机参数调乱、让飞机翻滚坠地只需要重启一个进程成本趋近于零。另一个容易被忽视的价值是可重复性。真机飞行受天气、磁场、GPS信号影响很大同一段代码在上午和下午飞出来的结果可能完全不一样。仿真环境里你可以固定一个起始坐标、固定一组环境参数反复验证同一条航线、同一个控制逻辑跑十次结果都应该一致。这对定位逻辑bug非常有帮助。但也要说清楚边界。仿真毕竟是模型传感器数据是理想化的缺乏真实环境中的磁场干扰、风场突变、GPS多径效应。最简单的例子真机上经常出现的GPS短时丢星仿真里就很难模拟得足够真实。所以仿真通过是基础真机试飞仍然是必要环节。更合理的做法是先用这套软件仿真把逻辑层面的问题全部过滤掉再带着相对可靠的代码去真机上做小范围试飞。2. 环境配置不走弯路安装与端口规划2.1 基础环境与Python虚拟环境三件套里DRONEKIT-SITL和MAVPROXY都是Python生态下的工具QGroundControl是独立编译的图形程序。所以系统环境的第一优先级是把Python环境弄干净。推荐使用Ubuntu 20.04或22.04。Windows下虽然也能跑但权限配置和网络端口的坑比较多。Mac也可以但后续一些ArduPilot固件工具链在macOS上兼容性略差。如果手头只有Windows电脑建议直接装虚拟机性能上完全够用。Python版本选择上3.8到3.10是比较稳的范围。太新的Python版本有时候会和较老的DroneKit库产生兼容问题太旧的又跟不上依赖包。安装之前先确认一下python3 --version pip3 --version强烈建议新建一个虚拟环境不要图省事直接怼到系统Python里。因为DroneKit、pymavlink这些库会有一些特定版本的依赖稍不注意就污染了系统环境后续装其他项目时会出现一堆奇怪的冲突。mkdir ~/uav-sim cd ~/uav-sim python3 -m venv venv source venv/bin/activate之后所有的安装和运行都在这个虚拟环境里进行干净又安全。2.2 安装DRONEKIT-SITL与MAVPROXY先装DroneKit-SITL以及配套的DroneKit库pip install dronekit dronekit-sitlDroneKit-SITL本身会从ArduPilot源码仓库拉取对应的固件并编译所以系统里需要具备基础编译环境。如果之前没装过编译工具先执行sudo apt update sudo apt install build-essential git cmake python3-wxgtk4.0装MAVProxy有两种方式。一种是apt直接装版本相对旧但稳定另一种是pip安装能用上最新功能pip install MAVProxy安装完成后验证一下dronekit-sitl --help mavproxy.py --help能正常打印帮助信息说明两个核心工具已经就位。这一步如果报错大概率是依赖缺失根据提示补装即可。2.3 安装并连接QGroundControlQGroundControl的安装最简单去官网下载AppImage格式的Linux版本给执行权限后直接运行chmod x QGroundControl.AppImage ./QGroundControl.AppImage首次打开会进入一个欢迎界面建议先跳过相机和参数设置的向导。QGC默认会尝试自动检测串口和网络上的无人设备但仿真环境里没有物理链路需要手动配置UDP连接。这里的端口规划非常关键。整条数据链路的默认约定是DRONEKIT-SITL监听TCP端口5760MAVPROXY连接这个TCP端口然后通过UDP端口14550向外转发。QGC连接时就走UDP 14550这个口。点开QGC右上角的齿轮图标进入“Comm Links”设置添加一个UDP连接端口号填14550点击连接。此时如果MAVPROXY已经在运行并转发数据QGC左侧就会弹出模拟飞机地图上会出现home点的绿色图标。3. 完整实操从冷启动到自动航线3.1 启动SITL并验证MAVLink数据流安装完成只是第一步真正复杂的是启动流程和端口对接。我的习惯是先开SITL再开MAVPROXY最后连QGC按顺序来不容易乱。开一个终端激活虚拟环境启动模拟四旋翼dronekit-sitl copter-3.3 --home35.123456,-120.123456,0,180这条命令的含义是启动一架模拟三号版本固件的四旋翼起始坐标设为北纬35.123456、西经120.123456海拔0米机头朝向正北。home坐标后面的数字180表示初始偏航角单位是度。如果启动成功终端会持续输出姿态、GPS状态等仿真信息。看到类似“GPS lock”的字样说明虚拟GPS已经完成了定位。注意这个过程中电脑会编译下载一些组件第一次跑可能比较慢耐心等待即可。此时SITL已经在TCP 5760端口等待连接。再开一个新终端激活虚拟环境启动MAVPROXYmavproxy.py --master tcp:127.0.0.1:5760 --out udp:127.0.0.1:14550--master tcp:127.0.0.1:5760表示从本机的TCP 5760端口读取数据源也就是SITL。--out udp:127.0.0.1:14550表示把数据以UDP形式转发到本机的14550端口QGC后续就从这里收数据。MAVPROXY启动后会进入交互式命令行模式。不要急着操作先输入status查看数据状态。正常情况应该能看到MAVLink数据线在持续跳动说明数据流已经通了。另一个常用验证命令是mavlink info可以查看当前数据收发数量和丢包率。如果丢包率持续为0数据链路就是健康的。3.2 用MAVPROXY命令行完成解锁、起飞与航线链路打通之后在MAVPROXY命令行里就可以像操作真机一样操控这架虚拟飞机了。先把飞行模式切到GUIDED也就是“自动驾驶指令引导”模式mode guided接着解锁电机arm throttle这里想多解释一下为什么需要先切模式再解锁。ArduPilot默认情况下禁止在STABILIZE等手动模式之外解锁起飞因为它需要知道“你要干什么”GUIDED模式会基于自动驾驶指令来控制飞机让后面的takeoff指令可以被正确执行。如果先解锁再切模式有些固件版本会直接拒绝起飞指令。解锁成功后会看到“ARMED”反馈。然后输入起飞高度单位是米takeoff 10虚拟飞机会开始缓慢爬升到10米高度MAVPROXY会打印当前高度和姿态数据。这个时候切换到QGC窗口就能看到代表飞机的三角形图标已经从地面升起来了姿态仪表盘也在实时变化。如果要让它飞到指定经纬度位置可以用guided命令guided 35.123456,-120.123456,10这相当于在地图上指定一个目标点飞机会自动调整机头方向并飞过去。航线规划也可以用命令输入多个航点不过图形化操作在QGC里更直观我一般只在调试命令行接口时才这么做。这里有个实操心得MAVPROXY命令行是排查数据链路问题的首选工具因为它在最底层任何数据流异常都能第一时间暴露。3.3 用DroneKit脚本实现自动化任务命令行模式用来验证链路没问题但真正做自动化测试时还是要靠DroneKit写Python脚本。先看一段完整的起飞并飞向目标点的代码from dronekit import connect, VehicleMode, LocationGlobalRelative import time # 连接到MAVPROXY转发的UDP端口 connection_string 127.0.0.1:14550 print(Connecting to vehicle on %s % connection_string) vehicle connect(connection_string, wait_readyTrue) # 读取基本信息 print(Vehicle initialized) print(Autopilot version: %s % vehicle.version) print(Mode: %s % vehicle.mode.name) # 切换到GUIDED模式 vehicle.mode VehicleMode(GUIDED) # 解锁电机 vehicle.armed True while not vehicle.armed: print(Waiting for arming...) time.sleep(1) print(Vehicle armed!) # 起飞到10米高度 target_altitude 10 vehicle.simple_takeoff(target_altitude) # 等待达到目标高度 while True: current_alt vehicle.location.global_relative_frame.alt print(Altitude: {:.2f}.format(current_alt)) if current_alt target_altitude * 0.95: print(Reached target altitude) break time.sleep(1) # 飞行到指定经纬度 target_location LocationGlobalRelative(35.123456, -120.123456, target_altitude) vehicle.simple_goto(target_location) # 持续监控一直到达到目标点附近 while True: dist abs(vehicle.location.global_relative_frame.lat - 35.123456) if dist 0.0001: print(Reached target location) break time.sleep(1) print(Returning to launch) vehicle.mode VehicleMode(RTL) time.sleep(20) vehicle.close()这段脚本的逻辑非常清晰连接、读信息、切模式、解锁、起飞、goto目标点、返航、关闭连接。其中几个重要的点wait_readyTrue参数的作用是让连接过程等待飞控参数下载完成再继续执行后面的代码。如果去掉这个参数可能出现飞行模式显示错误或高低空切换异常。simple_takeoff函数是DroneKit封装好的命令底层其实是发送MAVLink的MAV_CMD_NAV_TAKEOFF指令。执行它之前飞机必须在GUIDED模式下且已解锁。LocationGlobalRelative是相对高度坐标系第二个参数是地面高度我们传10表示相对家点高度10米。如果要用海拔绝对高度就得用LocationGlobal但一般航线任务都建议用相对高度避免地形变化导致高度异常。vehicle.close()不能忘。很多朋友跑脚本时出现“端口被占用”的报错就是因为上一次实例没有正常关闭。仿真环境虽然重启SITL就能解决但养成写资源释放的好习惯总是没错的。3.4 在QGroundControl里图形化监控脚本跑起来的时候切到QGC窗口你看到的画面会非常直观。地图上飞机图标沿航线运动右上角的高度条实时变化左侧的飞机状态面板会显示当前模式、GPS卫星数、速率、电池电压等。QGC还有一个很好用的功能是手动航点规划。地图上右键点击选择“添加航点”拖出几个点再把高度设为10米或20米保存后点“上传航线”。如果MAVProxy数据链路正常飞机会按照这条航线自动飞行。这个过程不需要写一行代码非常适合演示和快速验证航线逻辑。地图上航点用右键拖拽的方式添加移动时会自动吸附到鼠标位置。第一次使用建议把高度设低一些比如10米让飞机始终在可视范围内。在QGC里还能查看飞控参数。齿轮图标进入“参数”面板搜索框输关键词就能找到对应的参数项。比如调整PID参数时可以直接在QGC里修改RATE_PIT_I、RATE_PIT_P这些项改写后飞控会在下次启动或指令下生效。4. 仿真调试中的常见坑与速查表4.1 连接不上先按这几个顺序排查三件套组合最常遇到的问题就是“明明都启动了但QGC没有画面”。我遇到过的、以及身边朋友遇到过的基本可以归纳成三类问题。第一类是顺序问题。如果先启动QGC再启动MAVPROXY和SITLQGC可能已经优先占用了UDP端口导致数据无法送达。建议严格按SITL、MAVPROXY、QGC的顺序来或者在QGC里断开连接再重新连接一次。第二类是端口遗漏。很多人启动MAVPROXY时只写了--master tcp:127.0.0.1:5760忘了带--out udp:127.0.0.1:14550结果SITL和MAVPROXY自己通信正常但QGC收不到任何数据。这个参数遗漏很隐蔽因为MAVPROXY不会报错只有打开QGC才会发现问题。第三类是虚拟环境里启动MAVPROXY后没有保持终端常驻。命令行模式下如果输入了quit或者不小心按到CtrlC整个MAVPROXY进程退出数据链路自然就断了。仿真调试时建议单独开一个屏幕区域放MAVPROXY方便随时观察。如果以上都检查过还是不行用系统工具看看端口是否实时监听ss -ulnp | grep 14550有输出说明UDP 14550端口在监听数据在哪一步断了再去排查哪一步效率会高很多。4.2 模拟飞行表现异常的常见原因链路通了之后飞行表现怪异是另一个集中的问题来源。飞机解锁后一直在地上打转不抬头最常见原因是SITL的传感器数据出现异常特别是gyro calibration没有正确完成。可以重新启动SITL或者等待仿真环境自动完成传感器校准。更常见的一种情况是用户在MAVPROXY里发了manual模式指令导致飞控处于手动操控状态但没有遥控器信号输入飞机自然就只能在地上打转。飞机原地起飞后一直撞向同一个方向优先检查home坐标和目标点坐标的数值格式。--home参数里的经纬度必须是合法的全球坐标如果填了一个错误格式的位置飞控的EKF滤波器会报错飞机姿态就会乱漂。这个坑我踩过很多次后来养成了一个习惯坐标参数一律用十进制格式并且先在Google地图上复制真实位置不要凭感觉输入。脚本中takeoff后飞机不执行多半是mode没有切换成功或者GPS没有锁定。在脚本里最好加一段等待逻辑确认vehicle.mode.name GUIDED之后再触发simple_takeoff。仿真飞行速度比真实时间快很多DRONEKIT-SITL默认以接近真实时间的速度运行但有些版本在特定固件上会以几倍速运行。如果你发现整个任务在十几秒内就完成了说明处于加速模式。对于大多数逻辑测试加速模式没问题但如果涉及实时图像处理或通信延迟测试就必须加上--speedup 1参数让仿真保持真实时间速度。4.3 常用命令速查表把过程中最常用的命令整理成一个速查表建议截图收藏。操作命令说明启动模拟四旋翼dronekit-sitl copter-3.3 --home纬度,经度,海拔,朝向机型、坐标可自定义启动MAVProxymavproxy.py --master tcp:127.0.0.1:5760 --out udp:127.0.0.1:14550必须带out参数查看数据流状态status数据线跳动表示链路正常切换GUIDED模式mode guided自动驾驶指令引导模式解锁电机arm throttle必须切到GUIDED后执行起飞takeoff 10单位是米飞向指定坐标guided 纬度,经度,高度需要MAVProxy较新版本查看航点列表wp list可确认航线是否上传成功修改飞控参数param set 参数名 数值比如param set RATE_PIT_P 0.1保存参数param save 文件名仿真中同样适用提示MAVProxy的交互式命令是高度可扩展的。你可以用module load加载不同的模块比如module load console会弹出一个字符图形界面的姿态显示器调试时特别实用。5. 进阶多机仿真、硬件在环以及我的几点体会5.1 多机协同仿真怎么起单机跑通之后多机编队仿真是很多做集群算法的朋友会遇到的场景。多机仿真的核心是启动多个SITL实例并且给每个实例分配不同的数据端口避免冲突。dronekit-sitl copter-3.3 --home35.123456,-120.123456,0,180 --port5760 dronekit-sitl copter-3.3 --home35.123456,-120.123456,0,180 --port5770第二个实例的TCP端口设为5770其他参数保持相同。然后在MAVPROXY里分别连接这两个数据源并转发到不同的UDP端口mavproxy.py --master tcp:127.0.0.1:5760 --out udp:127.0.0.1:14550 mavproxy.py --master tcp:127.0.0.1:5770 --out udp:127.0.0.1:14560启动两个QGC实例分别连14550和14560就能同时看到两架虚拟飞机。如果你用的是ArduPilot官方SITL还可以通过--instance参数自动分配端口具体以你当前版本--help输出为准。多机仿真对电脑性能有一定要求建议内存至少16G。5.2 从软件在环到真机实践要注意什么SITL和真实飞行之间的差异值得单独强调一遍。传感器模型仿真得再好也无法完全复现真实环境中的磁场分布、地磁干扰、GPS多径效应、气压计受风影响等现象。在SITL里调好的PID参数到真机上往往需要重新微调。这个不是仿真环境的问题而是所有仿真系统的固有限制——模型的复杂度再高也不可能完全等于现实。但是SITL有一个优势是硬件在环HIL没有的完全免费、零风险、可大规模扩展。硬件在环需要一块真实飞控板通过模拟器把仿真传感器数据灌进飞控的串口或USB口让飞控以为自己在真实飞机上。这种方式更贴近真机但硬件成本和环境准备复杂度都上了一个台阶。对于绝大多数算法验证场景先用SITL跑通逻辑再用HIL做关键环节验证最后上真机小半径试飞是比较稳妥的路径。5.3 关于这套模拟环境我的几点实操体会最后说几个我在实际使用中总结出来的经验。第一先命令行后图形界面。每次搭新环境都先让MAVPROXY命令行里能看到status、mavlink info的输出再打开QGC。原因很简单QGC界面信息丰富但出现问题时定位慢不如命令行直接。等链路确认干净了再用图形界面做数据可视化。第二参数乱改了要记得保存。仿真环境里参数改坏了不会炸机但调试效率会下降。我一般改完一组有意义的参数会尽快用param save存一份标注文件名和日期方便回溯。有时候来回对比不同参数组合时这份手动保存会救你一命。第三把SITL当成一台“可重置的慢速真机”。仿真环境最大的价值不是替你真机飞行而是让你把代码里的低级错误全部暴露出来。这个角度想清楚之后你会更重视每次练习的复现性。实测下来用这套三件套跑完10次自动航线任务逻辑bug基本能在上真机前被过滤掉一大部分这种效率是盲目开机试飞很难达到的。如果你刚开始接触无人机开发我建议从今天这篇内容的第一步开始把环境搭好用MAVPROXY命令行飞一次再用DroneKit脚本飞一次最后把QGC连上整个过程两个小时左右就能完成。等这几条链路都通了后续无论做航点规划、编队算法还是故障检测你都会有一个非常顺手的试验台。
返回列表