【无人机开发】通讯协议MavLink详解

1. MAVLink简介

MAVLink(Micro Air Vehicle Link,微型空中飞行器链路通讯协议)是无人飞行器与地面站(Ground Control Station ,GCS)之间通讯,以及无人飞行器之间通讯最常用的协议。它已经在PX4、APM、PIXHAWK和Parrot AR.Drone飞控平台上进行了大量测试。

2.发明者Lorenz Meier简介

MAVLink的最初开发于2009年,由Lorenz Meier完成。Lorenz Meier的LinkedIn主页是:https://www.linkedin.com/in/meierlorenz,个人主页是:https://www.inf.ethz.ch/personal/lomeier/。 
根据官网和个人主页,Lorenz Meie的个人经历如下: 
 2004年~2008年在德国康斯坦茨大学(Universität Konstanz)就读信息工程专业; 
 2008 年~2011年在苏黎世联邦理工学院(德语:Eidgenössische Technische Hochschule Zürich,简称 ETH Zürich或ETHZ)就读视觉计算方向研究生; 
 2011~至今在ETHZ攻读博士后,研究方向是:Research on Drones and mobile phones focused on obstacle mapping, path planning and control. 
 2011年到现在,Lorenz Meier一直是开源无人机项目Autopilot的建立者和维护者。关于Autopilot,我会另辟章节介绍。 
从介绍来看,Lorenz Meier的研究方向包括了无人机避障、基于智能手机或无人机的3D重建、无人机通讯协议等有趣又前言的内容。 
这个页面是Lorenz Meier发表的几篇文章:https://www.researchgate.net/profile/Lorenz_Meier3

3. MAVLink相关资料

维基百科:https://en.wikipedia.org/wiki/MAVLink 
MavLink官方网站:http://qgroundcontrol.org/mavlink/start 
Python写的用于生成C、Java等语言的MavLink生成器软件:https://github.com/mavlink/mavlink

4.协议构成

下面内容引自官网。 
这里写图片描述 
• The checksum is the same as used in ITU X.25 and SAE AS-4 standards (CRC-16-CCITT), documented in SAE AS5669A. Please see the MAVLink source code for a documented C-implementation of it. LINK TO CHECKSUM 
• The minimum packet length is 8 bytes for acknowledgement packets without payload 
• The maximum packet length is 263 bytes for full payload

MavLink的长度是固定的,即 17byte= 6 bytes header + 9 bytes payload + 2 bytes checksum。

5.封包过程

由用户生成的部分包括PlayLoad本身、消息包的STX、COMP、MSG,其他部分自动生成。下图来自于博客MAVLink协议通信分析——(二)消息结构_Fergus-优快云博客,侵删。 
这里写图片描述

6.3DR Service实现MavLink协议

3DR Service是Autopilot提供的Android端的app服务,用于做SDK,提供与无人机通讯,以AIDL的方式为上层的App提供服务。基于3DRService,开发者可以不用处理复杂的MavLink通讯,只根据AIDL接口调用服务即可。 
这里下载了3DRService用于分析,地址为:https://github.com/ne0fhyk/3DRServices。3DRService将MavLink的协议部分作为单独的包,即项目中的dependencyLibs文件夹。

6.1. UML图

绘制dependencyLibs的UML图。该包主要提供了MavLink的所有类型的封包类和解析类。 
这里写图片描述

例如,对于MAVLinkPacket类,其核心部分为封包过程。

  1. /**

  2. * Encode this packet for transmission.

  3. *

  4. * @return Array with bytes to be transmitted

  5. */

  6. public byte[] encodePacket() {

  7. byte[] buffer = new byte[6 + len + 2];

  8. int i = 0;

  9. buffer[i++] = (byte) MAVLINK_STX;

  10. buffer[i++] = (byte) len;

  11. buffer[i++] = (byte) seq;

  12. buffer[i++] = (byte) sysid;

  13. buffer[i++] = (byte) compid;

  14. buffer[i++] = (byte) msgid;

  15. final int payloadSize = payload.size();

  16. for (int j = 0; j < payloadSize; j++) {

  17. buffer[i++] = payload.payload.get(j);

  18. }

  19. generateCRC();

  20. buffer[i++] = (byte) (crc.getLSB());

  21. buffer[i++] = (byte) (crc.getMSB());

  22. return buffer;

  23. }

解包的核心部分在Parser类中:

  1. /**

  2. * This is a convenience function which handles the complete MAVLink

  3. * parsing. the function will parse one byte at a time and return the

  4. * complete packet once it could be successfully decoded. Checksum and other

  5. * failures will be silently ignored.

  6. *

  7. * @param c

  8. * The char to parse

  9. */

  10. public MAVLinkPacket mavlink_parse_char(int c) {

  11. msg_received = false;

  12. switch (state) {

  13. case MAVLINK_PARSE_STATE_UNINIT:

  14. case MAVLINK_PARSE_STATE_IDLE:

  15. if (c == MAVLinkPacket.MAVLINK_STX) {

  16. state = MAV_states.MAVLINK_PARSE_STATE_GOT_STX;

  17. }

  18. break;

  19. case MAVLINK_PARSE_STATE_GOT_STX:

  20. if (msg_received) {

  21. msg_received = false;

  22. state = MAV_states.MAVLINK_PARSE_STATE_IDLE;

  23. } else {

  24. m = new MAVLinkPacket(c);

  25. state = MAV_states.MAVLINK_PARSE_STATE_GOT_LENGTH;

  26. }

  27. break;

  28. case MAVLINK_PARSE_STATE_GOT_LENGTH:

  29. m.seq = c;

  30. state = MAV_states.MAVLINK_PARSE_STATE_GOT_SEQ;

  31. break;

  32. case MAVLINK_PARSE_STATE_GOT_SEQ:

  33. m.sysid = c;

  34. state = MAV_states.MAVLINK_PARSE_STATE_GOT_SYSID;

  35. break;

  36. case MAVLINK_PARSE_STATE_GOT_SYSID:

  37. m.compid = c;

  38. state = MAV_states.MAVLINK_PARSE_STATE_GOT_COMPID;

  39. break;

  40. case MAVLINK_PARSE_STATE_GOT_COMPID:

  41. m.msgid = c;

  42. if (m.len == 0) {

  43. state = MAV_states.MAVLINK_PARSE_STATE_GOT_PAYLOAD;

  44. } else {

  45. state = MAV_states.MAVLINK_PARSE_STATE_GOT_MSGID;

  46. }

  47. break;

  48. case MAVLINK_PARSE_STATE_GOT_MSGID:

  49. m.payload.add((byte) c);

  50. if (m.payloadIsFilled()) {

  51. state = MAV_states.MAVLINK_PARSE_STATE_GOT_PAYLOAD;

  52. }

  53. break;

  54. case MAVLINK_PARSE_STATE_GOT_PAYLOAD:

  55. m.generateCRC();

  56. // Check first checksum byte

  57. if (c != m.crc.getLSB()) {

  58. msg_received = false;

  59. state = MAV_states.MAVLINK_PARSE_STATE_IDLE;

  60. if (c == MAVLinkPacket.MAVLINK_STX) {

  61. state = MAV_states.MAVLINK_PARSE_STATE_GOT_STX;

  62. m.crc.start_checksum();

  63. }

  64. stats.crcError();

  65. } else {

  66. state = MAV_states.MAVLINK_PARSE_STATE_GOT_CRC1;

  67. }

  68. break;

  69. case MAVLINK_PARSE_STATE_GOT_CRC1:

  70. // Check second checksum byte

  71. if (c != m.crc.getMSB()) {

  72. msg_received = false;

  73. state = MAV_states.MAVLINK_PARSE_STATE_IDLE;

  74. if (c == MAVLinkPacket.MAVLINK_STX) {

  75. state = MAV_states.MAVLINK_PARSE_STATE_GOT_STX;

  76. m.crc.start_checksum();

  77. }

  78. stats.crcError();

  79. } else { // Successfully received the message

  80. stats.newPacket(m);

  81. msg_received = true;

  82. state = MAV_states.MAVLINK_PARSE_STATE_IDLE;

  83. }

  84. break;

  85. }

  86. if (msg_received) {

  87. return m;

  88. } else {

  89. return null;

  90. }

  91. }

这个类的使用是逐个直接解析,解析完毕后返回完整的包,例如,对字节数组packet,解析过程如下:

 
  1. for(int i = 0; i < packet.length - 1; i++){

  2. parser.mavlink_parse_char(packet[i] & 0xFF);//每次解析1位

  3. }

  4. MAVLinkPacket m = parser.mavlink_parse_char(packet[packet.length - 1] & 0xFF);//最后1位即可返回

6.2 MavLink包测试

dependencyLibs提供了测试实例。以msg_altitude为例,判断生成的包和解析的包是否相同,即可判断该类是否正确。

  1. /**

  2. * The current system altitude.

  3. */

  4. public class msg_altitude_test{

  5. public static final int MAVLINK_MSG_ID_ALTITUDE = 141;

  6. public static final int MAVLINK_MSG_LENGTH = 24;

  7. private static final long serialVersionUID = MAVLINK_MSG_ID_ALTITUDE;

  8. private Parser parser = new Parser();//1位解析类

  9. public CRC generateCRC(byte[] packet){

  10. CRC crc = new CRC();

  11. for (int i = 1; i < packet.length - 2; i++) {

  12. crc.update_checksum(packet[i] & 0xFF);

  13. }

  14. crc.finish_checksum(MAVLINK_MSG_ID_ALTITUDE);

  15. return crc;

  16. }

  17. public byte[] generateTestPacket(){

  18. ByteBuffer payload = ByteBuffer.allocate(6 + MAVLINK_MSG_LENGTH + 2);

  19. payload.put((byte)MAVLinkPacket.MAVLINK_STX); //stx

  20. payload.put((byte)MAVLINK_MSG_LENGTH); //len

  21. payload.put((byte)0); //seq

  22. payload.put((byte)255); //sysid

  23. payload.put((byte)190); //comp id

  24. payload.put((byte)MAVLINK_MSG_ID_ALTITUDE); //msg id

  25. payload.putFloat((float)17.0); //altitude_monotonic

  26. payload.putFloat((float)45.0); //altitude_amsl

  27. payload.putFloat((float)73.0); //altitude_local

  28. payload.putFloat((float)101.0); //altitude_relative

  29. payload.putFloat((float)129.0); //altitude_terrain

  30. payload.putFloat((float)157.0); //bottom_clearance

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值