当前位置:   article > 正文

MAVLink分析及封装自定义的类MavLink通信协议_mavlink java开发

mavlink java开发

        MAVLink是一种非常轻量级的消息传输协议, 用于地面控制终端(地面站)与无人机之间 (以及机载无人机组件之间) 进行通信。

        MAVLink官方地址

  一、自动生成mavlink协议代码:

        1、安装MavLink环境

        2、生成 MAVLink 库文件

        3、装好环境后,利用mavgenerate把以下的demo.xml生成对应的mavlink JAVA/C/C++代码

  1. <?xml version="1.0"?>
  2. <mavlink>
  3. <version>1</version>
  4. <enums>
  5. <enum name="SYS_STATE">
  6. <description>System state.</description>
  7. <entry value="0" name="SYS_STOP">
  8. <description>System stop state</description>
  9. </entry>
  10. <entry value="1" name="SYS_RUN">
  11. <description>System run state</description>
  12. </entry>
  13. </enum>
  14. </enums>
  15. <messages>
  16. <message id="150" name="SysInfo">
  17. <description>System information.</description>
  18. <field type="uint8_t" name="sysState" >System state.</field>
  19. <field type="uint16_t" name="voltageBattery">Battery voltage</field>
  20. </message>
  21. </messages>
  22. </mavlink>

        生成的代码在项目MyMavlinkDemoModulede的heartbeat中。

        二、MavLink2帧格式:

        

         以上是MavLink的一帧格式,整个协议组包和解包过程都是围绕着这帧进行的

        三、自动生成mavlink的Java/C/C++代码分析:

                协议握手图:

        

        我们以Java相关的代码为GCS端,以C/C++相关代码为Drone端为例。

        GCS端Java代码分析:

        工具类MAVLinkMessage、MAVLinkPayload、MAVLinkPacket、Paser对象协议的封装起到至关重要的作用,而msg_sysinfo是具体到每条有效的命令。

  •  MAVLinkMessage 类定义了 sysid、compid、msgid的帧头的属性,提供了pack()对MAVLinkPacket的组装和unpack()剥离出命令中的属性的两个方法:
  1. /* AUTO-GENERATED FILE. DO NOT MODIFY.
  2. *
  3. * This class was automatically generated by the
  4. * java mavlink generator tool. It should not be modified by hand.
  5. */
  6. package com.MAVLink.Messages;
  7. import java.io.Serializable;
  8. import com.MAVLink.MAVLinkPacket;
  9. /**
  10. * Common interface for all MAVLink messages
  11. */
  12. public abstract class MAVLinkMessage implements Serializable {
  13. private static final long serialVersionUID = -7754622750478538539L;
  14. // The MAVLink message classes have been changed to implement Serializable,
  15. // this way is possible to pass a mavlink message through the Service-Acctivity interface
  16. public int sysid;
  17. public int compid;
  18. public int msgid;
  19. public boolean isMavlink2;
  20. public abstract MAVLinkPacket pack();
  21. public abstract void unpack(MAVLinkPayload payload);
  22. public abstract String toString();
  23. public abstract String name();
  24. }
  • msg_sysinfo类继承了MAVLinkMessage ,属性voltageBattery、sysState对象的是XML中标签<field>的两个命令值。
  1. // MESSAGE SysInfo PACKING
  2. package com.MAVLink.Demo_heart;
  3. import com.MAVLink.MAVLinkPacket;
  4. import com.MAVLink.Messages.MAVLinkMessage;
  5. import com.MAVLink.Messages.MAVLinkPayload;
  6. import com.MAVLink.Messages.Units;
  7. import com.MAVLink.Messages.Description;
  8. public class msg_sysinfo extends MAVLinkMessage {
  9. public static final int MAVLINK_MSG_ID_SysInfo = 150;
  10. public static final int MAVLINK_MSG_LENGTH = 3;
  11. private static final long serialVersionUID = MAVLINK_MSG_ID_SysInfo;
  12. @Description("Battery voltage")
  13. @Units("")
  14. public int voltageBattery;
  15. @Description("System state.")
  16. @Units("")
  17. public short sysState;
  18. @Override
  19. public MAVLinkPacket pack() {
  20. MAVLinkPacket packet = new MAVLinkPacket(MAVLINK_MSG_LENGTH,isMavlink2);
  21. packet.sysid = sysid;
  22. packet.compid = compid;
  23. packet.msgid = MAVLINK_MSG_ID_SysInfo;
  24. packet.payload.putUnsignedShort(voltageBattery);
  25. packet.payload.putUnsignedByte(sysState);
  26. if (isMavlink2) {
  27. }
  28. return packet;
  29. }
  30. @Override
  31. public void unpack(MAVLinkPayload payload) {
  32. payload.resetIndex();
  33. this.voltageBattery = payload.getUnsignedShort();
  34. this.sysState = payload.getUnsignedByte();
  35. if (isMavlink2) {
  36. }
  37. }
  38. public msg_sysinfo() {
  39. this.msgid = MAVLINK_MSG_ID_SysInfo;
  40. }
  41. public msg_sysinfo( int voltageBattery, short sysState) {
  42. this.msgid = MAVLINK_MSG_ID_SysInfo;
  43. this.voltageBattery = voltageBattery;
  44. this.sysState = sysState;
  45. }
  46. public msg_sysinfo( int voltageBattery, short sysState, int sysid, int compid, boolean isMavlink2) {
  47. this.msgid = MAVLINK_MSG_ID_SysInfo;
  48. this.sysid = sysid;
  49. this.compid = compid;
  50. this.isMavlink2 = isMavlink2;
  51. this.voltageBattery = voltageBattery;
  52. this.sysState = sysState;
  53. }
  54. public msg_sysinfo(MAVLinkPacket mavLinkPacket) {
  55. this.msgid = MAVLINK_MSG_ID_SysInfo;
  56. this.sysid = mavLinkPacket.sysid;
  57. this.compid = mavLinkPacket.compid;
  58. this.isMavlink2 = mavLinkPacket.isMavlink2;
  59. unpack(mavLinkPacket.payload);
  60. }
  61. @Override
  62. public String toString() {
  63. return "MAVLINK_MSG_ID_SysInfo - sysid:"+sysid+" compid:"+compid+" voltageBattery:"+voltageBattery+" sysState:"+sysState+"";
  64. }
  65. @Override
  66. public String name() {
  67. return "MAVLINK_MSG_ID_SysInfo";
  68. }
  69. }
  • MAVLinkPayload类对属性中的帧的有效负载payload做了数值的定义及拼装,例:在组帧pack()方法中对sysState的数据类型及消息命令顺序位置偏移。
  1. package com.MAVLink.Messages;
  2. import java.nio.ByteBuffer;
  3. public class MAVLinkPayload {
  4. private static final byte UNSIGNED_BYTE_MIN_VALUE = 0;
  5. private static final short UNSIGNED_BYTE_MAX_VALUE = Byte.MAX_VALUE - Byte.MIN_VALUE;
  6. private static final short UNSIGNED_SHORT_MIN_VALUE = 0;
  7. private static final int UNSIGNED_SHORT_MAX_VALUE = Short.MAX_VALUE - Short.MIN_VALUE;
  8. private static final int UNSIGNED_INT_MIN_VALUE = 0;
  9. private static final long UNSIGNED_INT_MAX_VALUE = (long) Integer.MAX_VALUE - Integer.MIN_VALUE;
  10. private static final long UNSIGNED_LONG_MIN_VALUE = 0;
  11. public static final int MAX_PAYLOAD_SIZE = 255;
  12. public final ByteBuffer payload;
  13. public int index;
  14. public MAVLinkPayload() {
  15. // This has to be larger than the received payloadSize since MAVLINK V2 will truncate the payloads to the last non-zero value
  16. payload = ByteBuffer.allocate(MAX_PAYLOAD_SIZE);
  17. }
  18. public ByteBuffer getData() {
  19. return payload;
  20. }
  21. public int size() {
  22. return payload.position();
  23. }
  24. public void add(byte c) {
  25. payload.put(c);
  26. }
  27. public void resetIndex() {
  28. index = 0;
  29. }
  30. public byte getByte() {
  31. byte result = 0;
  32. result |= (payload.get(index + 0) & 0xFF);
  33. index += 1;
  34. return result;
  35. }
  36. public short getUnsignedByte() {
  37. short result = 0;
  38. result |= payload.get(index + 0) & 0xFF;
  39. index += 1;
  40. return result;
  41. }
  42. public short getShort() {
  43. short result = 0;
  44. result |= (payload.get(index + 1) & 0xFF) << 8;
  45. result |= (payload.get(index + 0) & 0xFF);
  46. index += 2;
  47. return result;
  48. }
  49. public int getUnsignedShort() {
  50. int result = 0;
  51. result |= (payload.get(index + 1) & 0xFF) << 8;
  52. result |= (payload.get(index + 0) & 0xFF);
  53. index += 2;
  54. return result;
  55. }
  56. public int getInt() {
  57. int result = 0;
  58. result |= (payload.get(index + 3) & 0xFF) << 24;
  59. result |= (payload.get(index + 2) & 0xFF) << 16;
  60. result |= (payload.get(index + 1) & 0xFF) << 8;
  61. result |= (payload.get(index + 0) & 0xFF);
  62. index += 4;
  63. return result;
  64. }
  65. public long getUnsignedInt() {
  66. long result = 0;
  67. result |= (payload.get(index + 3) & 0xFFL) << 24;
  68. result |= (payload.get(index + 2) & 0xFFL) << 16;
  69. result |= (payload.get(index + 1) & 0xFFL) << 8;
  70. result |= (payload.get(index + 0) & 0xFFL);
  71. index += 4;
  72. return result;
  73. }
  74. public long getLong() {
  75. long result = 0;
  76. result |= (payload.get(index + 7) & 0xFFL) << 56;
  77. result |= (payload.get(index + 6) & 0xFFL) << 48;
  78. result |= (payload.get(index + 5) & 0xFFL) << 40;
  79. result |= (payload.get(index + 4) & 0xFFL) << 32;
  80. result |= (payload.get(index + 3) & 0xFFL) << 24;
  81. result |= (payload.get(index + 2) & 0xFFL) << 16;
  82. result |= (payload.get(index + 1) & 0xFFL) << 8;
  83. result |= (payload.get(index + 0) & 0xFFL);
  84. index += 8;
  85. return result;
  86. }
  87. public long getUnsignedLong(){
  88. return getLong();
  89. }
  90. public long getLongReverse() {
  91. long result = 0;
  92. result |= (payload.get(index + 0) & 0xFFL) << 56;
  93. result |= (payload.get(index + 1) & 0xFFL) << 48;
  94. result |= (payload.get(index + 2) & 0xFFL) << 40;
  95. result |= (payload.get(index + 3) & 0xFFL) << 32;
  96. result |= (payload.get(index + 4) & 0xFFL) << 24;
  97. result |= (payload.get(index + 5) & 0xFFL) << 16;
  98. result |= (payload.get(index + 6) & 0xFFL) << 8;
  99. result |= (payload.get(index + 7) & 0xFFL);
  100. index += 8;
  101. return result;
  102. }
  103. public float getFloat() {
  104. return Float.intBitsToFloat(getInt());
  105. }
  106. public double getDouble() {
  107. return Double.longBitsToDouble(getLong());
  108. }
  109. public void putByte(byte data) {
  110. add(data);
  111. }
  112. public void putUnsignedByte(short data) {
  113. if (data < UNSIGNED_BYTE_MIN_VALUE || data > UNSIGNED_BYTE_MAX_VALUE) {
  114. throw new IllegalArgumentException("Value is outside of the range of an unsigned byte: " + data);
  115. }
  116. putByte((byte) data);
  117. }
  118. public void putShort(short data) {
  119. add((byte) (data >> 0));
  120. add((byte) (data >> 8));
  121. }
  122. public void putUnsignedShort(int data) {
  123. if (data < UNSIGNED_SHORT_MIN_VALUE || data > UNSIGNED_SHORT_MAX_VALUE) {
  124. throw new IllegalArgumentException("Value is outside of the range of an unsigned short: " + data);
  125. }
  126. putShort((short) data);
  127. }
  128. public void putInt(int data) {
  129. add((byte) (data >> 0));
  130. add((byte) (data >> 8));
  131. add((byte) (data >> 16));
  132. add((byte) (data >> 24));
  133. }
  134. public void putUnsignedInt(long data) {
  135. if (data < UNSIGNED_INT_MIN_VALUE || data > UNSIGNED_INT_MAX_VALUE) {
  136. throw new IllegalArgumentException("Value is outside of the range of an unsigned int: " + data);
  137. }
  138. putInt((int) data);
  139. }
  140. public void putLong(long data) {
  141. add((byte) (data >> 0));
  142. add((byte) (data >> 8));
  143. add((byte) (data >> 16));
  144. add((byte) (data >> 24));
  145. add((byte) (data >> 32));
  146. add((byte) (data >> 40));
  147. add((byte) (data >> 48));
  148. add((byte) (data >> 56));
  149. }
  150. public void putUnsignedLong(long data) {
  151. if (data < UNSIGNED_LONG_MIN_VALUE) {
  152. throw new IllegalArgumentException("Value is outside of the range of an unsigned long: " + data);
  153. }
  154. putLong(data);
  155. }
  156. public void putFloat(float data) {
  157. putInt(Float.floatToIntBits(data));
  158. }
  159. public void putDouble(double data) {
  160. putLong(Double.doubleToLongBits(data));
  161. }
  162. }
  • Parser类对来自Drone端的字节数据流解析成一个完整的帧,mavlink_parse_char(int c)方法把Drone端组装成mavlink帧即MAVLinkPacket:
  1. package com.MAVLink;
  2. import com.MAVLink.MAVLinkPacket;
  3. import com.MAVLink.Messages.MAVLinkStats;
  4. public class Parser {
  5. static final String TAG = Parser.class.getSimpleName();
  6. static final boolean V = false;
  7. static void logv(String tag, String msg) {
  8. if(V) System.out.println(String.format("%s: %s", tag, msg));
  9. }
  10. enum MAV_states {
  11. MAVLINK_PARSE_STATE_UNINIT,
  12. MAVLINK_PARSE_STATE_IDLE,
  13. MAVLINK_PARSE_STATE_GOT_STX,
  14. MAVLINK_PARSE_STATE_GOT_LENGTH,
  15. MAVLINK_PARSE_STATE_GOT_INCOMPAT_FLAGS, // MAVLink 2
  16. MAVLINK_PARSE_STATE_GOT_COMPAT_FLAGS, // MAVLink 2
  17. MAVLINK_PARSE_STATE_GOT_SEQ,
  18. MAVLINK_PARSE_STATE_GOT_SYSID,
  19. MAVLINK_PARSE_STATE_GOT_COMPID,
  20. MAVLINK_PARSE_STATE_GOT_MSGID1,
  21. MAVLINK_PARSE_STATE_GOT_MSGID2, // MAVLink 2
  22. MAVLINK_PARSE_STATE_GOT_MSGID3, // MAVLink 2
  23. MAVLINK_PARSE_STATE_GOT_CRC1,
  24. MAVLINK_PARSE_STATE_GOT_CRC2, // MAVLink 2
  25. MAVLINK_PARSE_STATE_GOT_PAYLOAD,
  26. MAVLINK_PARSE_STATE_GOT_SIGNATURE, // MAVLink 2
  27. }
  28. private MAV_states state = MAV_states.MAVLINK_PARSE_STATE_UNINIT;
  29. public MAVLinkStats stats;
  30. private MAVLinkPacket m;
  31. private boolean isMavlink2;
  32. public Parser() {
  33. this(false);
  34. }
  35. public Parser(boolean ignoreRadioPacketStats) {
  36. stats = new MAVLinkStats(ignoreRadioPacketStats);
  37. isMavlink2 = false;
  38. }
  39. public MAVLinkPacket mavlink_parse_char(int c) {
  40. // force to 8 bits
  41. c &= 0xFF;
  42. switch (state) {
  43. case MAVLINK_PARSE_STATE_UNINIT:
  44. case MAVLINK_PARSE_STATE_IDLE:
  45. // MAVLink 1 and 2
  46. if (c == MAVLinkPacket.MAVLINK_STX_MAVLINK2) {
  47. state = MAV_states.MAVLINK_PARSE_STATE_GOT_STX;
  48. if (!isMavlink2) {
  49. isMavlink2 = true;
  50. logv(TAG, "Turning mavlink2 ON");
  51. }
  52. } else if (c == MAVLinkPacket.MAVLINK_STX_MAVLINK1) {
  53. state = MAV_states.MAVLINK_PARSE_STATE_GOT_STX;
  54. if (isMavlink2) {
  55. isMavlink2 = false;
  56. logv(TAG, "Turning mavlink2 OFF");
  57. }
  58. }
  59. break;
  60. case MAVLINK_PARSE_STATE_GOT_STX:
  61. // MAVLink 1 and 2
  62. m = new MAVLinkPacket(c, isMavlink2);
  63. if (isMavlink2) {
  64. state = MAV_states.MAVLINK_PARSE_STATE_GOT_LENGTH;
  65. } else {
  66. state = MAV_states.MAVLINK_PARSE_STATE_GOT_COMPAT_FLAGS;
  67. }
  68. break;
  69. case MAVLINK_PARSE_STATE_GOT_LENGTH:
  70. // MAVLink 1 and 2
  71. m.incompatFlags = c;
  72. if (c != 0 && c != 1) {
  73. // message includes an incompatible feature flag
  74. state = MAV_states.MAVLINK_PARSE_STATE_IDLE;
  75. break;
  76. }
  77. state = MAV_states.MAVLINK_PARSE_STATE_GOT_INCOMPAT_FLAGS;
  78. break;
  79. case MAVLINK_PARSE_STATE_GOT_INCOMPAT_FLAGS:
  80. // MAVLink 2 only
  81. m.compatFlags = c;
  82. state = MAV_states.MAVLINK_PARSE_STATE_GOT_COMPAT_FLAGS;
  83. break;
  84. case MAVLINK_PARSE_STATE_GOT_COMPAT_FLAGS:
  85. m.seq = c;
  86. state = MAV_states.MAVLINK_PARSE_STATE_GOT_SEQ;
  87. break;
  88. case MAVLINK_PARSE_STATE_GOT_SEQ:
  89. // back to MAVLink 1 and 2
  90. m.sysid = c;
  91. state = MAV_states.MAVLINK_PARSE_STATE_GOT_SYSID;
  92. break;
  93. case MAVLINK_PARSE_STATE_GOT_SYSID:
  94. // MAVLink 1 and 2
  95. m.compid = c;
  96. state = MAV_states.MAVLINK_PARSE_STATE_GOT_COMPID;
  97. break;
  98. case MAVLINK_PARSE_STATE_GOT_COMPID:
  99. // MAVLink 1 and 2
  100. m.msgid = c;
  101. if (isMavlink2) {
  102. state = MAV_states.MAVLINK_PARSE_STATE_GOT_MSGID1;
  103. } else if (m.len > 0) {
  104. state = MAV_states.MAVLINK_PARSE_STATE_GOT_MSGID3;
  105. } else {
  106. state = MAV_states.MAVLINK_PARSE_STATE_GOT_PAYLOAD;
  107. }
  108. break;
  109. case MAVLINK_PARSE_STATE_GOT_MSGID1:
  110. // MAVLink 2 only
  111. m.msgid |= c << 8;
  112. state = MAV_states.MAVLINK_PARSE_STATE_GOT_MSGID2;
  113. break;
  114. case MAVLINK_PARSE_STATE_GOT_MSGID2:
  115. // MAVLink 2 only
  116. m.msgid |= c << 16;
  117. if (m.len > 0) {
  118. state = MAV_states.MAVLINK_PARSE_STATE_GOT_MSGID3;
  119. } else {
  120. state = MAV_states.MAVLINK_PARSE_STATE_GOT_PAYLOAD;
  121. }
  122. break;
  123. case MAVLINK_PARSE_STATE_GOT_MSGID3:
  124. // back to MAVLink 1 and 2
  125. m.payload.add((byte) c);
  126. if (m.payloadIsFilled()) {
  127. state = MAV_states.MAVLINK_PARSE_STATE_GOT_PAYLOAD;
  128. }
  129. break;
  130. case MAVLINK_PARSE_STATE_GOT_PAYLOAD:
  131. boolean crcGen = m.generateCRC(m.payload.size());
  132. // Check first checksum byte and verify the CRC was successfully generated (msg extra exists)
  133. if (c != m.crc.getLSB() || !crcGen) {
  134. state = MAV_states.MAVLINK_PARSE_STATE_IDLE;
  135. stats.crcError();
  136. } else {
  137. state = MAV_states.MAVLINK_PARSE_STATE_GOT_CRC1;
  138. }
  139. break;
  140. case MAVLINK_PARSE_STATE_GOT_CRC1:
  141. // Check second checksum byte
  142. if (c != m.crc.getMSB()) {
  143. state = MAV_states.MAVLINK_PARSE_STATE_IDLE;
  144. stats.crcError();
  145. } else { // crc is good
  146. stats.newPacket(m);
  147. if (!isMavlink2 || (m.incompatFlags != 0x01)) {
  148. // If no signature, then return the message.
  149. state = MAV_states.MAVLINK_PARSE_STATE_IDLE;
  150. return m;
  151. } else {
  152. // TODO: MAVLink 2 - signed
  153. state = MAV_states.MAVLINK_PARSE_STATE_IDLE;
  154. stats.crcError();
  155. }
  156. }
  157. break;
  158. case MAVLINK_PARSE_STATE_GOT_CRC2:
  159. // TODO: implement signature parsing and validation
  160. state = MAV_states.MAVLINK_PARSE_STATE_IDLE;
  161. stats.crcError();
  162. break;
  163. } // switch
  164. return null;
  165. }
  166. }
  • MAVLinkPacket类是一个包装类包含了消息协议的组帧和解帧,encodePacket()会把mavlink帧的STX、payloadSize、flags、sysid、compid、msgid、payload、crc都拼接起来,unpack会根据msgid分离出不同类型的消息命令如msg_sysinfo:
  1. package com.MAVLink;
  2. import java.io.Serializable;
  3. import com.MAVLink.Messages.MAVLinkPayload;
  4. import com.MAVLink.Messages.MAVLinkMessage;
  5. import com.MAVLink.Demo_heart.CRC;
  6. import com.MAVLink.Demo_heart.*;
  7. public class MAVLinkPacket implements Serializable {
  8. private static final long serialVersionUID = 2095947771227815314L;
  9. public static final int MAVLINK_STX_MAVLINK1 = 0xFE; // 254
  10. public static final int MAVLINK_STX_MAVLINK2 = 0xFD; // 253
  11. public static final int MAVLINK1_HEADER_LEN = 6;
  12. public static final int MAVLINK2_HEADER_LEN = 10;
  13. public static final int MAVLINK1_NONPAYLOAD_LEN = MAVLINK1_HEADER_LEN + 2;
  14. public static final int MAVLINK2_NONPAYLOAD_LEN = MAVLINK2_HEADER_LEN + 2;
  15. static final boolean V = false;
  16. static void logv(String str) {
  17. if(V) System.out.println(String.format("MAVLinkPacket: %s", str));
  18. }
  19. public final int len;
  20. public int seq;
  21. public int sysid;
  22. public int compid;
  23. public int msgid;
  24. public MAVLinkPayload payload;
  25. public CRC crc;
  26. public boolean isMavlink2;
  27. public int incompatFlags;
  28. public int compatFlags;
  29. public MAVLinkPacket(int payloadLength) {
  30. this(payloadLength, false);
  31. }
  32. public MAVLinkPacket(final int payloadLength, final boolean isMavlink2) {
  33. len = payloadLength;
  34. payload = new MAVLinkPayload();
  35. this.isMavlink2 = isMavlink2;
  36. }
  37. public boolean payloadIsFilled() {
  38. return payload.size() >= len;
  39. }
  40. public boolean generateCRC(final int payloadSize) {
  41. if (crc == null) {
  42. crc = new CRC();
  43. } else {
  44. crc.start_checksum();
  45. }
  46. if (isMavlink2) {
  47. crc.update_checksum(payloadSize);
  48. crc.update_checksum(incompatFlags);
  49. crc.update_checksum(compatFlags);
  50. crc.update_checksum(seq);
  51. crc.update_checksum(sysid);
  52. crc.update_checksum(compid);
  53. crc.update_checksum(msgid);
  54. crc.update_checksum(msgid >>> 8);
  55. crc.update_checksum(msgid >>> 16);
  56. } else {
  57. crc.update_checksum(payloadSize);
  58. crc.update_checksum(seq);
  59. crc.update_checksum(sysid);
  60. crc.update_checksum(compid);
  61. crc.update_checksum(msgid);
  62. }
  63. payload.resetIndex();
  64. for (int i = 0; i < payloadSize; i++) {
  65. crc.update_checksum(payload.getByte());
  66. }
  67. return crc.finish_checksum(msgid);
  68. }
  69. private int mavTrimPayload(final byte[] payload)
  70. {
  71. int length = payload.length;
  72. while (length > 1 && payload[length-1] == 0) {
  73. length--;
  74. }
  75. return length;
  76. }
  77. public byte[] encodePacket() {
  78. final int bufLen;
  79. final int payloadSize;
  80. if (isMavlink2) {
  81. payloadSize = mavTrimPayload(payload.payload.array());
  82. bufLen = MAVLINK2_HEADER_LEN + payloadSize + 2;
  83. } else {
  84. payloadSize = payload.size();
  85. bufLen = MAVLINK1_HEADER_LEN + payloadSize + 2;
  86. }
  87. byte[] buffer = new byte[bufLen];
  88. int i = 0;
  89. if (isMavlink2) {
  90. buffer[i++] = (byte) MAVLINK_STX_MAVLINK2;
  91. buffer[i++] = (byte) payloadSize;
  92. buffer[i++] = (byte) incompatFlags;
  93. buffer[i++] = (byte) compatFlags;
  94. buffer[i++] = (byte) seq;
  95. buffer[i++] = (byte) sysid;
  96. buffer[i++] = (byte) compid;
  97. buffer[i++] = (byte) (msgid & 0XFF);
  98. buffer[i++] = (byte) ((msgid >>> 8) & 0XFF);
  99. buffer[i++] = (byte) ((msgid >>> 16) & 0XFF);
  100. } else {
  101. buffer[i++] = (byte) MAVLINK_STX_MAVLINK1;
  102. buffer[i++] = (byte) payloadSize;
  103. buffer[i++] = (byte) seq;
  104. buffer[i++] = (byte) sysid;
  105. buffer[i++] = (byte) compid;
  106. buffer[i++] = (byte) msgid;
  107. }
  108. for (int j = 0; j < payloadSize; ++j) {
  109. buffer[i++] = payload.payload.get(j);
  110. }
  111. generateCRC(payloadSize);
  112. buffer[i++] = (byte) (crc.getLSB());
  113. buffer[i++] = (byte) (crc.getMSB());
  114. logv(String.format("encode: isMavlink2=%s msgid=%d", isMavlink2, msgid));
  115. return buffer;
  116. }
  117. public MAVLinkMessage unpack() {
  118. switch (msgid) {
  119. case msg_sysinfo.MAVLINK_MSG_ID_SysInfo:
  120. return new msg_sysinfo(this);
  121. default:
  122. return null;
  123. }
  124. }
  125. }

        Drone端C/C++代码分析:

        mavlink_msg_sysinfo.hpp封装了有效的命令类比Java代码的msg_sysinfo类、mavlink_msg_sysinfo.hpp继承Message是相对于msg_sysinfo继承了MAVLinkMessage。工具类mavlink_helpers.h包含了组帧和解帧的具体操作及接收数据、发送数据的操作。

  • mavlink_msg_sysinfo的组帧的调用:
  1. static inline uint16_t
  2. mavlink_msg_sysinfo_encode(uint8_t system_id, uint8_t component_id, mavlink_message_t *msg,
  3. const mavlink_sysinfo_t *sysinfo) {
  4. return mavlink_msg_sysinfo_pack(system_id, component_id, msg, sysinfo->sysState,
  5. sysinfo->voltageBattery);
  6. }
  •  mavlink_helpers.h以下函数对传进来的数据进行组帧:
  1. MAVLINK_HELPER uint16_t mavlink_finalize_message_buffer(mavlink_message_t* msg, uint8_t system_id, uint8_t component_id,
  2. mavlink_status_t* status, uint8_t min_length, uint8_t length, uint8_t crc_extra)
  3. {
  4. bool mavlink1 = (status->flags & MAVLINK_STATUS_FLAG_OUT_MAVLINK1) != 0;
  5. #ifndef MAVLINK_NO_SIGN_PACKET
  6. bool signing = (!mavlink1) && status->signing && (status->signing->flags & MAVLINK_SIGNING_FLAG_SIGN_OUTGOING);
  7. #else
  8. bool signing = false;
  9. #endif
  10. uint8_t signature_len = signing? MAVLINK_SIGNATURE_BLOCK_LEN : 0;
  11. uint8_t header_len = MAVLINK_CORE_HEADER_LEN+1;
  12. uint8_t buf[MAVLINK_CORE_HEADER_LEN+1];
  13. if (mavlink1) {
  14. msg->magic = MAVLINK_STX_MAVLINK1;
  15. header_len = MAVLINK_CORE_HEADER_MAVLINK1_LEN+1;
  16. } else {
  17. msg->magic = MAVLINK_STX;
  18. }
  19. msg->len = mavlink1?min_length:_mav_trim_payload(_MAV_PAYLOAD(msg), length);
  20. msg->sysid = system_id;
  21. msg->compid = component_id;
  22. msg->incompat_flags = 0;
  23. if (signing) {
  24. msg->incompat_flags |= MAVLINK_IFLAG_SIGNED;
  25. }
  26. msg->compat_flags = 0;
  27. msg->seq = status->current_tx_seq;
  28. status->current_tx_seq = status->current_tx_seq + 1;
  29. // form the header as a byte array for the crc
  30. buf[0] = msg->magic;
  31. buf[1] = msg->len;
  32. if (mavlink1) {
  33. buf[2] = msg->seq;
  34. buf[3] = msg->sysid;
  35. buf[4] = msg->compid;
  36. buf[5] = msg->msgid & 0xFF;
  37. } else {
  38. buf[2] = msg->incompat_flags;
  39. buf[3] = msg->compat_flags;
  40. buf[4] = msg->seq;
  41. buf[5] = msg->sysid;
  42. buf[6] = msg->compid;
  43. buf[7] = msg->msgid & 0xFF;
  44. buf[8] = (msg->msgid >> 8) & 0xFF;
  45. buf[9] = (msg->msgid >> 16) & 0xFF;
  46. }
  47. uint16_t checksum = crc_calculate(&buf[1], header_len-1);
  48. crc_accumulate_buffer(&checksum, _MAV_PAYLOAD(msg), msg->len);
  49. crc_accumulate(crc_extra, &checksum);
  50. mavlink_ck_a(msg) = (uint8_t)(checksum & 0xFF);
  51. mavlink_ck_b(msg) = (uint8_t)(checksum >> 8);
  52. msg->checksum = checksum;
  53. #ifndef MAVLINK_NO_SIGN_PACKET
  54. if (signing) {
  55. mavlink_sign_packet(status->signing,
  56. msg->signature,
  57. (const uint8_t *)buf, header_len,
  58. (const uint8_t *)_MAV_PAYLOAD(msg), msg->len,
  59. (const uint8_t *)_MAV_PAYLOAD(msg)+(uint16_t)msg->len);
  60. }
  61. #endif
  62. return msg->len + header_len + 2 + signature_len;
  63. }
  • mavlink_helpers.h实现了几种不同数据流的发送函数:_mav_finalize_message_chan_sen()、_mavlink_resend_uart()、mavlink_msg_to_send_buffer()。以下以mavlink_msg_to_send_buffer()为例:
  1. /**
  2. * @brief Pack a message to send it over a serial byte stream
  3. */
  4. MAVLINK_HELPER uint16_t mavlink_msg_to_send_buffer(uint8_t *buf, const mavlink_message_t *msg)
  5. {
  6. uint8_t signature_len, header_len;
  7. uint8_t *ck;
  8. uint8_t length = msg->len;
  9. if (msg->magic == MAVLINK_STX_MAVLINK1) {
  10. signature_len = 0;
  11. header_len = MAVLINK_CORE_HEADER_MAVLINK1_LEN;
  12. buf[0] = msg->magic;
  13. buf[1] = length;
  14. buf[2] = msg->seq;
  15. buf[3] = msg->sysid;
  16. buf[4] = msg->compid;
  17. buf[5] = msg->msgid & 0xFF;
  18. memcpy(&buf[6], _MAV_PAYLOAD(msg), msg->len);
  19. ck = buf + header_len + 1 + (uint16_t)msg->len;
  20. } else {
  21. length = _mav_trim_payload(_MAV_PAYLOAD(msg), length);
  22. header_len = MAVLINK_CORE_HEADER_LEN;
  23. buf[0] = msg->magic;
  24. buf[1] = length;
  25. buf[2] = msg->incompat_flags;
  26. buf[3] = msg->compat_flags;
  27. buf[4] = msg->seq;
  28. buf[5] = msg->sysid;
  29. buf[6] = msg->compid;
  30. buf[7] = msg->msgid & 0xFF;
  31. buf[8] = (msg->msgid >> 8) & 0xFF;
  32. buf[9] = (msg->msgid >> 16) & 0xFF;
  33. memcpy(&buf[10], _MAV_PAYLOAD(msg), length);
  34. ck = buf + header_len + 1 + (uint16_t)length;
  35. signature_len = (msg->incompat_flags & MAVLINK_IFLAG_SIGNED)?MAVLINK_SIGNATURE_BLOCK_LEN:0;
  36. }
  37. ck[0] = (uint8_t)(msg->checksum & 0xFF);
  38. ck[1] = (uint8_t)(msg->checksum >> 8);
  39. if (signature_len > 0) {
  40. memcpy(&ck[2], msg->signature, signature_len);
  41. }
  42. return header_len + 1 + 2 + (uint16_t)length + (uint16_t)signature_len;
  43. }
  • mavlink_helpers.h的mavlink_frame_char_buffer()从接收的数据组成帧:
  1. /**
  2. * This is a variant of mavlink_frame_char() but with caller supplied
  3. * parsing buffers. It is useful when you want to create a MAVLink
  4. * parser in a library that doesn't use any global variables
  5. *
  6. * @param rxmsg parsing message buffer
  7. * @param status parsing status buffer
  8. * @param c The char to parse
  9. *
  10. * @param r_message NULL if no message could be decoded, otherwise the message data
  11. * @param r_mavlink_status if a message was decoded, this is filled with the channel's stats
  12. * @return 0 if no message could be decoded, 1 on good message and CRC, 2 on bad CRC
  13. *
  14. */
  15. MAVLINK_HELPER uint8_t mavlink_frame_char_buffer(mavlink_message_t* rxmsg,
  16. mavlink_status_t* status,
  17. uint8_t c,
  18. mavlink_message_t* r_message,
  19. mavlink_status_t* r_mavlink_status)
  20. {
  21. status->msg_received = MAVLINK_FRAMING_INCOMPLETE;
  22. switch (status->parse_state)
  23. {
  24. case MAVLINK_PARSE_STATE_UNINIT:
  25. case MAVLINK_PARSE_STATE_IDLE:
  26. if (c == MAVLINK_STX)
  27. {
  28. status->parse_state = MAVLINK_PARSE_STATE_GOT_STX;
  29. rxmsg->len = 0;
  30. rxmsg->magic = c;
  31. status->flags &= ~MAVLINK_STATUS_FLAG_IN_MAVLINK1;
  32. mavlink_start_checksum(rxmsg);
  33. } else if (c == MAVLINK_STX_MAVLINK1)
  34. {
  35. status->parse_state = MAVLINK_PARSE_STATE_GOT_STX;
  36. rxmsg->len = 0;
  37. rxmsg->magic = c;
  38. status->flags |= MAVLINK_STATUS_FLAG_IN_MAVLINK1;
  39. mavlink_start_checksum(rxmsg);
  40. }
  41. break;
  42. case MAVLINK_PARSE_STATE_GOT_STX:
  43. if (status->msg_received
  44. /* Support shorter buffers than the
  45. default maximum packet size */
  46. #if (MAVLINK_MAX_PAYLOAD_LEN < 255)
  47. || c > MAVLINK_MAX_PAYLOAD_LEN
  48. #endif
  49. )
  50. {
  51. status->buffer_overrun++;
  52. _mav_parse_error(status);
  53. status->msg_received = 0;
  54. status->parse_state = MAVLINK_PARSE_STATE_IDLE;
  55. }
  56. else
  57. {
  58. // NOT counting STX, LENGTH, SEQ, SYSID, COMPID, MSGID, CRC1 and CRC2
  59. rxmsg->len = c;
  60. status->packet_idx = 0;
  61. mavlink_update_checksum(rxmsg, c);
  62. if (status->flags & MAVLINK_STATUS_FLAG_IN_MAVLINK1) {
  63. rxmsg->incompat_flags = 0;
  64. rxmsg->compat_flags = 0;
  65. status->parse_state = MAVLINK_PARSE_STATE_GOT_COMPAT_FLAGS;
  66. } else {
  67. status->parse_state = MAVLINK_PARSE_STATE_GOT_LENGTH;
  68. }
  69. }
  70. break;
  71. case MAVLINK_PARSE_STATE_GOT_LENGTH:
  72. rxmsg->incompat_flags = c;
  73. if ((rxmsg->incompat_flags & ~MAVLINK_IFLAG_MASK) != 0) {
  74. // message includes an incompatible feature flag
  75. _mav_parse_error(status);
  76. status->msg_received = 0;
  77. status->parse_state = MAVLINK_PARSE_STATE_IDLE;
  78. break;
  79. }
  80. mavlink_update_checksum(rxmsg, c);
  81. status->parse_state = MAVLINK_PARSE_STATE_GOT_INCOMPAT_FLAGS;
  82. break;
  83. case MAVLINK_PARSE_STATE_GOT_INCOMPAT_FLAGS:
  84. rxmsg->compat_flags = c;
  85. mavlink_update_checksum(rxmsg, c);
  86. status->parse_state = MAVLINK_PARSE_STATE_GOT_COMPAT_FLAGS;
  87. break;
  88. case MAVLINK_PARSE_STATE_GOT_COMPAT_FLAGS:
  89. rxmsg->seq = c;
  90. mavlink_update_checksum(rxmsg, c);
  91. status->parse_state = MAVLINK_PARSE_STATE_GOT_SEQ;
  92. break;
  93. case MAVLINK_PARSE_STATE_GOT_SEQ:
  94. rxmsg->sysid = c;
  95. mavlink_update_checksum(rxmsg, c);
  96. status->parse_state = MAVLINK_PARSE_STATE_GOT_SYSID;
  97. break;
  98. case MAVLINK_PARSE_STATE_GOT_SYSID:
  99. rxmsg->compid = c;
  100. mavlink_update_checksum(rxmsg, c);
  101. status->parse_state = MAVLINK_PARSE_STATE_GOT_COMPID;
  102. break;
  103. case MAVLINK_PARSE_STATE_GOT_COMPID:
  104. rxmsg->msgid = c;
  105. mavlink_update_checksum(rxmsg, c);
  106. if (status->flags & MAVLINK_STATUS_FLAG_IN_MAVLINK1) {
  107. if(rxmsg->len > 0) {
  108. status->parse_state = MAVLINK_PARSE_STATE_GOT_MSGID3;
  109. } else {
  110. status->parse_state = MAVLINK_PARSE_STATE_GOT_PAYLOAD;
  111. }
  112. #ifdef MAVLINK_CHECK_MESSAGE_LENGTH
  113. if (rxmsg->len < mavlink_min_message_length(rxmsg) ||
  114. rxmsg->len > mavlink_max_message_length(rxmsg)) {
  115. _mav_parse_error(status);
  116. status->parse_state = MAVLINK_PARSE_STATE_IDLE;
  117. break;
  118. }
  119. #endif
  120. } else {
  121. status->parse_state = MAVLINK_PARSE_STATE_GOT_MSGID1;
  122. }
  123. break;
  124. case MAVLINK_PARSE_STATE_GOT_MSGID1:
  125. rxmsg->msgid |= ((uint32_t)c)<<8;
  126. mavlink_update_checksum(rxmsg, c);
  127. status->parse_state = MAVLINK_PARSE_STATE_GOT_MSGID2;
  128. break;
  129. case MAVLINK_PARSE_STATE_GOT_MSGID2:
  130. rxmsg->msgid |= ((uint32_t)c)<<16;
  131. mavlink_update_checksum(rxmsg, c);
  132. if(rxmsg->len > 0){
  133. status->parse_state = MAVLINK_PARSE_STATE_GOT_MSGID3;
  134. } else {
  135. status->parse_state = MAVLINK_PARSE_STATE_GOT_PAYLOAD;
  136. }
  137. #ifdef MAVLINK_CHECK_MESSAGE_LENGTH
  138. if (rxmsg->len < mavlink_min_message_length(rxmsg) ||
  139. rxmsg->len > mavlink_max_message_length(rxmsg))
  140. {
  141. _mav_parse_error(status);
  142. status->parse_state = MAVLINK_PARSE_STATE_IDLE;
  143. break;
  144. }
  145. #endif
  146. break;
  147. case MAVLINK_PARSE_STATE_GOT_MSGID3:
  148. _MAV_PAYLOAD_NON_CONST(rxmsg)[status->packet_idx++] = (char)c;
  149. mavlink_update_checksum(rxmsg, c);
  150. if (status->packet_idx == rxmsg->len)
  151. {
  152. status->parse_state = MAVLINK_PARSE_STATE_GOT_PAYLOAD;
  153. }
  154. break;
  155. case MAVLINK_PARSE_STATE_GOT_PAYLOAD: {
  156. const mavlink_msg_entry_t *e = mavlink_get_msg_entry(rxmsg->msgid);
  157. uint8_t crc_extra = e?e->crc_extra:0;
  158. mavlink_update_checksum(rxmsg, crc_extra);
  159. if (c != (rxmsg->checksum & 0xFF)) {
  160. status->parse_state = MAVLINK_PARSE_STATE_GOT_BAD_CRC1;
  161. } else {
  162. status->parse_state = MAVLINK_PARSE_STATE_GOT_CRC1;
  163. }
  164. rxmsg->ck[0] = c;
  165. // zero-fill the packet to cope with short incoming packets
  166. if (e && status->packet_idx < e->max_msg_len) {
  167. memset(&_MAV_PAYLOAD_NON_CONST(rxmsg)[status->packet_idx], 0, e->max_msg_len - status->packet_idx);
  168. }
  169. break;
  170. }
  171. case MAVLINK_PARSE_STATE_GOT_CRC1:
  172. case MAVLINK_PARSE_STATE_GOT_BAD_CRC1:
  173. if (status->parse_state == MAVLINK_PARSE_STATE_GOT_BAD_CRC1 || c != (rxmsg->checksum >> 8)) {
  174. // got a bad CRC message
  175. status->msg_received = MAVLINK_FRAMING_BAD_CRC;
  176. } else {
  177. // Successfully got message
  178. status->msg_received = MAVLINK_FRAMING_OK;
  179. }
  180. rxmsg->ck[1] = c;
  181. if (rxmsg->incompat_flags & MAVLINK_IFLAG_SIGNED) {
  182. status->parse_state = MAVLINK_PARSE_STATE_SIGNATURE_WAIT;
  183. status->signature_wait = MAVLINK_SIGNATURE_BLOCK_LEN;
  184. // If the CRC is already wrong, don't overwrite msg_received,
  185. // otherwise we can end up with garbage flagged as valid.
  186. if (status->msg_received != MAVLINK_FRAMING_BAD_CRC) {
  187. status->msg_received = MAVLINK_FRAMING_INCOMPLETE;
  188. }
  189. } else {
  190. if (status->signing &&
  191. (status->signing->accept_unsigned_callback == NULL ||
  192. !status->signing->accept_unsigned_callback(status, rxmsg->msgid))) {
  193. // If the CRC is already wrong, don't overwrite msg_received.
  194. if (status->msg_received != MAVLINK_FRAMING_BAD_CRC) {
  195. status->msg_received = MAVLINK_FRAMING_BAD_SIGNATURE;
  196. }
  197. }
  198. status->parse_state = MAVLINK_PARSE_STATE_IDLE;
  199. if (r_message != NULL) {
  200. memcpy(r_message, rxmsg, sizeof(mavlink_message_t));
  201. }
  202. }
  203. break;
  204. case MAVLINK_PARSE_STATE_SIGNATURE_WAIT:
  205. rxmsg->signature[MAVLINK_SIGNATURE_BLOCK_LEN-status->signature_wait] = c;
  206. status->signature_wait--;
  207. if (status->signature_wait == 0) {
  208. // we have the whole signature, check it is OK
  209. #ifndef MAVLINK_NO_SIGNATURE_CHECK
  210. bool sig_ok = mavlink_signature_check(status->signing, status->signing_streams, rxmsg);
  211. #else
  212. bool sig_ok = true;
  213. #endif
  214. if (!sig_ok &&
  215. (status->signing->accept_unsigned_callback &&
  216. status->signing->accept_unsigned_callback(status, rxmsg->msgid))) {
  217. // accepted via application level override
  218. sig_ok = true;
  219. }
  220. if (sig_ok) {
  221. status->msg_received = MAVLINK_FRAMING_OK;
  222. } else {
  223. status->msg_received = MAVLINK_FRAMING_BAD_SIGNATURE;
  224. }
  225. status->parse_state = MAVLINK_PARSE_STATE_IDLE;
  226. if (r_message !=NULL) {
  227. memcpy(r_message, rxmsg, sizeof(mavlink_message_t));
  228. }
  229. }
  230. break;
  231. }
  232. // If a message has been successfully decoded, check index
  233. if (status->msg_received == MAVLINK_FRAMING_OK)
  234. {
  235. //while(status->current_seq != rxmsg->seq)
  236. //{
  237. // status->packet_rx_drop_count++;
  238. // status->current_seq++;
  239. //}
  240. status->current_rx_seq = rxmsg->seq;
  241. // Initial condition: If no packet has been received so far, drop count is undefined
  242. if (status->packet_rx_success_count == 0) status->packet_rx_drop_count = 0;
  243. // Count this packet as received
  244. status->packet_rx_success_count++;
  245. }
  246. if (r_message != NULL) {
  247. r_message->len = rxmsg->len; // Provide visibility on how far we are into current msg
  248. }
  249. if (r_mavlink_status != NULL) {
  250. r_mavlink_status->parse_state = status->parse_state;
  251. r_mavlink_status->packet_idx = status->packet_idx;
  252. r_mavlink_status->current_rx_seq = status->current_rx_seq+1;
  253. r_mavlink_status->packet_rx_success_count = status->packet_rx_success_count;
  254. r_mavlink_status->packet_rx_drop_count = status->parse_error;
  255. r_mavlink_status->flags = status->flags;
  256. }
  257. status->parse_error = 0;
  258. if (status->msg_received == MAVLINK_FRAMING_BAD_CRC) {
  259. /*
  260. the CRC came out wrong. We now need to overwrite the
  261. msg CRC with the one on the wire so that if the
  262. caller decides to forward the message anyway that
  263. mavlink_msg_to_send_buffer() won't overwrite the
  264. checksum
  265. */
  266. if (r_message != NULL) {
  267. r_message->checksum = rxmsg->ck[0] | (rxmsg->ck[1]<<8);
  268. }
  269. }
  270. return status->msg_received;
  271. }

四、封装自定义的类MavLink通信协议:

        通过自动生成mavlink的协议代码,我们可以此基础上进行自定义的拓展。形成自己通信协议。

协议的帧的设计:

        下图是mavlink2中一帧的结构,在我们自己的项目也可以类似的加入项目中需要的字段定义,更加丰富灵活的用于不同需求的项目中。

        介于设备有多种模块组成,比如无人机有相机模块(MODULE_CAMERA)、中继遥控器模块(MODULE_REPEATER_RC)、中继无人机模块(MODULE_REPEATER_VEHICLE)、遥控器模块(MODULE_RC)、视觉识别模块(MODULE_CV)、云台模块(MODULE_GIMBAL)、电芯模块(MODULE_BATTERY)、超声波模块(MODULE_ULTRASONIC)、地面站模块(MODULE_GCS)等等多种模块组成,这些模块间要互相通信。

        模块之间会进行互相的通信,交叉的信息交换这样就要明确发送端和接收端。这样的话可以在帧头加上两个标识SrcId和destId来区分源端和目的端,如从GCS发送至Drone对应的SrcId=MODULE_GCS/DestId=MODULE_REPEATER_VEHICLE。

        鉴于通信的安全也可在帧头位置加入对应的加解密算法的类型标识,总之按照项目自身的需求加入对应的帧头标识。

        现在基于MavLink2的基础上添加SrcId和destId两个帧头标识为例进行代码编程的自定义类MavLink2项目。     

         自定义类MavLink2 GCS端Java代码分析:

  ··首先我们把协议通信命令区分为发送和接收:AckMsg和CmdMsg两类,分别用于接收和发送。

  •      AckSysInfo类会解析出playload的属性值:
  1. public class AckSysInfo extends BaseAckMsg {
  2. public static final int MAVLINK_MSG_ID_SysInfo = 150;
  3. public static final int DEST_ID_SysInfo = 3;
  4. public static final int SRC_ID_SysInfo = 2;
  5. public static final int MAVLINK_MSG_LENGTH = 3;
  6. private static final long serialVersionUID = MAVLINK_MSG_ID_SysInfo;
  7. public int voltageBattery;
  8. public short sysState;
  9. public AckSysInfo() {
  10. }
  11. public AckSysInfo(MyLinkPacket myLinkPacket) {
  12. this.sysid = myLinkPacket.sysid;
  13. desId = myLinkPacket.destId;
  14. srcId = myLinkPacket.srcId;
  15. this.compid = myLinkPacket.compid;
  16. this.msgid = MAVLINK_MSG_ID_SysInfo;
  17. unpack(myLinkPacket);
  18. }
  19. //解析出payload包含的实体数值
  20. private void unpack(MyLinkPacket myLinkPacket) {
  21. super.decrypt(myLinkPacket);
  22. sysState = myLinkPacket.payload.getShort();
  23. voltageBattery = myLinkPacket.payload.getInt();
  24. }
  25. @Override
  26. public String toString() {
  27. return "AckSysInfo{" +
  28. "voltageBattery=" + voltageBattery +
  29. ", sysState=" + sysState +
  30. '}';
  31. }
  32. }
  •  CmdSysInfo会包playload的属性值包装成一个MyLinkPacket:
  1. public class CmdSysInfo extends BaseCmd {
  2. public static final int MAVLINK_MSG_ID_SysInfo = 150;
  3. public static final int MAVLINK_MSG_LENGTH = 3;
  4. public static final int DEST_ID_SysInfo = 3;
  5. public static final int SRC_ID_SysInfo = 2;
  6. private static final long serialVersionUID = MAVLINK_MSG_ID_SysInfo;
  7. public int voltageBattery;
  8. public short sysState;
  9. public CmdSysInfo(int voltageBattery, short sysState) {
  10. this.voltageBattery = voltageBattery;
  11. this.sysState = sysState;
  12. }
  13. @Override
  14. public MyLinkPacket pack() {
  15. MyLinkPacket myLinkPacket = new MyLinkPacket(MAVLINK_MSG_LENGTH);
  16. //设置帧头的sysid、destId、srcId、compid、msgid
  17. myLinkPacket.sysid = 1;
  18. myLinkPacket.destId = DEST_ID_SysInfo;
  19. myLinkPacket.srcId = SRC_ID_SysInfo;
  20. myLinkPacket.compid = 3;
  21. myLinkPacket.msgid = 3;
  22. //添加命令playload实际的值
  23. myLinkPacket.payload.putUnsignedShort(voltageBattery);
  24. myLinkPacket.payload.putUnsignedByte(sysState);
  25. return null;
  26. }
  27. @Override
  28. public String toString() {
  29. return "AckSysInfo{" +
  30. "voltageBattery=" + voltageBattery +
  31. ", sysState=" + sysState +
  32. '}';
  33. }
  34. }

     接收ACK类:

  • ReceiveThread是一个接收处理类,如接收UDP的数据或者是AOA串口的数据这个因项目而异。作用是在于接收的数据处理成对应的ACK(如:AckSysInfo)的数据。
  • MyParser如MavLink2中Parse功能一样,这里增加了对SrcId和destId的解析处理。
  1. public class MyParser {
  2. static final String TAG = MyParser.class.getSimpleName();
  3. enum MAV_states {
  4. MAVLINK_PARSE_STATE_UNINIT,
  5. MAVLINK_PARSE_STATE_IDLE,
  6. MAVLINK_PARSE_STATE_GOT_STX,
  7. MAVLINK_PARSE_STATE_GOT_LENGTH,
  8. MAVLINK_PARSE_STATE_GOT_INCOMPAT_FLAGS, // MAVLink 2
  9. MAVLINK_PARSE_STATE_GOT_COMPAT_FLAGS, // MAVLink 2
  10. MAVLINK_PARSE_STATE_GOT_SEQ,
  11. MAVLINK_PARSE_STATE_GOT_SYSID,
  12. MAVLINK_PARSE_STATE_GOT_DESTID,
  13. MAVLINK_PARSE_STATE_GOT_SRCID,
  14. MAVLINK_PARSE_STATE_GOT_COMPID,
  15. MAVLINK_PARSE_STATE_GOT_MSGID1,
  16. MAVLINK_PARSE_STATE_GOT_MSGID2,
  17. MAVLINK_PARSE_STATE_GOT_MSGID3,
  18. MAVLINK_PARSE_STATE_GOT_CRC1,
  19. MAVLINK_PARSE_STATE_GOT_CRC2,
  20. MAVLINK_PARSE_STATE_GOT_PAYLOAD,
  21. MAVLINK_PARSE_STATE_GOT_SIGNATURE,
  22. }
  23. private MAV_states state = MAV_states.MAVLINK_PARSE_STATE_UNINIT;
  24. public MyLinkStats stats;
  25. private MyLinkPacket m;
  26. public MyParser() {
  27. this(false);
  28. }
  29. public MyParser(boolean ignoreRadioPacketStats) {
  30. stats = new MyLinkStats(ignoreRadioPacketStats);
  31. }
  32. public MyLinkPacket mavlink_parse_char(int c) {
  33. // force to 8 bits
  34. c &= 0xFF;
  35. switch (state) {
  36. case MAVLINK_PARSE_STATE_UNINIT:
  37. case MAVLINK_PARSE_STATE_IDLE:
  38. // MAVLink 1 and 2
  39. if (c == MyLinkPacket.MAVLINK_STX) {
  40. state = MAV_states.MAVLINK_PARSE_STATE_GOT_STX;
  41. }
  42. break;
  43. case MAVLINK_PARSE_STATE_GOT_STX:
  44. // MAVLink 1 and 2
  45. m = new MyLinkPacket(c);
  46. state = MAV_states.MAVLINK_PARSE_STATE_GOT_LENGTH;
  47. break;
  48. case MAVLINK_PARSE_STATE_GOT_LENGTH:
  49. m.incompatFlags = c;
  50. if (c != 0 && c != 1) {
  51. state = MAV_states.MAVLINK_PARSE_STATE_IDLE;
  52. break;
  53. }
  54. state = MAV_states.MAVLINK_PARSE_STATE_GOT_INCOMPAT_FLAGS;
  55. break;
  56. case MAVLINK_PARSE_STATE_GOT_INCOMPAT_FLAGS:
  57. m.compatFlags = c;
  58. state = MAV_states.MAVLINK_PARSE_STATE_GOT_COMPAT_FLAGS;
  59. break;
  60. case MAVLINK_PARSE_STATE_GOT_COMPAT_FLAGS:
  61. m.seq = c;
  62. state = MAV_states.MAVLINK_PARSE_STATE_GOT_SEQ;
  63. break;
  64. case MAVLINK_PARSE_STATE_GOT_SEQ:
  65. // back to MAVLink 1 and 2
  66. m.sysid = c;
  67. state = MAV_states.MAVLINK_PARSE_STATE_GOT_SYSID;
  68. break;
  69. case MAVLINK_PARSE_STATE_GOT_SYSID:
  70. m.compid = c;
  71. state = MAV_states.MAVLINK_PARSE_STATE_GOT_DESTID;
  72. break;
  73. case MAVLINK_PARSE_STATE_GOT_DESTID:
  74. m.compid = c;
  75. state = MAV_states.MAVLINK_PARSE_STATE_GOT_SRCID;
  76. break;
  77. case MAVLINK_PARSE_STATE_GOT_SRCID:
  78. m.compid = c;
  79. state = MAV_states.MAVLINK_PARSE_STATE_GOT_COMPID;
  80. break;
  81. case MAVLINK_PARSE_STATE_GOT_COMPID:
  82. // MAVLink 1 and 2
  83. m.msgid = c;
  84. state = MAV_states.MAVLINK_PARSE_STATE_GOT_MSGID1;
  85. if (m.len > 0) {
  86. state = MAV_states.MAVLINK_PARSE_STATE_GOT_MSGID3;
  87. } else {
  88. state = MAV_states.MAVLINK_PARSE_STATE_GOT_PAYLOAD;
  89. }
  90. break;
  91. case MAVLINK_PARSE_STATE_GOT_MSGID1:
  92. m.msgid |= c << 8;
  93. state = MAV_states.MAVLINK_PARSE_STATE_GOT_MSGID2;
  94. break;
  95. case MAVLINK_PARSE_STATE_GOT_MSGID2:
  96. m.msgid |= c << 16;
  97. if (m.len > 0) {
  98. state = MAV_states.MAVLINK_PARSE_STATE_GOT_MSGID3;
  99. } else {
  100. state = MAV_states.MAVLINK_PARSE_STATE_GOT_PAYLOAD;
  101. }
  102. break;
  103. case MAVLINK_PARSE_STATE_GOT_MSGID3:
  104. //将payload的数据加入
  105. m.payload.add((byte) c);
  106. if (m.payloadIsFilled()) {
  107. state = MAV_states.MAVLINK_PARSE_STATE_GOT_PAYLOAD;
  108. }
  109. break;
  110. case MAVLINK_PARSE_STATE_GOT_PAYLOAD:
  111. boolean crcGen = m.generateCRC(m.payload.size());
  112. // Check first checksum byte and verify the CRC was successfully generated (msg extra exists)
  113. if (c != m.crc.getLSB() || !crcGen) {
  114. state = MAV_states.MAVLINK_PARSE_STATE_IDLE;
  115. stats.crcError();
  116. } else {
  117. state = MAV_states.MAVLINK_PARSE_STATE_GOT_CRC1;
  118. }
  119. break;
  120. case MAVLINK_PARSE_STATE_GOT_CRC1:
  121. // Check second checksum byte
  122. if (c != m.crc.getMSB()) {
  123. state = MAV_states.MAVLINK_PARSE_STATE_IDLE;
  124. stats.crcError();
  125. } else { // crc is good
  126. // stats.newPacket(m);
  127. state = MAV_states.MAVLINK_PARSE_STATE_IDLE;
  128. stats.crcError();
  129. }
  130. break;
  131. case MAVLINK_PARSE_STATE_GOT_CRC2:
  132. state = MAV_states.MAVLINK_PARSE_STATE_IDLE;
  133. stats.crcError();
  134. break;
  135. } // switch
  136. return null;
  137. }
  138. }

        发送Cmd类 

  •  SendMav是把CmdSysInfo拼装一个MyLinkPacket装成字节流的形式;
  • MyLinkPacket编码成一个类MavLink协议帧:
  1. public class MyLinkPacket implements Serializable {
  2. private static final long serialVersionUID = 2095947771227815314L;
  3. public static final int MAVLINK_STX = 0xFD; // 253
  4. public static final int HEADER_LEN = 12;
  5. public final int len;
  6. public int seq;
  7. public int sysid;
  8. public int destId;
  9. public int srcId;
  10. public int compid;
  11. public int msgid;
  12. public MyLinkPayload payload;
  13. public CRC crc;
  14. public int incompatFlags;
  15. public int compatFlags;
  16. public MyLinkPacket(int payloadLength) {
  17. len = payloadLength;
  18. payload = new MyLinkPayload();
  19. }
  20. public boolean payloadIsFilled() {
  21. return payload.size() >= len;
  22. }
  23. public boolean generateCRC(final int payloadSize) {
  24. if (crc == null) {
  25. crc = new CRC();
  26. } else {
  27. crc.start_checksum();
  28. }
  29. crc.update_checksum(payloadSize);
  30. crc.update_checksum(incompatFlags);
  31. crc.update_checksum(compatFlags);
  32. crc.update_checksum(seq);
  33. crc.update_checksum(sysid);
  34. crc.update_checksum(destId);
  35. crc.update_checksum(srcId);
  36. crc.update_checksum(compid);
  37. crc.update_checksum(msgid);
  38. crc.update_checksum(msgid >>> 8);
  39. crc.update_checksum(msgid >>> 16);
  40. payload.resetIndex();
  41. for (int i = 0; i < payloadSize; i++) {
  42. crc.update_checksum(payload.getByte());
  43. }
  44. return crc.finish_checksum(msgid);
  45. }
  46. private int mavTrimPayload(final byte[] payload) {
  47. int length = payload.length;
  48. while (length > 1 && payload[length - 1] == 0) {
  49. length--;
  50. }
  51. return length;
  52. }
  53. public byte[] encodePacket() {
  54. final int bufLen;
  55. final int payloadSize;
  56. payloadSize = mavTrimPayload(payload.payload.array());
  57. bufLen = HEADER_LEN + payloadSize + 2;
  58. byte[] buffer = new byte[bufLen];
  59. int i = 0;
  60. buffer[i++] = (byte) MAVLINK_STX;
  61. buffer[i++] = (byte) payloadSize;
  62. buffer[i++] = (byte) incompatFlags;
  63. buffer[i++] = (byte) compatFlags;
  64. buffer[i++] = (byte) seq;
  65. buffer[i++] = (byte) sysid;
  66. buffer[i++] = (byte) destId;
  67. buffer[i++] = (byte) srcId;
  68. buffer[i++] = (byte) compid;
  69. buffer[i++] = (byte) (msgid & 0XFF);
  70. buffer[i++] = (byte) ((msgid >>> 8) & 0XFF);
  71. buffer[i++] = (byte) ((msgid >>> 16) & 0XFF);
  72. for (int j = 0; j < payloadSize; ++j) {
  73. buffer[i++] = payload.payload.get(j);
  74. }
  75. generateCRC(payloadSize);
  76. buffer[i++] = (byte) (crc.getLSB());
  77. buffer[i++] = (byte) (crc.getMSB());
  78. return buffer;
  79. }
  80. }

自定义类MavLink1 Drone端C/C++代码分析:

        

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/688863
推荐阅读
相关标签
  

闽ICP备14008679号