昇腾910B单机8卡环境配置全流程:从驱动安装到hccl-test运行
å‰�言MAVLinkMicro Air Vehicle Link是一款轻é‡�级ã€�ä½�带宽ã€�高å�¯é� 性的微å°�å�‹æ— 人机通信å��议由 PX4 团队主导设计广泛应用äº�æ— äººæœºã€�æ— äººè½¦ã€�机器人ç‰åµŒå…¥å¼�ç³»ç»Ÿçš„è·¨è®¾å¤‡é€šä¿¡åœºæ™¯ã€‚å…¶æ ¸å¿ƒä¼˜åŠ¿åœ¨äº�专为资æº�å�—é™�的硬件如 MCUã€�å°�å�‹åµŒå…¥å¼�æ�¿å�¡ä¼˜åŒ–采用二进制编ç �æ ¼å¼�相比 JSONã€�XML ç‰æ–‡æœ¬å��è®®ä¼ è¾“æ•ˆç�‡æ��å�‡æ•°å€�å�Œæ—¶æ”¯æŒ�æ•°æ�®æ ¡éªŒã€�é‡�ä¼ æœºåˆ¶èƒ½åœ¨å¤�æ�‚电ç£�ç�¯å¢ƒä¸‹ä¿�è¯�通信稳定性。ä»� MAVLink å��è®®æ ¸å¿ƒå�Ÿç�†å‡ºå�‘结å�ˆ C è¯è¨€å®�ç�°å®Œæ•´çš„通信æµ�程涵盖å��è®®ç�¯å¢ƒæ�建ã€�消æ�¯ç¼–è§£ç �ã€�串å�£ / 网络通信ã€�æ•°æ�®æ”¶å�‘å®�æˆ˜ç‰æ ¸å¿ƒå†…容所有代ç �å�‡å�¯ç›´æ�¥ç§»æ¤�到 Linux/Windows 嵌入å¼�ç�¯å¢ƒåŠ©åŠ›å¿«é€Ÿä¸Šæ‰‹ MAVLink C å¼€å�‘。一ã€�MAVLink å��è®®æ ¸å¿ƒå�Ÿç�†
1 å��议定ä½�ä¸�æ ¸å¿ƒç‰¹ç‚¹MAVLink 是应用层å��议基äº�串å�£UARTã€�CANã€�TCP/UDP ç‰ä¼ 输层å®�ç�°è·¨è®¾å¤‡é€šä¿¡ä¸»ä»�æ�¶æ�„为主地é�¢ç«™ / GCSä»�æ— äººæœº / é£�æ�§æ¨¡å¼�支æŒ� 1 å¯¹å¤šè®¾å¤‡é€šä¿¡ã€‚æ ¸å¿ƒç‰¹ç‚¹è½»é‡�级最å°�消æ�¯å¸§ä»… 8 å—èŠ‚æ— é¢�外冗余数æ�®äºŒè¿›åˆ¶ç¼–ç �æ— éœ€è§£æ��文本编解ç �效ç�‡æ��高高å�¯é� 内置 CRC æ ¡éªŒã€�消æ�¯åº�列å�·ã€�系统 ID / 组件 ID æ ‡è¯†å�¯æ‰©å±•支æŒ�自定义消æ�¯å…¼å®¹å®˜æ–¹æ ‡å‡†æ¶ˆæ�¯é›†common.xmlã€�ardupilotmega.xml跨平å�°å�Ÿç”Ÿæ”¯æŒ� C/Cã€�Pythonã€�MATLAB ç‰è¯è¨€é€‚é…� Linux/Windows/RTOS。
2 æ ¸å¿ƒæ¶ˆæ�¯å¸§ç»“æ�„MAVLink v
0当�主�版本兼容 v
0采用固定 å�¯å�˜é•¿åº¦çš„帧结æ�„æ ‡å‡†å¸§å…± 10N å—节N 为有效载è�·é•¿åº¦æœ€å¤§ 255 å—节结æ�„如下ä»�ä½�å—节到高å—èŠ‚å—æ®µé•¿åº¦å—节作用帧起始符1固定为0xFDv
0æ ‡è¯†æ¶ˆæ�¯å¸§å¼€å§‹v
0 为0xFE有效载è�·é•¿åº¦1å��ç»æ•°æ�®å—段payloadçš„å—节数0~255å…¼å®¹æ ‡å¿—1v
0 新��下兼容 v
0 çš„æ ‡å¿—ä½�ä¸�å…¼å®¹æ ‡å¿—1v
0 新��兼容 v
0 çš„æ ‡å¿—ä½�如å�¯ç”¨ç¾å��消æ�¯åº�列å�·1消æ�¯è®¡æ•°0~255 循ç�¯ç”¨äº�检测丢包系统 IDSID1è®¾å¤‡å”¯ä¸€æ ‡è¯†å¦‚åœ°é�¢ç«™ SID1æ— äººæœº 12æ— äººæœº 23区分多设备组件 IDCID1è®¾å¤‡å†…ç»„ä»¶æ ‡è¯†å¦‚é£�æ�§ CID1æ‘„åƒ�头 CID2区分å�•设备多组件消æ�¯ ID3消æ�¯ç±»å�‹æ ‡è¯†å¦‚心跳消æ�¯ ID0å§¿æ€�消æ�¯ ID30v
0 为 1 å—节有效载è�·Nå®�际业务数æ�®å¦‚å§¿æ€�è§’ã€�速度ã€�æŒ‡ä»¤ç‰æŒ‰å��è®®å®šä¹‰çš„æ ¼å¼�å˜å‚¨CRC æ ¡éªŒç �2对帧起始符到消æ�¯ ID çš„æ‰€æœ‰å—æ®µæ ¡éªŒæ£€æµ‹æ•°æ�®ä¼ 输错误ç¾å��å�¯é€‰13å®‰å…¨æ ¡éªŒå—æ®µç”¨äº�åŠ å¯†é€šä¿¡éœ€æ‰‹åŠ¨å�¯ç”¨
3 æ ¸å¿ƒè®¾è®¡æ€�æƒ³æ— è¿�æ�¥é€šä¿¡æ— 需建立 TCP å¼�çš„è¿�æ�¥ç›´æ�¥åŸºäº�ä¼ è¾“å±‚å�‘é€�帧数æ�®é™�ä½�é€šä¿¡å¼€é”€è®¾å¤‡å”¯ä¸€æ ‡è¯†é€šè¿‡ç³»ç»ŸID组件IDå®�ç�°å¤šè®¾å¤‡ / 多组件的精准寻å�€åœ°é�¢ç«™å�¯å�Œæ—¶ç®¡ç�†å¤šå�°æ— 人机轻é‡�化编解ç �基äº�预定义的 XML 消æ�¯é›†ç”Ÿæˆ� C/C 头文件编解ç �仅需简å�•çš„å†…å˜æ‹·è´�å’Œæ ¡éªŒæ— åŠ¨æ€�内å˜åˆ†é…�适é…�嵌入å¼�系统é²�棒性机制消æ�¯åº�列å�·æ£€æµ‹ä¸¢åŒ…ã€�CRC æ ¡éªŒæ£€æµ‹æ•°æ�®æ�Ÿå��ã€�è¶…æ—¶é‡�ä¼ æœºåˆ¶ä¿�è¯�消æ�¯é€�达。二ã€�å¼€å�‘ç�¯å¢ƒæ�建ä¸�ä¾�èµ–MAVLink C å¼€å�‘æ— å¤�æ�‚ä¾�èµ–æ ¸å¿ƒä»…éœ€MAVLink å®˜æ–¹å¤´æ–‡ä»¶æ— éœ€ç¼–è¯‘åº“çº¯å¤´æ–‡ä»¶å®�ç�°æ”¯æŒ�跨平å�°ç¼–译以下为 LinuxUbuntuå’Œ Windows ç�¯å¢ƒçš„æ�建æ¥éª¤ã€‚
1 æ ¸å¿ƒä¾�赖编译ç�¯å¢ƒLinuxg/cmakeã€�WindowsMSVC/MinGW通信ä¾�èµ–Linuxtermios串å�£åº“ã€�socket网络库ã€�WindowsWin32 API串å�£åº“ã€�Winsock网络库MAVLink 头文件官方自动生æˆ�适é…�指定消æ�¯é›†å¦‚ commonã€�ardupilotmega。
2 MAVLink 头文件è�·å�–两ç§�æ–¹å¼�æ–¹å¼� 1官方在线生æˆ�æ�¨è��简å�•å¿«æ�·æ‰“å¼€ MAVLink 在线生æˆ�工具https://mavlink.io/en/gen/选择消æ�¯é›†æ�¨è��common通用消æ�¯é›†åŒ…å�«å¿ƒè·³ã€�å§¿æ€�ã€�æŒ‡ä»¤ç‰æ ¸å¿ƒæ¶ˆæ�¯é€‰æ‹©ç‰ˆæœ¬MAVLink
0点击Generate生æˆ�å�‹ç¼©åŒ…è§£å�‹å��得到mavlink文件夹包å�«æ‰€æœ‰å¤´æ–‡ä»¶æ ¸å¿ƒä¸ºmavlink.h。方å¼� 2本地 Python 生æˆ�适å�ˆè‡ªå®šä¹‰æ¶ˆæ�¯å®‰è£… Python3sudo apt install python3 python3-pipLinux/ 官网下载Windows克隆 MAVLink æº�ç �git clone https://github.com/mavlink/mavlink.git进入工具目录cd mavlink/pymavlink/tools生æˆ�头文件python3 mavgen.py --lang C --wire-protocol
0 --output ../generated/mavlink/v
0 common.xml生�的头文件��../generated/mavlink/v
0目录下。
3 ç�¯å¢ƒé…�置将生æˆ�çš„mavlink头文件文件夹放入项目目录在 C 代ç �ä¸é€šè¿‡#include mavlink/mavlink.h引入å�³å�¯æ— 需链æ�¥ä»»ä½•库纯头文件å®�ç�°ç¼–è§£ç �逻辑在头文件ä¸ã€‚三ã€�C å®�ç�° MAVLink 完整通信æµ�程MAVLink C é€šä¿¡çš„æ ¸å¿ƒæµ�程为ç�¯å¢ƒåˆ�始化→消æ�¯ç¼–ç �→数æ�®ä¼ 输→消æ�¯è§£ç �→数æ�®è§£æ��以下å®�ç�°è·¨å¹³å�°ä¸²å�£é€šä¿¡æœ€å¸¸ç”¨çš„ MAVLink 通信方å¼�æ— äººæœºé£�æ�§å¤šé€šè¿‡ä¸²å�£ä¸�地é�¢ç«™é€šä¿¡å�Œæ—¶å…¼å®¹ MAVLink
0 �议包�心跳消�HEARTBEAT和姿�消�ATTITUDE的收��战。
1 æ ¸å¿ƒä»£ç �å®�ç�°å�«è·¨å¹³å�°å…¼å®¹åˆ›å»ºé¡¹ç›®æ–‡ä»¶ç»“æ�„plaintextmavlink_cpp_demo/ ├── mavlink/ # MAVLink官方头文件文件夹 │ └── mavlink.h # æ ¸å¿ƒå¤´æ–‡ä»¶ ├── MavlinkSerial.h # 串å�£é€šä¿¡å°�装头文件 ├── MavlinkSerial.cpp # 串å�£é€šä¿¡å°�装å®�ç�° └── main.cpp # 主函数收å�‘å®�战文件 1MavlinkSerial.h跨平å�°ä¸²å�£å°�装 MAVLink 基础cppè¿�行#ifndef MAVLINK_SERIAL_H #define MAVLINK_SERIAL_H #include cstdint #include string // 引入MAVLinkæ ¸å¿ƒå¤´æ–‡ä»¶ #include mavlink/mavlink.h // 跨平å�°ä¸²å�£å�¥æŸ„定义 #ifdef _WIN32 #include windows.h typedef HANDLE SerialHandle; #else #include termios.h typedef int SerialHandle; #endif // MAVLink设备é…�ç½® const uint8_t SYS_ID 1; // 本设备系统ID地é�¢ç«™è®¾ä¸º1æ— äººæœºè®¾ä¸º2 const uint8_t COMP_ID 1; // 本设备组件IDé£�æ�§/地é�¢ç«™å�‡è®¾ä¸º1å�³å�¯ const uint32_t BAUDRATE 115200; // MAVLink默认波特ç�‡115200 class MavlinkSerial { public: MavlinkSerial(); ~MavlinkSerial(); // 打开串å�£port为串å�£å��Linux:/dev/ttyUSB0Windows:COM3 bool openSerial(const std::string port); // å…³é—串å�£ void closeSerial(); // 判æ–串å�£æ˜¯å�¦æ‰“å¼€ bool isOpen() const { return m_isOpen; } // MAVLink消æ�¯å�‘é€�ç¼–ç �å¹¶å�‘é€�MAVLink消æ�¯ bool sendMavlinkMsg(const mavlink_message_t msg); // MAVLink消æ�¯æ�¥æ”¶è¯»å�–串å�£æ•°æ�®å¹¶è§£ç �为MAVLink消æ�¯ bool recvMavlinkMsg(mavlink_message_t msg, mavlink_status_t status); private: SerialHandle m_serialHandle; // 串å�£å�¥æŸ„ bool m_isOpen; // 串å�£æ‰“å¼€æ ‡å¿— // 跨平å�°ä¸²å�£é…�置波特ç�‡ã€�æ•°æ�®ä½�ã€�å�œæ¢ä½�ã€�æ ¡éªŒä½� bool configSerial(uint32_t baudrate); }; #endif // MAVLINK_SERIAL_H文件 2MavlinkSerial.cpp跨平å�°ä¸²å�£å®�ç�° MAVLink ç¼–è§£ç �cppè¿�行#include MavlinkSerial.h #include cstring #include unistd.h // æ�„é€ å‡½æ•° MavlinkSerial::MavlinkSerial() : m_serialHandle(
, m_isOpen(false) { #ifdef _WIN32 // Windowsåˆ�始化Winsockè‹¥å��ç»ç”¨ç½‘络通信æ¤å¤„å�¯æ��å‰�åˆ�始化 WSADATA wsaData; WSAStartup(MAKEWORD(2,
, wsaData); #endif } // æ��æ�„函数 MavlinkSerial::~MavlinkSerial() { if (m_isOpen) { closeSerial(); } #ifdef _WIN32 WSACleanup(); #endif } // 打开串å�£ bool MavlinkSerial::openSerial(const std::string port) { if (m_isOpen) { return true; } #ifdef _WIN32 // Windows打开串å�£é€šç”¨æ³¢ç‰¹ç�‡é…�ç½®é‡�å� I/O m_serialHandle CreateFileA(port.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (m_serialHandle INVALID_HANDLE_VALUE) { return false; } #else // Linux打开串å�£O_RDWR读写ã€�O_NOCTTYä¸�æˆ�为æ�§åˆ¶ç»ˆç«¯ã€�O_NDELAYé��阻å¡� m_serialHandle open(port.c_str(), O_RDWR | O_NOCTTY | O_NDELAY); if (m_serialHandle
{ return false; } // ��串�阻�模���数�读�稳定 fcntl(m_serialHandle, F_SETFL,
; #endif // é…�置串å�£å�‚数波特ç�‡ã€�8N18æ•°æ�®ä½�ã€�æ— æ ¡éªŒã€�1å�œæ¢ä½�MAVLink默认é…�ç½® if (!configSerial(BAUDRATE)) { closeSerial(); return false; } m_isOpen true; return true; } // å…³é—串å�£ void MavlinkSerial::closeSerial() { if (!m_isOpen) { return; } #ifdef _WIN32 CloseHandle(m_serialHandle); #else close(m_serialHandle); #endif m_serialHandle 0; m_isOpen false; } // 跨平å�°ä¸²å�£é…�ç½® bool MavlinkSerial::configSerial(uint32_t baudrate) { #ifdef _WIN32 DCB dcbSerial {0}; dcbSerial.DCBlength sizeof(dcbSerial); if (!GetCommState(m_serialHandle, dcbSerial)) { return false; } // é…�ç½®8N1波特ç�‡ dcbSerial.BaudRate baudrate; dcbSerial.ByteSize 8; dcbSerial.Parity NOPARITY; dcbSerial.StopBits ONESTOPBIT; if (!SetCommState(m_serialHandle, dcbSerial)) { return false; } // é…�置超时读超时100ms写超时50ms COMMTIMEOUTS timeouts {0}; timeouts.ReadIntervalTimeout 100; timeouts.ReadTotalTimeoutConstant 100; timeouts.WriteTotalTimeoutConstant 50; SetCommTimeouts(m_serialHandle, timeouts); #else struct termios tty; memset(tty, 0, sizeof(tty)); // è�·å�–当å‰�串å�£é…�ç½® if (tcgetattr(m_serialHandle, tty) !
{ return false; } // 设置波特ç�‡ speed_t speed; switch (baudrate) { case 9600: speed B9600; break; case 115200: speed B115200; break; case 230400: speed B230400; break; default: speed B115200; break; } cfsetispeed(tty, speed); cfsetospeed(tty, speed); // é…�ç½®8N1å�¯ç”¨è¯»å†™ tty.c_cflag | (CLOCAL | CREAD); // 忽略调制解调器线ã€�å�¯ç”¨æ�¥æ”¶ tty.c_cflag ~CSIZE; tty.c_cflag | CS8; // 8æ•°æ�®ä½� tty.c_cflag ~PARENB; // æ— æ ¡éªŒ tty.c_cflag ~CSTOPB; // 1å�œæ¢ä½� tty.c_cflag ~CRTSCTS; // å…³é—硬件æµ�æ�§ // é…�ç½®å�Ÿå§‹æ¨¡å¼�æ— å›�车æ�¢è¡Œè½¬æ�¢MAVLink为二进制数æ�® tty.c_lflag ~(ICANON | ECHO | ECHOE | ISIG); tty.c_oflag ~OPOST; // é…�置超时MIN1最少读å�–1å—节TIME10è¶…æ—¶10*
11s tty.c_cc[VMIN] 1; tty.c_cc[VTIME] 10; // 应用�置 if (tcsetattr(m_serialHandle, TCSANOW, tty) !
{ return false; } #endif return true; } // å�‘é€�MAVLink消æ�¯æ ¸å¿ƒä¸ºmavlink_msg_to_send_bufferç¼–ç � bool MavlinkSerial::sendMavlinkMsg(const mavlink_message_t msg) { if (!m_isOpen) { return false; } // æ ¸å¿ƒç¼–ç �函数将mavlink_message_tç¼–ç �为二进制å—节æµ� // buf为输出缓冲区返å›�值为编ç �å��çš„å—节数å�³æ¶ˆæ�¯å¸§æ€»é•¿åº¦ uint8_t buf[MAVLINK_MAX_PACKET_LEN]; uint16_t len mavlink_msg_to_send_buffer(buf, msg); // 跨平å�°å†™ä¸²å�£ #ifdef _WIN32 DWORD written 0; WriteFile(m_serialHandle, buf, len, written, NULL); return (written len); #else ssize_t written write(m_serialHandle, buf, len); return (written len); #endif } // æ�¥æ”¶MAVLink消æ�¯æ ¸å¿ƒä¸ºmavlink_parse_charè§£ç � bool MavlinkSerial::recvMavlinkMsg(mavlink_message_t msg, mavlink_status_t status) { if (!m_isOpen) { return false; } uint8_t ch; ssize_t readLen 0; // é€�å—节读å�–串å�£æ•°æ�®MAVLinkè§£ç �需é€�å—节解æ�� #ifdef _WIN32 DWORD read 0; ReadFile(m_serialHandle, ch, 1, read, NULL); readLen read; #else readLen read(m_serialHandle, ch,
; #endif if (readLen !
{ return false; } // æ ¸å¿ƒè§£ç �函数é€�å—节解æ��完æˆ�一帧å��è¿”å›�MAVLINK_FRAMING_OK // statusè§£ç �状æ€�包å�«åº�列å�·ã€�è§£æ��ç»Ÿè®¡ç‰ // msgè§£ç �å��çš„MAVLink消æ�¯ if (mavlink_parse_char(MAVLINK_COMM_0, ch, msg, status) MAVLINK_FRAMING_OK) { return true; } return false; }文件 3main.cppMAVLink 消æ�¯æ”¶å�‘å®�战心跳 å§¿æ€�cppè¿�行#include MavlinkSerial.h #include iostream #include chrono #include thread int main() { //
åˆ�始化MAVLink串å�£å¯¹è±¡ MavlinkSerial mavSerial; std::string serialPort; // 跨平å�°é€‰æ‹©ä¸²å�£å�� #ifdef _WIN32 serialPort COM3; // Windows串å�£éœ€æ ¹æ�®å®�际修改 #else serialPort /dev/ttyUSB0; // Linux串å�£éœ€æ ¹æ�®å®�际修改æ�ƒé™�sudo chmod 777 /dev/ttyUSB0 #endif //
打开串� if (!mavSerial.openSerial(serialPort)) { std::cerr 打开串�失败请检查串��和�� std::endl; return -1; } std::cout 串�打开�功开始MAVLink通信... std::endl; //
åˆ�始化MAVLink状æ€�和消æ�¯å¯¹è±¡ mavlink_status_t mavStatus; mavlink_message_t mavMsg; mavlink_heartbeat_t heartbeatMsg; // 心跳消æ�¯ç»“æ�„体 mavlink_attitude_t attitudeMsg; // å§¿æ€�消æ�¯ç»“æ�„体 uint8_t msgSeq 0; // 消æ�¯åº�列å�·è‡ªå¢�0~255循ç�¯ // åˆ�始化心跳消æ�¯MAVLinkæ ‡å‡†å®šä¹‰ heartbeatMsg.type MAV_TYPE_GCS; // 设备类å�‹åœ°é�¢ç«™æ— 人机为MAV_TYPE_QUADROTOR heartbeatMsg.autopilot MAV_AUTOPILOT_GENERIC; // é£�æ�§ç±»å�‹é€šç”¨ heartbeatMsg.base_mode 0; heartbeatMsg.custom_mode 0; heartbeatMsg.system_status MAV_STATE_STANDBY; // 系统状æ€�待机 heartbeatMsg.mavlink_version 2; // MAVLink版本
0 while (true) { // ��MAVLink消� //
å�‘é€�心跳消æ�¯æ¯�1ç§’å�‘é€�1次MAVLinkæ ‡å‡†å¿ƒè·³é¢‘ç�‡ static auto lastHeartbeat std::chrono::steady_clock::now(); auto now std::chrono::steady_clock::now(); if (std::chrono::duration_caststd::chrono::seconds(now - lastHeartbeat).count()
{ // æ ¸å¿ƒç¼–ç �心跳消æ�¯ä¸ºmavlink_message_t mavlink_msg_heartbeat_encode( SYS_ID, // 本设备系统ID COMP_ID, // 本设备组件ID mavMsg, // 输出的MAVLink消æ�¯ heartbeatMsg // å¾…ç¼–ç �的心跳消æ�¯ç»“æ�„体 ); mavMsg.seq msgSeq; // 设置消æ�¯åº�列å�·è‡ªå¢� // å�‘é€�消æ�¯ if (mavSerial.sendMavlinkMsg(mavMsg)) { std::cout å�‘é€�心跳消æ�¯æˆ�功åº�列å�· (int)(msgSeq-
std::endl; } else { std::cerr ��心跳消�失败 std::endl; } lastHeartbeat now; } //
模拟å�‘é€�å§¿æ€�消æ�¯æ¯�500mså�‘é€�1次仅演示å®�é™…ä»�ä¼ æ„Ÿå™¨è�·å�–æ•°æ�® static auto lastAttitude std::chrono::steady_clock::now(); if (std::chrono::duration_caststd::chrono::milliseconds(now - lastAttitude).count()
{ // 模拟姿�数�滚转/俯仰/�航��弧度 attitudeMsg.roll
05f; attitudeMsg.pitch -
02f; attitudeMsg.yaw
1f; attitudeMsg.rollspeed
01f; attitudeMsg.pitchspeed
005f; attitudeMsg.yawspeed
02f; attitudeMsg.time_boot_ms std::chrono::duration_caststd::chrono::milliseconds( std::chrono::steady_clock::now().time_since_epoch() ).count(); // 开机时间戳 // æ ¸å¿ƒç¼–ç �å§¿æ€�消æ�¯ä¸ºmavlink_message_t mavlink_msg_attitude_encode( SYS_ID, COMP_ID, mavMsg, attitudeMsg ); mavMsg.seq msgSeq; if (mavSerial.sendMavlinkMsg(mavMsg)) { std::cout å�‘é€�å§¿æ€�消æ�¯æˆ�功滚转 attitudeMsg.roll rad std::endl; } else { std::cerr å�‘é€�å§¿æ€�消æ�¯å¤±è´¥ std::endl; } lastAttitude now; } // æ�¥æ”¶MAVLink消æ�¯ if (mavSerial.recvMavlinkMsg(mavMsg, mavStatus)) { std::cout \næ�¥æ”¶åˆ°MAVLink消æ�¯ std::endl; std::cout 系统ID (int)mavMsg.sysid 组件ID (int)mavMsg.compid std::endl; std::cout 消æ�¯ID (int)mavMsg.msgid åº�列å�· (int)mavMsg.seq std::endl; // æ ¹æ�®æ¶ˆæ�¯IDè§£æ��ä¸�å�Œç±»å�‹çš„æ¶ˆæ�¯ switch (mavMsg.msgid) { case MAVLINK_MSG_ID_HEARTBEAT: { // 心跳消æ�¯ID0 mavlink_heartbeat_t recvHeartbeat; mavlink_msg_heartbeat_decode(mavMsg, recvHeartbeat); std::cout 消æ�¯ç±»å�‹å¿ƒè·³ std::endl; std::cout 设备类å�‹ (int)recvHeartbeat.type 系统状æ€� (int)recvHeartbeat.system_status std::endl; break; } case MAVLINK_MSG_ID_ATTITUDE: { // å§¿æ€�消æ�¯ID30 mavlink_attitude_t recvAttitude; mavlink_msg_attitude_decode(mavMsg, recvAttitude); std::cout 消æ�¯ç±»å�‹å§¿æ€� std::endl; std::cout 滚转 recvAttitude.roll rad俯仰 recvAttitude.pitch radå��航 recvAttitude.yaw rad std::endl; break; } default: std::cout 消æ�¯ç±»å�‹æœªçŸ¥ID (int)mavMsg.msgid std::endl; break; } } // 轻微延时é™�ä½�CPUå� 用 std::this_thread::sleep_for(std::chrono::milliseconds(
); } // å…³é—串å�£å®�际循ç�¯ä¸ä¸�会执行å�¯æ ¹æ�®éœ€æ±‚æ·»åŠ é€€å‡ºé€»è¾‘ mavSerial.closeSerial(); return 0; }
2 æ ¸å¿ƒ API 说æ˜�MAVLink ç¼–è§£ç �关键函数MAVLink 的编解ç �逻辑全部å°�è£…åœ¨å®˜æ–¹å¤´æ–‡ä»¶ä¸æ ¸å¿ƒ API 为以下 4 个是 C å¼€å�‘的基础
消æ�¯ç¼–ç �mavlink_msg_XXX_encode功能将消æ�¯ç»“æ�„体如mavlink_heartbeat_tç¼–ç �为 MAVLink æ ‡å‡†æ¶ˆæ�¯å¯¹è±¡mavlink_message_t命å��规则XXX为消æ�¯å��如 heartbeatã€�attitudeä¸�消æ�¯ç»“æ�„体对应å�‚æ•°sysid本设备系统 IDã€�compid本设备组件 IDã€�msg输出消æ�¯å¯¹è±¡ã€�XXXå¾…ç¼–ç �的消æ�¯ç»“æ�„体示例mavlink_msg_heartbeat_encode(SYS_ID, COMP_ID, mavMsg, heartbeatMsg)。
å—节æµ�转æ�¢mavlink_msg_to_send_buffer功能MAVLinkæ ¸å¿ƒç¼–ç �函数将mavlink_message_t对象转æ�¢ä¸ºå�¯ä¼ 输的二进制å—节æµ�符å�ˆ MAVLink 帧结æ�„å�‚æ•°buf输出å—节æµ�缓冲区需大äº�MAVLINK_MAX_PACKET_LENã€�msg待转æ�¢çš„ MAVLink 消æ�¯å¯¹è±¡è¿”å›�值编ç �å��çš„å—节æµ�长度å�³æ¶ˆæ�¯å¸§æ€»å—节数å�¯ç›´æ�¥é€šè¿‡ä¸²å�£ / 网络å�‘é€�示例uint16_t len mavlink_msg_to_send_buffer(buf, mavMsg)。
é€�å—节解ç �mavlink_parse_char功能MAVLinkæ ¸å¿ƒè§£ç �函数é€�å—节解æ��二进制æµ�è‡ªåŠ¨æ ¡éªŒå¸§ç»“æ�„ã€�CRCã€�åº�列å�·å®Œæˆ�一帧解æ��å��è¿”å›�æˆ�åŠŸæ ‡å¿—å�‚æ•°chan通信通é�“默认MAVLINK_COMM_0ã€�chå¾…è§£æ��çš„å�•个å—节ã€�msg输出解ç �å��的消æ�¯å¯¹è±¡ã€�statusè§£ç �状æ€�包å�«è§£æ��统计返å›�值MAVLINK_FRAMING_OK表示解æ��完æˆ�一帧有效消æ�¯å…¶ä»–值为解æ��ä¸ / 错误示例if (mavlink_parse_char(MAVLINK_COMM_0, ch, msg, status) MAVLINK_FRAMING_OK)。
消æ�¯è§£æ��mavlink_msg_XXX_decode功能将解ç �å��çš„mavlink_message_t对象解æ��为消æ�¯ç»“æ�„体方便æ��å�–业务数æ�®å‘½å��规则ä¸�ç¼–ç �函数对应XXX为消æ�¯å��å�‚æ•°msgè§£ç �å��çš„ MAVLink 消æ�¯å¯¹è±¡ã€�XXX输出消æ�¯ç»“æ�„体示例mavlink_msg_heartbeat_decode(mavMsg, recvHeartbeat)。四ã€�编译ä¸�è¿�行
1 LinuxUbuntu编译è¿�行安装编译工具sudo apt install g cmake进入项目目录创建编译脚本build.shbashè¿�行#!/bin/bash g -stdc11 main.cpp MavlinkSerial.cpp -o mavlink_demo # 赋予串å�£æ�ƒé™�æ ¹æ�®å®�际串å�£å��修改 sudo chmod 777 /dev/ttyUSB0执行脚本chmod x build.sh ./build.shè¿�行程åº�./mavlink_demo。
2 WindowsMinGW编译è¿�行安装 MinGWé…�ç½®ç�¯å¢ƒå�˜é‡�打开 CMD进入项目目录执行编译命令cmdg -stdc11 main.cpp MavlinkSerial.cpp -o mavlink_demo.exe -lws2_32-lws2_32链æ�¥ Windows 网络库必须添åŠ
è¿�行程åº�mavlink_demo.exe需确ä¿�串å�£COM3å˜åœ¨æ ¹æ�®å®�际修改。
3 è¿�行结æ�œè¯´æ˜�程åº�è¿�行å��å°†æ¯�ç§’å�‘é€� 1 次心跳消æ�¯ã€�æ¯� 500ms å�‘é€� 1 次模拟姿æ€�消æ�¯å�Œæ—¶å®�æ—¶æ�¥æ”¶ä¸²å�£ç«¯çš„ MAVLink 消æ�¯å¹¶è§£æ��打å�°ã€‚è‹¥è¿�æ�¥æ— 人机é£�æ�§å¦‚ PX4ã€�ArduPilot将能æ�¥æ”¶åˆ°é£�æ�§å�‘é€�的真å®�心跳ã€�å§¿æ€�ã€�GPS ç‰æ¶ˆæ�¯ã€‚五ã€�扩展开å�‘网络通信TCP/UDP除了串å�£é€šä¿¡MAVLink 也广泛用äº�网络通信如地é�¢ç«™é€šè¿‡ WiFi/4G ä¸�æ— äººæœºé€šä¿¡å…¶æ ¸å¿ƒç¼–è§£ç �逻辑ä¸�串å�£å®Œå…¨ä¸€è‡´ä»…需替æ�¢æ•°æ�®ä¼ 输层将串å�£çš„read/write替æ�¢ä¸ºç½‘络的send/recvã€‚æ ¸å¿ƒæ‰©å±•æ€�路基äº� Linuxsocket/WindowsWinsockå®�ç�° TCP/UDP 客户端 / æœ�务端网络数æ�®å�‘é€�å°†mavlink_msg_to_send_bufferç¼–ç �å��çš„å—节æµ�通过send/sendtoå�‘é€�网络数æ�®æ�¥æ”¶é€šè¿‡recv/recvfrom读å�–网络å—节æµ�å†�通过mavlink_parse_charé€�å—节解ç �ç¼–è§£ç � APIã€�消æ�¯å¯¹è±¡mavlink_message_t完全å¤�ç”¨æ— éœ€ä¿®æ”¹ã€‚å…ã€�常è§�问题ä¸�解决方案
1 串å�£æ‰“开失败å�Ÿå› 1串å�£å��错误→解决方案Linux 通过dmesg | grep tty查看串å�£å��Windows 通过设备管ç�†å™¨æŸ¥çœ‹å�Ÿå› 2Linux 串å�£æ�ƒé™�ä¸�足→解决方案sudo chmod 777 /dev/ttyUSB0æˆ–æ·»åŠ ç”¨æˆ·åˆ° dialout 组sudo usermod -aG dialout 用户å��é‡�å�¯ç”Ÿæ•ˆå�Ÿå› 3串å�£è¢«å…¶ä»–程åº�å� 用→解决方案关é—串å�£è°ƒè¯•工具如串å�£åŠ©æ‰‹ã€�QGroundControl。
2 消æ�¯å�‘é€�æˆ�功但æ�¥æ”¶ä¸�到å�Ÿå› 1波特ç�‡ / 串å�£é…�ç½®ä¸�匹é…�→解决方案确ä¿�两端波特ç�‡å�‡ä¸º 115200ã€�8N1æ— æ ¡éªŒã€�1 å�œæ¢ä½�å�Ÿå› 2MAVLink 版本ä¸�兼容→解决方案两端å�‡ä½¿ç”¨ MAVLink
0��一端 v
0 一端 v
0å�Ÿå› 3系统 ID / 组件 ID é…�置错误→解决方案确ä¿�通信å�Œæ–¹çš„寻å�€ ID æ£ç¡®åœ°é�¢ç«™å�¯æ�¥æ”¶æ‰€æœ‰ ID 的消æ�¯ã€‚
3 è§£ç �失败 / CRC æ ¡éªŒé”™è¯¯å�Ÿå› 1æ•°æ�®ä¼ è¾“è¿‡ç¨‹ä¸æ�Ÿå��→解决方案检查硬件è¿�æ�¥å¦‚串å�£çº¿æ�¥è§¦ä¸�良ã€�WiFi ä¿¡å�·å·®å�Ÿå› 2è§£ç �时未é€�å—节解æ��â†’è§£å†³æ–¹æ¡ˆä¸¥æ ¼ä½¿ç”¨mavlink_parse_charé€�å—节解æ��ä¸�å�¯æ‰¹é‡�è§£æ��å�Ÿå› 3MAVLink 头文件版本ä¸�匹é…�→解决方案确ä¿�通信å�Œæ–¹ä½¿ç”¨ç›¸å�Œæ¶ˆæ�¯é›†å¦‚ common.xml生æˆ�的头文件。
4 编译报错MAVLink 头文件未找到解决方案检查代ç �ä¸#include mavlink/mavlink.h的路径确ä¿�mavlinkæ–‡ä»¶å¤¹åœ¨é¡¹ç›®æ ¹ç›®å½•æˆ–æ·»åŠ å¤´æ–‡ä»¶è·¯å¾„ç¼–è¯‘g -I/xxx/mavlink_dir main.cpp ...。七ã€�总结本文详细讲解了 MAVLink 通信å��è®®çš„æ ¸å¿ƒå�Ÿç�†å’Œ C å®�战å®�ç�°æ ¸å¿ƒè¦�点总结如下MAVLink 是轻é‡�级应用层å��议基äº�二进制编ç �专为嵌入å¼�è®¾å¤‡ä¼˜åŒ–æ ¸å¿ƒå¸§ç»“æ�„包å�«èµ·å§‹ç¬¦ã€�有效载è�·ã€�CRC æ ¡éªŒç‰å—段MAVLink C å¼€å�‘æ— éœ€ç¼–è¯‘åº“ä»…éœ€å®˜æ–¹å¤´æ–‡ä»¶æ ¸å¿ƒç¼–è§£ç �通过 4 个 API 完æˆ�encode结æ�„体转消æ�¯å¯¹è±¡ã€�mavlink_msg_to_send_buffer消æ�¯å¯¹è±¡è½¬äºŒè¿›åˆ¶æµ�ã€�mavlink_parse_charé€�å—节解ç �ã€�decode消æ�¯å¯¹è±¡è½¬ç»“æ�„体å®�ç�°äº†è·¨å¹³å�°ä¸²å�£é€šä¿¡çš„ MAVLink æ”¶å�‘兼容 Linux/Windowså�¯ç›´æ�¥ç§»æ¤�到嵌入å¼�系统消æ�¯æ”¶å�‘æµ�程为「编ç �â†’ä¼ è¾“â†’è§£ç �→解æ��ã€�网络通信TCP/UDPå�¯ç›´æ�¥å¤�用编解ç �逻辑仅需替æ�¢æ•°æ�®ä¼ 输层扩展性æ��强。
人配兽猪马狗logo-人配兽猪马狗应用