Pixhawk is an open-source autopilot platform. In this article, I explained the basic architecture of Pixhawk source code. And how to customize it in your own project.
It's recommended to use Ubuntu 14.04 LTS, otherwise you may have strange issues.
Please get familiar with GIT, it's a very powerfull software version control tool. You can install the GUI tool
git cola (In terminal: apt-get install git-cola) if you are not comfortable with the git commands in terminal.
SublimeText 3 is a convenient editor to navigate the numerous source files. There is already a project file in the source folder that you can import to SublimeText. One feature that I used every day is that: Press "Ctrl + p" and type in the filename, and you can find the file you want instantly.
1. Understand Pixhawk source code
1.1 Install the toolchain and build the code
1.2 How are the source code directories organised
After you have cloned the source code repository, you might be scared by so many directories and files. Actually you don't need to know all of them. I list the directory tree below(only the very import directories), and explain what are in the folders.
Firmware ├── cmake ├── msg │ └── templates │ ├── px4 │ └── uorb ├── ROMFS │ ├── px4fmu_common │ │ ├── init.d │ │ ├── logging │ │ └── mixers │ └── px4fmu_test │ ├── init.d │ ├── mixers │ └── unit_test_data └── src ├── drivers ├── examples ├── modules │ ├── attitude_estimator_ekf │ ├── attitude_estimator_q │ ├── bottle_drop │ ├── commander │ ├── controllib_test │ ├── dataman │ ├── ekf2 │ ├── ekf2_replay │ ├── ekf_att_pos_estimator │ ├── fw_att_control │ ├── fw_pos_control_l1 │ ├── gpio_led │ ├── land_detector │ ├── local_position_estimator │ ├── mavlink │ ├── mc_att_control │ ├── mc_att_control_multiplatform │ ├── mc_pos_control │ ├── mc_pos_control_multiplatform │ ├── muorb │ ├── navigator │ ├── param │ ├── position_estimator_inav │ ├── px4iofirmware │ ├── sdlog2 │ ├── segway │ ├── sensors │ ├── simulator │ ├── systemlib │ ├── uavcan │ ├── unit_test │ ├── uORB │ └── vtol_att_control └── systemcmds ├── bl_update ├── config ├── dumpfile ├── esc_calib ├── i2c ├── mixer ├── motor_test ├── mtd ├── nshterm ├── param ├── perf ├── pwm ├── reboot ├── reflect ├── tests ├── top ├── topic_listener ├── usb_connected └── ver
|msg||uORB msg template, the uORB msg headers are generated from this folder|
|ROMFS||startup scripts and mixer files|
|src||drivers, examples, flight control tasks|
|src/drivers||all the drivers: gps, gyro, pwm...|
|src/examples||some simple examples help you understand the code|
|src/modules||estimators, controllers ....|
|src/systemcmds||some handy commands can be used in Nuttx shell|
As you can see, the source code files are well organised. Though you still need time to get familiar with them.
1.3 The boot process
If you power on your Pixhawk board through USB cable or BEC, the LED will flash and the buzzer will play a special tune(you can check the tune meaning here). But you may wander what exactly happen during this process.
When powering on the board, the bootloader will run first. Bootloader is like BIOS in your PC. And it's already in the board when you buy it. So you may never need to bother it. The bootloader will launch the Nuttx Operating System. After some initialization of the hardware, memory... the Nuttx will execute a script file called "init.d/rcS" in function
nsh_initscript() of file
nsh_script.c. You can check the script file folder in section 1.2). This is a very important step. By executing this script file, some parameters in the EEPROM will be read, and the corresponding tasks related to these parameters will be launched. I will explain this in the next section.
1.4 The startup scripts
Nuttx is like a simplified Linux, moreover it's real time. So the script file is quite the same as Bash script in Linux. You can easily understand it if you know linux well.
Let's read some lines in
...... # # Try to mount the microSD card. # # REBOOTWORK this needs to start after the flight control loop if mount -t vfat /dev/mmcsd0 /fs/microsd then echo "[i] microSD mounted: /fs/microsd" # Start playing the startup tune tone_alarm start else tone_alarm MBAGP if mkfatfs /dev/mmcsd0 then if mount -t vfat /dev/mmcsd0 /fs/microsd then echo "[i] microSD card formatted" else echo "[i] format failed" tone_alarm MNBG set LOG_FILE /dev/null fi else set LOG_FILE /dev/null fi fi ......
At first it will start serial driver and set some parameters, which is not interested by us and not listed here. Then you will see
if mount -t vfat /dev/mmcsd0 /fs/microsd.
mount is a built-in command supported by Nuttx (Linux has the same command). It will try to mount the microSD card. If the return value is true, which means microSD card is mounted successfully, the
echo will print the result in shell window. And you should hear the buzzer alarm by
There are many similar statements like
tone_alarm start. If you understand this, you will almost know how the script file works and how to modify it to satisfy your own needs. Well, the grammar is simple:
command -arguments, just like the commands in Linux Terminal.
tone_alrm is a command compiled from file
tone_alarm.cpp by some tricks in makefile. If you scrutinise the function
tone_alarm_main() in this file, you will find this command has arguments
Let's read another piece of code in this file to see if you have any clue.
...... if [ $MODE == autostart ] then # # Start the ORB (first app to start) # uorb start # # Load parameters # set PARAM_FILE /fs/microsd/params if mtd start then set PARAM_FILE /fs/mtd_params fi param select $PARAM_FILE if param load then echo "[param] Loaded: $PARAM_FILE" else echo "[param] FAILED loading $PARAM_FILE" if param reset then fi fi ......
You can find the commands
uorb, mtd, param in files:
uORBMain.cpp, mtd.c, param.c. You don't need to go deep inside these files right now, anyway we may use this method to scrutinise other files later (For instance: flight control files). This piece of code will just start uORB to provide communication service, and load parameter file
mtd_params which contains airframe configuration, PID parameters, etc.
I assume you have read through this file. So to summarize, the startup scripts are very important in the boot process. I list the things happened in this process to our concern:
- Read the parameter file
- Start the sensor drivers (script
- Set and load the mixer corresponding to the airframe parameter
SYS_AUTOSTART, set the pwm channel (script
rc.autostart, this file is generated after you build the code)
- Start the flight tasks corresponding to the airframe parameter
1.5 The architecture
All the flight control tasks run in Nuttx system. They communicate with each other through uORB. uORB is a implementation of publish-subscribe pattern.
To control a vehicle, you need to navigate to waypoints, estimate the position and attitude, and control the position and attitude by using feedback control theory. That's the idea in pixhawk flight control architecture.
These flight control modules are in folder
Firmware/src/modules. I list the modules used by different airframes below. Actually you can find where they are launched in the startup scripts.
|Fixed Wing||Multi Copter||VTOL|
The architectural overview could be seen here. The tasks communicate by publishing and subscribing uORB messages. For instance, the messages related to the module
attitude_estimator_q are as follows:
- Published messages:
- Subscribed messages:
You can check the meaning of these messages in folder
2. How to costumize
2.1 A small tutorial
We can do a small exercise to understand the code better, and then go even further. Please follow this tutorial. The FTDI 3.3v cable is a necessary hardware for developpers to interact with Nuttx through Nuttx Shell(NSH).
2.2 Add you own controller
Following the same concept, you can add a simple control law in
Firmware/src/examples/fixedwing_control/main.c. The program subscribes the estimated position and attitude, manual control input. The only thing you need to do is to implement the PID control law, and calculate the normalized control value. Then publish it in the
actuator_controls_0 message to mixer to control the servos or motors.
2.3 Change the mixer
The key concept of the mixer is to translate the normalized control output from the controller to pwm to actuators, Which greatly improves reusability of code. If you have a special airframe, you may need to have you own mixer to control the acuators. Please refer to this webpage and the source file folder
2.4 Change the makefile and the startup script
You can add you own program in
Firmware/cmake/configs/nuttx_px4fmu-v2_default.cmake as you did before in section 2.1, so as to compile it. But you still need to launch it in Nuttx shell. An alternative and simple way is to start it in startup script like below (Take fixed wing airframe for instance):
...... # # Start attitude controller # # fw_att_control start # fw_pos_control_l1 start ex_fixedwing_control start ......
This piece of code is from
rc.fw_apps. As you can see, two lines are commented, one line is inserted. So your own controller
ex_fixedwing_control from section 2.2 is started instead of the original one:
3. Try this example
I have modified some Pixhawk code for my internship project. So you can try my code and use the same method to customize pixhawk in your own project too.
In my example, the
MAIN OUT channel 1 and 2 can be controlled by the roll angle. And the
MAIN OUT channel 3, 4, 5 and 6 are controlled by vertical speed.
3.1 How to Try it
In terminal, go to the folder where you want to store the source code, type in the following commands:
# clone the repository git clone https://github.com/oneWayOut/Firmware.git cd Firmware git checkout caidev git submodule update --init --recursive # please connect pixhawk to your computer through USB cable make px4fmu-v2_default upload
After you have execute the commands above, connect the servo and motor to the
MAIN OUT channels. Connect a FTDI 3.3v cable to pixhawk as explained here. I assume you have installed
screen. So you can connect to Nuttx shell by the command below(change
/dev/ttyXXX to your own device name, something like
screen /dev/ttyXXX 57600 8N1
And start my customized task in Nuttx shell:
nsh> ex_visionair_control start
Press the safety button to arm the board, now you can observe how the servo and motor react when you change the roll angle and the vertical speed of Pixhawk board.
3.2 What I have changed
As I said before, I changed the startup scripts, makefile. And I renamed the folder
visionair_control. In the file
main.c from this folder, I connect the sensor value directly to pwm channel, but not using mixer. You can see what I have changed here.