写在前头
本系列主要介绍,本人在开发 iOS App 时,用 Mavlink 协议和 CocoaAsyncSocket 与无人设备进行通信;包括接收数据、发送指令、自动执行任务等功能。
本系列的主要内容是介绍 Mavlink消息、Mavlink 指令、参考地面站发送指令逻辑并移植到App中等等;只涉及到 Mavlink 的应用。
而不是告诉你 什么是 Mavlink,Mavlink 是如何工作的等等。
这些内容官网介绍的非常非常非常的详细,很多博客也会介绍相关 Mavlink 是什么的巴拉巴拉。
但是本人在实际开发过程中,很多时候遇到使用某些指令产生了问题,需要了解这个问题的原因、具体的解决方法等等,但可能是搜索资料能力不行吧,反正全网搜索半天都搜不到相关资料。
同时地面站(GCS)的源码是C和C++的。如果你能看懂地面站源代码。那么这个系列可能对于你太过于肤浅
地面站是一个非常全面且功能强大的;如果在某些指令逻辑处理时,或者对某条指令参数不确定时;地面站源码是最佳的老师。
就比我们的飞控测试工程师对我说:如果你的 App 操作有BUG,但是地面站对应的操作没有问题,那么你就不要甩锅给无人设备的硬件、飞控代码、遥控器代码上,肯定是你的代码问题
地面站开源代码:github.com/mavlink/qgr…
用户手册:docs.qgroundcontrol.com/master/en/i…
开发手册:mavlink.io/zh/
一、获取 iOS 的开源工具库
iOS的开源库分为两种,C语言和Swift语言,可以通过官网的生成器生成对应代码的 Mavlink 库。
mavlink.io/zh/getting_…
本系列使用 Objective-C的主要语言,使用C语言的 Mavlink 库
文件名后面的 _rover
是后续加入的,实际获取的 Mavlink 库是没有的
二、请求接收数据流(无人机/无人船/无人车)
在描述 Mavlink相关协议 前,需要了解的是,Mavlink 接收和发送指令都是有格式的。
如果不按照格式进行;则会出现,发消息没反应,收消息解析不对。
工具类封装了一个发送消息的方法,接收 mavlink_message_t
对象,根据 Mavlink 协议封装内容并send
在连接无人设备成功后,会在连接成功过的代理方法中向无人设备发送一条 REQUEST_DATA_STREAM
指令。
这个指令作用是用于向无人设备请求数据流。
虽然官网标记该指令已被弃用和代替,但是实际还是能够使用。
mavlink_message_t
:消息载体(结构体),基本上发送指令的消息都是通过他
mavlink_msg_request_data_stream_pack
:#66 的封装消息函数,将相应参数封装至mavlink_message_t
FSYSTEMID, FCOMID
:固定参数,分别是255和190;componentId
指的是主系统中的子系统;190 MAV_COMP_ID_MISSIONPLANNER
的枚举值。我当前项目实际上没有用到。
MAV_DATA_STREAM_ALL
:所有数据流,实际可根据数据内容选择相应枚举
如图所示,发送指令的方式实际上非常简单,但是也比较难。难点主要是这些参数的选择。
对于刚接触 Mavlink 的小伙伴,可能都不清楚这些参数的含义;不过一般情况下不用担心,因为如果涉及到无人设备的项目,通常会有一个资深?飞控工程师.对于参数方面的选择,一般不需要前端人员进行选择。
当该指令发送成功后;- (void)socket:didReadData:withTag:
就会源源不断收到无人设备的各种状态数据。
三、Mavlink 消息处理
Socket接收到的 data 数据需要处理,通过固定模板转换后根据msgid来判断接收到的消息的tag值
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
mavlink_message_t msg;
mavlink_status_t status;
char *bytes = (char *)[data bytes];
for (NSInteger i = 0; i < [data length]; ++i) {
if (mavlink_parse_char(MAVLINK_COMM_0, bytes[i], &msg, &status)) {
// do something
switch(msg.msgid) {
}
}
}
}
复制代码
四、msgid 指定消息tag值查找手册
无论是刚入门或者是入门一段时候后,都会存在对消息的某一个tag值不了解的情况,
因为在msg.msgid
中存在大量tag值,而且每个tag值使用不同的c函数解析
如果对消息中参数定义不清楚,可以使用官方开发手册找到对应枚举表,查看每个参数的定义。
以心跳包MAVLINK_MSG_ID_HEARTBEAT
了解参数内容进行举例:
1、使用 Xcode 定义跳转能够得到枚举的具体值
2、官网查找对应枚举表
command指导表:mavlink.io/zh/messages…
3、页面全局搜索
搜索#0
关键字,0 是对应的枚举值,可根据实际情况查找
五、Mavlink 消息不同Tag的处理
还是以MAVLINK_MSG_ID_HEARTBEAT
举例
1、先使用对应文件中结构体:mavlink_heartbeat_t
作为处理结果的对象载体
2、再使用mavlink_msg_heartbeat_decode(const mavlink_message_t* msg, mavlink_heartbeat_t* heartbeat)
将msg
解析成mavlink_heartbeat_t
这样就能使用接收从无人设备传过来的具体参数值,具体代码块:
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
mavlink_message_t msg;
mavlink_status_t status;
char *bytes = (char *)[data bytes];
for (NSInteger i = 0; i < [data length]; ++i) {
if (mavlink_parse_char(MAVLINK_COMM_0, bytes[i], &msg, &status)) {
// do something
switch(msg.msgid) {
case MAVLINK_MSG_ID_HEARTBEAT: {
// code: 0
mavlink_heartbeat_t heartbeat;
mavlink_msg_heartbeat_decode(&msg, &heartbeat);
NSLog(@"%d",heartbeat.custom_mode);
break;
}
}
}
}
复制代码
基本上消息的处理就是这几步就能完成。
本次的 Mavlink 开发笔记先到此为止。下次的内容主要是介绍当前项目中,常用的消息Tag值,以及对应tag值的解析