MAVLink功能開發
-----------------本文由“智御電子”提供,同時提供視頻移植教程,以便電子愛好者交流學習。----------------
1.MAVLink簡介##
MAVLink是一種針對微型飛行器,推出的輕量化,僅由頭文件信息編碼而成的軟件通信協議庫。
MAVLink遵循一種混合發布和點對點設計模式:主要的信息可以作為主數據流向多個目標目標進行發送,而一些子協議如(mission protocol或者parameter protocol)可以采用點對點通信模式,利用重傳機制進行可靠的數據傳輸。
MAVLink的信息包(各種數據包類型的組合如姿態信息包、GPS信息包)都是定義在XML格式的原始文件中。利用這個XML文件可以生成如下支持語言的MAVLink源代碼。針對不同的的應用場合,XML文件也被定義了多種。比如針對絕大多數的地面站系統和自動駕駛系統,這樣一些系統所需要的信息包類型就被定義一種取名為“common.xml”文件中。
MAVLink最早是在2009年由Lorenz Meier發布的第一版本,並且有有一群貢獻者參與其中。
因為MAVLink不需要額外的設計框架要求,所以它非常適合在一些通信帶寬有限的程序中使用。比如用XML文件生產的C語言源代碼非常適合用在RAM或者flash受限制的嵌入式系統中。目前MAVLink已經在許多的產品中被用來作為不同設備制造商之間通信的接口而得到應用和驗證。
支持生成的語言
MAVLink2 可以生成如下語言
- C
- C++11
- Python
MAVLink1可以生成如下語言
- C
- C#
- Objective C
- Java
- JavaScript
- Lua
- Swift
- Python
XML文件種類:
- common.xml
- ardupilotmega.xml
- ASLUAV.xml
- autoquad.xml
- icarous.xml
- matrixpilot.xml
- minimal.xml
- paparazzi.xml
- python_array_test.xml
- slugs.xml
- standard.xml
- test.xml
- ualberta.xml
- uAvionix.xml
2.開發流程
本文依據官方開發文檔,一步步完成MAVLink的開發。從獲取文檔、生產源代碼到最后的代碼工程實例(STM32 KEIL C工程)。
2.1 安裝MAVLink工具鏈
首先需要安裝MAVLink相關的工具鏈:包括XML信息文件、GUI/命令行工具。利用這些工具來獲取到MAVLink的源代碼。
使用到的工具鏈如下:
- Python 2.7+ or Python 3.3+
- Python future module
- (Optional) Python TkInter module (required to use the GUI tool).
- PYTHONPATH environment variable must be set to the directory path containing the mavlink repository.
安裝步驟:
-
安裝windows版本Python 2.7+ or 3.3+ (Python for Windows)
根據自己的電腦版本下載版本,本文下載Python3.6.5、64bit、version號為“Windows x86-64 executable installer”安裝文件進行安裝。如下圖所示
到安裝程序的頁面時,勾選上“Add Python 3.6 to PATH”,將path的路徑添加到系統的環境變量中。后面直接就直接下一步即可。
-
安裝future模塊
鍵盤輸入“win+R”調出“運行”界面,輸入“CMD”調出命令行界面。
接着輸入“pip install future”命令。會發現開始安裝這個模塊,一般安裝完即可。如下圖所示如果出現如下圖所示的提示,按照其推薦的命令“python -m pip install --upgrade pip”輸入即可。
-
安裝Git
Git是目前世界上最先進的分布式控制版本系統,主要是代碼管理。我們這邊主要是利用這個Git工具將MAVLink的代碼及生成器下載下來。Git官方點擊下載
選擇自己合適的電腦版本,進行一路安裝,注冊賬戶即可。新建一個文件夾,在文件夾中右擊鼠標出現如下圖標。點擊Git GUI Here.
在出現的命令行中輸入“git clone https://github.com/mavlink/mavlink.git --recursive”。此時git從遠程代碼倉庫中下載代碼。如下圖所示
最終得到如下的源代碼。
-
添加MAVLink文件夾路徑
將下載好的源代碼所在的文件夾路徑添加到python環境變量中。 打開windows命令行,輸入如下命令。
set PYTHONPATH=C:\your_path_to_mavlink_clone
-
生成需要的語言代碼
在下載好的GIT源代碼中,可以發現MAVLink生成器“mavgenerate.py”,它是一個GUI圖形界面。我們可以操作這個圖像界面獲取到想到的語言代碼。
在windows命令行中繼續輸入如下命令,用來執行“mavgenerate.py”腳本。出現如下的GUI。
python -m mavgenerate
根據自己的目標應用場景選擇目標XML文件。本文選擇“mavlink\message_definitions\v1.0\common.xml”
設置out保存路徑;選擇C語言,協議2.0。點擊生成即可。到相應的out目錄就會發現生成好的C語言代碼。
-
KEIL工程移植
本文利用STM32F4的控制板的PX4控制板,並且利用cubeMX進行工程配置來實現MAVLink的移植。最終實現PX4控制板與QGC上位機的通信,以此來驗證MAVLink是否成功移植。
1.因為轉換的C語言代碼都是以.h的文件夾實現的,所以把上圖的文件包含到工程路徑中,並且包含如下的頭文件即可包含全部實現的
#include <mavlink/mavlink.h>
接着利用cubeMx進行串口的配置,我們使用中斷DMA接收與普通輪詢模式發送。不是本文重點,不做描述,可百度,亦可有興趣觀看視頻。
接着我們可以在keil工程里面全局編譯一下,會發現好多的錯誤。這個錯誤跟編譯器有關。一種方式是直接修改每一個錯誤,可以自行百度“mavlink移植 ”;當然還有一種方法,是在工程配置中加入如下配置:
--no_strict --gnu
目的是想讓MAVLink這段代碼采用gun的格式進行編譯,但是要注意其他的代碼需要保證是使用的keil的默認編譯器__CC_ARM進行編譯。再次編譯會發現沒有錯誤。
2.接着就是實現發送、接收數據的底層函數。
C MAVLink庫的實現的多通道的數據流,同樣的程序可以在不同的獨立通道流上進行傳輸。如果只存在一個MAVLink數據流,channel 0默認被用來進行數據傳輸(MAVLINK_COMM_0)
接收數據的處理函數是在MAVLink的
mavlink_helpers.h:mavlink_parse_char()
函數里面實現的。這個函數實際上需要在每次接收到一個字節數據的時候調用它來解析的信息,直到一個完整的數據包被解析完成。發送數據可以用
mavlink_msg_*_pack()
這些函數,然后調用mavlink_helpers.h:mavlink_msg_to_send_buffer()
進行序列化。同時,為了方便,MAVLink為每一種類型的傳輸數據都定義了一個函數,例如mavlink_msg_raw_imu_send
。想要發送IMU數據調用這個函數即可。那我們移植需要關系的是這些函數最后是調用什么的底層硬件接口進行真正的數據傳送的。其實最后是調用的
_mavlink_send_uart(mavlink_channel_t chan, const char *buf, uint16_t len)
這個函數。在這個函數里面有2種底層方式進行數據傳送:多字節和單字節。我們來實現多字節。首先,定義宏
#define MAVLINK_USE_CONVENIENCE_FUNCTIONS
// 移植必須要設定這個宏,詳見代碼#define MAVLINK_SEND_UART_BYTES mavlink_send_uart_bytes
//mavlink_send_uart_bytes是我們用戶自己需要實現的底層代碼。void mavlink_send_uart_bytes(mavlink_channel_t chan, const uint8_t *ch, int length) { HAL_UART_Transmit(&huart8, (uint8_t *)ch, length, 2000); }
3.到這邊基本移植都差不多了。本文在main中做了一個
mavlink_test()
測試函數用於發數據給上位機,void mavlink_test(void) { static uint16_t test_count=0; mavlink_message_t lastmsg; test_count++; //5hz if((test_count%100)==0) { mavlink_test_heartbeat2(1,1,&lastmsg); } if((test_count%50)==0) { mavlink_test_raw_imu2(1,1,&lastmsg); } }
同時利用ringbuffer接收數據,然后在main中實時解析
Loop_Mavlink_Parse()
上位機發送過來的數據。void Loop_Mavlink_Parse(void) { if(Mavlink_RB_IsOverFlow()) { Mavlink_RB_Clear(); } while(Mavlink_RB_HasNew()) { uint8_t read = Mavlink_RB_Pop(); if(mavlink_parse_char(MAVLINK_COMM_0, read, &msg, &status)) { //信號處理函數 Mavlink_Msg_Handle(msg); //printf("Received message with ID %d, sequence: %d from component %d of system %d", msg.msgid, msg.seq, msg.compid, msg.sysid); } } }
最后實際測試移植成功。