MAVLINK代码分析
MAVLINK代码分析涉及初始化过程、循环调用、消息发送和解包过程。初始化通过setup_uart设置串口和协议,循环调用包括检查输入、发送心跳、延迟消息和数据流。消息发送使用队列系统,确保系统实时性。解包过程使用mavlink_parse_char处理数据包,并可在packetReceived中添加自定义消息处理。
type
status
date
slug
summary
tags
category
icon
password
初始化过程
1.创建对象,调用构造函数。
copter.h
2.初始化
setup_uart()
可以看到,在调用
setup_uart
的时候,调用了init()
函数。调用
setup_uart()
,主要是获取串口对象指针,根据设置的协议类型,是否采用MAVLINK_2 协议。MAVLINK2 协议在使用的时候,可以加密。采用哪个串口,以及采用的协议,可以在参数中进行设置。
参数:
SERIAL0_BAUD
SERIAL0_PROTOCOL
在
init
中主要对_port
, mavlink_comm_port[]
赋值。_port
当前串口的指针,mavlink_comm_port
,记录对应通道的串口指针。循环调用过程
Arducopter.cpp
主要是四个循环调用函数。
第一个
gcs_check_input()
, 检查串口数据,对串口数据解析,解包操作。gcs_send_heartbeat()
, 发送心跳包。gcs_send_deferred()
, 发送队列消息,status_text
, 和data_stream
. gcs_data_stream_send()
, 发送data_stream
.在主线程没有启动之前,通过
Mavlink_delay_cb
进行通GCS_Mavlink.cpp
可以参考这个函数的声明过程,如果delay超过5ms,则调用该函数。
system.cpp
消息发送过程
有两个循环调用接口。
gcs_send_deferred()
和 gcs_data_stream_send()
第一个
gcs_send_deferred()
,gcs_send_message(MSG_RETRY_DEFERRED);
gcs_chan[i].send_message(id);
这是一个队列,mavlink在发送的时候,首先将消息放到队列里面,如果空闲则开始发送数据。在开发其它通信过程中,可以参考。队列,先进先出。
try_send_message()
是一个纯虚函数,它的实现在上层。gcs_mavlink_copter
类中。具体的实现,主要对一些重要的函数,进行解释。telemetry_delayed()
, 在启动时,不能不能立刻发送数据包,因为xbee的启动时间延后。同时,为了保证系统的实时性,保证main_loop 最高的优先级,只有当剩余时间大于250ms 时才执行发送命令操作。
随后执行发送特性的消息ID,具体的实现在上层实现。例如:
调用底层发送发送接口,发送数据包到响应的数据接口上。
这是按照消息ID的发送过程。注意这里采用NOINLINE,接口。具体的原因,跟采用sigleliton的设计模式有关。
发送status_text过程
与发送特性ID的,消息类似。
从
_statustext_queue
中查找是否有数据,如果有数据,从中取出数据。_statustext_queue
定义了一个模板,这个模板,是一个环数据结构。在通信过程中,经常用到。自己写传感器数据,或者对传感器数据进行滤波处理,经常用到ring buffer.status_text
gcs_data_stream_send()
, 定时发送数据包通过设置参数
SR0_RAW_SENS: Raw sensor stream rate
Note: This parameter is for advanced users
Stream rate of RAW_IMU, SCALED_IMU2, SCALED_IMU3, SCALED_PRESSURE, SCALED_PRESSURE2, SCALED_PRESSURE3 and SENSOR_OFFSETS to ground station
Range | Increment | Unit
s |
0 10 | 1 | hertz |
控制发送的数据流的频率。
随后调用
send_message()
尝试发送消息,如果在队列中,则不会发送,把消息号,放在队列中,等待发送。
消息解包过程
循环函数:
gcs_check_input()
调用
gcs_chan[i].update(nullptr);
mavlink_parse_char
对收到的串口数据,形成数据包操作。mavlink_parse_char
由mavlink 库提供。在写串口驱动的时候,可以参考这种处理方式,先组包,然后根据包的类型,进行解包操作。分包数据都可以采用这种处理模式。调用子类的
packet_received()
, 这里packet_received()
,是一个虚函数,所以父类调用的时候,调用子类的函数。这就是虚函数简单的用法,在子类中重新定义。这个特性,也就是多态,是面向对象的基本特性之一。在这里可以看到,如果我们想添加自己的消息,非标准的MAVLINK消息,可以在这里进行处置。类似避障的消息处理机制。
调用父类的
packetReceived()
。accept_packet()
,是否准备接收这个消息,主要是查看,发送者的system ID 是否跟参数设置的相符,如果相符返回true.handle_message()
,用户层,数据包解包,赋值操作。根据msg 结构体的内容赋值。
设计思想是,尽量把需要用户修改的部分放在子类,不需要用户修改的部分放在基类。这样方便我们对的代码,修改。在以后的开发中,可以借鉴这种设计思想。
总结
初始化过程
- MAVLINK对象创建和初始化,包括设置串口和协议
setup_uart
函数负责串口设置,包括波特率和协议选择
循环调用过程
- 主要有四个循环调用函数:检查输入、发送心跳、发送延迟消息和发送数据流
- 在主线程启动前,通过
mavlink_delay_cb
进行通信
消息发送过程
- 使用消息队列系统,先将消息放入队列,空闲时发送
- 发送过程考虑系统实时性,只在剩余时间充足时发送
消息解包过程
- 使用
mavlink_parse_char
函数组包,然后根据包类型解包
- 可以在
packetReceived
函数中添加自定义消息处理
Loading...