PX4程序架构
一、从RCS启动脚本可以看出哪些东西
启动脚本是一个神奇的东西,它能够识别出你对应的飞机类型,加载对应的混控器,选择对应的姿态、位置估计程序以及控制程序,初始化你需要的驱动程序。下面来分析下。
1.1RCS位置
- Firmware->ROMFS->px4fmu_common->init.d->rcs,最新版本的启动脚本如下:
#!/bin/sh
# Un comment and use set +e to ignore and set -e to enable 'exit on error control'
set +e
# Un comment the line below to help debug scripts by printing a trace of the script commands
#set -x
# PX4FMU startup script.
#
# NOTE: environment variable references:
# If the dollar sign ('$') is followed by a left bracket ('{') then the
# variable name is terminated with the right bracket character ('}').
# Otherwise, the variable name goes to the end of the argument.
#
#
# NOTE: COMMENT LINES ARE REMOVED BEFORE STORED IN ROMFS.
#
#------------------------------------------------------------------------------
#
# Set default paramter values.
# Do not add intra word spaces
# it wastes flash
#
set R /
set AUTOCNF no
set AUX_MODE pwm
set DATAMAN_OPT ""
set FAILSAFE none
set FAILSAFE_AUX none
set FCONFIG /fs/microsd/etc/config.txt
set FEXTRAS /fs/microsd/etc/extras.txt
set FMU_MODE pwm
set FRC /fs/microsd/etc/rc.txt
set IOFW "/etc/extras/px4_io-v2_default.bin"
set IO_PRESENT no
set LOG_FILE /fs/microsd/bootlog.txt
set LOGGER_ARGS ""
set LOGGER_BUF 14
set MAV_TYPE none
set MIXER none
set MIXER_AUX none
set MIXER_FILE none
set MK_MODE none
set MKBLCTRL_ARG ""
set OUTPUT_MODE none
set PARAM_FILE /fs/microsd/params
set PWM_AUX_DISARMED p:PWM_AUX_DISARMED
set PWM_AUX_MAX p:PWM_AUX_MAX
set PWM_AUX_MIN p:PWM_AUX_MIN
set PWM_AUX_OUT none
set PWM_AUX_RATE p:PWM_AUX_RATE
set PWM_DISARMED p:PWM_DISARMED
set PWM_MAX p:PWM_MAX
set PWM_MIN p:PWM_MIN
set PWM_OUT none
set PWM_RATE p:PWM_RATE
set RC_INPUT_ARGS ""
set SDCARD_MIXERS_PATH /fs/microsd/etc/mixers
set STARTUP_TUNE 1
set USE_IO no
set VEHICLE_TYPE none
# Airframe parameter versioning: airframe maintainers can set this in the
# airframe startup script, and then increase it by one whenever an airframe
# parameter is updated - it will ensure that these parameters will be updated
# when the firmware is flashed.
set PARAM_DEFAULTS_VER 1
#
# Mount the procfs.
#
mount -t procfs /proc
#
# Start CDC/ACM serial driver.
#
sercon
#
# Print full system version.
#
ver all
#
# Start the ORB (first app to start)
# tone_alarm and tune_control
# is dependent.
#
uorb start
#
# 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
if hardfault_log check
then
# Error tune.
set STARTUP_TUNE 2
if hardfault_log commit
then
hardfault_log reset
fi
fi
# Prevent MacOS and Ubuntu from creating unnecessary temporary files on the microSD card
# block MacOS Spotlight indexing (.Spotlight-V100 folder)
if [ ! -f "/fs/microsd/.metadata_never_index" ]; then
cat > /fs/microsd/.metadata_never_index
fi
# block MacOS trashes
if [ ! -f "/fs/microsd/.Trashes" ]; then
cat > /fs/microsd/.Trashes
fi
# block MacOS logging of filesystem events
if [ ! -d "/fs/microsd/.fseventsd" ]; then
mkdir /fs/microsd/.fseventsd
fi
if [ ! -f "/fs/microsd/.fseventsd/no_log" ]; then
cat > /fs/microsd/.fseventsd/no_log
fi
# block Ubuntu trash
if [ ! -f "/fs/microsd/.Trash-1000" ]; then
cat > /fs/microsd/.Trash-1000
fi
else
# tune SD_INIT
set STARTUP_TUNE 14 # tune 14 = SD_INIT
if mkfatfs /dev/mmcsd0
then
if mount -t vfat /dev/mmcsd0 /fs/microsd
then
echo "INFO [init] card formatted"
else
set STARTUP_TUNE 15 # tune 15 = SD_ERROR
echo "ERROR [init] format failed"
set LOG_FILE /dev/null
fi
else
set LOG_FILE /dev/null
fi
fi
#
# Look for an init script on the microSD card.
# Disable autostart if the script found.
#
if [ -f $FRC ]
then
. $FRC
else
#
# Set the parameter file if mtd starts successfully.
#
if mtd start
then
set PARAM_FILE /fs/mtd_params
fi
#
# Load parameters.
#
# if MTD has a secondary storage it is used for (factory) calibration data
if mtd has-secondary
then
if mtd start -i 1 /fs/mtd_caldata
then
param load /fs/mtd_caldata
fi
fi
param select $PARAM_FILE
if ! param import
then
param reset_all
fi
#
# Set AUTOCNF flag to use it in AUTOSTART scripts.
#
if param greater SYS_AUTOCONFIG 0
then
if param compare SYS_AUTOCONFIG 1
then
# Wipe out params except RC*, flight modes, total flight time, accel cal, gyro cal, next flight UUID
param reset_all SYS_AUTOSTART SYS_AUTOCONFIG RC* COM_FLTMODE* LND_FLIGHT_T_* TC_* CAL_ACC* CAL_GYRO* COM_FLIGHT_UUID
fi
set AUTOCNF yes
fi
#
# Optional board defaults: rc.board_defaults
#
set BOARD_RC_DEFAULTS ${R}etc/init.d/rc.board_defaults
if [ -f $BOARD_RC_DEFAULTS ]
then
echo "Board defaults: ${BOARD_RC_DEFAULTS}"
. $BOARD_RC_DEFAULTS
fi
unset BOARD_RC_DEFAULTS
#
# Start the tone_alarm driver.
# Needs to be started after the parameters are loaded (for CBRK_BUZZER).
#
tone_alarm start
#
# Play the startup tune (if not disabled or there is an error)
#
param compare CBRK_BUZZER 782090
if [ $? != 0 -o $STARTUP_TUNE != 1 ]
then
tune_control play -t $STARTUP_TUNE
fi
#
# Waypoint storage.
# REBOOTWORK this needs to start in parallel.
#
dataman start $DATAMAN_OPT
#
# Start the socket communication send_event handler.
#
send_event start
#
# Start the resource load monitor.
#
load_mon start
#
# Start system state indicator.
#
rgbled start -X -q
rgbled_ncp5623c start -X -q
if param greater LIGHT_EN_BLINKM 0
then
if blinkm start -X
then
blinkm systemstate
fi
fi
#
# Set parameters and env variables for selected AUTOSTART.
#
if ! param compare SYS_AUTOSTART 0
then
. ${R}etc/init.d/rc.autostart
fi
#
# Override parameters from user configuration file.
#
if [ -f $FCONFIG ]
then
echo "Custom: ${FCONFIG}"
. $FCONFIG
fi
#
# If autoconfig parameter was set, reset it and save parameters.
#
if [ $AUTOCNF = yes ]
then
param set SYS_AUTOCONFIG 0
fi
#
# Check if PX4IO present and update firmware if needed.
# Assumption IOFW set to firmware file and IO_PRESENT = no
#
if [ -f $IOFW ]
then
# Check for the mini using build with px4io fw file
# but not a px4IO
if ver hwtypecmp V540 V560
then
param set SYS_USE_IO 0
else
if px4io checkcrc ${IOFW}
then
set IO_PRESENT yes
else
# tune Program PX4IO
tune_control play -t 16 # tune 16 = PROG_PX4IO
if px4io start
then
# Try to safety px4 io so motor outputs don't go crazy.
if ! px4io safety_on
then
# px4io did not respond to the safety command.
px4io stop
fi
fi
if px4io forceupdate 14662 ${IOFW}
then
usleep 10000
tune_control stop
if px4io checkcrc ${IOFW}
then
echo "PX4IO CRC OK after updating" >> $LOG_FILE
tune_control play -t 17 # tune 17 = PROG_PX4IO_OK
set IO_PRESENT yes
fi
fi
if [ $IO_PRESENT = no ]
then
echo "PX4IO update failed" >> $LOG_FILE
tune_control play -t 18 # tune 18 = PROG_PX4IO_ERR
fi
fi
fi
fi
#
# Set USE_IO flag.
#
if param compare -s SYS_USE_IO 1
then
set USE_IO yes
fi
if [ $USE_IO = yes -a $IO_PRESENT = no ]
then
echo "PX4IO not found" >> $LOG_FILE
tune_control play error
fi
#
# RC update (map raw RC input to calibrate manual control)
# start before commander
#
rc_update start
#
# Sensors System (start before Commander so Preflight checks are properly run).
# Commander needs to be this early for in-air-restarts.
#
if param greater SYS_HITL 0
then
set OUTPUT_MODE hil
sensors start -h
commander start -h
# disable GPS
param set GPS_1_CONFIG 0
# start the simulator in hardware if needed
if param compare SYS_HITL 2
then
sih start
fi
else
#
# board sensors: rc.sensors
#
set BOARD_RC_SENSORS ${R}etc/init.d/rc.board_sensors
if [ -f $BOARD_RC_SENSORS ]
then
echo "Board sensors: ${BOARD_RC_SENSORS}"
. $BOARD_RC_SENSORS
fi
unset BOARD_RC_SENSORS
. ${R}etc/init.d/rc.sensors
if param compare -s BAT1_SOURCE 2
then
esc_battery start
fi
if ! param compare BAT1_SOURCE 1
then
battery_status start
fi
commander start
fi
# Sensors on the PWM interface bank.
if param compare -s SENS_EN_LL40LS 1
then
# Clear pins 5 and 6.
set FMU_MODE pwm4
set AUX_MODE pwm4
fi
# Check if ATS is enabled
if param compare FD_EXT_ATS_EN 1
then
# Clear pins 5 and 6.
set FMU_MODE pwm4
set AUX_MODE pwm4
fi
if param greater TRIG_MODE 0
then
# We ONLY support trigger on pins 5+6 or 7+8 when simultanously using AUX for actuator output.
if param compare TRIG_PINS 56
then
# clear pins 5 and 6
set FMU_MODE pwm4
set AUX_MODE pwm4
else
if param compare TRIG_PINS 78
then
# clear pins 7 and 8
set FMU_MODE pwm6
set AUX_MODE pwm6
else
set FMU_MODE none
set AUX_MODE none
fi
fi
camera_trigger start
camera_feedback start
fi
#
# Check if UAVCAN is enabled, default to it for ESCs.
#
if param greater -s UAVCAN_ENABLE 0
then
# Start core UAVCAN module.
if uavcan start
then
if param greater UAVCAN_ENABLE 1
then
# Start UAVCAN firmware update server and dynamic node ID allocation server.
uavcan start fw
if param greater UAVCAN_ENABLE 2
then
set OUTPUT_MODE uavcan_esc
fi
fi
else
tune_control play error
fi
fi
#
# Optional board mavlink streams: rc.board_mavlink
#
set BOARD_RC_MAVLINK ${R}etc/init.d/rc.board_mavlink
if [ -f $BOARD_RC_MAVLINK ]
then
echo "Board extras: ${BOARD_RC_MAVLINK}"
. $BOARD_RC_MAVLINK
fi
unset BOARD_RC_MAVLINK
#
# Start UART/Serial device drivers.
# Note: rc.serial is auto-generated from Tools/serial/generate_config.py
#
. ${R}etc/init.d/rc.serial
if [ $IO_PRESENT = no ]
then
# Must be started after the serial config is read
rc_input start $RC_INPUT_ARGS
fi
#
# Configure vehicle type specific parameters.
# Note: rc.vehicle_setup is the entry point for rc.interface,
# rc.fw_apps, rc.mc_apps, rc.rover_apps, and rc.vtol_apps.
#
. ${R}etc/init.d/rc.vehicle_setup
# Camera capture driver
if param greater -s CAM_CAP_FBACK 0
then
if camera_capture start
then
camera_capture on
fi
fi
#
# Start the navigator.
#
navigator start
#
# Start a thermal calibration if required.
#
. ${R}etc/init.d/rc.thermal_cal
#
# Start vmount to control mounts such as gimbals, disabled by default.
#
if ! param compare MNT_MODE_IN -1
then
vmount start
fi
# Check for flow sensor
if param compare SENS_EN_PX4FLOW 1
then
px4flow start -X
fi
# Blacksheep telemetry
if param greater TEL_BST_EN 0
then
bst start -X
fi
#
# Optional board supplied extras: rc.board_extras
#
set BOARD_RC_EXTRAS ${R}etc/init.d/rc.board_extras
if [ -f $BOARD_RC_EXTRAS ]
then
echo "Board extras: ${BOARD_RC_EXTRAS}"
. $BOARD_RC_EXTRAS
fi
unset BOARD_RC_EXTRAS
#
# Start any custom addons from the sdcard.
#
if [ -f $FEXTRAS ]
then
echo "Addons script: ${FEXTRAS}"
. $FEXTRAS
fi
#
# Start the logger.
#
. ${R}etc/init.d/rc.logging
#
# Set additional parameters and env variables for selected AUTOSTART.
#
if ! param compare SYS_AUTOSTART 0
then
. ${R}etc/init.d/rc.autostart.post
fi
if ! param compare SYS_PARAM_VER ${PARAM_DEFAULTS_VER}
then
echo "Switched to different parameter version. Resetting parameters."
param set SYS_PARAM_VER ${PARAM_DEFAULTS_VER}
param set SYS_AUTOCONFIG 2
param save
reboot
fi
#
# End of autostart.
#
fi
#
# Unset all script parameters to free RAM.
#
unset R
unset AUTOCNF
unset AUX_MODE
unset DATAMAN_OPT
unset FAILSAFE
unset FAILSAFE_AUX
unset FCONFIG
unset FEXTRAS
unset FMU_MODE
unset FRC
unset IO_PRESENT
unset IOFW
unset LOG_FILE
unset LOGGER_ARGS
unset LOGGER_BUF
unset MAV_TYPE
unset MIXER
unset MIXER_AUX
unset MIXER_FILE
unset MK_MODE
unset MKBLCTRL_ARG
unset OUTPUT_MODE
unset PARAM_DEFAULTS_VER
unset PARAM_FILE
unset PWM_AUX_DISARMED
unset PWM_AUX_MAX
unset PWM_AUX_MIN
unset PWM_AUX_OUT
unset PWM_AUX_RATE
unset PWM_DISARMED
unset PWM_MAX
unset PWM_MIN
unset PWM_OUT
unset PWM_RATE
unset RC_INPUT_ARGS
unset SDCARD_MIXERS_PATH
unset STARTUP_TUNE
unset USE_IO
unset VEHICLE_TYPE
#
# Boot is complete, inform MAVLink app(s) that the system is now fully up and running.
#
mavlink boot_complete
- 下图从网络上找的的对应启动的顺序一个图示,版本不太一样,但是大致差不多
- 总结:
从上述的图片分析,可以知道,一个启动脚本实现了挂载SD卡,设置存储好的一些飞行控制的初始参数(可以通过地面站修改),启动所有的外设传感器,启动与地面站通行的Mavlink服务,以及机型的选择后对应启动的控制服务(以固定翼为例,启动了ekf2,fw_att_control,fw_pos_control_l1,airspeed_selector,land_detector等服务),打开navigator服务。
1.2 src下在固定翼模式下modules中启动的app有哪些
我们可以通过地面站连接飞控,然后通过mavlink控制台,读取各个应用的工作状态,输入help可以看见一些可以使用的app, 然后在控制台输入app status可以查询其状态,通过查询得知以下src中的app被启动了:
-
airspeed_selector
-
battery_status
-
commander
-
dataman
-
计算单元ekf2
-
fw_att_control
-
fw_pos_control_l1
-
land_detector工作在固定翼模式下
-
load_mon
-
logger
-
mavlink
-
navigator
-
rc_update
-
sensors
-
uorb
二、PX4程序架构详解——固定翼
从上述分析我们知道了哪些app被启动了,接下来看一下,控制逻辑顺序,下图从网上找到的一个简化的模块使用的控制流程:
我们可以将上图从中间分成两个看,其中右边为传感器采集(GPS、optical_flow、inertial_sensors)回来的数据,并经过一些处理(position_estimator、attitude_estimator)发布到msg消息中,供左侧控制程序订阅使用。
px4的控制部分程序,采用的是分层设计。
-
用户设定commander和stickmapper生成的控制命令
-
控制命令使navigator去生成期望的位置信息
-
pos_ctrl通过期望位置与实际位置的偏差使用PID的算法输出期望姿态信息
-
att_ctrl通过期望姿态信息与实际姿态信息使用PID输出控制信息
-
经过混控器mixer根据机型进行力矩分配然后经过motor_driver输出实际舵面控制的pwm占空比
下图为各个模块之间的数据流:
2.1 commander
2.2 navigator
摘自PX4飞控之导航及任务架构
Navigator模块主要功能在于确定任务类型、地理围栏、失效保护,把任务航点更新后送给位置控制器。其中task_main函数是主函数。
在task_main 函数中,主要分为如下几个部分:
当commander中的传输来的导航模式为mission时,依次运行mission.cpp中的三个函数:初始化on_activation()、主函数on_active()、退出函数on_inactive()。
对于mission模式的主函数on_active(),代码逻辑如下:
mission的主要功能在于对航点数组pos_sp_triplet更新和赋值,航点数组包括previous、current、next三个航点,这一功能由函数set_mission_item()来实现,主要的逻辑为先从SD卡中读取航点信息read_mission_item()赋值给结构体mission_item,然后再将当前航点复制给pos_sp_triplet.current
每当一个航点任务完成is_mission_item_reached()返回值为true,则指针++,读取SD卡中的下一个航点。而判断航点的是否完成由三个判断条件:
航向控制由函数heading_sp_update()实现,将航向setpoint计算赋值给pos_sp_triplet.current.yaw,给到pos控制环,进行航向控制。
至此,导航完成了航点经纬高、航点类型、航向等信息的更新。而位置控制环以pos_sp_triplet为目标进行控制。
注:航点数组中的高度为绝对高度。
2.3 fw_pos_control_l1
2.3.1 程序框架
2.3.2 总能量控制系统
1、Total Energy Control System (TECS):总能量控制系统
该模块可以同时控制固定翼飞机的真实空速和高度
如上图所示,TECS接收空速和高度设定点作为输入,并输出油门和俯仰角设定点。 这两个输出被发送到固定翼姿态控制器,后者执行姿态控制解决方案。 因此,重要的是要了解,TECS的性能直接受变桨控制回路的性能影响。 对空速和高度的不良跟踪通常是由对飞机俯仰角的不良跟踪引起的。
同时控制真实空速和高度并不是一件容易的事。 飞机俯仰角的增加将导致高度的增加,但也会导致空速的降低。 增加节气门将增加空速,但由于升力的增加,高度也会增加。 因此,我们有两个输入(俯仰角和节气门),它们都影响两个输出(空速和高度),这使控制问题变得很困难。
TECS通过用能量而不是原始设定值来表示问题来提供解决方案。飞机的总能量是动能和势能之和。推力(通过节气门控制)增加了飞机的总能量状态。给定的总能量状态可以通过势能和动能的任意组合来实现。换句话说,在总的能量意义上,在高海拔但以低速飞行可以等同于在低海拔但以更快的空速飞行。我们将此称为特定能量平衡,它是根据当前高度和真实空速设定点计算得出的。通过飞机俯仰角控制比能量平衡。桨距角的增加将动能转移到势能,而桨距角为负的情况则相反。因此,通过将初始设定值转换为可以独立控制的能量来消除控制问题。我们使用推力来调节车辆的总能量,而俯仰角则在势能(高度)和动能(速度)之间保持特定的平衡。
2、总能量控制回路
3、总能量平衡控制回路
2.3.2 总能量控制系统实现(tecs_update_pitch_throttl();)
void
FixedwingPositionControl::tecs_update_pitch_throttle(const hrt_abstime &now, float alt_sp, float airspeed_sp,
float pitch_min_rad, float pitch_max_rad,
float throttle_min, float throttle_max, float throttle_cruise,
bool climbout_mode, float climbout_pitch_min_rad,
uint8_t mode)
{
const float dt = math::constrain((now - _last_tecs_update) * 1e-6f, 0.01f, 0.05f);
_last_tecs_update = now;
// do not run TECS if we are not in air
bool run_tecs = !_vehicle_land_detected.landed;
// do not run TECS if vehicle is a VTOL and we are in rotary wing mode or in transition
// (it should also not run during VTOL blending because airspeed is too low still)
if (_vehicle_status.is_vtol) {
if (_vehicle_status.vehicle_type == vehicle_status_s::VEHICLE_TYPE_ROTARY_WING || _vehicle_status.in_transition_mode) {
run_tecs = false;
}
if (_vehicle_status.in_transition_mode) {
// we're in transition
_was_in_transition = true;
// set this to transition airspeed to init tecs correctly
if (_param_fw_arsp_mode.get() == 1 && PX4_ISFINITE(_param_airspeed_trans)) {
// some vtols fly without airspeed sensor
_asp_after_transition = _param_airspeed_trans;
} else {
_asp_after_transition = _airspeed;
}
_asp_after_transition = constrain(_asp_after_transition, _param_fw_airspd_min.get(), _param_fw_airspd_max.get());
} else if (_was_in_transition) {
// after transition we ramp up desired airspeed from the speed we had coming out of the transition
_asp_after_transition += dt * 2; // increase 2m/s
if (_asp_after_transition < airspeed_sp && _airspeed < airspeed_sp) {
airspeed_sp = max(_asp_after_transition, _airspeed);
} else {
_was_in_transition = false;
_asp_after_transition = 0;
}
}
}
_is_tecs_running = run_tecs;
if (!run_tecs) {
// next time we run TECS we should reinitialize states
_reinitialize_tecs = true;
return;
}
if (_reinitialize_tecs) {
_tecs.reset_state();
_reinitialize_tecs = false;
}
if (_vehicle_status.engine_failure) {
/* Force the slow downwards spiral */
pitch_min_rad = M_DEG_TO_RAD_F * -1.0f;
pitch_max_rad = M_DEG_TO_RAD_F * 5.0f;
}
/* No underspeed protection in landing mode */
_tecs.set_detect_underspeed_enabled(!(mode == tecs_status_s::TECS_MODE_LAND
|| mode == tecs_status_s::TECS_MODE_LAND_THROTTLELIM));
/* Using tecs library */
float pitch_for_tecs = _pitch - radians(_param_fw_psp_off.get());
/* filter speed and altitude for controller */
Vector3f accel_body(_vehicle_acceleration_sub.get().xyz);
// tailsitters use the multicopter frame as reference, in fixed wing
// we need to use the fixed wing frame
if (_vt