目前Copter/Plane/Rover共享了以下的顶层Library设计:
Library的功能很多,有驱动/算法/组件/应用等等,但是从设计思路上来考虑,它遵循Library开发的模式,或者说有设计框架。
了解如何通过设计思路和框架代码来理解Library设计,就能站在一个抽象的高度,设计的思维来分析业务模型(驱动/算法/组件/应用)。
这也是为什么我们来研读下Library Example Sketches的原因,这个Sketch有点类似Library Demo for Test。
换句话说,Sketch是可以独立运行的,而真正的Library是无法单独运行,需要系统来启动加载的,但是逻辑上来说类似,方便初期的开发和调试。
因此,了解ArduPilot中使用的库API和约定对理解代码至关重要。
Library Sketches共性:
其中AP_HAL_MAIN宏定义,是通过hal.run函数对设备代码进行关联执行的。
#define AP_HAL_MAIN() \
AP_HAL::HAL::FunCallbacks callbacks(setup, loop); \
extern "C" { \
int AP_MAIN(int argc, char* const argv[]); \
int AP_MAIN(int argc, char* const argv[]) { \
hal.run(argc, argv, &callbacks); \
return 0; \
} \
}
而这里run是一个虚构函数,对特定的系统可以各自重构。
virtual void run(int argc, char * const argv[], Callbacks* callbacks) const = 0;
简单了解下工程上面分别对ChibiOS/Linux系统做了HAL抽象,详见:
HAL_ChibiOS in HAL_ChibiOS_Class.h
HAL_Linux in HAL_Linux_Class.h
当然,ESP32前些时间也确实做了对ArduPilot的支持,鉴于其OS并非ChibiOS/Linux,所以增加了ESP32系统的支持,详见:
HAL_ESP32 in HAL_ESP32_Class.h
在以上特定系统的run函数内部,除了系统板级初始化以外,就是调用step()/loop()来初始化ArduPilot的Library。
注:这里的Library,主要侧重的是应用。因为从Library技术本身的角度只是库,一些列的函数实现,是静态的。而应用比较侧重的动态,比如:实例。
ArduPilot代码中有很多Demo可供参考:
$ cd $ARDUPILOT_HOME
$ ./waf list | grep 'examples'
examples/AC_PID_test
examples/AHRS_Test
examples/AP_Common
examples/AP_Compass_test
examples/AP_Declination_test
examples/AP_Logger_AllTypes
examples/AP_Logger_test
examples/AP_Marvelmind_test
examples/AP_Mission_test
examples/AP_Motors_test
examples/AP_Notify_test
examples/AP_OpticalFlow_test
examples/AP_Parachute_test
examples/Airspeed
examples/AnalogIn
examples/BARO_generic
examples/CompassCalibrator_index_test
examples/DSP_test
examples/Derivative
examples/File_IO
examples/Filter
examples/FlashTest
examples/GPS_AUTO_test
examples/GPS_UBLOX_passthrough
examples/Hello
examples/ICM20789
examples/INS_generic
examples/LowPassFilter
examples/LowPassFilter2p
examples/ModuleTest
examples/NMEA_Output
examples/Printf
examples/RCInput
examples/RCInputToRCOutput
examples/RCOutput
examples/RCOutput2
examples/RCProtocolDecoder
examples/RCProtocolTest
examples/RC_Channel
examples/RC_UART
examples/RFIND_test
examples/RNG_test
examples/RPM_generic
examples/RTC_test
examples/RingBuffer
examples/Scheduler_test
examples/SmartRTL_test
examples/Storage
examples/StorageTest
examples/ToshibaLED_test
examples/UART_chargen
examples/UART_test
examples/UAVCAN_sniffer
examples/eulers
examples/expo_inverse_test
examples/jedec_test
examples/location
examples/matrix_alg
examples/onvif_test
examples/polygon
examples/rotations
examples/routing
$ cd $ARDUPILOT_HOME
$ ./waf configure --board sitl
Setting top to : /home/daniel/Work/ardupilot
Setting out to : /home/daniel/Work/ardupilot/build
Autoconfiguration : enabled
Setting board to : sitl
Using toolchain : native
Checking for 'g++' (C++ compiler) : /usr/lib/ccache/g++
Checking for 'gcc' (C compiler) : /usr/lib/ccache/gcc
Checking for c flags '-MMD' : yes
Checking for cxx flags '-MMD' : yes
CXX Compiler : g++ 11.3.0
Checking for need to link with librt : not necessary
Checking for feenableexcept : yes
Enabled OpenDroneID : no
Enabled firmware ID checking : no
GPS Debug Logging : no
Enabled custom controller : yes
Checking for HAVE_CMATH_ISFINITE : yes
Checking for HAVE_CMATH_ISINF : yes
Checking for HAVE_CMATH_ISNAN : yes
Checking for NEED_CMATH_ISFINITE_STD_NAMESPACE : yes
Checking for NEED_CMATH_ISINF_STD_NAMESPACE : yes
Checking for NEED_CMATH_ISNAN_STD_NAMESPACE : yes
Checking for header endian.h : yes
Checking for header byteswap.h : yes
Checking for HAVE_MEMRCHR : yes
Configured VSCode Intellisense: : no
Checking for program 'python' : /usr/bin/python
Checking for python version >= 2.7.0 : 3.10.6
Checking for program 'python' : /usr/bin/python
Checking for python version >= 2.7.0 : 3.10.6
Source is git repository : yes
Update submodules : yes
Checking for program 'git' : /usr/bin/git
Checking for program 'size' : /usr/bin/size
Benchmarks : disabled
Unit tests : enabled
Scripting : enabled
Scripting runtime checks : enabled
Debug build : disabled
Coverage build : disabled
SITL 32-bit build : disabled
Checking for program 'rsync' : /usr/bin/rsync
'configure' finished successfully (7.749s)
$ ./waf build --target examples/AP_Common
Waf: Entering directory `/home/daniel/Work/ardupilot/build/sitl'
Embedding file locations.txt:Tools/autotest/locations.txt
Embedding file models/Callisto.json:Tools/autotest/models/Callisto.json
[ 15/896] Compiling libraries/AC_AttitudeControl/AC_WeatherVane.cpp
[ 16/896] Compiling libraries/AC_AttitudeControl/AC_PosControl.cpp
[ 49/896] Compiling libraries/AC_AttitudeControl/AC_AttitudeControl.cpp
[ 50/896] Compiling libraries/AC_AutoTune/AC_AutoTune.cpp
[ 51/896] Compiling libraries/AC_Avoidance/AP_OABendyRuler.cpp
[ 52/896] Compiling libraries/AC_Avoidance/AP_OADatabase.cpp
[ 53/896] Compiling libraries/AC_Avoidance/AC_Avoid.cpp
[ 54/896] Compiling libraries/AC_Fence/AC_Fence.cpp
[ 55/896] Compiling libraries/AC_Fence/AC_PolyFence_loader.cpp
[ 56/896] Compiling libraries/AC_PrecLand/AC_PrecLand.cpp
[ 62/896] Compiling libraries/AC_WPNav/AC_Loiter.cpp
[ 63/896] Compiling libraries/APM_Control/AP_SteerController.cpp
[ 66/896] Compiling libraries/APM_Control/AP_AutoTune.cpp
[ 67/896] Compiling libraries/APM_Control/AP_YawController.cpp
[ 68/896] Compiling libraries/APM_Control/AP_PitchController.cpp
[ 69/896] Compiling libraries/APM_Control/AR_AttitudeControl.cpp
[ 85/896] Compiling libraries/APM_Control/AP_RollController.cpp
[ 86/896] Compiling libraries/APM_Control/AR_PosControl.cpp
[ 87/896] Compiling libraries/AP_ADSB/AP_ADSB_Sagetech_MXS.cpp
[ 88/896] Compiling libraries/AP_ADSB/AP_ADSB.cpp
[ 89/896] Compiling libraries/AP_AHRS/AP_AHRS_Backend.cpp
[110/896] Compiling libraries/AP_AHRS/AP_AHRS_DCM.cpp
[111/896] Compiling libraries/AP_AHRS/AP_AHRS.cpp
[132/896] Compiling libraries/AP_AIS/AP_AIS.cpp
[133/896] Compiling libraries/AP_Airspeed/AP_Airspeed.cpp
[142/896] Compiling libraries/AP_Airspeed/AP_Airspeed_NMEA.cpp
[149/896] Compiling libraries/AP_Arming/AP_Arming.cpp
[150/896] Compiling libraries/AP_Avoidance/AP_Avoidance.cpp
[189/896] Compiling libraries/AP_BLHeli/AP_BLHeli.cpp
[190/896] Compiling libraries/AP_Baro/AP_Baro.cpp
[191/896] Compiling libraries/AP_Baro/AP_Baro_SITL.cpp
[197/896] Compiling libraries/AP_BattMonitor/AP_BattMonitor.cpp
[198/896] Compiling libraries/AP_BattMonitor/AP_BattMonitor_Params.cpp
[199/896] Compiling libraries/AP_BoardConfig/AP_BoardConfig.cpp
[200/896] Compiling libraries/AP_CANManager/AP_CANManager.cpp
[229/896] Compiling libraries/AP_CANManager/AP_CANDriver.cpp
[230/896] Compiling libraries/AP_Compass/AP_Compass.cpp
[231/896] Compiling libraries/AP_CustomRotations/AP_CustomRotations_params.cpp
[242/896] Compiling libraries/AP_CustomRotations/AP_CustomRotations.cpp
[271/896] Compiling libraries/AP_DAL/AP_DAL_RangeFinder.cpp
[301/896] Compiling libraries/AP_DAL/AP_DAL_Beacon.cpp
[303/896] Compiling libraries/AP_DAL/AP_DAL.cpp
[305/896] Compiling libraries/AP_DAL/AP_DAL_VisualOdom.cpp
[307/896] Compiling libraries/AP_Filesystem/AP_Filesystem_posix.cpp
[308/896] Compiling libraries/AP_FlashIface/AP_FlashIface_JEDEC.cpp
[309/896] Compiling libraries/AP_Follow/AP_Follow.cpp
[311/896] Compiling libraries/AP_Frsky_Telem/AP_Frsky_SPort_Passthrough.cpp
[312/896] Compiling libraries/AP_GyroFFT/AP_GyroFFT.cpp
[313/896] Compiling libraries/AP_InertialSensor/AP_InertialSensor.cpp
[314/896] Compiling libraries/AP_JSButton/AP_JSButton.cpp
[321/896] Compiling libraries/AP_L1_Control/AP_L1_Control.cpp
[322/896] Compiling libraries/AP_Landing/AP_Landing.cpp
[323/896] Compiling libraries/AP_Landing/AP_Landing_Slope.cpp
[324/896] Compiling libraries/AP_Landing/AP_Landing_Deepstall.cpp
[347/896] Compiling libraries/AP_LeakDetector/AP_LeakDetector_Analog.cpp
[348/896] Compiling libraries/AP_LeakDetector/AP_LeakDetector_Backend.cpp
[349/896] Compiling libraries/AP_LeakDetector/AP_LeakDetector.cpp
[350/896] Compiling libraries/AP_LeakDetector/AP_LeakDetector_Digital.cpp
[357/896] Compiling libraries/AP_Logger/AP_Logger_Backend.cpp
[369/896] Compiling libraries/AP_Logger/AP_Logger.cpp
[370/896] Compiling libraries/AP_Logger/AP_Logger_File.cpp
[402/896] Compiling libraries/AP_Logger/LoggerMessageWriter.cpp
[403/896] Compiling libraries/AP_Math/quaternion.cpp
[404/896] Compiling libraries/AP_Math/SCurve.cpp
[405/896] Compiling libraries/AP_Math/vector3.cpp
[406/896] Compiling libraries/AP_Menu/AP_Menu.cpp
[407/896] Compiling libraries/AP_Mission/AP_Mission.cpp
[408/896] Compiling libraries/AP_Motors/AP_MotorsMatrix.cpp
[409/896] Compiling libraries/AP_Motors/AP_MotorsTri.cpp
[410/896] Compiling libraries/AP_NavEKF2/AP_NavEKF2.cpp
[411/896] Compiling libraries/AP_NavEKF3/AP_NavEKF3_RngBcnFusion.cpp
[412/896] Compiling libraries/AP_NavEKF3/AP_NavEKF3_OptFlowFusion.cpp
[413/896] Compiling libraries/AP_NavEKF3/AP_NavEKF3_PosVelFusion.cpp
[414/896] Compiling libraries/AP_NavEKF3/AP_NavEKF3_Logging.cpp
[415/896] Compiling libraries/AP_NavEKF3/AP_NavEKF3_GyroBias.cpp
[447/896] Compiling libraries/AP_NavEKF3/AP_NavEKF3_Control.cpp
[448/896] Compiling libraries/AP_NavEKF3/AP_NavEKF3_AirDataFusion.cpp
[449/896] Compiling libraries/AP_NavEKF3/AP_NavEKF3.cpp
[457/896] Compiling libraries/AP_NavEKF3/AP_NavEKF3_MagFusion.cpp
[458/896] Compiling libraries/AP_NavEKF3/AP_NavEKF3_Outputs.cpp
[459/896] Compiling libraries/AP_NavEKF3/AP_NavEKF3_VehicleStatus.cpp
[504/896] Compiling libraries/AP_NavEKF3/AP_NavEKF3_Measurements.cpp
[505/896] Compiling libraries/AP_NavEKF3/AP_NavEKF3_core.cpp
[506/896] Compiling libraries/AP_ONVIF/base64.cpp
[507/896] Compiling libraries/AP_ONVIF/sha1.cpp
[508/896] Compiling libraries/AP_ONVIF/AP_ONVIF.cpp
[509/896] Compiling libraries/AP_OSD/AP_OSD_ParamSetting.cpp
[510/896] Compiling libraries/AP_OSD/AP_OSD_ParamScreen.cpp
[512/896] Compiling libraries/AP_OSD/AP_OSD_Screen.cpp
[513/896] Compiling libraries/AP_RCProtocol/AP_RCProtocol_FPort2.cpp
[536/896] Compiling libraries/AP_RCProtocol/AP_RCProtocol_CRSF.cpp
[570/896] Compiling libraries/AP_RCProtocol/AP_RCProtocol.cpp
[575/896] Compiling libraries/AP_RCProtocol/AP_RCProtocol_FPort.cpp
[580/896] Compiling libraries/AP_RCProtocol/AP_RCProtocol_Backend.cpp
[581/896] Compiling libraries/AP_RCProtocol/AP_RCProtocol_DSM.cpp
[582/896] Compiling libraries/AP_RCProtocol/AP_RCProtocol_SRXL2.cpp
[583/896] Compiling libraries/AP_RCTelemetry/AP_CRSF_Telem.cpp
[585/896] Compiling libraries/AP_RCTelemetry/AP_RCTelemetry.cpp
[587/896] Compiling libraries/AP_Rally/AP_Rally.cpp
[592/896] Compiling libraries/AP_RangeFinder/AP_RangeFinder.cpp
[599/896] Compiling libraries/AP_Scheduler/AP_Scheduler.cpp
[618/896] Compiling libraries/AP_Soaring/AP_Soaring.cpp
[619/896] Compiling libraries/AP_Soaring/Variometer.cpp
[620/896] Compiling libraries/AP_Soaring/SpeedToFly.cpp
[621/896] Compiling libraries/AP_Soaring/ExtendedKalmanFilter.cpp
[622/896] Compiling libraries/AP_TECS/AP_TECS.cpp
[623/896] Compiling libraries/AP_TemperatureSensor/TSYS01.cpp
[624/896] Compiling libraries/AP_Terrain/AP_Terrain.cpp
[625/896] Compiling libraries/AP_Vehicle/AP_Vehicle.cpp
[626/896] Compiling libraries/AP_WindVane/AP_WindVane_Home.cpp
[627/896] Compiling libraries/AP_WindVane/AP_WindVane_Airspeed.cpp
[628/896] Compiling libraries/AP_WindVane/AP_WindVane_ModernDevice.cpp
[629/896] Compiling libraries/AP_WindVane/AP_WindVane_RPM.cpp
[630/896] Compiling libraries/AP_WindVane/AP_WindVane_SITL.cpp
[641/896] Compiling libraries/AP_WindVane/AP_WindVane_Backend.cpp
[653/896] Compiling libraries/AP_WindVane/AP_WindVane_Analog.cpp
[654/896] Compiling libraries/AP_WindVane/AP_WindVane_NMEA.cpp
[655/896] Compiling libraries/AP_WindVane/AP_WindVane.cpp
[657/896] Compiling libraries/AR_Motors/AP_MotorsUGV.cpp
[660/896] Compiling libraries/AR_WPNav/AR_PivotTurn.cpp
[661/896] Compiling libraries/AR_WPNav/AR_WPNav.cpp
[689/896] Compiling libraries/AR_WPNav/AR_WPNav_OA.cpp
[744/896] Compiling libraries/GCS_MAVLink/GCS_Common.cpp
[745/896] Compiling libraries/GCS_MAVLink/GCS_Fence.cpp
[746/896] Compiling libraries/GCS_MAVLink/GCS_Dummy.cpp
[846/896] Compiling libraries/PID/PID.cpp
[847/896] Compiling libraries/RC_Channel/RC_Channel.cpp
[848/896] Compiling libraries/SRV_Channel/SRV_Channels.cpp
[849/896] Compiling libraries/StorageManager/StorageManager.cpp
[850/896] Compiling libraries/AP_HAL/SIMState.cpp
[886/896] Compiling libraries/AP_HAL_SITL/UARTDriver.cpp
[887/896] Compiling libraries/AP_HAL_SITL/SITL_cmdline.cpp
[888/896] Compiling libraries/AP_HAL_SITL/Storage.cpp
[889/896] Compiling libraries/AP_Scripting/lua_scripts.cpp
[890/896] Compiling libraries/AP_Scripting/lua_repl.cpp
[891/896] Compiling libraries/AP_Scripting/lua_bindings.cpp
[892/896] Compiling libraries/AP_Scripting/lua_boxed_numerics.cpp
[893/896] Compiling build/sitl/libraries/AP_Scripting/lua_generated_bindings.cpp
[894/896] Compiling libraries/AP_Common/examples/AP_Common/AP_Common.cpp
[895/896] Linking build/sitl/lib/libap.a
[896/896] Linking build/sitl/examples/AP_Common
Waf: Leaving directory `/home/daniel/Work/ardupilot/build/sitl'
BUILD SUMMARY
Build directory: /home/daniel/Work/ardupilot/build/sitl
Target Text (B) Data (B) BSS (B) Total Flash Used (B) Free Flash (B)
-------------------------------------------------------------------------------------
examples/AP_Common 901928 26343 129264 928271 Not Applicable
Build commands will be stored in build/sitl/compile_commands.json
'build' finished successfully (3m51.704s)
$ ./build/sitl/examples/AP_Common -M quad -C
Suggested EK3_DRAG_BCOEF_* = 16.288, EK3_DRAG_MCOEF = 0.209
Starting sketch 'UNKNOWN'
Starting SITL input
AP_Common tests
i:0 high:0 low:0
i:1 high:0 low:1
i:2 high:0 low:2
i:3 high:0 low:3
i:4 high:0 low:4
i:5 high:0 low:5
i:6 high:0 low:6
i:7 high:0 low:7
i:8 high:0 low:8
i:9 high:0 low:9
i:10 high:0 low:10
i:11 high:0 low:11
i:12 high:0 low:12
i:13 high:0 low:13
i:14 high:0 low:14
i:15 high:0 low:15
i:16 high:0 low:16
i:17 high:0 low:17
i:18 high:0 low:18
i:19 high:0 low:19
i:20 high:0 low:20
i:21 high:0 low:21
... ...
从代码中,可以看出AP_Common的loop()函数中没有代码,因此,主要是setup时做了两个循环。
//
// Unit tests for the AP_Common code
//
#include <AP_Common/AP_Common.h>
#include <AP_HAL/AP_HAL.h>
void setup();
void loop();
void test_high_low_byte(void);
const AP_HAL::HAL& hal = AP_HAL::get_HAL();
void test_high_low_byte(void)
{
// test each value from 0 to 300
for (uint16_t i = 0; i <= 300; i++) {
uint8_t high = HIGHBYTE(i);
uint8_t low = LOWBYTE(i);
hal.console->printf("\ni:%u high:%u low:%u", (unsigned int)i, (unsigned int)high, (unsigned int)low);
}
// test values from 300 to 65400 at increments of 200
for (uint16_t i = 301; i <= 65400; i += 200) {
uint8_t high = HIGHBYTE(i);
uint8_t low = LOWBYTE(i);
hal.console->printf("\ni:%u high:%u low:%u", (unsigned int)i, (unsigned int)high, (unsigned int)low);
}
}
/*
* euler angle tests
*/
void setup(void)
{
hal.console->printf("AP_Common tests\n\n");
test_high_low_byte();
}
void loop(void)
{
// do nothing
}
AP_HAL_MAIN();
关于Library Example Sketches设计,大家可能已经比较能够理解其来龙去脉,更多的可以理解为最小粒度的测试Library单元(单元测试可以在这个级别做)。
而ArduPilot飞控程序则是并非如此简单,Library Example Sketches算是管中窥豹,但是ArduPilot关于Library在系统级别的关联也是类似:
#define AP_HAL_MAIN_CALLBACKS(CALLBACKS) extern "C" { \
int AP_MAIN(int argc, char* const argv[]); \
int AP_MAIN(int argc, char* const argv[]) { \
hal.run(argc, argv, CALLBACKS); \
return 0; \
} \
}
上述宏定义是ArduPilot设备代码宏定义入口部分,比如:ArduCopter\Copter.cpp
AP_HAL_MAIN_CALLBACKS(&copter);
好了,说倒这里。可能大家有点迷茫。其实大家可以对比AP_Common中的AP_HAL_MAIN();
AP_Common = hal.run + setup + loop
ArduCopter = hal.run + copter + AP_Vehicle(setup + loop)
因为,ArduPilot采用了C++的一个对象模型,建立了Copter设备对象,并将Copter的setup/loop打包在AP_Vehicle中实现了。
好了,到这里我们可以看出Library Example Sketches是一个mini的基于setup/loop函数类似Ardunio的应用。
ArduPilot的所有设备AntennaTracker/ArduCopter/ArduPlane/ArduSub/Rover/Blimp都是这么展开的。
./ArduCopter/Copter.cpp:797:AP_HAL_MAIN_CALLBACKS(&copter);
./AntennaTracker/Tracker.cpp:173:AP_HAL_MAIN_CALLBACKS(&tracker);
./Rover/Rover.cpp:503:AP_HAL_MAIN_CALLBACKS(&rover);
./ArduSub/ArduSub.cpp:349:AP_HAL_MAIN_CALLBACKS(&sub);
./ArduPlane/ArduPlane.cpp:895:AP_HAL_MAIN_CALLBACKS(&plane);
./Blimp/Blimp.cpp:275:AP_HAL_MAIN_CALLBACKS(&blimp);
总的来说,ArduPilot从代码框架设计结构上遵循了Ardunio设计思路;
在上述基础上,加入了设备应用建模,并对模型共性部分Library化抽象,方便维护。
当然,这里只是从概念和代码的角度管中窥豹,很多细节问题:驱动,数据共享,通信等问题我们在后面的章节中再行深入的讨论和学习。
【1】ArduPilot开源飞控系统之简单介绍
【2】ArduPilot之开源代码框架
【3】ArduPilot飞控之ubuntu22.04-SITL安装
【4】ArduPilot飞控之ubuntu22.04-Gazebo模拟
【5】ArduPilot飞控之Mission Planner模拟
【6】ArduPilot飞控AOCODARC-H7DUAL固件编译