前面说到px4是基于Nuttx实时 操作系统上的,那么px4也是由一些程序所构成,这些程序实现了飞行器的自主控制,只不过这些程序并不是我们通常所见到的单片机或者windows编程那样的程序,但基本编程思想是一致的。我认为如果要看懂px4的源码,那你一定要了解px4的那些程序是怎么编写出来,怎么运行的。所以本章我就大概介绍一下基于Nuttx的编程,我以一个所有编程入门都会介绍的一个程序作为例子。这个程序就是大名鼎鼎的 hello world
![大笑](http://static.blog.csdn.net/xheditor/xheditor_emot/default/laugh.gif)
![大笑](http://static.blog.csdn.net/xheditor/xheditor_emot/default/laugh.gif)
![大笑](http://static.blog.csdn.net/xheditor/xheditor_emot/default/laugh.gif)
。
在讲解编程之前,我得交代两个重要的东西,因为这两个东西存在于px4的源码系统当中,非常重要,它们就是make和Cmake。
首先谈谈何为make,熟悉Linux系统的朋友对make肯定不陌生,它就是用来读取Makefile文件然后执行,把源码编译链接为可执行程序的一个软件。我们只要把待编译的源码文件和这些源码所需要用到的库写到Makefile文件里面执行make命令就能得到可执行或者可烧录的二进制文件。
那何为Cmake呢?
我们可以这样理解,早期人们直接使用gcc命令编译程序,当源码文件多起了之后,直接用gcc命令过长,链接的库过多,这样就太麻烦了。这时候Make就应运而生,解决了人们对于代码文件过多的困扰。但随着项目越来越大,文件越来越多,人们发现make也捉襟见肘,因为编写Makefile文件又会变得异常复杂。这个时候聪明的程序猿就想能不能有个程序可以帮我写Makefile文件呢?这样就引出了Cmake,当然Cmake不是智能的,它不可能自己去辨别那些是代码,那些是文件,需要什么库。这样就引入了另外一套规则,也引入了一个文件CMakeLists.txt,这个文件就是Cmake程序识别的文件,有这个文件,Cmake就能帮助程序猿自动生成Makefile文件。
总的来说流程应该是这样的:
cmake make
CMakeLists.txt-------------->Makefile---------------------->可执行文件
src,lib
看过px4源码文件的朋友肯定会发现里面有很多CMakeLists.txt文件,事实上整个px4源码的文件都是基于CMakeLists.txt的(Nuttx系统不是,Nuttx是基于Makefile的,px4源码基本都在Firmware/src下,Nuttx操作系统源码在Firmware/NuttX下)
有了上面这个两个概念之后,我们就开始着手编写我们的hello world程序。
首先进入/Firmware/src/examples文件夹,然后在这个文件夹下面建立一个文件夹hello_world,再进入hello_world文件夹,在该文件夹下建立两个文件:CMakeLists.txt,hello_world.c。
首先编辑hello_world.c文件。
- #include <px4_config.h>
- #include <px4_tasks.h>
- #include <px4_posix.h>
- #include <unistd.h>
- #include <stdio.h>
- #include <poll.h>
- #include <string.h>
- __EXPORT int hello_world_main(int argc, char *argv[]);
- int hello_world_main(int argc, char *argv[]){
- PX4_INFO("hello world!");
- return 0;
- }
然后编辑CMakeLists.txt文件
- px4_add_module(
- MODULE examples__hello_world
- MAIN hello_world
- STACK_MAIN 2000
- SRCS
- hello_world.c
- DEPENDS
- platforms__common
- )
最后最重要的是我们要将这个程序注册到Nuttx的系统当中
找到文件/Firmware/cmake/configs/nuttx_px4fmu-v2_default.cmake
针对不同的硬件所注册的文件是不同的,下面是不同硬件的注册方式:
- Posix SITL: Firmware/cmake/configs/posix_sitl_default.cmake
- Pixhawk v1/2: Firmware/cmake/configs/nuttx_px4fmu-v2_default.cmake
- Pixracer: Firmware/cmake/configs/nuttx_px4fmu-v4_default.cmake
在cmake文件中添加“examples/hello_world”
像下面这样:
- include(nuttx/px4_impl_nuttx)
- set(CMAKE_TOOLCHAIN_FILE ${PX4_SOURCE_DIR}/cmake/toolchains/Toolchain-arm-none-eabi.cmake)
- set(config_uavcan_num_ifaces 2)
- set(config_module_list
- #
- # Board support modules
- #
- drivers/device
- drivers/stm32
- drivers/stm32/adc
- drivers/stm32/tone_alarm
- drivers/led
- drivers/px4fmu
- drivers/px4io
- drivers/boards/px4fmu-v2
- drivers/rgbled
- drivers/mpu6000
- #drivers/mpu9250
- drivers/lsm303d
- drivers/l3gd20
- drivers/hmc5883
- drivers/ms5611
- #drivers/mb12xx
- #drivers/srf02
- drivers/sf0x
- #drivers/ll40ls
- drivers/trone
- drivers/gps
- drivers/pwm_out_sim
- #drivers/hott
- #drivers/hott/hott_telemetry
- #drivers/hott/hott_sensors
- #drivers/blinkm
- drivers/airspeed
- drivers/ets_airspeed
- drivers/meas_airspeed
- #drivers/frsky_telemetry
- modules/sensors
- #drivers/mkblctrl
- drivers/px4flow
- #drivers/oreoled
- #drivers/vmount
- drivers/pwm_input
- drivers/camera_trigger
- drivers/bst
- #drivers/snapdragon_rc_pwm
- drivers/lis3mdl
- #example
- examples/px4_simple_app
- <span style="color:#FF0000;">examples/hello_world</span>
- #
- # System commands
- #
- systemcmds/bl_update
- systemcmds/config
- systemcmds/dumpfile
- #systemcmds/esc_calib
- systemcmds/mixer
- #systemcmds/motor_ramp
- systemcmds/mtd
- systemcmds/nshterm
- systemcmds/param
- systemcmds/perf
- systemcmds/pwm
- systemcmds/reboot
- #systemcmds/sd_bench
- systemcmds/top
- #systemcmds/topic_listener
- systemcmds/ver
- #
- # Testing
- #
- #drivers/sf0x/sf0x_tests
- #drivers/test_ppm
- #lib/rc/rc_tests
- #modules/commander/commander_tests
- #modules/controllib_test
- #modules/mavlink/mavlink_tests
- #modules/unit_test
- #modules/uORB/uORB_tests
- #systemcmds/tests
- #
- # General system control
- #
- modules/commander
- modules/load_mon
- modules/navigator
- modules/mavlink
- modules/gpio_led
- modules/uavcan
- modules/land_detector
- #
- # Estimation modules
- #
- modules/attitude_estimator_q
- #modules/position_estimator_inav
- modules/local_position_estimator
- modules/ekf2
- #
- # Vehicle Control
- #
- modules/fw_pos_control_l1
- modules/fw_att_control
- modules/mc_att_control
- modules/mc_pos_control
- modules/vtol_att_control
- #
- # Logging
- #
- #modules/logger
- modules/sdlog2
- #
- # Library modules
- #
- modules/param
- modules/systemlib
- modules/systemlib/mixer
- modules/uORB
- modules/dataman
- #
- # Libraries
- #
- lib/controllib
- lib/mathlib
- lib/mathlib/math/filter
- lib/ecl
- lib/external_lgpl
- lib/geo
- lib/geo_lookup
- lib/conversion
- lib/launchdetection
- lib/terrain_estimation
- lib/runway_takeoff
- lib/tailsitter_recovery
- lib/DriverFramework/framework
- platforms/nuttx
- # had to add for cmake, not sure why wasn't in original config
- platforms/common
- platforms/nuttx/px4_layer
- #
- # OBC challenge
- #
- #modules/bottle_drop
- #
- # Rover apps
- #
- #examples/rover_steering_control
- #
- # Demo apps
- #
- #examples/math_demo
- # Tutorial code from
- # https://px4.io/dev/px4_simple_app
- #examples/px4_simple_app
- # Tutorial code from
- # https://px4.io/dev/daemon
- #examples/px4_daemon_app
- # Tutorial code from
- # https://px4.io/dev/debug_values
- #examples/px4_mavlink_debug
- # Tutorial code from
- # https://px4.io/dev/example_fixedwing_control
- #examples/fixedwing_control
- # Hardware test
- #examples/hwtest
- )
- set(config_extra_builtin_cmds
- serdis
- sercon
- )
- set(config_io_board
- px4io-v2
- )
- set(config_extra_libs
- uavcan
- uavcan_stm32_driver
- )
- set(config_io_extra_libs
- )
- add_custom_target(sercon)
- set_target_properties(sercon PROPERTIES
- PRIORITY "SCHED_PRIORITY_DEFAULT"
- MAIN "sercon" STACK_MAIN "2048"
- COMPILE_FLAGS "-Os")
- add_custom_target(serdis)
- set_target_properties(serdis PROPERTIES
- PRIORITY "SCHED_PRIORITY_DEFAULT"
- MAIN "serdis" STACK_MAIN "2048"
- COMPILE_FLAGS "-Os")
这样cmake的编译系统就会将这个程序加入到编译链中去了。
在Firmware文件夹下面执行make px4fmu-v2_default,如果不出问题的话,编译成功会显示下面的画面:
然后将硬件连接至虚拟机,执行烧录命令:make px4fmu-v2_default upload
按照上一篇文章所讲的那样同Nuttx shell通信
./mavlink_shell.py /dev/ttyACM0
在nsh中输入help命令之后,你就会在Builtin Apps下面找到hello_world程序
执行hello_world程序:
可以看到输出了hello world!
那么这一切是怎么做到的呢?首先看看代码文件即hello_world.c文件
首先是include
- #include <px4_config.h>
- #include <px4_tasks.h>
- #include <px4_posix.h>
- #include <unistd.h>
- #include <stdio.h>
- #include <poll.h>
- #include <string.h>
这些库文件你可以认为是编写基于Nuttx操作系统修改的px4程序程序必不可少的库文件包含(其实px4团队修改了不少Nuttx操作系统的东西,使其使用更加方便,所以这些程序并不是真正意义上的Nuttx程序)
然后是main函数(这里要提醒一下广大同学,可能px4基于stm32的编译器语法规则过于严格,所以在编写一个函数之前,必须要去申明这个函数,即使这个函数是main函数也要申明,不然编译报错,无法通过)
- int hello_world_main(int argc, char *argv[]){
- PX4_INFO("hello world!");
- return 0;
- }
可以看到基于Nuttx操作系统的main函数和其它系统的命名有很大不同,但也有自己的规律,那就是函数名+_+main,即name_main(),程序主函数里的参数(int argc, char *argv[])和其它系统main函数所带的参数没什么不同(如果不懂main函数带形参的同学最好自己百度一下,因为px4的那些程序基本都带参数的)。
PX4_INFO();是一个类似于printf的函数(事实上他就是是基于printf实现的),用来输出PX4的一些信息的。
再来看看CMakeLists.txt文件
- px4_add_module(
- MODULE examples__hello_world
- MAIN hello_world
- STACK_MAIN 2000
- SRCS
- hello_world.c
- DEPENDS
- platforms__common
- )
从字面上可以了解到每个程序在CMake里面都是一个模块,最后总的Cmake文件会去自动将这些模块添加到最后的生成的Makefile文件里面。所以我们要做的就是把我们写的模块的一些属性描写清楚,然后将其注册到nuttx_px4fmu-v2_default.cmake文件当中。
首先是模块名MODULE:这个名字的命名规则是当前文件夹+__+主函数名。
然后是MIAN :这个就是用来确定代码中那个函数为主函数的,填写主函数名即可。
STACK_MAIN:目前暂不清楚用途
SRCS:所用到的源文件。
DEPENDS :依赖。
以上就是关于编写一个基于Nuttx操作系统hello world程序的全过程。
因为我本人对Cmake的一些语法还不是很清楚,所以以上有些东西可能描述的不是很清楚,如有大神,还望指点。
下面一篇文章我将简介一下大家都很关心和迫切想知道的问题,就是px4的飞控程序是怎么开始执行的,程序入口在哪。