教你從無到有開始自己 build ArduPilot 飛控程式碼！(MacOS)
上一篇我們在筆電上安裝了 Git 等工具，這期我們來實際設定 build ArduPilot 所需要的環境啦～本篇的教學其實在 ArduPilot 官方網站都有，但有鑒於不是每一個想要研究無人機的人都是軟體背景出身，所以才有這系列文章，希望可以讓不同背景的人更容易入門囉！

首先呢，根據上一期的教學，讓我們 cd 到 ArduPilot 的 repository，如果你聽不懂我在說什麼，可以回顧一下 [Part I]

好的，那麼打開你的 Terminal (MacOS) 或 Powershell (Windows)，然後輸入以下指令

cd ~/Studio/repos/ardupilot

當然如果你把 ardupilot repositoy 放在其他地方的話，就 cd 到該位置就對啦～

環境設置

根據你所使用的作業系統不同，會有不一樣的東西需要設置。 Mac 的電腦上預設都會安裝好 Xcode，這是一個讓工程師可以開發 Apple 相關系列產品 app 的 IDE (編輯器)。除此之外，Xcode 也讓使用者可以在電腦上安裝一些套件。所以，第一步你需要做的呢，是在 Terminal 輸入以下指令

xcode-select --install

接著呢，上一期我們教大家在自己筆電上裝好了 Homebrew 這個套件管理工具，現在我們就需要使用它安裝各種 ArduPilot 會需要的各種套件，方法如下

brew tap ardupilot/homebrew-px4

brew update

brew install genromfs

brew install gcc-arm-none-eabi

brew install gawk

接著我們還需要一些 Python 相關的套件。Mac 預設是有內建 Python3 的，所以我們可以透過以下指令安裝需要的套件

sudo easy_install pip

sudo pip install pyserial future empy

這樣你就設定好基本需要的環境啦！～

2. 開始建置

ArduPilot 使用 waf 這個工具進行編譯，而 repository 裡面就附帶有 waf script，因此可以直接拿來用。第一步呢，你需要根據你所使用的飛控硬體選擇相對應的 board 配置。如果你使用的是 Pixhawk 1，那可以用下列指令進行配置

./waf configure --board Pixhawk1

啊如果你用的是 Pixhawk 2，Pixhack 或其他 ChibiOS 的板子，那用以下指令

./waf configure --board fmuv3

run 下去後會跑出一大堆訊息，基本上是在確認你的電腦上是不是具備編譯時所需的工具。通常大家看到一大串的 console output 都會有點慌張，不怕不怕，我把我的執行結果放在這裡，大家可以參考一下是不是長得差不多

Setting top to : /path/to/ardupilot

Setting out to : /path/to/ardupilot/build

Autoconfiguration : enabled

Setting board to : fmuv3

Using toolchain : arm-none-eabi

Checking for 'g++' (C++ compiler) : /usr/local/bin/arm-none-eabi-g++

Checking for 'gcc' (C compiler) : /usr/local/bin/arm-none-eabi-gcc

Checking for c flags '-MMD' : yes

Checking for cxx flags '-MMD' : yes

CXX Compiler : g++ 9.3.1

Checking for program 'make' : /usr/bin/make

Checking for program 'arm-none-eabi-objcopy' : /usr/local/bin/arm-none-eabi-objcopy

Setup for MCU STM32F427xx

Writing hwdef setup in /path/to/ardupilot/build/fmuv3/hwdef.h

Writing DMA map

Generating ldscript.ld

No default parameter file found

Checking for env.py

env set HAL_NUM_CAN_IFACES=2

env set BOARD_FLASH_SIZE=2048

env set APJ_BOARD_TYPE=STM32F427xx

env set PERIPH_FW=0

env set USBID=0x1209/0x5741

env set MAIN_STACK=0x400

env set APJ_BOARD_ID=9

env set CORTEX=cortex-m4

env set FLASH_TOTAL=2080768

env set FLASH_RESERVE_START_KB=16

env set CHIBIOS_BUILD_FLAGS=USE_FATFS=yes MCU=cortex-m4 ENV_UDEFS=-DCHPRINTF_USE_FLOAT=1 CHIBIOS_PLATFORM_MK=os/hal/ports/STM32/STM32F4xx/platform.mk CHIBIOS_STARTUP_MK=os/common/startup/ARMCMx/compilers/GCC/mk/startup_stm32f4xx.mk

env set CPU_FLAGS=['-mcpu=cortex-m4', '-mfpu=fpv4-sp-d16', '-mfloat-abi=hard', '-DARM_MATH_CM4', '-u_printf_float']

env set IOMCU_FW=0

env set PROCESS_STACK=0x2000

Enabling ChibiOS asserts : no

Enabling -Werror : yes

Checking for intelhex module: : disabled

Checking for HAVE_CMATH_ISFINITE : yes

Checking for HAVE_CMATH_ISINF : yes

Checking for HAVE_CMATH_ISNAN : yes

Checking for NEED_CMATH_ISFINITE_STD_NAMESPACE : yes

Checking for NEED_CMATH_ISINF_STD_NAMESPACE : yes

Checking for NEED_CMATH_ISNAN_STD_NAMESPACE : yes

Checking for header endian.h : not found

Checking for header byteswap.h : not found

Checking for HAVE_MEMRCHR : no

Checking for program 'python' : /usr/local/opt/python@2/bin/python2.7

Checking for python version >= 2.7.0 : 2.7.17

Checking for program 'python' : /usr/local/opt/python@2/bin/python2.7

Checking for python version >= 2.7.0 : 2.7.17

Source is git repository : yes

Update submodules : yes

Checking for program 'git' : /usr/local/bin/git

Gtest : STM32 boards currently don't support compiling gtest

Checking for program 'arm-none-eabi-size' : /usr/local/bin/arm-none-eabi-size

Benchmarks : disabled

Unit tests : disabled

Scripting : enabled

Scripting runtime checks : enabled

Checking for program 'rsync' : /usr/bin/rsync

'configure' finished successfully (1.861s)

基本上只要看到最後寫 ‘configure’ finished successfully 就代表沒問題惹。

接著呢，使用以下指令，就會開始進行飛控程式碼的編譯。這裡說明一下，ArduPilot 支援的載具種類很多，有多旋翼、直升機、地面車、潛艇等等。這個範例會以多旋翼為主。

./waf copter

這個可能會跑一點時間，我用的是 16 吋 Macbook Pro，處理器 2.3 GHz 8 核 Intel core i9，記憶體 16 G，大概會花 3~5 分鐘 build，如果電腦效能不高可能就會比較久一點。跑起來的結果大概長下面這樣，中間很長的部分我刪掉了一些。

❯ ./waf copter

Waf: Entering directory `/path/to/ardupilot/build/fmuv3'

Checking for env.py

env added HAL_NUM_CAN_IFACES=2

env added BOARD_FLASH_SIZE=2048

env added APJ_BOARD_TYPE=STM32F427xx

env added PERIPH_FW=0

env added USBID=0x1209/0x5741

env added MAIN_STACK=0x400

env added APJ_BOARD_ID=9

env added CORTEX=cortex-m4

env added FLASH_TOTAL=2080768

env added FLASH_RESERVE_START_KB=16

env added CHIBIOS_BUILD_FLAGS=USE_FATFS=yes MCU=cortex-m4 ENV_UDEFS=-DCHPRINTF_USE_FLOAT=1 CHIBIOS_PLATFORM_MK=os/hal/ports/STM32/STM32F4xx/platform.mk CHIBIOS_STARTUP_MK=os/common/startup/ARMCMx/compilers/GCC/mk/startup_stm32f4xx.mk

env appended CPU_FLAGS=['-mcpu=cortex-m4', '-mfpu=fpv4-sp-d16', '-mfloat-abi=hard', '-DARM_MATH_CM4', '-u_printf_float']

env added IOMCU_FW=0

env added PROCESS_STACK=0x2000

Embedding file bootloader.bin:/path/to/ardupilot/Tools/bootloaders/fmuv3_bl.bin

Embedding file hwdef.dat:/path/to/ardupilot/build/fmuv3/hw.dat

Embedding file io_firmware.bin:Tools/IO_Firmware/iofirmware_lowpolh.bin

[ 3/10] Creating build/fmuv3/hwdef.h

[ 4/10] Creating build/fmuv3/modules/ChibiOS/include_dirs

[ 5/10] Compiling libraries/AP_Scripting/generator/src/main.c

[ 6/10] Processing modules/mavlink/message_definitions/v1.0/ardupilotmega.xml

Setup for MCU STM32F427xx

Writing hwdef setup in /path/to/ardupilot/build/fmuv3/hwdef.h

Writing DMA map

Generating ldscript.ld

No default parameter file found [ 7/10] Processing uavcangen: libraries/AP_UAVCAN/dsdl/ardupilot libraries/AP_UAVCAN/dsdl/com modules/uavcan/dsdl/uavcan

[ 8/10] Creating build/fmuv3/ap_version.h

Validation skipped for /path/to/ardupilot/modules/mavlink/message_definitions/v1.0/ardupilotmega.xml.

Parsing /path/to/ardupilot/modules/mavlink/message_definitions/v1.0/ardupilotmega.xml

Validation skipped for /path/to/ardupilot/modules/mavlink/message_definitions/v1.0/common.xml.

Parsing /path/to/ardupilot/modules/mavlink/message_definitions/v1.0/common.xml

Validation skipped for /path/to/ardupilot/modules/mavlink/message_definitions/v1.0/uAvionix.xml.

Parsing /path/to/ardupilot/modules/mavlink/message_definitions/v1.0/uAvionix.xml

Validation skipped for /path/to/ardupilot/modules/mavlink/message_definitions/v1.0/icarous.xml.

Parsing /path/to/ardupilot/modules/mavlink/message_definitions/v1.0/icarous.xml

Merged enum MAV_CMD

Found 231 MAVLink message types in 4 XML files

Generating C implementation in directory /path/to/ardupilot/build/fmuv3/libraries/GCS_MAVLink/include/mavlink/v2.0/ardupilotmega

Generating C implementation in directory /path/to/ardupilot/build/fmuv3/libraries/GCS_MAVLink/include/mavlink/v2.0/common

Generating C implementation in directory /path/to/ardupilot/build/fmuv3/libraries/GCS_MAVLink/include/mavlink/v2.0/uAvionix

Generating C implementation in directory /path/to/ardupilot/build/fmuv3/libraries/GCS_MAVLink/include/mavlink/v2.0/icarous

Copying fixed headers for protocol 2.0 to /path/to/ardupilot/build/fmuv3/libraries/GCS_MAVLink/include/mavlink/v2.0

[ 9/10] Linking build/fmuv3/modules/ChibiOS/libch.a

[10/10] Processing /path/to/ardupilot/build/fmuv3/libraries/AP_Scripting/lua_generated_bindings.cpp,/path/to/ardupilot/build/fmuv3/libraries/AP_Scripting/lua_generated_bindings.h: libraries/AP_Scripting/generator/description/bindings.desc build/fmuv3/gen-bindings -> build/fmuv3/libraries/AP_Scripting/lua_generated_bindings.cpp build/fmuv3/libraries/AP_Scripting/lua_generated_bindings.h

[1/103] ChibiOS: Compiling crt0_v7m.S

[2/103] ChibiOS: Compiling vectors.S ...... 中間省略約七百行...... [713/714] Generating bin/arducopter.bin

[714/714] apj_gen build/fmuv3/bin/arducopter.bin

Waf: Leaving directory `/path/to/ardupilot/build/fmuv3' BUILD SUMMARY

Build directory: /path/to/ardupilot/build/fmuv3

Target Text Data BSS Total

----------------------------------------------

bin/arducopter 1344892 1468 195348 1541708 Build commands will be stored in build/fmuv3/compile_commands.json

'copter' finished successfully (1m41.012s)



很長對吧～這裡做的事情除了檢查參數以外，主要的事情就是把所有的程式碼編譯一次，並進行連結，最後產出能夠上傳到飛控的 bin 檔，位置是在

build/fmuv3/bin/arducopter.bin

中間的 fmuv3 會根據前面你所用的 board 不同而有所不同。

3. 上傳飛控韌體

好啦！到此我們已經從原始碼自己建置了一版飛控韌體！那要怎麼上傳到硬體上呢？已經有在玩無人機的朋友應該會知道地面站這個東西，Windows 上常見的是 Mission Planner，而 Mac 則是使用 QGroundControl。所謂地面站就是可以讓使用者進行任務規劃、參數調整，並即時監看無人機飛行狀態資訊的軟體。QGroundControl 可以到這裡下載

打開後呢，大概會長這樣：

不過我的版本是 daily build (就是你在那個網站載不到的最新版本，我就潮✌🏼✌🏼)，可能會跟你看到的長得不太一樣。在 QGC 的官網其實有教大家怎麼上傳韌體，但是如果你要上傳自己 build 的韌體的話，步驟不太一樣。首先，你需要進入到 upload firmware 的頁面，長這樣

然後把你的飛控板用 micro USB 線接到你的筆電上。注意噢！一定要讓 QGC 先進入這個頁面，再連接飛控。

好的，然後 QGC 的頁面就會變這樣

有幾個要注意的地方，首先一定要選 ArduPilot，作業系統要選 ChibiOS，載具型態要選 Multi-Rotor，然後你要打開 Advanced Settings 的勾勾，他才會讓你選擇自己的韌體版本。最下面的那個下拉選單選到 Choose Firmware File，然後按下左上角的 Ok。

接著他會要你選擇檔案路徑，那當然就是要選我們剛剛親手 build 過的 bin 檔啦～位置會在 ardupilot/build/fmuv3/bin/arducopter.bin 。按下打開後，給他一點點時間，看到以下畫面就代表上傳成功囉！

恭喜你！～現在你的飛控上跑的就是自己親手從原始碼編譯過後的飛控韌體囉！至於為何要這麼大費周章自己 build 呢？我的經驗是很多時候其實很難理解飛控的行為，例如說明明叫他 Return to Launch，他怎麼他媽給我往上飛了咧？！原來是飛控預設 RTL 會先往上飛到一個“安全”高度再返航。這對室外飛行來說通常是個好的設定，但我在室內做群飛，他往上飛就直接撞天花板了啊@@搞得我看得一臉矇。當然這些設置努力找的話還是會看到文件說明，但是身為一個攻城獅，我就是很鐵齒的想要改改 code 親眼看看飛控到底在衝三小ＸＤ 下一期我會教一些最簡單的方法，讓不太懂程式的大家也可以額外得知更多飛控的狀態，敬請期待囉！

Fienna loves you ❤
['Jay Liang']
['Uav Technology', 'Ardupilot', 'Drones', 'Autopilot', 'Uav']