shuanger88 发表于 2022-10-27 15:47:25

Ardupilot串口代码解析(应用篇)

代码解析之前

之前三篇文章分别介绍了Ardupilot开发环境的搭建、基于MAVProxy的软件在环仿真以及基于MissionPlanner的软件在环仿真。
Ardupilot开发环境搭建(Ubuntu18.04,20190407)
ArduPilot 软件在环仿真SITL(SITL+MAVProxy)
ArduPilot 软件在环仿真SITL(SITL+Mission Planner)
按照上述顺序本想先整理Ardupilot硬件在环仿真,之后再对Ardupilot的代码进行深入分析,但在实现Ardupilot硬件在环仿真中发现目前论坛上所提供的硬件在环方式有如下几种:

[*]X-Plane + QGroundControl 或是 X-Plane + Missionplanner(1.3.10)
[*]FlightGear + Missionplanner
[*]JSBSim + QGroundControl
这几种方案在实际仿真过程中都会有很多问题,之后我会单独写文章介绍每种方案仿真过程。而上述方案都具有相同的缺点,首先飞机模型不是我们自己,很难去修正或是更改参数,另外都需要使用之前Ardupilot固件,当前最先Ardupilot已经不包含确切的说是不支持硬件在环仿真(在源码中还能看到部分硬件在环的代码)。这样硬件在环并不是有效可控的,对于无人机飞控的研究帮助不大,所以需要实现自主可控硬件在环方案。
对于固定翼无人机来说,硬件在环仿真就是将飞行模型生成的传感数据(GPS、罗盘、地磁、高度、空速等)通过某种方式注入到硬件飞控上,并将飞控输出控制指令(升降舵、副翼、方向舵、油门等)回传飞行模型进行迭代计算。而注入和回传数据通过串口实现是最为简单的,所以先整理Ardupilot串口代码,分析Ardupilot中串口的实现方法。
串口代码解析(如何在Ardupilot框架下使用串口)

我认为对Ardupilot的代码的理解可以分为两个层面:一个层面,可以在Ardupilot的框架下使用外设,另一个层面,从飞控硬件出发分析串口如何建立的。
现在从固定翼Ardupilot代码开始分析,不深入到ChibiOS如何运行等细节。对于固定翼Ardupilot从基类的Plane::setup()开始执行,之后由Plane::loop()建立周期任务循环。在Plane::setup()中使用init_ardupilot()初始化外设。



Arduplane.cpp

init_ardupilot在同目录下的system.cpp中,分别使用serial_manager.init_console()和serial_manager.init()来初始化串口。



system.cpp



system.cpp

这两个函数在APSerialManager.cpp中分别初始化不同串口,init_console()中初始化串口A,在pixhawk中此串口为USB串口并绑定地面站,init()中初始化其余串口。



AP_SerialManager.cpp



AP_SerialManager.cpp

有上面代码可见,init_console()初始化uartA,波特率为115200 (AP_SERIALMANAGER_ CONSOLE_BAUD),接收缓冲区为128(AP_SERIALMANAGER_CONSOLE_BUFSIZE _RX),发送缓冲区为128(AP_SERIALMANAGER_CONSOLE_BUFSIZE_TX)。
init()中初始化uartB、uartC、uartD、uartE、uartF和uartG,若此时uartA没有初始化,会重新初始化uartA。串口uartB和串口uartE一般为主GPS和从GPS,串口uartC和uartD一般为主数传和从数传。init()函数内在switch(state.protocol)中根据state中设置的参数进行串口配置。举一个例子,uartB通常作为主GPS的接口,下面看一下设置过程。首先通过AP_GROUPINFO初始化参数,此参数可以通过地面站进行配置。



AP_SerialManager.cpp

配置state.protocol为Serialprotocol_GPS,波特率设置为AP_SERIALMANGER_GPS _BAUD。而在init()函数中在switch(state.protocol)通过查询这些参数设置,来配置串口。


之后,传感器后台也通过state.protocol来查询传感器对应的串口。现在串口已经配置完成,下一步我们看一下可以通过什么API来使用串口。串口驱动对应为libraries/AP_HAL_ ChibiOS/UARTDriver.cpp,可以发现基本串口的控制API如下:
    uint32_t available() //获取有效数据数量
    int16_t read() //读取一个数据
    size_t write(uint8_t c) //发送一个数据
    size_t write(const uint8_t *buffer, size_t size) //发送一帧数据通过上述API我就可以控制串口收发,下面看GPS的部分代码,先是通过available()函数确定有效数据个数,之后按照获取的数据个数依次读取串口数据,并且将每个数据输入的_decode函数进行解码。


_decode函数在串行数据流中查找帧头、校验字分别进行处理,最后通过_term_complete()解析出GPS模块发送过来数据。


参考文档

[*]APM飞控学习之路:5 串口概述与收发调试
[*]Ardupilot设备驱动 IIC、SPI、USART
[*]Ardupilot 串口代码学习
页: [1]
查看完整版本: Ardupilot串口代码解析(应用篇)