(2)学习ArduPilot源码——shetch范例
我的tip:在了解了ArduPilot源码的基本信息和架构后,下面开始实战,下面开始学习第一个范例。
你自己探索这些代码的第一步是使用libraries的例程。根据arduino的传统,我们的大部分libraies都会有范例。范例(“sketch”)是写成cpp文件的主程序。
认识Ardupilot使用的API库和协议是理解代码的前提,因此使用范例是入门的好方法。刚开始你应该阅读、编译和运行下面的库的范例:
· libraries/AP_GPS/examples/GPS_AUTO_test
· libraries/AP_InertialSensor/examples/INS_generic
· libraries/AP_Compass/examples/AP_Compass_test
· libraries/AP_Baro/examples/BARO_generic
· libraries/AP_AHRS/examples/AHRS_Test
例如,下面命令可以编译和安装AP_GPS范例到Pixhawk上:
cdl ibraries/AP_GPS/examples/GPS_AUTO_test make px4-clean make px4-v2 make px4-v2-upload
我的tip(自己实践的经历):首次运行第二个命令时
make px4-clean
可能会出现下面的错误(我在ubuntu14.04上运行出现了下面的错误),提示找不到gawk
这是因为缺少一个虚拟包,在联网的情况下执行下面的安装命令
sudo apt-get install gawk
安装好gawk后,继续执行
make px4-clean
就可以正常编译了,如下图所示,会显示编译进度,编译可能会花挺长一段时间
编译到后面可能会提示一些错误和失败,可以先不用管,继续执行下一步命令
make px4-v2
接下来又是漫长的等待,真的要很久。
经过漫长的等待,最后发现有一些错误提示,这到底怎么解决?这些错误提示会影响到后面的操作吗?到目前的学习为止或许我们还没能力去解决,我们先带着这样的问题继续学习,或许后面积累的东西多了就会柳暗花明又一村。
电脑连接好飞控pixhawk,继续执行命令:
make px4-v2-upload
最后发现又是一堆错误,很正常,编译总会遇到这样那样的错误,根据提示试着解决,要是解决不了,后面继续学习想办法解决。
一旦你上传范例你就可以通过连接控制台查看输出。使用什么样的控制台由硬件板决定。在PX4板(比如PX4v1和pixhawk)就是USB连接器。
比如,如果你安装了mavproxy代理,你可以这样操作,在linux上连接pixhawk:
mavproxy.py--setup--master/dev/serial/by-id/usb-3D_Robotics_PX4_FMU_v2.x_0-if00
使用--setup选项使mavproxy进入原串行模式,而不是执行MAVlink模式。这就是范例中你需要做的。
理解范例代码
当你阅读范例代码(比如GPS_AUTO_test代码)就会留意到一些奇怪的事情:
l 它声明了一个‘hal’变量作为引用
l 这些代码很粗糙,没有好评
l setup()函数和loop()函数
hal引用
每个使用AP_HAL特征的文件需要声明一个hal引用。这给了进入AP_HAL的入口,AP_HAL提供了所有硬件特定函数的入口,包括打印消息到控制台,休眠和使用I2C和SPI总线。
真实的hal变量是隐藏在特定的AP_HAL_XXX 库里,在每个文件的引用只是提供了获取hal的便利方法。
最常用的hal函数是:
· hal.console->printf() and hal.console->printf_P()to print strings (use the _P to use less memory on AVR)
· hal.scheduler->millis() and hal.scheduler->micros()to get the time since boot
· hal.scheduler->delay() andhal.scheduler->delay_microseconds() to sleep for a short time
· hal.gpio->pinMode(), hal.gpio->read() andhal.gpio->write() for accessing GPIO pins
· I2C access via hal.i2c
· SPI access via hal.spi
继续去看一下libraries/AP_HAL目录,了解在HAL上可用的所有函数列表。如下图所示
setup()和loop()函数
你或许会发现每个范例都会有setup()函数和loop()函数。在硬件板启动时就会调用setup函数,真实的调用来自每个板的HAL,因此main()函数是隐藏在HAL里的,硬件板完全启动后,main()函数就会调用setup()。
setup()函数只会调用一次,它初始化libraries,在启动时还可能答应一个“hello”来显示。
在setup()运行完成后,loop()函数接着被调用(被AP_HAL的主代码调用)范例的主要工作通常在loop()函数里进行。
要注意,在复杂的硬件板上,setup()/loop()函数只是冰山一角。这会使得Ardupilot看起来好像是单线程的,但是实际上有很多在底层运行的线程,硬件板(如PX4和基于linux的板)实际上有大量实时线程正在启动,具体请看后面的内容——理解ArduPilot线程。
AP_HAL_MAIN()宏
你会注意到在每个范例的后面会有额外的一行代码:
AP_HAL_MAIN();
这个就是HAL宏,它会根据硬件板为初始化HAL的代码,生成一些必要的代码来声明C++main()函数,你几乎不用担心它是怎样工作的,如果你对此感到好奇,可以查看AP_HAL_XXX目录里每个HAL的关于#define的内容,它通常在AP_HAL_XXX_Main.h.。
粗糙的示例代码
你会注意到范例的代码是相当粗糙的,且缺少注释。这也是你为代码贡献力量的机会!但你阅读过这些示例代码和知道它们怎样工作后,就可以添加注释在代码里,解释APIs然后提交一个推送,这样别人也会从你的学习中受益。