传感器驱动程序

ArduPilot 支持许多不同制造商生产的各种传感器。其中一个明显的例子是 测距仪列表 (又称声纳、激光雷达)。本页试图解释传感器驱动程序是如何编写并集成到载具代码中的。

支持的协议

I2C, SPI, UART(又称串行)CANBUS (特别是 UAVCAN/DroneCAN)协议。

如果您计划编写新的驱动程序,则可能需要参考传感器的数据表,以确定其使用的协议。另外,您也可以利用中间节点将必要的数据传回(飞行)控制器。

I2C

  • 一主多从

  • 是一种相对简单的协议,适用于短距离通信(即小于 1 米)。

  • 总线的运行频率为 100kHz 或 400kHz,但与其他协议相比,数据传输速率相对较低。

  • 只需 4 个引脚(VCC、GND、SDA、SCL)

../_images/code-overview-sensor-driver-i2c1.png ../_images/code-overview-sensor-driver-i2c2.png

SPI

  • 一主一奴

  • 20Mhz 以上的速度意味着它非常快,特别是与 I2C 相比

  • 只能在短距离(10 厘米)内使用

  • 每个从站至少需要 5 个引脚(VCC、GND、SCLK、主输出-从输入、主输入-从输出)+ 1 个从站选择引脚

../_images/code-overview-sensor-driver-spi1.png ../_images/code-overview-sensor-driver-spi2.png

串行/UART

  • 一主一奴

  • 与 I2C 和 SPI(即 1 米)相比,基于字符的协议更适合长距离通信

  • 相对较快,为 57Kbps ~ 1.5Mbps

  • 至少需要 4 个引脚(VCC、GND、TX、RX),外加 2 个可选引脚(发送清零、接收清零)

带 UAVCAN 的 CAN 总线

  • 多主总线,任何节点都可以在需要时启动数据传输

  • 基于数据包的超长距离协议

  • 高速度,通常为 1 Mb(但只有 50%的总线比特率可以真正使用,而不会发生重大碰撞)

  • 至少需要 3 个引脚(GND、CAN HI、CAN LO)。可选择使用 VCC 为节点供电

  • 点对点拓扑结构。不建议采用星型或桩型拓扑结构

  • 总线两端都需要终端

../_images/code-overview-can-bus.png

前端/后端分离

传感器驱动程序架构的一个重要概念是前端/后端分离。

../_images/code-overview-sensor-drivers-febesplit.png

载具代码只调用库(又称传感器驾驶员)的前端。

启动时,前端会根据传感器的自动检测(即探测已知 I2C 地址的响应)或使用用户定义的 _TYPE 参数(即 RNGFND_TYPE、RNGFND_TYPE2)创建一个或多个后端。前端维护指向每个后端的指针,这些指针通常保存在名为 _drivers[] 的数组中。

用户可设置的参数始终保留在前端。

运行驱动程序代码的方式和时间

../_images/copter-code-overview-architecture2.png

上图是 ardupilot 架构的放大图。左上方的蓝色方框说明了传感器驱动程序的后端是如何在后台线程中运行的。从传感器收集原始数据,转换成标准单位,然后保存在驱动程序的缓冲区中。

载具代码的主线程定期运行(如旋翼飞行器为 400 赫兹),并通过驱动程序前端的方法访问最新数据。例如,为了计算最新的姿态估计值,AHRS/EKF 将从传感器驱动器前端获取最新的加速计、陀螺仪和指南针信息。

对于使用 I2C 或 SPI 的驱动程序来说,它们必须在后台线程中运行,这样与传感器的高速通信才不会影响主循环的性能,但对于使用串行(又称 UART)接口的驱动程序来说,在主线程中运行是安全的,因为底层串行驱动程序本身会在后台收集数据并包含一个缓冲区。

载具代码和前端示例

下面的示例显示了 Copter 载具代码如何从测距仪(又称声纳、激光雷达)驱动器中提取数据。Copter 代码的 调度 以 20Hz 的频率调用载具的 read_rangefinder() 方法。下面是该方法的图片,最新版本可在 传感器.cpp 文件。rangefinder.update() 方法是对驱动程序前端的调用。

../_images/code-overview-sensor-driver1.png

以下是测距仪驱动器的前端 更新方法.这样,驱动程序就有机会在主线程内进行它可能想进行的任何常规处理。每个后端更新方法依次被调用。

../_images/code-overview-sensor-driver2.png

UART/Serial 后端示例

接下来是 LightWare 后端 使用串行协议。正如 用户维基 串行测距仪可以连接到飞行控制器的任何一个串行端口,但用户必须通过设置 SERIALX_BAUD 和 SERIALX_PROTOCOL 参数来指定使用哪个串行端口和哪个波特率。

../_images/code-overview-sensor-driver-uart1.png

在串行驱动程序的 后台代码首先,它将通过串行管理器类(serial_manager)找到用户希望使用的 UART,该类将查找上述参数设置。

../_images/code-overview-sensor-driver8.png

每次调用驱动程序的后端 update() 方法时,都会调用 get_reading 方法,该方法会检查传感器是否发送了新字符,然后对其进行解码。

如上所述,由于串行协议实现了自己的缓冲,因此来自传感器的任何数据(见 get_reading 方法)的处理都在主线程中进行。也就是说,不存在 I2C 和 SPI 驱动程序中的 "register_periodic_callback"。

../_images/code-overview-sensor-driver3.png ../_images/code-overview-sensor-driver4.png

I2C 后端示例

该示例展示了 Lightware I2C 驱动程序的后端。在这种情况下,前端获取 I2C 总线,并在初始化过程中将其传递给后端。

../_images/code-overview-sensor-driver5.png

然后,后端 init 方法注册其 "定时器 "方法,以便在 20 赫兹时调用。在定时器方法中(未显示),get_reading() 方法被调用,该方法从传感器读取字节并将距离转换为厘米。

SPI 后端示例

该示例显示了 MPU9250 IMU 的后端,其中包括陀螺仪、加速计和罗盘。前端获取 SPI 总线,并在初始化过程中将其传递给后端。

../_images/code-overview-sensor-driver6.png

start() 方法在初始化过程中被调用,用于配置传感器。它使用信号传递器,以确保不干扰同一总线上的其他 SPI 设备。

对 _read_sample 方法进行了注册,以便以 1000hz 的频率调用该方法。请注意,无需在 _read_sample 方法中获取/给予 Semaphores,因为这已作为定期回调代码的一部分完成。

block_read 方法显示了如何从传感器寄存器中读取数据。

../_images/code-overview-sensor-driver7.png

补充建议

在编写传感器驱动程序时,切勿包含任何等待或休眠代码,因为这要么会延迟主线程,要么会延迟与所使用总线相关的后台线程。

如果编写了新库,必须将其添加到飞行器目录(即 /ardupilot/ArduCopter/wscript)中的 wscript 文件中,以便将其链接到最终二进制文件中。