引言
本文将介绍如何使用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] << 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);
}