一、開篇
? ? ? ? 首先告訴大家一個壞消息,DJI提供了SDK~~~~
? ? ? ? 然后再來一個好消息,本篇博文很多干貨哦~~~~~
? ? ? ? 最近比較糾結的一個問題ardupilot和pixhawk原生代碼到底有什么區別和聯系。經過和群友的討論,最終方向一致認為單獨的pixhawk原生代碼是可以正常飛行的(群友Mr一直在用這套試飛的),其上電以后在rcS(nsh的啟動腳本,其存儲在ROMFS中,后面會詳細介紹)中開啟相應的進程對無人機進行姿態等復雜的控制,關于這個大家最先認識到的應該是各種飛行模式的確定,關于flight_mode后續再結合ardupilot介紹;ardupilot這套源代碼前一篇博文已經分析過了,而且前一篇博文里面涉及的網站鏈接都是關于這個ardupilot的,很多人稱之為APM,但是這個APM的HAL層也可以使用pixhawk硬件,此APM非彼apm,官網有介紹。Ardupilot是基于pixhawk原生代碼開發的上層應用,即有了常見的mian和loop函數,正如前一篇博文中給出的一幅圖,ardupilot把底層的PX4Firmware和NuttX等都抽象為HAL,developer只需要關心上層應用即可,基于pixhawk原生設計上層控制邏輯。這個非常類似于CC26xx的stack和application部分,而TI關于這個做的更好。ardupilot其實是開源的、玩具級飛控,它為了兼容各種亂七八糟的板子、機型,有很多冗余的代碼,這些冗余的代碼讓我們理解飛控本身增加了難度和學習成本。如果我們需要一款專業的飛控,完全可以去掉這些冗余的代碼,只保留我們需要的精簡過的功能,這樣也就能大大降低它代碼的復雜程度。從程序設計的方法論來看(面向對象):就是要把一個個對象確立好,把問題的復雜程度控制住,才能設計出邏輯清晰的程序出來。但是我的博文寫的沒什么邏輯,水平有限,大家湊合看吧。
? ? ? ? 也就是說,假如你打算開一家無人機公司,不需要從最底層一行一行的代碼寫起,可以直接把這套開源的pixhawk原生代碼搞透徹(這套可以不是一己之力可以完成的,這個開源項目N人N年了),然后基于它進行上層開發,加入自己NB的算法,聽說進DJI的第一年就是給你一個pixhawk,玩一年。非常懷疑DJI現在是不是也是基于pixhawk(雖然DJI成立2006,ETH Zurich? pixhawk項目成立2009年),有待考證或者有在DJI工作的給大家普及一下唄。
? ? ? ? 好吧,用哪套源碼分析都行,我用的ardupilot,最后還是需要到底層的PX4Firmware。感謝群友彩虹小羊、灰灰、Mr等提供的幫助(排名按字母順序,哈哈)。
二、版權聲明
博主:summer
聲明:喝水不忘挖井人,轉載請注明出處。
原文地址:http://blog.csdn.net/qq_21842557
聯系方式:dxl0725@126.com
技術交流QQ:1073811738
三、實驗平臺
Software?Version:ArduCopter(Ver_3.3)
Hardware Version:pixhawk
IDE:eclipse Juno (Windows)
四、基本知識介紹
1、關于坐標系
1)GeographicCoordinate System
? ? ? ? Represents position on earth with alongitude and latitude value (Geographic_coordinate_system). Additionally thealtitude may may be included. The altitude can be expressed as distance fromthe earth center or as altitude above the mean sea level. All in all, thisgives a spherical coordinate system.?
2)Earth-Fixed frame
? ? ? ? Cartesian coordinate system at the center of the earth. Thepositive z axis goes through the north pole. The x and y axes are on theequatorial plane.
3)Body Fixed Frame
? ? ? ? The x axis points in forward (defined bygeometry and not by movement) direction. (= roll axis)
? ? ? ? The y axis points to the right(geometrically) (= pitch axis)
? ? ? ? The z axis points downwards (geometrically)(= yaw axis)
4)EulerAngles
? ? ? ? Usually a conversion between a earth fixed“ground” frame and the body fixed “in-air” frame is described via Euler-Angles.There are multiple conventions of the Euler angles.
? ? ? ? The rotation order for the Tait-Bryan angles is? Z? Y’X”?(see thefigure): rotation?of??around?Z?(yaw) rotation?of??around?Y'?(pitch) rotation?of??around?X”?(roll)?
2、pixhawk的HAL
3、pixhawk的控制圖
五、正文
1、關于兩個控制器和任務優先級
? ? ? ? 在PX4Firmware/src/modules中的mc_att_control:姿態控制器和mc_pos_control位置控制器(mc:multicopter),整個系統都是圍繞著這兩個控制器。
? ? ? ? mc_att_control – Multirotor attitude controller
? ? ? ? mc_pos_control – Multirotor position controller
? ? ? ? The PX4 firmware is organized in priority bands:
1) (interrupt level) fast sensordrivers
2) watchdog/system state monitors
3) actuator outputs (PWM outputdriver thread, IO comms sender thread)
4)? attitude controller(s)
5) slow/blocking sensor drivers(must not block attitude controllers)
6)? destination/positioncontroller(s)
7) default priority - generic usercode, shell commands, random crap, all RR scheduled
8) logger, parameter syncer
9) idle
2、
? 關于.mk文件(
必須深入理解
)
? ? ? ? 了解整個代碼運行過程的最簡便方法就是通過其makefile了解文件的包含關系和調用關系。請仔細閱讀arducopter中的.mk和modules/PX4Firmware中的.mk文件。.mk文件就是在Linux下編寫的一些腳本文件(makefile),類似于編譯過程中的條件編譯,便于直接使用命令行進行編譯鏈接。
? ? ? ? 1)首先介紹上層應用的.mk。在ardupilot/mk/PX4/Tool中px4_common.mk文件中是關于所有PX4平臺的通用編譯文件,config_px4fmu_v2_APM.mk中針對pixhawk的特有硬件的編譯文件。下面實例代碼是config_px4fmu_v2_APM.mk中的代碼,.mk腳本主要目的是為了選擇需要編譯的
MODULES
。
[plain] ?view plain
?copy ? #?Makefile?for?the?px4fmu-v2_APM?configuration?? include?$(SKETCHBOOK)/mk/PX4/px4_common.mk?? MODULES?+=?drivers/lsm303d?? MODULES?+=?drivers/l3gd20?? MODULES?+=?drivers/mpu9250?? MODULES?+=?drivers/boards/px4fmu-v2?? MODULES?+=?drivers/pwm_input?? MODULES?+=?modules/uavcan?? MODULES?+=?lib/mathlib?? MODULES?+=?drivers/px4io?? MODULES?+=?drivers/px4flow?? MODULES?+=?drivers/oreoled???
? ? ? ? Makefile的文件夾,指定編譯的規則,編譯順序:
ardupilot/ArduCopter/Makefile àmk/apm.mkà environ.mk, targets.mk, sketch_sources.mk, board_px4.mkà find_tools.mk,?px4_targets.mk 。
? ? ? ? 尤其是上面的這個px4_targets.mk文件,該文件中涉及了所有的需要編譯的文件,最后使用命令行px4-v2編譯整個工程,它是最終的編譯過程的執行者,注意其中px4-v2規則的詳細執行情況,它會去調用 PX4Firmware 的 makefile 。下面針對pixhawk硬件平臺摘錄比較重要一部分。
[plain] ?view plain
?copy ? ………?? /*指定PX4Firmware、PX4NuttX、uavcan?*/?? #?these?can?be?overridden?in?developer.mk?? PX4FIRMWARE_DIRECTORY??=?$(SKETCHBOOK)/modules/PX4Firmware?? PX4NUTTX_DIRECTORY??=?$(SKETCHBOOK)/modules/PX4NuttX?? UAVCAN_DIRECTORY??=?$(SKETCHBOOK)/modules/uavcan?? PX4_ROOT?:=?$(shell?cd?$(PX4FIRMWARE_DIRECTORY)?&&?pwd)?? NUTTX_ROOT?:=?$(shell?cd?$(PX4NUTTX_DIRECTORY)?&&?pwd)?? NUTTX_SRC?:=?$(NUTTX_ROOT)/nuttx/?? UAVCAN_DIR=$(shell?cd?$(UAVCAN_DIRECTORY)?&&?pwd)/?? ………?? /*選擇硬件平臺*/?? #?we?have?different?config?files?for?V1?and?V2?? PX4_V1_CONFIG_FILE=$(MK_DIR)/PX4/config_px4fmu-v1_APM.mk?? PX4_V2_CONFIG_FILE=$(MK_DIR)/PX4/config_px4fmu-v2_APM.mk?? PX4_V4_CONFIG_FILE=$(MK_DIR)/PX4/config_px4fmu-v4_APM.mk?? ………?? /*針對pixhawk,請詳細了解該部分的實現*/?? px4-v2:?$(BUILDROOT)/make.flags?CHECK_MODULES?$(MAVLINK_HEADERS)?$(PX4_ROOT)/Archives/px4fmu-v2.export?$(SKETCHCPP)?module_mk?px4-io-v2?? ????$(RULEHDR)/*?PX4_ROOT??=?ardupilot/modules/PX4Firmware*/?? ????$(v)?rm?-f?$(PX4_ROOT)/makefiles/$(PX4_V2_CONFIG_FILE)?? ????$(v)?cp?$(PX4_V2_CONFIG_FILE)?$(PX4_ROOT)/makefiles/nuttx/?? ????$(PX4_MAKE)?px4fmu-v2_APM?? ????$(v)?/bin/rm?-f?$(SKETCH)-v2.px4?? ????$(v)?arm-none-eabi-size?$(PX4_ROOT)/Build/px4fmu-v2_APM.build/firmware.elf?? ????$(v)?cp?$(PX4_ROOT)/Images/px4fmu-v2_APM.px4?$(SKETCH)-v2.px4?? ????$(v)?$(SKETCHBOOK)/Tools/scripts/add_git_hashes.py?$(HASHADDER_FLAGS)?"$(SKETCH)-v2.px4"?"$(SKETCH)-v2.px4"?? ????$(v)?echo?"PX4?$(SKETCH)?Firmware?is?in?$(SKETCH)-v2.px4"?? /*最后編譯生成的*.px4文件,直接下載到飛控板中即可實現飛行控制*/?? ………?? px4-clean:?clean?CHECK_MODULES?px4-archives-clean?px4-cleandep?? ????$(v)?/bin/rm?-rf?$(PX4_ROOT)/makefiles/build?$(PX4_ROOT)/Build?$(PX4_ROOT)/Images/*.px4?$(PX4_ROOT)/Images/*.bin?? ????$(v)?/bin/rm?-rf?$(PX4_ROOT)/src/modules/uORB/topics?$(PX4_ROOT)/src/platforms/nuttx/px4_messages?? px4-cleandep:?clean?? ????$(v)?find?$(PX4_ROOT)/Build?-type?f?-name?'*.d'?|?xargs?rm?-f?? ????$(v)?find?$(UAVCAN_DIRECTORY)?-type?f?-name?'*.d'?|?xargs?rm?-f?? ????$(v)?find?$(SKETCHBOOK)/$(SKETCH)?-type?f?-name?'*.d'?|?xargs?rm?-f?? px4-v2-upload-solo:?px4-v2?? ????scp?$(SKETCH)-v2.px4?root@10.1.1.10:/tmp/?? ????ssh?root@10.1.1.10?PYTHONUNBUFFERED=1?loadPixhawk.py?/tmp/ArduCopter-v2.px4?? ????ssh?root@10.1.1.10?rm?/tmp/ArduCopter-v2.px4;?? ………?? px4-v2-upload:?px4-v2?? ????$(RULEHDR)?? ????$(v)?$(PX4_MAKE)?px4fmu-v2_APM?upload?? px4-upload:?px4-v1-upload?? px4-archives-clean:?? ????$(v)?/bin/rm?-rf?$(PX4_ROOT)/Archives??
? ? ? ? 2)接下來就是PX4Firmware中的.mk。如果仔細了解了上面所講述的,那么這部分就很easy了,不再細講,自己去看代碼吧。需要說明的是在PX4Firmware的makefile文件中有一個README.txt文本,該文本詳細的介紹了PX4Firmware中的.mk的調用關系和作用。補充一點,PX4Firmware/makefile/nuttx中的config_px4fmu-v2_default.mk包含了所有基本的模塊,從這里再一次驗證了開篇講述的ardupilot的代碼是基于pixhawk原生代碼PX4Firmware“閹割”而來的。所以在后期做開發的過程中編寫應用程序只是按照ardupilot現有的子模塊添加自己的就可以,參考mc_att_control實現。
? ? ? ? 在PX4Firmware/src/modules中添加一個新的文件夾,命名為summer
? ? ? ? 在summer文件夾中創建module.mk文件,并輸入以下內容:
[plain] ?view plain
?copy ? MODULE_COMMAND?=?summer?? SRCS?=?summer.cpp??
? ? ? ? 在summer文件夾中創建summer.c文件,編譯需要實現的功能代碼。
? ? ? ? 注冊新添加的應用到NuttShell中:PX4Firmware/makefiles/nuttx/config_px4fmu-v2_default.mk文件中添加如下內容:
[plain] ?view plain
?copy ? MODULES?+=?modules/summer??
? ? ? ??任務的啟動就是靠NuttShell的內建命令啟動的,包含rcS,特別是rcS一定要了解,下面會詳細介紹。
3、關于編譯鏈接庫(上層應用庫?
libraries
)
? ? ? ? 在ardupilot/Arducopter中有一個make.inc文件,指定了編譯ArduCopter時需要編譯哪些依賴庫,它對系統及硬件進行了抽象,以獲取更好的可移植性。
? ? ? ??http://dev.ardupilot.com/wiki/apmcopter-programming-libraries/
? ? ? ? 如果想添加或者刪除編譯的文件,就在此處進行修改。如下是官方默認的。
[plain] ?view plain
?copy ? LIBRARIES?+=?AP_Common?? LIBRARIES?+=?AP_Menu?? LIBRARIES?+=?AP_Param?? LIBRARIES?+=?StorageManager?? LIBRARIES?+=?GCS?? LIBRARIES?+=?GCS_MAVLink?? LIBRARIES?+=?AP_SerialManager?? LIBRARIES?+=?AP_GPS?? LIBRARIES?+=?DataFlash?? LIBRARIES?+=?AP_ADC?? LIBRARIES?+=?AP_Baro?? LIBRARIES?+=?AP_Compass?? LIBRARIES?+=?AP_Math?? LIBRARIES?+=?AP_InertialSensor?? LIBRARIES?+=?AP_AccelCal?? LIBRARIES?+=?AP_AHRS?? LIBRARIES?+=?AP_NavEKF?? ………??
4、啟動腳本(rcS:有兩個,比較重要,任務分工)
? ? ? ? 所謂啟動腳本其實是用shellscript寫的啟動文件以前寫過比較簡單的腳本文件,還是參考的鳥哥的那本書,還有就是Linux啟動文件也是用的這個寫的,有興趣的可以去Linux平臺下查看一下,會寫C的學這個很快,該死的C++什么時候能學會啊。
? ? ? ? 1)其中之一就是負責較為底層driver里面的(比如mpu9250的register map、驅動),在使用命令px4-v2-upload以后,會在modules/PX4Firmware目錄下生成build文件夾,內部是編譯生成的文件(不編譯沒有),在modules/PX4Firmware/build/px4fmu-v2_APM.build/romfs_scratch/init.d文件下就是rcS和rc.APM,這個rcS是自啟動腳本(setMODE autostart)。rcS腳本會掛載SD卡(這就是沒有 SD 飛控板不能使用的原因所在 ),然后跳轉rc.APM中,該腳本會在pixhawk系統中創建binfs,判斷硬件類型,然后啟動orb(對,就是那個uORB),然后啟動各種傳感器,然后咔咔咔,咔咔咔,完了,自己去看腳本吧。摘一部分鑒賞,關于shell腳本的編寫自己百度吧,跟C語言的風格很像。
? ? ? ? 其中類似于mpu9250 start就啟動了mpu9250模塊的驅動,理解該部分需要結合modules/PX4Firmware/src/drivers/mpu9250中的CMakeLists.txt和module.mk這兩個,其中CMakeLists.txt是使用Cmake寫的,和module.mk類似,在最新的pixhawk原生代碼中刪除了make,使用清一色的Cmake。
? ? ? ? 上面標紅的MODULE_COMMAND = mpu9250 就是為了以后可以直接在.mk文件直接使用的命令mpu9250。理解了上述以后,其他的driver中的所有的傳感器模塊、各種總線和modules/PX4Firmware/src/modules中的各種算法(mc_att_control、land_detector等等)都是按照此類方法實現的,不在贅述,但是這個rcS只是負責啟動driver中的,modules/PX4Firmware/src/modules需要靠下面的一個rcS啟動,兩個rcS各自分工。全部都是.mk啊,.mk,.mk~~~~
? ? ? ??下一階段主要應該就是放在這個 modules/PX4Firmware/src/modules 內部了,整個控制響應過程全靠它了,尤其是 commander ,校磁什么的都在里面,各種 calibration ,見過 2000+ 行的函數么?!怕么? ~~~ ?? 168MHZ 的主頻呢,怕啥
? ? ? ? PS:需要注意的是,在modules/PX4Firmware/src/drivers/boards/px4fmu-v2中有幾個.c文件,其中px4fmu_spi.c和board_config.h。
? ? ? ?? px4fmu_spi.c?? 會在入口函數 __start() 中被調用初始化 SPI,下面會提到 。
[plain] ?view plain
?copy ? *?Name:?stm32_spiinitialize?? ?*?Description:?? ?*???Called?to?configure?SPI?chip?select?GPIO?pins?for?the?PX4FMU?board.??
? ? ? ? board_config.h:如下的代碼是不是很熟悉,用過單片機的肯定都見過,尤其是pixhawk使用的又是STM32,再加上ST公司的芯片在各個高校中的普及程度,雖然我沒用過,我是菜鳥。
? ? ? ? 2)另外一個rcS就是modules/PX4Firmware/ROMFS/px4fmu_common/init.d中的rcS,PX4FMU的自啟動文件,它主要是負責啟動modules/PX4Firmware/modules里面的關于各自控制算法的模塊。同時,該rcS會以腳本的形式啟動同一級目錄中的rc.mc_apps、rc_io等等。詳細實現過程參見源代碼。
? ? ? ? 地址:https://github.com/PX4/Firmware/tree/master/ROMFS/px4fmu_common/init.d
? ? ? ? 舉一例說明問題,rc.mc_apps:關于姿態估計、位置估計和姿態控制和位置控制的,源代碼如下。
[plain] ?view plain
?copy ? #!nsh?? #?Standard?apps?for?multirotors:?? #?att?&?pos?estimator,?att?&?pos?control.?? #?The?system?is?defaulting?to?INAV_ENABLED?=?1?? #?but?users?can?alternatively?try?the?EKF-based?? #?filter?by?setting?INAV_ENABLED?=?0?? if?param?compare?INAV_ENABLED?1?? then?? ????attitude_estimator_q?start??//姿態估計?? ????position_estimator_inav?start//位置估計?? else?? ????if?param?compare?LPE_ENABLED?1?? ????then?? ????????attitude_estimator_q?start?? ????????local_position_estimator?start?? ????else?? ????????ekf2?start?? ????fi?? fi?? if?mc_att_control?start?//姿態控制?? then?? else?? ????#?try?the?multiplatform?version?? ????mc_att_control_m?start?? fi?? if?mc_pos_control?start?//位置控制?? then?? else?? ????#?try?the?multiplatform?version?? ????mc_pos_control_m?start?? fi?? #?Start?Land?Detector?? land_detector?start?multicopter?//啟動落地檢測??
? ? ? ?? 應該能了解代碼中的xxxxx start的含義了吧~~~~還不了解的話請撥打114,有專人為您解答
六、
再深入一點
1、主控STM32F4的選擇(肯定很多人不知道這個)
? ? ? ? 在ardupilot/modules/PX4NuttX/nuttx/arch/arm/src/stm32中,主要是通過在stm32_start.c中包含頭文件<arch/board/board.h>,board.h中包含<stm32.h>并且配置了STM32 的時鐘( Clock ) ,stm32.h中包含<chip.h>。另外, stm32.h 中還包含了關于 stm32 的各種 Peripherals 的頭文件,即各種外設( spi 、 can 、 uart 、 i2c 等等)的驅動 。
? ? ? ? 在ardupilot/modules/PX4NuttX/nuttx/arch/arm/src/stm32文件下有頭文件chip.h,內部通過條件編譯執行進行主控MCU的選擇。實例代碼如下。
[plain] ?view plain
?copy ? /*?STM32?F2?Family?******************************************************************/?? #elif?defined(CONFIG_STM32_STM32F20XX)?? #??include?"chip/stm32f20xxx_pinmap.h"?? /*?STM32?F3?Family?******************************************************************/?? #elif?defined(CONFIG_STM32_STM32F30XX)?? #??include?"chip/stm32f30xxx_pinmap.h"?? /*?STM32?F4?Family?******************************************************************/?? #elif?defined(CONFIG_STM32_STM32F40XX)?? #??include?"chip/stm32f40xxx_pinmap.h"?? #else?? #??error?"No?pinmap?file?for?this?STM32?chip"?? #endif???
2、入口函數 (__start())(這個就更不知道了吧)
? ? ? ? 在ardupilot/modules/PX4NuttX/nuttx/arch/arm/src/stm32文件下有定義文件stm32_start.c,內部有個上電/重啟的函數入口__start(void) 。仔細看,一行行的看,別偷懶,代碼附加列出了幾個小問題,檢查自己一下都會么?!!!
[plain] ?view plain
?copy ? /****************************************************************************?? ?*?Public?Functions?? ?****************************************************************************/?? /****************************************************************************?? ?*?Name:?_start?? ?*?? ?*?Description:?? ?*???This?is?the?reset?entry?point.?? ?*?? ?****************************************************************************/?? void?__start(void)?? {?? ??const?uint32_t?*src;?? ??uint32_t?*dest;?? #ifdef?CONFIG_ARMV7M_STACKCHECK?? ??/*?Set?the?stack?limit?before?we?attempt?to?call?any?functions?*/?? ??__asm__?volatile?("sub?r10,?sp,?%0"?:?:?"r"?(CONFIG_IDLETHREAD_STACKSIZE?-?64)?:?);?/*限制棧大小,可以防止遞歸把棧內存浪費完了,知道原因么?!*/?? #endif?? ??/*?Configure?the?uart?so?that?we?can?get?debug?output?as?soon?as?possible?*/?? ??stm32_clockconfig();?? ??stm32_fpuconfig();?? ??stm32_lowsetup();?? ??stm32_gpioinit();?? ??showprogress('A');?? ??/*?Clear?.bss.??We'll?do?this?inline?(vs.?calling?memset)?just?to?be?? ???*?certain?that?there?are?no?issues?with?the?state?of?global?variables.?? ????inline的好處。?? */?? ??for?(dest?=?&_sbss;?dest?<?&_ebss;?)?? ????{?? ??????*dest++?=?0;?? ????}?? ??showprogress('B');?? ??/*?Move?the?intialized?data?section?from?his?temporary?holding?spot?in?? ???*?FLASH?into?the?correct?place?in?SRAM.??The?correct?place?in?SRAM?is?? ???*?give?by?_sdata?and?_edata.??The?temporary?location?is?in?FLASH?at?the?? ???*?end?of?all?of?the?other?read-only?data?(.text,?.rodata)?at?_eronly.?? ???*?知道上述所講的幾個segments的分布么?!*/?? ??for?(src?=?&_eronly,?dest?=?&_sdata;?dest?<?&_edata;?)?? ????{?? ??????*dest++?=?*src++;?? ????}?? ??showprogress('C');?? ??/*?Perform?early?serial?initialization?*/?? #ifdef?USE_EARLYSERIALINIT?? ??up_earlyserialinit();?? #endif?? ??showprogress('D');?? ??/*?For?the?case?of?the?separate?user-/kernel-space(知道幾比幾么?)?build,?perform?whatever?? ???*?platform?specific?initialization?of?the?user?memory?is?required.?? ???*?Normally?this?just?means?initializing?the?user?space?.data?and?.bss?? ???*?segments.?? ???*/?? #ifdef?CONFIG_NUTTX_KERNEL?? ??stm32_userspace();?? ??showprogress('E');?? #endif?? ??/*?Initialize?onboard?resources?*/?? ??stm32_boardinitialize();//初始化SPI(飛控板上的傳感器都是通過SPI通信)和LEDs。???? ?????????????????????????//?還記上面提到的px4fmu_spi.c么?!??? ??showprogress('F');?? ??/*?Then?start?NuttX?*/?? ??showprogress('\r');?? ??showprogress('\n');?? ??os_start();//還記得上一篇博文的這個么??? ??/*?Shoulnd't?get?here?*/?? ??for(;;);?? }??
? ? ? ? 輕松一下:飛控板上為什么使用SPI而不用I2C?如下是官方原版解釋,說白了就是速度問題,如下權當練練English~~~
? ? ? ? I2C was not intended by Philips as a high rate sensor bus - this is what SPI has been invented for. Running multiple sensors at a suitably high rateover I2C is not recommended. Our hardware is designed to rely on SPI for allcritical sensors, and is available globally. Given the individual cost of thediscovery kit and sensor boards and power supply, one of the available Pixhawkkits is actually not more expensive, and will save a lot of trouble duringdevelopment and operation.
3、 Init sensors
? ? ? ? 飛控板是干嘛的?
? ? ? ? 控制無人機飛行滴(逼格高點就是通過各種傳感器檢測無人機的實時姿態信息和位置信息并結合MCU輸出控制信息)。
? ? ? ? 那sensor使用前要干嘛呢?
? ? ? ? !#¥@¥!@%¥!#%
? ? ? ? 初始化,初始化,初始化~~~~
? ? ? ? 上面那么多傳感器必須得初始化以后才能使用啊,所以需要先初始化用到的所有的傳感器,在哪配置呢,你找到沒?! 在ardupilot/modules/PX4Firmware/src/modules/sensors文件中有定義文件sensor.c(關于飛控板中的各個sensor的初始化函數,以task的方式啟動,初始化完成以后kill掉這個task,都是POSIX接口的API)。
? ? ? ? 首先是sensors_main函數
[plain] ?view plain
?copy ? int?sensors_main(int?argc,?char?*argv[])?? {?? ?………?? if?(OK?!=?sensors::g_sensors->start())?{??//2293?line?number?? delete?sensors::g_sensors;?? sensors::g_sensors?=?nullptr;?? warnx("start?failed");?? return?1;?? }?? ………??
? ? ? ? 然后捏:start()函數
[plain] ?view plain
?copy ? Int?Sensors::start()?? {?? ASSERT(_sensors_task?==?-1);?? /*?start?the?task?*/?? /*創建任務進程對sensors進行初始化以后,在task_main()函數執行的最后會調用px4_task_exit()函數退出該任務進程*//*?px4_task_spawn_cmd()創建任務的接口函數是posix接口的,具體實現參見源碼*/?? _sensors_task?=?px4_task_spawn_cmd("sensors",?SCHED_DEFAULT,??? ?SCHED_PRIORITY_MAX?-?5,?? ???2000,?? ???(px4_main_t)&Sensors::task_main_trampoline,?? ???nullptr);?? /*?wait?until?the?task?is?up?and?running?or?has?failed?*/?? while?(_sensors_task?>?0?&&?_task_should_exit)?{?? usleep(100);?? }?? if?(_sensors_task?<?0)?{?? return?-ERROR;?? }?? return?OK;?? }???
? ? ? ? 然后捏:task_main_trampoline()函數
[plain] ?view plain
?copy ? Void?Sensors::task_main_trampoline(int?argc,?char?*argv[])?? {?? sensors::g_sensors->task_main();?? }???
? ? ? ? 再然后捏:task_main()函數,大牌終于出場了
[plain] ?view plain
?copy ? Void?Sensors::task_main()?? {?? /*?start?individual?sensors?*/?? int?ret?=?0;?? do?{?/*?create?a?scope?to?handle?exit?with?break?*//*do_while用的精妙*/?? ret?=?accel_init();/*?return?0?*/?? if?(ret)?{?break;?}?? ret?=?gyro_init();?? if?(ret)?{?break;?}?? ret?=?mag_init();?? if?(ret)?{?break;?}?? ret?=?baro_init();?? if?(ret)?{?break;?}?? ret?=?adc_init();?? if?(ret)?{?break;?}?? break;?? }?while?(0);?? ………//2059?? /*?? ?*?do?subscriptions??這就是所謂的IPC使用的uORB模型(?publish_subscribe)吧?,我也不懂??? ?*/?? unsigned?gcount_prev?=?_gyro_count;?? ………?? _gyro_count?=?init_sensor_class(ORB_ID(sensor_gyro),?&_gyro_sub[0],?? &raw.gyro_priority[0],?&raw.gyro_errcount[0]);?? ………?? /*?get?a?set?of?initial?values?*/?? accel_poll(raw);//通過uORB模型獲取acc值?? gyro_poll(raw);?? mag_poll(raw);?? baro_poll(raw);?? diff_pres_poll(raw);?? parameter_update_poll(true?/*?forced?*/);?? rc_parameter_map_poll(true?/*?forced?*/);?? ………?? /*?check?vehicle?status?for?changes?to?publication?state?*/?? vehicle_control_mode_poll();?? /*?the?timestamp?of?the?raw?struct?is?updated?by?the?gyro_poll()?method?*/?? /*?copy?most?recent?sensor?data?*/?? gyro_poll(raw);?? accel_poll(raw);?? mag_poll(raw);?? baro_poll(raw);?? ………?? /*?check?battery?voltage?*/?? adc_poll(raw);?? diff_pres_poll(raw);?? /*?Inform?other?processes?that?new?data?is?available?to?copy?*/?? if?(_publishing?&&?raw.timestamp?>?0)?{?? orb_publish(ORB_ID(sensor_combined),?_sensor_pub,?&raw);?? }?? /*?keep?adding?sensors?as?long?as?we?are?not?armed,?? ?*?when?not?adding?sensors?poll?for?param?updates?? ?*/?? if?(!_armed?&&?hrt_elapsed_time(&_last_config_update)?>?500?*?1000)?{?? _gyro_count?=?init_sensor_class(ORB_ID(sensor_gyro),?&_gyro_sub[0],?? &raw.gyro_priority[0],?&raw.gyro_errcount[0]);?? _mag_count?=?init_sensor_class(ORB_ID(sensor_mag),?&_mag_sub[0],?? ???????&raw.magnetometer_priority[0],?&raw.magnetometer_errcount[0]);?? _accel_count?=?init_sensor_class(ORB_ID(sensor_accel),?&_accel_sub[0],?? ?&raw.accelerometer_priority[0],?&raw.accelerometer_errcount[0]);?? _baro_count?=?init_sensor_class(ORB_ID(sensor_baro),?&_baro_sub[0],?? &raw.baro_priority[0],?&raw.baro_errcount[0]);?? _last_config_update?=?hrt_absolute_time();?? }?else?{?? /*?check?parameters?for?updates?*/?? parameter_update_poll();?? /*?check?rc?parameter?map?for?updates?*/?? rc_parameter_map_poll();?? }?? /*?Look?for?new?r/c?input?data?*/?? rc_poll();?? perf_end(_loop_perf);?? }?? warnx("exiting.");?? _sensors_task?=?-1;?? px4_task_exit(ret);/*?px4_task_exit?()終止任務的接口函數也是posix接口的*/?? }??
? ? ? ??PS:關于IPC使用的 uORB的簡單介紹(摘自官網)。
? ? ? ??The micro Object Request Broker (uORB) application is used toshare data structures between threads and applications, Communications between processes / applications (e.g. sendingsensor values from the sensors app to the attitude filter app) is a key part ofthe PX4 software architecture. Processes (often called? nodes?in this context) exchange messagesover?named buses, called?topics.In PX4, a topic contains only one?message type, e.g. the?vehicle_attitude ? topic transports a message containing the? attitude ? struct (roll, pitch and yaw estimates). Nodes can? publish?a message on a bus/topic (“send” data)or?subscribe?toa bus/topic (“receive” data). They are not aware of who they are communicatingwith. There can be multiple publishers and multiple subscribers to a topic.This design pattern prevents locking issues and is very common in robotics. Tomake this efficient, there is always only?one?message on the bus and no queue iskept.
? ? ? ??詳細介紹:https://pixhawk.org/dev/shared_object_communication
4、如何獲取精確時間(timestamp )
? ? ? ? 在控制過程中多數環節都是使用經典的PID控制算法,為了獲取較為實時的響應最重要的時間變量,這就涉及如何獲取高精度的時間問題。
? ? ? ? Pixhawk主控使用ST公司的STM32F4系列處理器,其主頻達168MHZ,內部有高精度RTC,以RTC為基準獲取精確計時。根據分析源碼發現,在modules/PX4Firmware/src/drivers中有一個頭文件drv_hrt.h(High-resolutiontimer with callouts and timekeeping),內部對其作出了一部分的介紹,微妙(us)級的精確計時,在中斷上下文中調用,與其他函數并行執行不會被堵塞。摘抄幾個典型函數如下。
[plain] ?view plain
?copy ? /**?Get?absolute?time.*/?? __EXPORT?extern?hrt_abstime?hrt_absolute_time(void);?? /**?Compute?the?delta?between?a?timestamp?taken?in?the?past?and?now.?? *?This?function?is?safe?to?use?even?if?the?timestamp?is?updated?by?an?interrupt?during?execution.?*/?? __EXPORT?extern?hrt_abstime?hrt_elapsed_time(const?volatile?hrt_abstime?*then);?? /**?Store?the?absolute?time?in?an?interrupt-safe?fashion.?? *?This?function?ensures?that?the?timestamp?cannot?be?seen?half-written?by?an?interrupt?handler.*/?? __EXPORT?extern?hrt_abstime?hrt_store_absolute_time(volatile?hrt_abstime?*now);?? /*?initialise?a?hrt_call?structure?*/?? __EXPORT?extern?void????hrt_call_init(struct?hrt_call?*entry);?? /*?Initialise?the?HRT.?*/?? __EXPORT?extern?void????hrt_init(void);??
? ? ? ? 針對上述hrt_absolute_time (void )函數做闡述,其他的都類似,它的原型在modules/PX4Firmware/unittests中的hrt.cpp。
[plain] ?view plain
?copy ? hrt_abstime?hrt_absolute_time()?? {?? ????struct?timeval?te;?? ????gettimeofday(&te,?NULL);?//?get?current?time?? ????hrt_abstime?us?=?static_cast<uint64_t>(te.tv_sec)?*?1e6?+?te.tv_usec;?//?caculate?us?? ????return?us;?? }??
? ? ? ? 然后捏:直接進入操作系統(NuttX),輪到操作系統上場了,modules/PX4NuttX/nuttx/schedclock_gettimeofday.c,自己跟蹤進去看吧,不在贅述。
七、總結
? ? ? ? 一句話兩句話也寫清楚,那就不寫了吧~~~其實也不知道寫啥了。
? ? ? ? 反正就是這套代碼不簡單,不簡單。
? ? ? ? 接下來可能是繼續研究ardupilot這套代碼,這套的話就是到上層應用了,即關于loop函數和scheduler_task的問題了;或者轉變到pixhawk的原生代碼上,這套就是直接到控制算法上,commander。。。。。
總結
以上是生活随笔 為你收集整理的Pixhawk之启动代码和入口函数(.mk、rcS、__start、hrt) 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。