PS. Mission Planner是一款開源的無人機地面站軟件,APM/ PX4則分別為兩種飛控固件(類似於windows和linux的關系)。而pixhawk是飛控硬件,它可以安裝上述兩種固件中的任何一個。
本教程假定:
-
你是個小白☹我曾經也是,但現在不再是了!
-
你至少在C語言方面具備一定的編程技能(例如,在C/C++/C#/Java中編寫過簡單的switch cases)。如果你已經是專業級,那么return 0;
-
你很嚴肅地打算去學習知識,因為你將為此失去一些睡眠!
但不管怎樣,請始終保持學習的意願,我衷心希望你永遠不會忘記這一點🙂我可以開始了嗎?
我為你而來,MavLink
MavLink消息的結構:
消息長度 = 17 (6 bytes header + 9 bytes payload + 2 bytes checksum)
長度為6個字節的首部 header 0. message header, 永遠為 0xFE 1. message length (9) 2. sequence number -- 在 255 和 0 之間輪轉(0x4e,前一個是 0x4d) 3. System ID - 什么系統在發送這個消息 (1) 4. Component ID- 系統的哪個組件正在發送消息 (1) 5. Message ID (例如 0 = heartbeat 等等! 別害羞,你也可以添加..) 可變長的有效負載 Payload (由八位組構成, 范圍是 0..255) ** Payload (我們感興趣的實際數據) 校驗和 Checksum: 用於錯誤檢測
(APM以及地面站)軟件所做的事情是,檢查它是否為一個有效的消息(通過檢查Checksum判斷消息是否已損壞,丟棄已經損壞的消息)。這是遙測的波特率為什么設置為57,600而不是115,200 bps的原因之一。該數值越低,軟件容易發生的錯誤就越少,雖然消息更新到地面站的速度會慢一些。如果你想在采用MavLink協議的同時取得更遠點的距離,進一步降低波特率可能是一個好主意。然而,需要注意的是,經過測試,57,600bps在理論上可以通過3DR遙測無線電提供大約一英里半徑的覆蓋范圍。還記得高中時的信噪比(SNIR)的概念嗎?
現在,根據上面的內容,我們感興趣的東西是:
-
System ID(亦稱消息的來源):這是指通過無線遙測或USB端口向APM發送消息的發送源(也就是MP),軟件會定期進行檢查,以確認消息是發送給它的。
-
Component ID (亦稱系統中的子系統):主系統中的任何子系統。目前,這里並沒有子系統,我們也沒有真正利用這個字段。
-
Message ID:標識這是條關於什么的信息。在本教程中,我們將其稱為“主消息(main message)”。
-
Payload(實際數據):這就是肉!這就是你想要的!!
MavLink到底是如何工作的
“消息”是一個包含“常量字節數”(如前所述,即17字節)的數據包。APM(從空中)獲取流字節,將其傳輸到硬件接口(例如,通過UART或遙測),並在軟件中對消息進行解碼。注意,消息包含着我們即將提取的有效負載(payload)。
我們對有效負載很感興趣,但是,嘿,和有效負載在一起的是Message ID(見上面),我們可以通過它了解有效負載代表着什么。在這之前,先看看程序解釋一切MavLink消息的幾個步驟:
-
我們有一個名為handlemessage (msg)的方法。這個就是你需要學習和了解的方法!在GCS_MavLink.pde中找到它(在Arducopter/ ArduPlane里)。
PS. 該方法隸屬APM固件的源代碼。GCS_MavLink.pde現在似乎是這個https://github.com/ArduPilot/ardupilot/blob/8f550ffdd48a3165c115ca24d6ce5227a5f826d1/ArduCopter/GCS_Mavlink.cpp
它基本上是在問信息包:嘿,你是誰?你是為我而來還是試圖侵入我的系統?在我給予你許可之前,讓我先讀一下你的系統ID和組件ID。任何使用MavLink的系統都有一個系統ID和組件ID。例如,你的MP和正在飛行的四軸飛行器將具有相同的系統ID。組件ID則用於附加到APM/PX4的“子系統”。
注意:當前,系統ID和組件ID被硬編碼為相同的。
現在,你僅有一個遙測和一架安裝了APM的直升機,就是這樣,去愉快地飛行吧-不用再考慮其它的!這些東西對多直升機有幫助(在未來),未來將會有不同的系統ID🙂
-
我們從消息中提取有效負載並放入一個包(packet)中。包是基於一種“信息類型”的數據結構。我們將不再使用“消息”一詞,那玩意兒到這里就結束了。我們基本上只對由“原始數據”打包而成的包感興趣。
-
包被放入一個“適當的數據結構”中。有許多數據結構 ,例如用來存放姿態(俯仰,橫搖,偏航方向)的、GPS的、無線電控制信道的,等等,也就是,把相似的東西組合在一起,形成易於理解的模塊。這些數據結構在發送端和接收端(即在MP端和APM端)“100%完全相同”。 如果不一樣的話,你的直升機就會在奇怪的時間墜毀!
PS. 無線電控制信道原文中為RC channel
此外,這也是MavLink GUI生成器大展身手的地方。為了生成這些數據結構,我們不需要編寫任何代碼!!嗯,也不完全是,但只有一點點。
到目前為止很簡單對不對?如果覺得困難請重讀一遍!!當個笨蛋沒關系的🙂
好了,現在說正事。我們使用MavLink發送雙向消息。
從地面控制站(GCS)到APM/PX4或從APM/PX4到地面控制站(GCS)。注意,我說的GCS是指Mission Planner(MP)或者QGroundControl(QGC)、DroidPlanner(DP)或者你自定義的與直升機通信的工具。
地面控制站(GCS)到四軸飛行器:
截至2013年11月,在Arducopter最新的3.0.1 RC5(候選版本)中,以下是你可能看到的參數。我已經試着列出所有可能的MavLink消息的“主消息”ID。
請注意,在每個“主消息”類別中(如粗體部分下面的東西)你會找到屬於那個類別的“子消息”,它們基本上與有效負載信息(真正的肉)及其處理方式密切相關。就像“自行車”類別有雅馬哈,鈴木,哈雷戴維森等。我列出了所有的主要信息類別,但只指定了一些子類別。你可以自己查一下細節🙂因為如果你明白我到目前為止的意思,你就不再是個傻瓜了。明白我的意思嗎?
PS. 因為下面的部分,准確含義並不太清楚,所以只選了若干個翻譯。欲看每個條目的詳情可查看原文:https://diydrones.com/forum/topics/mavlink-tutorial-for-absolute-dummies-part-i?groupUrl=arducopterusergroup
-
MAVLINK_MSG_ID_HEARTBEAT://0
這是最重要的信息。GCS不斷地向APM/PX4發送信息,以確定它是否與之相連(每1秒一次)。這是為了確保在更新某些參數時MP與APM是同步的。如果錯過了許多心跳信號,則會觸發故障保護(可能),接着直升機可能着陸、繼續執行任務或返回發射(Returns to launch,也稱為RTL)。在MP的“配置/設置故障保護選項”下,可以啟用/禁用故障保護選項。但你不能停止心跳,對嗎?這個名字很有道理!!
-
MAVLINK_MSG_ID_REQUEST_DATA_STREAM://66
請求傳感器,無線電控制信道,GPS位置,狀態,Extra 1/2/3 等數據
-
MAVLINK_MSG_ID_COMMAND_LONG://76
無限制懸停(Loiter unlimited),RTL,着陸,任務開始(Mission start),飛控解鎖/鎖定(Arm/Disarm ),重新啟動(Reboot)。
PS. 例如在航前檢查未通過時是禁止直接用commander arm對飛控解鎖的。
-
SET_MODE: //11
E.g. set_mode(packet.custom_mode);
-
MAVLINK_MSG_ID_MISSION_REQUEST_LIST: //43
-
MAVLINK_MSG_ID_MISSION_REQUEST: //40
-
MAVLINK_MSG_ID_MISSION_ACK: //47
-
MAVLINK_MSG_ID_PARAM_REQUEST_LIST: //21
-
MAVLINK_MSG_ID_PARAM_REQUEST_READ: //20
-
MAVLINK_MSG_ID_MISSION_CLEAR_ALL: //45
-
MAVLINK_MSG_ID_MISSION_SET_CURRENT: //41
-
MAVLINK_MSG_ID_MISSION_COUNT: // 44
-
MAVLINK_MSG_ID_MISSION_WRITE_PARTIAL_LIST: //
-
MAVLINK_MSG_ID_SET_MAG_OFFSETS: //151
-
MAVLINK_MSG_ID_MISSION_ITEM: //39
-
-
MAVLINK_MSG_ID_RC_CHANNELS_OVERRIDE: //70
-
MAVLINK_MSG_ID_HIL_STATE: //90
-
MAVLINK_MSG_ID_DIGICAM_CONFIGURE: //
-
MAVLINK_MSG_ID_MOUNT_CONFIGURE: //
-
MAVLINK_MSG_ID_MOUNT_CONTROL: //
-
MAVLINK_MSG_ID_MOUNT_STATUS://
-
MAVLINK_MSG_ID_RADIO, MAVLINK_MSG_ID_RADIO_STATUS: //
四軸飛行器到地面控制站(GCS)到四軸飛行器:
如果你打開了Arducopter.pde文件,請查看代碼的這一部分:
PS. Arducopter.pde現在似乎是這個https://github.com/ArduPilot/ardupilot/blob/master/ArduCopter/Copter.cpp
static const AP_Scheduler::Task scheduler_tasks[] PROGMEM = { . . . . . . { gcs_send_heartbeat, 100, 150 }, { update_notify, 2, 100 }, { one_hz_loop, 100, 420 }, { gcs_check_input, 2, 550 }, { gcs_send_heartbeat, 100, 150 }, { gcs_send_deferred, 2, 720 }, { gcs_data_stream_send, 2, 950 }, . . . . . . . . .
第一個參數是函數名,
第二個是“它應該花費的時間”(以10毫秒為單位,例如2表示20毫秒執行一次,即50赫茲,即該功能每秒運行50次)。
PS. 1s = 1000ms 故 1000 / 20 = 50 ms/次 = 50Hz
第三個參數是“最長執行時間,超出該時間函數就不應繼續運行”。
我覺得這很簡單!你在這里看到的每一個函數,它的未來都是確定的,運行時間都是一成不變的。這就是為什么我們在這些討厭的機器上采用實時系統,這可以保證它的安全,讓其變得可預測而不是不可預測!!
所有這些函數都是為你精心挑選的,以便讓你知道它們與GCS系統的更新相關。簡單地說,進入每一個函數的定義,這些函數將始終可以在GCS_Mavlink.pde中找到,在那里GCS系統通信的實際操作發生了!!
最有趣(也是最重要)的是:
/* * send data streams in the given rate range on both links */ static void gcs_data_stream_send(void) { gcs0.data_stream_send(); if (gcs3.initialised) { gcs3.data_stream_send(); } }
例如,當你用手移動你的直升機時,瞧瞧MP的HUD屏幕發生了什么?你將看到直升機在屏幕上移動。並且,我們得到了每個時間單位的飛行姿態數據(俯仰、橫搖和偏航)。同樣,我們還可以看到IMU數據、GPS數據、電池數據等。