一、mavlink消息定义
Mavlink传输时的基本单位是消息帧。协议设计的目标是传输速度和安全性。它允许消息内容检查、消息丢失检测 ;每个数据包需要6 字节报头。每次发完一个消息,SEQ的内容会加1,加到255后会从0重新开始。这个序号用于mavlink消息帧接收端计算消息丢失比例用的,在地面站处理中相当于是信号强度。
STX:起始标志位,在v1.0版本中用“FE”表示。用于消息帧接收端进行消息解码。
LEN:代表PAYLOAD的字节长度,取值0~255,用于消息帧接收端验证有效载荷长度是否正确。
SEQ:表示本次消息帧的序号,每发完一次消息,该字节内容会加1,加到255后会从0开始。用于Mavlink消息帧接收端计算消息丢失比,相当于信号强度。
SYS:代表发送本条消息帧的设备的系统编号,用于接收端识别消息来自哪个设备。
COMP:代表发送本条消息帧的设备的单元编号,用于接收端识别消息来自设备的哪个单元。
MSG:表示有效载荷中消息包的编号,与SEQ不同,接收端要根据该字节确定有效载荷里的消息包类型,然后选择对应的方式处理消息包。
PAYLOAD:有效载荷,即要传送的数据,范围0~255字节。
CKA,CKB:这两个字节是16位校验位,CKB是高8位,CKA是低8位,统称校验和。校验码由CRC16算法得到,算法将整个消息(从LEN到PAYLOAD结束,还要额外加上MAVLINK_CRC_EXTRA对应的1个字节)进行CRC16计算,得出一个16位的校验码。每种PAYLOAD都会对应一个MAVLINK_CRC_EXTRA,这是由生成Mavlink代码的xml文件生成的。加入校验是为了应对以下情况:当飞行器和地面站使用不同版本的Mavlink协议时,双方计算的校验码不同。
Mavlink1.0 升级到 Mavlink2.0,有如下几个变化:
(1)INC FLAGS(Incompatibility flags):此标志位会影响报文的结构,该标志指示数据包是否包含一些特殊功能。例如标志等于0x01表示该数据包已签名,并且在数据包的末尾附加了签名;
(2)CMP FLAGS(compatibility flags):不影响报文的结构,即使无法解释标志,也不会阻止解析器处理消息;
(3)Message ID (MSGID):相较于V1.0版本的8位变为24位,它允许在Mavlink 2.0中使用更多类型的消息,最多可以达到16777215种类型;
(4)可选用的SIGNATURE:最后,Mavlink 2.0使用可选的13字节签名字段来确保链接被篡改。此功能显着改善了Mavlink 1.0的安全性,因为它允许对消息进行身份验证并验证消息源自受信任的源。如果INC FLAGS设置为0x01,则会附加消息的签名;
(5)STX:1.0版本中为0XFE,2.0版本中为0XFD。
对应wireshark解析报文如下:
Mavlink协议优点:
(1)Mavlink基于LGPL开源协议而来,作为商业公司可以免费使用,相对于GPL要求使用开发的商业软件也必须开源,LGPL并无此要求,所以作为商业公司可以放心使用;
(2)支持不同的传输层和传输媒介,可以通过WiFi、以太网、遥测低频通道,即433MHz、868MHz或915MHz等物理层承载应用协议。下表列出了一些常用的遥测设备。
(3)可靠性较高
Mavlink设定了心跳包机制,可用于检测无人设备与地面站之间连通性的检测。
尽管Mavlink通信协议很强大,而且使用最广泛,但它缺乏安全机制,使其容易受到一些攻击,如拒绝服务攻击(DDoS)、窃听和中间人攻击。因为Mavlink协议没有对通信中的信息进行加密,这使得Mavlink很容易成为安全攻击的目标,损害了无人机的飞行安全。以下就Mavlink协议面临的威胁做出详细分析。
二、mavlink-router中的sender.py脚本解析
#!/usr/bin/python3command:workbench.trust.manage
from threading import Thread
from time import sleep
import sys
import time
from pymavlink import mavutil
TARGET_COMP_ID = 1
if len(sys.argv) != 4:
print("Usage: %s <ip:udp_port> <system-id> <target-system-id>" % (sys.argv[0]))
print("Send mavlink custom message, using given <system-id> and <target-system-id>, to specified interface")
sys.exit()
mav = mavutil.mavlink_connection('udpout:' + sys.argv[1], source_system=int(sys.argv[2]))
def send_custom_message(mav, message_text):
# Create and send a custom STATUSTEXT message
mav.mav.statustext_send(
severity=1, # Information severity level
text=message_text.encode('utf-8') # Message text, encoded to bytes
)
def message_loop():
i = 0
while True:
message_text = f"Custom message {i}"
send_custom_message(mav, message_text)
print("Custom message sent:", message_text)
i += 1
sleep(1)
msg_thread = Thread(target=message_loop)
msg_thread.daemon = True
msg_thread.start()
while True:
msg = mav.recv_match(blocking=True)
print("Message from %d: %s" % (msg.get_srcSystem(), msg))
执行命令:python3 sender1.py 127.0.0.1:3000 100 0
这个脚本和命令参数
100 0
直接相关,因为脚本中的system-id
和target-system-id
参数就是从命令行中传入的。在这个脚本中,sys.argv[2]
和sys.argv[3]
分别代表system-id
和target-system-id
。具体分析如下:命令参数解释
127.0.0.1:3000
:目标IP地址和端口(本地回环地址和端口3000)。100
:system-id
,表示发送消息的系统ID。0
:target-system-id
,表示目标系统ID。脚本解析
- 第11行:检查命令行参数数量是否为4(脚本名、IP和端口、
system-id
和target-system-id
)。- 第12行:如果参数数量不正确,打印用法说明并退出。
- 第16行:使用
mavutil.mavlink_connection
创建一个MAVLink连接,其中sys.argv[1]
是127.0.0.1:3000
,sys.argv[2]
是100
。- 第18-23行:定义
send_custom_message
函数,用于发送自定义的STATUSTEXT
消息。- 第25-32行:定义
message_loop
函数,在一个循环中每秒发送一次自定义消息。- 第34-36行:启动一个新的线程运行
message_loop
函数。- 第38-40行:在主线程中接收并打印来自MAVLink的消息。