飞控与外界无线数据通信
遥控器用于用户手动操纵指令传达。除此之外,四旋翼无人机还需要与地面站或其他四旋翼有数据交互,用于状态监控,集群协同等
一 硬件与协议
无人机与外界通信主流方案包括三种:WiFi,蓝牙,2.4G无线数传。其中WiFi与蓝牙也是传输信号也在2.4G频段,一般硬件设备都内置有WiFi,蓝牙功能,2.4G收发端都需要额外配置模块
也有部分数传模块可以工作在433MHz、915MHz频段,相同功率,频率低衍射性能好,传输距离远;频率高则带宽大一点,传输速度快
通常开发这三类硬件需要一个2.4G射频芯片,在上层开发协议栈。这三类方案一些常见产品指标对比如下,其中蓝牙5.0比4.0在带宽和传输距离上有提升,数传模块产品性能区间较大,可以结合价格和场景需要选用
市面上这三种都是模块产品如ESP8366 WiFi模块,3DR 915MHz无线数传模块,对外屏蔽协议栈细节。与飞控走串口协议,在PX4中只需要读写串口解析应用层MAVLink协议即可
二 MAVLink协议
MAVLink定义了轻量级无人机之间传输数据格式,支持多种语言和多种平台,支持至多255种机型,并且高度可靠与安全。2009年发布MAVLink v1,2017年发布版本MAVLink v2. MAVLink系列无论是数据帧格式还是交互过程,都和socket十分相似,我们下面一起来看一下
1 MAVLink实现
1.1 协议
MAVLink v2相比于v1,头部标记由8字节升级到14字节,扩展性进一步提高。我们重点关注MAVLink v2,下面为MAVLink v2序列化后的数据帧格式
收发端首先四次握手进行版本协商,然后即建立连接
系统与组件的认证ID标识了发送端可以广播给网络中的全部系统或组件,也可以发给指定系统或组件
接收端等待数据帧开始标志位,然后读取包长度的字节序列,并且做一些校验工作,再放入缓存做拼接,最后提供给上层应用
有两个很重要的API用于程序中数据结构和二进制消息相互转化,对MAVLink协议感兴趣的朋友可以阅读它的实现来了解协议设计细节
反序列化mavlink_parse_char
https://github.com/mavlink/c_library_v2/blob/master/mavlink_helpers.h#L988
序列化mavlink_msg_to_send_buffer
https://github.com/mavlink/c_library_v2/blob/master/mavlink_helpers.h#L445
1.2 消息类型
MAVLink消息定义在XML文件中,形式上可以参考下面的内容
https://github.com/mavlink/mavlink/blob/18955a04c7c7467e00ea42b704addb4a9c12b53a/message_definitions/v1.0/common.xml
MAVLink内置消息可以分为两类,主协议通用消息和子协议,如果内置消息仍然不能满足用户需要,MAVLink也支持用户自定义消息
a.主协议通用消息
通用消息设计已经足够满足大多数应用场景需求
https://mavlink.io/en/messages/common.html
包括飞机机型,飞行模式,飞机传感器数据,飞行状态的细节等
b.子协议
子协议通常用于特定场景,比较Domain-Specific。比如心跳协议用于确认组件状态,计算丢包率;参数协议用于交换组件参数等
有个比较有意思的是解锁认证协议
https://mavlink.io/en/services/arm_authorization.html
意思是说需要第三方认证如空管部门或一些私人认证机构,才允许解锁飞行
c.自定义消息
XML完成自定义消息后,可以用官方提供的codegen工具生成对应语言的消息定义源码。对C语言官方提供了一份已经生成好的消息定义头文件,并且针对嵌入式系统高度优化。
PX4作为发送端中用到的common消息可以参考
https://github.com/PX4/PX4-Autopilot/tree/2f448e9d9f3996698dffc5d24e90b405bc55c045/src/modules/mavlink/streams
其中主要是定义了send接口,用于uORB订阅话题后序列化为二进制并发送到串口
对其他语言的支持可以参考官方开发者手册
https://mavlink.io/en/
1.3 测试
官方提供了一份测试用例,实现了串口和UDP简单收发接口
https://github.com/mavlink/c_uart_interface_example
另外也有一份比较完善的基于C++17的软件开发包,支持包括同步、异步回调更多好用的上层封装
https://github.com/mavlink/MAVSDK/tree/main
我们留到后面实践篇再做详细测评
2 MAVLink在PX4中的使用
对于MAVLink消息上层接口需求,总体可以归为同步、异步两类。既需要同步消息统一处理关心的数据,又需要异步接口来支持随时打印调试信息
2.1通过MAVLink发布异步调试信息
比较常见的是mavlink_log_info
https://github.com/PX4/PX4-Autopilot/blob/2f448e9d9f3996698dffc5d24e90b405bc55c045/src/lib/systemlib/mavlink_log.h#L82
不过这类接口将会逐渐被Events机制替代,events::send()接口封装调试信息,实际上是通过uORB发布事件
https://github.com/PX4/PX4-Autopilot/blob/2f448e9d9f3996698dffc5d24e90b405bc55c045/platforms/common/events.cpp#L48
下面订阅进队列,再统一发布MAVLink消息,这样方便和同步消息统一管理
https://github.com/PX4/PX4-Autopilot/blob/2f448e9d9f3996698dffc5d24e90b405bc55c045/src/modules/mavlink/mavlink_main.cpp#L2545
2.2 通过MAVLink例行发布接收关心的数据
此时飞控设备既是发送端,又是接收端,相应任务由两个task执行
(1)发送端
在MAVLink模块发送任务中,完成外设配置,需要输出消息订阅发送以及接收消息的反序列化和发布
在主循环中,统一对关注的消息进行订阅和发布:
结合带宽调整发送速率
https://github.com/PX4/PX4-Autopilot/blob/2f448e9d9f3996698dffc5d24e90b405bc55c045/src/modules/mavlink/mavlink_main.cpp#L2320
对udp或串口外设进行配置
https://github.com/PX4/PX4-Autopilot/blob/2f448e9d9f3996698dffc5d24e90b405bc55c045/src/modules/mavlink/mavlink_main.cpp#L2332
兼容旧MAVLink版本,直接调MAVLink序列化接口发布云台消息
https://github.com/PX4/PX4-Autopilot/blob/2f448e9d9f3996698dffc5d24e90b405bc55c045/src/modules/mavlink/mavlink_main.cpp#L2463
检查通过shell传进来的消息,通过MAVLink发送
https://github.com/PX4/PX4-Autopilot/blob/2f448e9d9f3996698dffc5d24e90b405bc55c045/src/modules/mavlink/mavlink_main.cpp#L2486
从MAVLinkShell实现来看,主要是对于父子关系的两个任务,子任务会继承得到文件描述符,并通过stdio管道通信,从shell读入消息并且发送,很显然,可用于调试
通过uORB订阅消息,并逐个通过MAVLink发送
https://github.com/PX4/PX4-Autopilot/blob/2f448e9d9f3996698dffc5d24e90b405bc55c045/src/modules/mavlink/mavlink_main.cpp#L2503
(2)接收端
接收端启动
https://github.com/PX4/PX4-Autopilot/blob/2f448e9d9f3996698dffc5d24e90b405bc55c045/src/modules/mavlink/mavlink_receiver.cpp#LL3276C4-L3276C24
流程上和发送端刚好相反,不过消息反序列化后,都是直接实现的处理函数,也包括一些子协议的处理,如FTP协议、Mission子协议等,然后通过uORB发布
这就是飞机与外部数据交互的软硬件层面原理以及PX4实现。
源自:SantyNotebook