本文为《无人机飞控固件开发教程》系列视频的辅助资料,已经在“网易云课堂”上线 , 链接如下: https://study.163.com/course/introduction/1209568864.htm?share=1&shareId=1448054983
无人机调试,飞控硬件定制、固件修改,日志分析,请QQ联系:3500985284
无人机固件编程与平常的纯软件编程不同,它的测试受限于天气、光线、空域等因素,测试成本非常高,因此对于飞控代码的控制逻辑的测试,应该先在仿真环境上测试,然后再进行实际飞行测试,这样可以大大提高工作效率。本文讲述如何建立APM软件仿真环境。
2021年3月6日更新:最近我在日常的无人机研发中发现,熟练掌握本节课的软件仿真方法,极大地节省了外场测试人员的工作量,绝大部分情况下仿真没有问题的固件,外场实际测试的效果都不会太差。在有空调或者暖气的房间里通过仿真找出逻辑上的大部分bug,远比在烈日下或者寒风中改代码舒服。
一、创建自动运行脚本
1、在C:\cygwin64\home\计算机用户名\目录下创建一个新的文件夹,重命名为“sim”;
注意,以你的计算机用户名为“AS123”为例,如果你打开“ C:\cygwin64\home\ ”文件夹,你会发现里面已经有一个名称为“AS123”的文件夹(这个文件夹应该是你第一次打开cygwin64软件时系统自动创建的),你需要做的是在 “ C:\cygwin64\home\ AS123”文件夹里新建一个“sim”文件夹。视频教程中,我的那个虚拟机的用户名是“FC”,从而我是在 “ C:\cygwin64\home\FC”文件夹下新建“sim”文件夹。
2、在sim文件夹中新建一个txt文件,输入如下内容:
# 特别注意,当你在将下面的一行命令复制到txt文件中时,一定不要在其下面再添加一个空行,
# 否则会被识别成两行命令,并且由于第二行是一个空行,没有实际的命令,从而运行时报错
/cygdrive/d/ardupilot/Tools/autotest/sim_vehicle.py -v ArduCopter
注:这句话的意思就是:运行“/cygdrive/d/ardupilot/Tools/autotest/”文件夹下的“sim_vehicle.py”文件,输入参数“-v ArduCopter”指定了我们运行的是多旋翼仿真。
如果大家要仿真“直升机”固件,由于直升机和多旋翼共用一套代码,并且控制逻辑十分相近,因此仿真时只需要在上述多旋翼仿真命令的结尾加上“-f heli”即可,也就是告诉仿真环境,要仿真的机架类型为直升机。
/cygdrive/d/ardupilot/Tools/autotest/sim_vehicle.py -v ArduCopter -f heli
如果大家要仿真固定翼固件,就将“ArduCopter”改为“ArduPlane”,修改后文件内容如下:
/cygdrive/d/ardupilot/Tools/autotest/sim_vehicle.py -v ArduPlane
如果仿真的是“无人车”,那么修改方法如下:
/cygdrive/d/ardupilot/Tools/autotest/sim_vehicle.py -v APMrover2
仿真时还支持很多机架类型,大家可以通过查看“ardupilot/Tools/autotest/pysim/vehicleinfo.py”的1~281行看看还支持哪种类型设备的仿真。
注意,上述命令中“/cygdrive/d”中的“d”指的是“电脑的D盘”,如果你把飞控源代码放到了E盘根目录下,那么这个“d”应该改为“e”(注意是小写!)。
3、将这个文件保存为“s”,并删除“.txt”后缀,我们将这类文件称为“脚本文件”;
4、打开Cygwin64 Terminal,输入如下命令:
// 进入sim目录
cd sim
// 运行名称为“s”的脚本文件
./s
5、系统将自动开始编译仿真代码,编译完成后,仿真代码将自动运行。
如果这一步报错(比如No module named pymavlink、task in ‘objs/AP_NavEKF2’ failed、错误H_MAG[16]等等),请看看本页面底部的“疑难解答”章节,基本上本章节里大家常遇到的问题的解决方法都在里面。以后的所有章节对应的网页资料里底部也都是对应章节内容的“疑难解答”。为了让你看到这段文字,我把这段话的字体调的已经很大了,不能再大了。
如果里面没有你遇到问题,并且经过一定的独立尝试后依然无法解决问题,请到我们的微信群里提问。
注意:仿真时,其实是重新编译了一次固件,不过这个固件的编译目标是SITL,这个固件跟实物固件使用的是同一套源代码,二者关系如下图所示:

注意,按照上面的脚本文件运行时,会自动重新编译生成“仿真专用固件”,然后再自动运行此“仿真专用固件”,因此如果你修改了飞控程序,运行上述脚本文件后,你修改的地方就会被编译并仿真起来,不需要进行额外的操作。
但是如果你不想每次都重新编译一遍,可以在上述脚本后面加上“-N”参数,这样仿真环境会直接运行上次编译出的仿真固件,节省不少时间:
// 注意,下面的命令只是在前面的命令结尾加了“-N”
/cygdrive/d/ardupilot/Tools/autotest/sim_vehicle.py -v ArduCopter -N
// 我习惯的用法是:仿照前面的做法,新建一个sn文件,填入这个结尾加了“-N”的命令,当我没有修改代码,只是想运行之前编译过的仿真固件时,直接执行此脚本即可:
./sn
二、进行仿真飞行
1、打开MissionPlanner,软件将自动连接虚拟无人机(如果没有自动连接,删除飞控源代码文件夹ardupilot下的build文件夹,重新从本文第一步的第4步运行);
2、规划一个自动航线
3、输入解锁命令:
arm throttle
注意,APM固件不允许在“AUTO模式”下起飞,如果在AUTO模式下输入“arm throttle”,仿真环境将提示“APM: PreArm: Mode not armable”。正确的做法是先将飞控切换到“Loiter模式”、“AltHold模式”、“Stablized模式”这三种模式中的任意一种,然后解锁起飞,起飞后再切到“AUTO模式”。
3、推油门中位以上,起飞
rc 3 1700
4、切换自动模式
mode auto
如果仿真中出现如下图所示“re-requesting WPS [0, 1, 2, 3 ,4]”,不用管它,这是正常的,并且目前没有找到可以关掉这个提示的方法。

上述几个命令在普通功能仿真中基本够用,但是仿真飞行的命令远不止这几个,更多功能请大家自行研究APM官网对应页面,链接如下:
https://ardupilot.org/dev/docs/using-sitl-for-ardupilot-testing.html
上面这个链接是APM官网的开发者页面,纯英文的,但是难度不大,这个页面中包含了不少有趣的仿真技巧,请大家主动探索一下。
另外,请大家不要陷入这样一个误区:我讲过什么,你会什么,我没讲过的,你连主动出击去探索的兴趣都没有,那将是我的失败,你的悲哀。
三、仿真技巧
1、列出仿真中所有可用命令
如下图所示,仿真环境运行起来后,输入“help”命令并按回车后,会自动列出所有可用命令。

如下图所示,在某个命令后面添加“help”参数,系统会自动列出该命令可接受的参数列表,非常方便,这时候根据各个参数名基本可以推断出其用法,请大家大胆尝试,搞研究就是这样的。

2、设置仿真起始位置和初始航向
我们可以将仿真的起始位置修改为地球上的任何一个位置,同时还可以修改初始航向,方法如下:
a、打开“ardupilot\Tools\autotest”文件夹下的“locations.txt”文件,在第二行添加一个新的位置点。注意,如下图所示,这个文件给出了很明确的注释,每一行表示一个位置点。我这里添加了一个名称为“NFCY_Home”、纬度为“36.123456”、经度为“112.56789”、海拔高度为200米、初始航向为30度的位置点(纬度:北纬为正,南纬为负;经度:东经为正,西经为负);

注意:1、上述经纬高以及航向数据间是用“英文逗号”隔开的,注意不能用“中文逗号”或者“空格”隔开。2、“=”前后不能有空格。对于格式问题,请尽量严格按照已有的例子的方式写,不要自己想当然,否则会经常自己坑到自己。
b、打开本节课中我们建立的那个名称为“s”的仿真脚本文件,在那一行命令的结尾添加一个命令:“-L 你的位置名称”,以我们的这个例子为例,添加完后脚本命令如下:
/cygdrive/d/ardupilot/Tools/autotest/sim_vehicle.py -v ArduCopter -L NFCY_Home
c、重新开始仿真,连接MissionPlanner后可能不会显示正确的home点,在“飞行计划”页面,点击右侧边栏中的“起始位置”四个字,即可跳转到刚才设置的位置。

3、在仿真飞行中使用“定高设备”(模拟出超声波或者毫米波雷达的效果)
如果想在仿真飞行中添加“定高设备”的功能,模拟出超声波或者毫米波雷达的定高效果,可以在运行仿真程序并通过MissionPlanner连接上模拟器后,在全部参数列表中将如下参数设置一下:
SIM_SONAR_SCALE 10 // 注意,这个参数是仿真固件特有的,实物固件中没有这个参数
RNGFNDA_TYPE 1 // 设置定高设备类型,请设置为1,在仿真环境下指定为其他类型的定高设备类型是没有意义的,本质上模拟器只是模拟出了一个高度值,跟外设类型没有关系
RNGFNDA_SCALING 10 // 就按照这个设置就行,与上面的SIM_SONAR_SCALE对应
RNGFNDA_PIN 0 // 同理,仿真环境,不要当真
RNGFNDA_MAX_CM 5000 // 定高设备最远探测距离,单位:厘米,这个参数可以自行调整
RNGFNDA_MIN_CM 0 // 定高设备最近探测距离,单位:厘米,这个参数可以自行调整
注意:
1、参数修改后不要忘了点击右上角的“写入参数”按钮!
2、参数修改后,请关闭MissionPlanner、关闭仿真环境,然后重新运行仿真环境,这时定高设备才会生效。
4、分析仿真飞行的日志
仿真飞行跟实物飞行一样,都会产生标准的日志,不过仿真飞行的日志是直接保存在电脑里的,不需要再通过MissionPlanner下载。日志在本节课第一步我们创建的那个自动化运行脚本所在文件夹中的“logs”文件夹中,其内部的日志按照顺序依次排列,名称最大的日志就是最后一次仿真生成的日志。
日志分析教程见如下网页:https://www.bilibili.com/video/BV1Bg4y1B7cU/
注意,APM支持很多种仿真方法,本课程只讲述了其中最简单也最常用的方法,大家有兴趣的话可以到APM官网的开发者页面自行探索:https://ardupilot.org/dev/docs/simulation-2.html
四、疑难解答
1、编译过仿真代码后,飞控整个代码工程的编译目标就变成了“仿真固件”,而不是我们之前章节中设置的针对某款飞控硬件(比如fmuv3)设置的编译目标。因此,我们通常的做法是在Eclipse中添加一个编译目标设置命令,每次如果编译过仿真代码,在编译实物硬件代码前,先运行一下这个设置命令,命令如下:
configure --board fmuv3
设置完后,Eclipse右侧界面如下图所示(注意,添加这个命令的方法跟添加“copter”的方法是一样的):


a、这样,双击“configure –board fmuv3”后,等效于在cygwin64命令行中运行了“./waf configure –board fmuv3”,即将编译目标设置为fmuv3。
注意,视频教程中这个命令后面还多了“–no-submodule-update”,这个是不需要的,以本网页为准。(注意,由于视频剪辑一次比较麻烦,因此有更新时我会优先更新到网页中,大家遇到二者冲突的地方,都以网页为准)
b、然后,再双击“copter”,等效于运行了“./waf copter”,就开始编译多旋翼固件了。
2、解锁时,提示“PreArm:Throttle too high”的解决办法
如果你尝试解锁时,提示“ PreArm:Throttle too high ”,这个意思是说“解锁前自检,发现油门过高,禁止解锁”,一般情况下,飞控默认参数下油门通道的PWM值范围为1100~1900,可能你的模拟器中默认的初始油门是1500,从而解锁时飞控发现油门不为最低,禁止解锁;另外,也有可能是你刚仿真的时候,将油门推到了一个较大的值,然后自动返航降落后,遥控器油门通道忘记手动收到零位了。

解决办法:在解锁前,先输入如下命令,把油门通道设置为零油门(一个小于1100的值,但是也不能太小,有些情况下,飞控的遥控器的失控保护门限是油门小于950)。
rc 3 1000
3、有时打开MissionPlanner后不会自动连接仿真环境
有时候打开MissionPlanner后不会自动连接仿真环境,请按照如下步骤尝试解决:
a、在仿真环境已经运行起来后,打开MissionPlanner,按照下图所示选择UDP,并点击“连接”按钮;然后会弹出选择端口的窗口,直接点击“OK”,一般情况下就能连接成功;


b、上一步如果不行,关闭MissionPlanner,并关闭仿真环境,删除源代码中“ardupilot/build”文件夹,重新运行仿真环境再试试。
4、开始仿真时提示“ImportError: No module named pymavlink”
这个提示的意思是我们缺少一个名为“pymavlink”的python库,解决方法是:打开cygwin64,然后输入如下代码,自动下载“pymavlink”库,然后就可以正常仿真了:
pip install pymavlink
# 如果运行上述命令后还不行,则尝试运行下面这条命令
pip3 install pymavlink
如果其中的下载步骤非常慢,请参考如下链接,体会一下下载速度飞一般的感觉:
https://jingyan.baidu.com/article/2f9b480d5480c500ca6cc24b.html
请大家明白遇到问题后解决问题的基本思路:
1、发现pip下载速度慢;
2、反复尝试都是下载失败;
3、怀疑是不是网络的问题,发现下载其他东西很快,就是这个速度慢;
4、打开百度,输入“pip 下载速度慢”,然后按回车,发现第一个链接里的方法就完美解决了此问题。
5、仿真时提示“MAV -> link 1 down”
如下图所示,仿真时可能遇到卡住一段时间后提示“MAV -> link 1 down”的情况。我发现在仿真时,将参数“RCx_OPTION”修改为一个非默认值后(比如将RC7_OPTION改为自定义的值102),下一次仿真时就会出现这种问题。

解决方法如下:
1、如果在某次正常仿真时修改过“RCx_OPTION”之类的参数,那么在关闭仿真环境之前将这个参数改为默认值,这样下次仿真时就没有问题(特别注意,RC7_OPTION的默认值不是0,而是7);
2、如果已经不小心关闭了仿真环境,就将“C:\cygwin64\home\计算机用户名\sim”文件夹下的“eeprom.bin”文件删除,这样等效于将实物飞控的FRAM存储器芯片全片擦除,下次重新开始仿真时系统会自动新建这个文件并将各个参数恢复默认值(之前修改的参数都没有了,因此即使是仿真系统,也请经常及时备份参数,好的习惯将使你受益无穷);
3、有时候,偶发这个link 1 down的问题,这时候重启一下电脑可能解决问题;
4、有时候,也可能是你按照第一节课中的方法建立的编译环境不完整(网络不稳定导致的),导致仿真出问题,这时候使用第一节课中的脚本文件重新建立编译环境,可能就解决问题了。
6、提示“错误:’H_MAG[16]’ … 有些警告被当作是错误” 或者 “task in ‘objs/AP_NavEKF2’ failed ”


上述两种报错都是由于cygwin64环境内部使用了较新的gcc导致的,这时会出现编译实物固件时可以编译成功,但是仿真时不行,这是由于仿真时是使用cygwin64环境内部的gcc,而编译实物飞控固件时使用的是我们建立编译环境时单独安装的那个gcc。(注意,由于Cygwin64不支持通过脚本文件安装软件包时指定软件包的版本,因此使用第一节课的脚本建立编译环境时无法避开这个坑)
解决方法很简单,将cygwin64环境内的gcc版本号降级即可,步骤如下:
(1)下载cygwin64安装工具:https://cygwin.com/setup-x86_64.exe,下载后的文件名为“setup-x86_64.exe”;
(2)双击它,然后一路点击“下一步”,如果中途出现“Could not download mirror sites list”,点击“确定”即可;
(3)出现下图所示窗口后,在“User URL”后面的框里输入下面的链接,然后点击“Add”按钮,然后选中刚添加的链接,再点击“下一步”;
http://mirrors.163.com/cygwin/

(4)在下图窗口中,先将“View”从“Pending”改为“Full”,然后在Search框中输入“gcc”,之后在搜索出的列表中将“gcc-core”、“gcc-g++”、“libgcc1”三个包的版本号改为“9.3.0-2”,之后一路点击“下一步”到结尾即可;
注意:cygwin软件在不断更新,如果大家发现下面的版本号中没有“9.3.0-2”,那么选择“7.4.0-1”版本也是可以的。

(5)最后弹出的窗口中,勾选“Create icon on Desktop”和“Add icon to Start Menu”,然后点击“完成”;
(6)删除“ardupilot/build”文件夹,防止之前编译产生的临时文件影响编译结果;
(7)重启一下电脑,避免某些修改没有生效。
注意,这里将GCC降级,并不会影响实物飞控固件的编译!放心降级即可。(本质上,编译实物飞控固件时,使用的是arm版GCC,而编译仿真固件时,使用的是PC版GCC。这也是导致实物固件编译没问题,但是仿真固件编译出错的本质原因)
7、仿真环境连接MissionPlanner时卡在“Checking for Param MAVFTP”一直过不去
最新版的飞控固件仿真时,连接MissionPlanner时会卡在下图所示的小窗口处,这是飞控的新的功能,但是仿真环境好像不支持它,因此卡住了。处理办法:直接点击这个小窗口里的“取消”按钮,然后等待几秒就可以连上了。

8、仿真时修改的代码疑似没有生效
如果我们在一次仿真后直接关闭仿真环境,然后修改了部分代码,之后重新开始仿真,这时候有一定的概率会发现修改的代码没有生效,仿真环境好像还是在运行修改之前的代码。这可能是由于上次仿真的后台程序没有真正退出导致的。
解决方法:如下图所示,在windows的“任务管理器”中手动将仿真进程结束掉即可。(注意,如果你仿真的是固定翼程序,这个进程名可能叫“arduplane.exe”,其他类型的程序以此类推)

9、运行仿真脚本时报错:“a bytes-like object is required, not ‘str’”
出现这个报错,原因有如下几种可能,请逐个尝试:
1、有时候明明之前仿真正常,突然某次仿真的时候就报这个错误,并且往上翻找后没有发现其他报错,这时候只需要将ardupilot/build文件夹删掉然后重新开始仿真即可。导致这个报错的可能原因是build文件夹中之前编译的中间文件与本次编译冲突,导致出的问题;
2、APM官方从Copter-4.1.0开始更换了编译器的版本,从而使用Copter-4.1.0之前的脚本建立的编译环境无法编译Copter-4.1.0之后的源代码,同样使用Copter-4.1.0之后的脚本建立的编译环境也无法编译Copter-4.1.0之前的源代码(详见课时1)。否则就会报“a bytes-like object is required, not ‘str’”的错误,因此请检查一下自己的编译环境版本与源代码版本是否对应;
3、运行仿真脚本时,如果出现如下图所示的报错,也可能是由于你在创建仿真脚本文件时多打了一个回车,从而在第二行产生了一个空行,进而运行环境将其识别成两行命令,而第二行命令又是一个空命令,随即报错。解决方法很简单,删除此空行即可。

10、运行仿真脚本时提示:“No such file or directory”
如下图所示,运行仿真脚本时提示没有找到“sim_vehicle.py”这个文件。经检查发现,是由于建立仿真脚本时,漏掉了第一个字符“/”,从而由绝对路径变成了相对路径,下图中已经在“~/sim”目录下,从而调用时实际上是去“~/sim/cygdrive/d/ardupilot/Tools/autotest”目录下找“sim_vehicle.py”文件,当然找不到。
解决方法:在仿真文件头部加上那个“/”,并且以后复制代码时看清楚了,不要再漏掉任何字符了(举一反三:也不要多复制字符)。

11、提示“由于目标计算机积极拒绝,无法连接。sleeping”

这是由于仿真程序无法打开图形窗口导致的,应该是编译仿真环境建立过程中缺少了某些功能,可以通过手动安装“xming”来解决,“xming”安装程序如下:
链接:https://pan.baidu.com/s/116hlseBcEZoDVNBbrfedww
提取码:nfcy
注意,安装“xming”后重启一下电脑后生效。
12、仿真时提示编译完成,但是启动仿真时报错(如下图所示)
这种情况下,通过重装“mavproxy”这个软件即可解决(这个软件在第一节课里安装过)。

无人机调试,飞控硬件定制,固件修改,log日志分析,飞控驱动添加
请QQ联系:3500985284
微信公众号:“怒飞垂云”,扫描下图添加
