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...