█ 【无人机学习之DroidPlanner】MAVLink协议
█ 系列文章目录
提示:这里是收集了无人机的相关文章
- 【无人机学习】无人机基础知识
- 【无人机学习】Mission Planner(pc端)和QGroundControl(android端)
- 【无人机学习之DroidPlanner】MAVLink协议
- 【无人机学习之DroidPlanner】msg_heartbeat心跳处理
- 【无人机学习之DroidPlanner】msg_sys_status系统状态
- 【无人机学习之QGroundControl】android端App初解1
- 【无人机学习之QGroundControl】android端App初解2-APMPowerComponent(含QML的介绍)
- 【无人机学习之QGroundControl】android端App初解3-ParameterEditorController
█ 文章目录
█ 读前说明
-
本文通过学习别人写demo,学习一些课件,参考一些博客,学习相关知识,如有涉及侵权请告知
-
本文可能只简单罗列了一些相关的代码实现过程,复制了一些大神的高论,如内容有误请自行辨别
-
涉及到的逻辑以及说明可能只做了简单的介绍,主要当做笔记,了解过程而已,如有不同看法,欢迎下方评论
-
MAVLink定义:
MAVLink - common - msg_attitude
MissionPlanner-master2021 - Mavlink.cs
█ MAVLink
1.简介
- 官网:MAVLink
- MAVLink是一种非常轻量级的通信协议,主要是用于无人机上,还有无人车等;
- 目前MAVLink有两个版本:V1.0(2013年发布)和V2.0版本(2017年发布);
- V2是V1的拓展版本,简化传输,向下兼容V1.0,是一个更加安全和可扩展的协议;
- MAVLink通信内容包含常见通信协议帧头、帧尾、长度、校验等。
- MAVLink目前最新版本是 V 2.3;
- qgc地面站使用的是mavlink ,和px4是同一个人研发的;
2.协议格式
官网:mavlink协议格式
比较重要的字段是msgid和payload,msgid用来区分消息类型,判断需要转换成什么类型的对话,payload是对应的值
uint8_t magic; ///< protocol magic marker
uint8_t len; ///< Length of payload
uint8_t incompat_flags; ///< flags that must be understood (V2.0增加)
uint8_t compat_flags; ///< flags that can be ignored if not understood(V2.0增加)
uint8_t seq; ///< Sequence of packet
uint8_t sysid; ///< ID of message sender system/aircraft
uint8_t compid; ///< ID of the message sender component
uint8_t msgid 0:7; ///< first 8 bits of the ID of the message
uint8_t msgid 8:15; ///< middle 8 bits of the ID of the message
uint8_t msgid 16:23; ///< last 8 bits of the ID of the message
uint8_t payload[max 255]; ///< A maximum of 255 payload bytes
uint16_t checksum; ///< CRC-16/MCRF4XX
uint8_t signature[13]; ///< Signature which allows ensuring that the link is tamper-proof (optional)(V2.0增加)
索引 | C 版 | 内容 | 值 | 说明 | |
---|---|---|---|---|---|
STX | 0 | uint8_t magic | 起始标志位 | 0xFD | 表示新数据包的开始,固定以“FD”开头 |
LEN | 1 | uint8_t len | 载荷长度 | 0 - 255 | 有效载荷数据的字节长度(N) |
INC FLAGS | 2 | uint8_t incompat_flags | 不兼容标志 | 不了解标志,则实现将丢弃数据包 | |
CMP FLAGS | 3 | uint8_t compat_flags | 兼容性标志 | 不理解该标志,仍可以处理数据包 | |
SEQ | 4 | uint8_t seq | 包序号 | 0 - 255 | 用于检测数据包丢失,每发送完一个消息,加1 |
SYS ID | 5 | uint8_t sysid | 系统ID(发送者) | 1 - 255 | 发送消息的系统(飞机/车辆)的ID |
COMP ID | 6 | uint8_t compid | 部件 ID (发送者) | 1 - 255 | 发送消息的部件的ID 。用来区分在系统中的不同组件,如自动驾驶仪和照相机 |
MSG ID | 7 to 9 | uint32_t msgid:24 | 消息ID(低,中,高字节) | 0 - 16777215 | 有效载荷中消息类型的ID 。用于将数据解码回消息对象。 |
PLAYLOAD | 10 to (n+10) | uint8_t payload[max 255] | 载荷 | 消息数据。取决于消息类型(即消息ID)和内容。 | |
CHECKSUM | (n+10) to (n+11) | uint16_t checksum | 冗余校验/校验和(低字节,高字节) | 消息的CRC-16 / MCRF4XX(不包括magic字节),包括CRC_EXTRA字节 | |
SIGNATURE | (n+12) to (n+25) | uint8_t signature[13] | 签名 | (可选)签名以确保链接是防篡改的。 |
3.使用Python写的用于生成C、Java等语言的MavLink生成器软件:
█ DroidPlanner怎么发送消息(mavlink v1.0)
1.mavlink 版本
从代码中可以看出:
使用的mavlink的版本是v1.0;
其实比V2.0少了INC FLAGS、CMP FLAGS、SIGNATURE 三个参数;
2.代码过程
过程 | 说明 |
---|---|
new msg_command_long() | msgid = 76; |
设置target_system | drone.getSysid(); drone.getCompid(); |
设置target_component | drone.getCompid(); |
3.配置起飞模式(MavLinkCommands.java)
提示:此文件全路径为:org.droidplanner.services.android.impl.core.MAVLink.MavLinkCommands.java
- 首先看下这份代码的1个发送命令方法:(配置起飞模式)
public static void sendTakeoff(MavLinkDrone drone, double alt, ICommandListener listener) {
msg_command_long msg = new msg_command_long();// msgid = 76;
msg.target_system = drone.getSysid();
msg.target_component = drone.getCompid();
msg.command = MAV_CMD.MAV_CMD_NAV_TAKEOFF;// 起飞模式
msg.param7 = (float) alt;// z轴,即高度
drone.getMavClient().sendMessage(msg, listener);// 下一步需要查看的信息:MAVLinkClient.sendMessage()
}
- new msg_command_long()就是创建了一个 msgid = MAVLINK_MSG_ID_COMMAND_LONG;即76;
- 查看#76的协议文档:
提示:注意到command的数据类型是MAV_CMD
- 查看MAV_CMD的协议文档:
MAVLink Commands (MAV_CMD)
MAVLink命令(MAV_CMD)和消息不同,定义了最多7个参数的值,被打包在特定任务中使用的协议和命令协议的消息。命令执行的飞行器
MAV_CMD_NAV_TAKEOFF:(22 起飞模式)
4.发送(MAVLinkClient.java)
提示:此文件全路径为:org.droidplanner.services.android.impl.communication.service.MAVLinkClient.java
private static final int DEFAULT_SYS_ID = 255;
private static final int DEFAULT_COMP_ID = 190;
@Override
public synchronized void sendMessage(MAVLinkMessage message, ICommandListener listener) {
sendMavMessage(message, DEFAULT_SYS_ID, DEFAULT_COMP_ID, listener);
}
protected void sendMavMessage(MAVLinkMessage message, int sysId, int compId, ICommandListener listener){
if (isDisconnected() || message == null) {
return;
}
final MAVLinkPacket packet = message.pack();
packet.sysid = sysId;
packet.compid = compId;
packet.seq = packetSeqNumber;
mavlinkConn.sendMavPacket(packet);// 下一步需要查看的信息:MavLinkConnection
packetSeqNumber = (packetSeqNumber + 1) % (MAX_PACKET_SEQUENCE + 1);
if (commandTracker != null && listener != null) {
commandTracker.onCommandSubmitted(message, listener);
}
}
5.发送(MavLinkConnection.java)
提示:此文件全路径为:org.droidplanner.services.android.impl.core.MAVLink.connection.MavLinkConnection.java
// 转换成16进制大写字符串发送出去
public void sendMavPacket(MAVLinkPacket packet) {
final byte[] packetData = packet.encodePacket();
Log.e("sendMavPacket", String2ByteArrayUtils.INSTANCE.bytes2Hex(packetData));
if (!mPacketsToSend.offer(packetData)) {
mLogger.logErr(TAG, "Unable to send mavlink packet. Packet queue is full!");
}
}
6.MAVLink协议
提示:
每个数基本上都是一个字节(uint8_t )即0x00-0xff;
msg_command_long 的发送结构
| STX | LEN|SEQ|SYS ID|COMPID ID|MSG ID|PLAYLOAD|CHECK SUM|
|–|–|–|–|–|–|–|–|–|
|起始位|载荷长度|包序号|地面站系统ID|地面站部件 ID|消息ID|载荷|校验|
|固定值|自动|自动|固定值|固定值|COMMAND LONG|–|自动|
|0xFE|–|–|255|190|76|–|–|
PLAYLOAD的发送结构(MAV_CMD_NAV_TAKEOFF)
target system | target component | command | confirmation | Pitch | param2 | param3 | Yaw | Latitude | Longitude | Altitude |
---|---|---|---|---|---|---|---|---|---|---|
飞控系统id | 飞控部件 ID | MAV_CMD指令 | 确认位 | 最高点 | Empty | Empty | 偏航角 | 维度 | 经度 | 高度 |
drone.Sysid | drone.Compid | TAKEOFF | – | – | – | – | – | – | – | alt |
7.其他
1.MissionPlanner 使用的是 MAVLink 2.0(参考 “MissionPlanner-master\ExtLibs\Mavlink\Mavlink.cs”)
public partial class MAVLink
{
public const string MAVLINK_BUILD_DATE = "Sat Dec 26 2020";
public const string MAVLINK_WIRE_PROTOCOL_VERSION = "2.0";// ###V2.0标记
public const int MAVLINK_MAX_PAYLOAD_LEN = 255;
public const byte MAVLINK_CORE_HEADER_LEN = 9;///< Length of core header (of the comm. layer)
public const byte MAVLINK_CORE_HEADER_MAVLINK1_LEN = 5;///< Length of MAVLink1 core header (of the comm. layer)
public const byte MAVLINK_NUM_HEADER_BYTES = (MAVLINK_CORE_HEADER_LEN + 1);///< Length of all header bytes, including core and stx
public const byte MAVLINK_NUM_CHECKSUM_BYTES = 2;
public const byte MAVLINK_NUM_NON_PAYLOAD_BYTES = (MAVLINK_NUM_HEADER_BYTES + MAVLINK_NUM_CHECKSUM_BYTES);
public const byte MAVLINK_STX_MAVLINK1 = 0xFE;// ###V2.0标记,V1.0是0xFD
。。。。。。
// msgid, name, crc, minlength, length, type
public static message_info[] MAVLINK_MESSAGE_INFOS = new message_info[] {
new message_info(148, "AUTOPILOT_VERSION", 178, 60, 78, typeof( mavlink_autopilot_version_t )),
new message_info(42001, "ICAROUS_KINEMATIC_BANDS", 239, 46, 46, typeof( mavlink_icarous_kinematic_bands_t )),
new message_info(269, "VIDEO_STREAM_INFORMATION", 58, 246, 246, typeof( mavlink_video_stream_information_t )),
new message_info(0, "HEARTBEAT", 50, 9, 9, typeof( mavlink_heartbeat_t )),
};
public const byte MAVLINK_VERSION = 2;
public const byte MAVLINK_IFLAG_SIGNED= 0x01;
public const byte MAVLINK_IFLAG_MASK = 0x01;
public struct message_info
{
public uint msgid { get; internal set; }
public string name { get; internal set; }
public byte crc { get; internal set; }
public uint minlength { get; internal set; }
public uint length { get; internal set; }
public Type type { get; internal set; }
}
public struct mavlink_autopilot_version_t
{
public mavlink_autopilot_version_t(/*MAV_PROTOCOL_CAPABILITY*/ulong capabilities,ulong uid,uint flight_sw_version,uint middleware_sw_version,uint os_sw_version,uint board_version,ushort vendor_id,ushort product_id,byte[] flight_custom_version,byte[] middleware_custom_version,byte[] os_custom_version,byte[] uid2)
{
this.capabilities = capabilities;
this.uid = uid;
this.flight_sw_version = flight_sw_version;
this.middleware_sw_version = middleware_sw_version;
this.os_sw_version = os_sw_version;
this.board_version = board_version;
this.vendor_id = vendor_id;
this.product_id = product_id;
this.flight_custom_version = flight_custom_version;
this.middleware_custom_version = middleware_custom_version;
this.os_custom_version = os_custom_version;
this.uid2 = uid2;
}
/// <summary>Bitmap of capabilities MAV_PROTOCOL_CAPABILITY bitmask</summary>
[Units("")]
[Description("Bitmap of capabilities")]
public /*MAV_PROTOCOL_CAPABILITY*/ulong capabilities;
/// <summary>UID if provided by hardware (see uid2) </summary>
[Units("")]
[Description("UID if provided by hardware (see uid2)")]
public ulong uid;
/// <summary>Firmware version number </summary>
[Units("")]
[Description("Firmware version number")]
public uint flight_sw_version;
/// <summary>Middleware version number </summary>
[Units("")]
[Description("Middleware version number")]
public uint middleware_sw_version;
/// <summary>Operating system version number </summary>
[Units("")]
[Description("Operating system version number")]
public uint os_sw_version;
/// <summary>HW / board version (last 8 bytes should be silicon ID, if any) </summary>
[Units("")]
[Description("HW / board version (last 8 bytes should be silicon ID, if any)")]
public uint board_version;
/// <summary>ID of the board vendor </summary>
[Units("")]
[Description("ID of the board vendor")]
public ushort vendor_id;
/// <summary>ID of the product </summary>
[Units("")]
[Description("ID of the product")]
public ushort product_id;
/// <summary>Custom version field, commonly the first 8 bytes of the git hash. This is not an unique identifier, but should allow to identify the commit using the main version number even for very large code bases. </summary>
[Units("")]
[Description("Custom version field, commonly the first 8 bytes of the git hash. This is not an unique identifier, but should allow to identify the commit using the main version number even for very large code bases.")]
[MarshalAs(UnmanagedType.ByValArray,SizeConst=8)]
public byte[] flight_custom_version;
/// <summary>Custom version field, commonly the first 8 bytes of the git hash. This is not an unique identifier, but should allow to identify the commit using the main version number even for very large code bases. </summary>
[Units("")]
[Description("Custom version field, commonly the first 8 bytes of the git hash. This is not an unique identifier, but should allow to identify the commit using the main version number even for very large code bases.")]
[MarshalAs(UnmanagedType.ByValArray,SizeConst=8)]
public byte[] middleware_custom_version;
/// <summary>Custom version field, commonly the first 8 bytes of the git hash. This is not an unique identifier, but should allow to identify the commit using the main version number even for very large code bases. </summary>
[Units("")]
[Description("Custom version field, commonly the first 8 bytes of the git hash. This is not an unique identifier, but should allow to identify the commit using the main version number even for very large code bases.")]
[MarshalAs(UnmanagedType.ByValArray,SizeConst=8)]
public byte[] os_custom_version;
/// <summary>UID if provided by hardware (supersedes the uid field. If this is non-zero, use this field, otherwise use uid) </summary>
[Units("")]
[Description("UID if provided by hardware (supersedes the uid field. If this is non-zero, use this field, otherwise use uid)")]
[MarshalAs(UnmanagedType.ByValArray,SizeConst=18)]
public byte[] uid2;
};
}
█ 相关资料
提示:这里是参考的相关文章
- mavlink官网:MAVLink
- pixhawk官网:Mavlink 消息简介 - pixhawk
- 2020-10-06 ardupilot 如何为android 增加mavlink协议_陌城烟雨-CSDN博客
- 打造自己的HelloDrone 无人机APP过程《2》_陌城烟雨-CSDN博客_drone无人机怎么下app
- 2015-04-02 Mavlink协议理解Pixhawk APM(一)_super_mice的专栏-CSDN博客
- 2018-12-24 无人机中级篇:第十四讲:外部通信总线Mavlink服务 - 知乎
- 2019-02-15 MAVLINK 请求参数和接收参数_小马哔哔-CSDN博客
- 很直白:2020-02-06 MAVLink笔记 #02# MAVLink绝对傻瓜教程(译) - xkfx - 博客园
█ 免责声明
博主分享的所有文章内容,部分参考网上教程,引用大神高论,部分亲身实践,记下笔录,内容可能存在诸多不实之处,还望海涵,本内容仅供学习研究使用,切勿用于商业用途,若您是部分内容的作者,不喜欢此内容被分享出来,可联系博主说明相关情况通知删除,感谢您的理解与支持! |
---|
提示:转载请注明出处:
https://blog.csdn.net/ljb568838953/article/details/112827387