电赛 · 2023/07/27 0

Arduino与MATEK光流模块通过MSP协议通信

引言

本文将介绍如何使用Arduino与MATEK光流模块通过MSP协议进行通信。我们将从整体上了解通信的原理和流程,然后分步讲解代码的实现,最后给出完整的代码并附上详尽的中文注释。

通信原理

MSP(MultiWii Serial Protocol)协议是多旋翼飞控系统常用的通信协议,用于在飞行控制板(如Arduino)与传感器之间进行数据交换。MATEK光流模块集成了TOF测距模块和PW3901光流模块,通过MSP协议将光流数据传输给飞控板。

在本例中,我们将使用Arduino作为飞控板,通过串口与MATEK光流模块进行通信。MATEK光流模块将传输数据包含在MSP消息中发送给Arduino,然后Arduino解析MSP消息并提取光流数据。

2. 代码实现

#define BAUD 115200
#define RX1PIN 2
#define TX1PIN 3
#define USART_MODE SERIAL_8N1

int distance, xMove, yMove;

void setup() {
  Serial.begin(BAUD);
  Serial1.begin(BAUD, USART_MODE, RX1PIN, TX1PIN);
}

void loop() {
  if (Serial1.available() > 0) {
    uint8_t mark = Serial1.read();

    // 判断数据标识是否为36,标识着接下来的数据为光流传感器的数据
    if (mark == 36) {
      uint8_t bytesB[5];
      uint8_t bytesC[2];
      uint8_t bytesD[9];
      uint8_t bytesE[1];
      uint8_t psize;

      // 读取接下来的数据
      Serial1.readBytes(bytesB, 5);
      Serial1.readBytes(bytesC, 2);
      psize = bytesC[0] + (bytesC[1] << 8);
      Serial1.readBytes(bytesD, psize);
      Serial1.readBytes(bytesE, 1);

      // 解析数据
      if (psize == 5) {
        int temp = (int32_t)(bytesD[1] | bytesD[2] << 8 | bytesD[3] << 16 | bytesD[4] << 24 | bytesD[5] << 32);
        if (temp != 0) {
          distance = temp;
        }
      } else if (psize == 9) {
        xMove = (int32_t)(bytesD[1] | bytesD[2] << 8 | bytesD[3] << 16 | bytesD[4] << 24);
        yMove = (int32_t)(bytesD[5] | bytesD[6] << 8 | bytesD[7] << 16 | bytesD[8] << 24);
      } else {
        xMove = 0;
        yMove = 0;
      }

      // 打印接收到的数据
      Serial.print("distance:");
      Serial.print(distance);
      Serial.print("  xMove:");
      Serial.print(xMove);
      Serial.print("  yMove:");
      Serial.println(yMove);
    }
  }
}

代码讲解

解析MSP消息

loop()函数中,我们通过Serial1.available()检查是否有数据可用。如果有数据可用,我们读取标识字节 mark,判断是否为36,这标志着接下来的数据为光流传感器的数据。

    uint8_t mark = Serial1.read();

    // 判断数据标识是否为36,标识着接下来的数据为光流传感器的数据
    if (mark == 36)

读取数据和解析

如果数据标识为36,我们就按照MSP消息的格式读取接下来的数据,并根据数据长度进行解析。

      uint8_t bytesB[5];
      uint8_t bytesC[2];
      uint8_t bytesD[9];
      uint8_t bytesE[1];
      uint8_t psize;

      // 读取接下来的数据
      Serial1.readBytes(bytesB, 5);
      Serial1.readBytes(bytesC, 2);
      psize = bytesC[0] + (bytesC[1] &lt;&lt; 8);
      Serial1.readBytes(bytesD, psize);
      Serial1.readBytes(bytesE, 1);

如果数据长度为5,则是TOF传感器的数据。使用移位操作将5个字节组合成一个32位的整数,并将其作为距离 distance 的值。

if (psize == 5) {
        int temp = (int32_t)(bytesD[1] | bytesD[2] << 8 | bytesD[3] << 16 | bytesD[4] << 24 | bytesD[5] << 32);
        if (temp != 0) {
          distance = temp;
        }
      }

如果数据长度为9,则是光流传感器的数据。使用移位操作将9个字节中的前4个字节组合成一个32位的整数,作为X方向移动的值 xMove,同时将后4个字节组合成另一个32位的整数,作为Y方向移动的值 yMove

else if (psize == 9) {
        xMove = (int32_t)(bytesD[1] | bytesD[2] << 8 | bytesD[3] << 16 | bytesD[4] << 24);
        yMove = (int32_t)(bytesD[5] | bytesD[6] << 8 | bytesD[7] << 16 | bytesD[8] << 24);
      }