Merged master into driver_framework

This commit is contained in:
Lorenz Meier
2015-11-20 09:14:37 +01:00
102 changed files with 2985 additions and 474 deletions
+2 -4
View File
@@ -9,7 +9,7 @@ matrix:
- os: linux - os: linux
sudo: false sudo: false
- os: osx - os: osx
osx_image: beta-xcode6.3 osx_image: xcode7
sudo: true sudo: true
cache: cache:
@@ -60,11 +60,9 @@ before_install:
elif [ "${TRAVIS_OS_NAME}" = "osx" ]; then elif [ "${TRAVIS_OS_NAME}" = "osx" ]; then
brew tap PX4/homebrew-px4 brew tap PX4/homebrew-px4
&& brew update && brew update
&& brew install astyle && brew install cmake ninja astyle gcc-arm-none-eabi
&& brew install gcc-arm-none-eabi
&& brew install genromfs && brew install genromfs
&& brew install kconfig-frontends && brew install kconfig-frontends
&& brew install ninja
&& sudo easy_install pip && sudo easy_install pip
&& sudo pip install pyserial empy && sudo pip install pyserial empy
; ;
+1 -1
View File
@@ -184,7 +184,7 @@ clean:
# targets handled by cmake # targets handled by cmake
cmake_targets = test upload package package_source debug debug_tui debug_ddd debug_io debug_io_tui debug_io_ddd check_weak \ cmake_targets = test upload package package_source debug debug_tui debug_ddd debug_io debug_io_tui debug_io_ddd check_weak \
run_cmake_config config gazebo gazebo_gdb gazebo_lldb jmavsim \ run_cmake_config config gazebo gazebo_gdb gazebo_lldb jmavsim \
jmavsim_gdb jmavsim_lldb gazebo_gdb_iris gazebo_lldb_vtol gazebo_iris gazebo_vtol jmavsim_gdb jmavsim_lldb gazebo_gdb_iris gazebo_lldb_tailsitter gazebo_iris gazebo_tailsitter
$(foreach targ,$(cmake_targets),$(eval $(call cmake-targ,$(targ)))) $(foreach targ,$(cmake_targets),$(eval $(call cmake-targ,$(targ))))
.PHONY: clean .PHONY: clean
+5 -3
View File
@@ -6,8 +6,8 @@
# #
# @output MAIN1 aileron # @output MAIN1 aileron
# @output MAIN2 elevator # @output MAIN2 elevator
# @output MAIN4 rudder # @output MAIN3 rudder
# @output MAIN3 throttle # @output MAIN4 throttle
# @output MAIN5 flaps # @output MAIN5 flaps
# #
# @output AUX1 feed-through of RC AUX1 channel # @output AUX1 feed-through of RC AUX1 channel
@@ -21,6 +21,8 @@ sh /etc/init.d/rc.fw_defaults
set MIXER AERT set MIXER AERT
# The ESC requires a specific pulse to arm. # use PWM parameters for throttle channel
set PWM_OUT 4 set PWM_OUT 4
set PWM_DISARMED p:PWM_DISARMED set PWM_DISARMED p:PWM_DISARMED
set PWM_MIN p:PWM_MIN
set PWM_MAX p:PWM_MAX
+3 -1
View File
@@ -21,6 +21,8 @@ sh /etc/init.d/rc.fw_defaults
set MIXER AETR set MIXER AETR
# The ESC requires a specific pulse to arm. # use PWM parameters for throttle channel
set PWM_OUT 3 set PWM_OUT 3
set PWM_DISARMED p:PWM_DISARMED set PWM_DISARMED p:PWM_DISARMED
set PWM_MIN p:PWM_MIN
set PWM_MAX p:PWM_MAX
+50
View File
@@ -0,0 +1,50 @@
#!nsh
#
# @name Bormatec Maja
#
# @type Standard Plane
#
# @output MAIN1 aileron
# @output MAIN2 aileron
# @output MAIN3 elevator
# @output MAIN4 rudder
# @output MAIN5 throttle
# @output MAIN6 wheel
# @output MAIN7 flaps
#
# @output AUX1 feed-through of RC AUX1 channel
# @output AUX2 feed-through of RC AUX2 channel
# @output AUX3 feed-through of RC AUX3 channel
#
# @maintainer Andreas Antener <andreas@uaventure.com>
#
sh /etc/init.d/rc.fw_defaults
if [ $AUTOCNF == yes ]
then
param set FW_AIRSPD_MIN 10
param set FW_AIRSPD_TRIM 15
param set FW_AIRSPD_MAX 20
param set FW_MAN_P_MAX 55
param set FW_MAN_R_MAX 55
param set FW_R_LIM 55
param set FW_WR_FF 0.2
param set FW_WR_I 0.2
param set FW_WR_IMAX 0.8
param set FW_WR_P 1
param set FW_W_RMAX 0
# set disarmed value for the ESC
param set PWM_DISARMED 1000
fi
set MIXER AAERTWF
# use PWM parameters for throttle channel
set PWM_OUT 5
set PWM_DISARMED p:PWM_DISARMED
set PWM_MIN p:PWM_MIN
set PWM_MAX p:PWM_MAX
+51
View File
@@ -0,0 +1,51 @@
#!nsh
#
# @name Applied Aeronautics Albatross
#
# @type Standard Plane
#
# @output MAIN1 aileron right
# @output MAIN2 aileron left
# @output MAIN3 v-tail right
# @output MAIN4 v-tail left
# @output MAIN5 throttle
# @output MAIN6 wheel
# @output MAIN7 flaps right
# @output MAIN8 flaps left
#
# @output AUX1 feed-through of RC AUX1 channel
# @output AUX2 feed-through of RC AUX2 channel
# @output AUX3 feed-through of RC AUX3 channel
#
# @maintainer Andreas Antener <andreas@uaventure.com>
#
sh /etc/init.d/rc.fw_defaults
if [ $AUTOCNF == yes ]
then
param set FW_AIRSPD_MIN 10
param set FW_AIRSPD_TRIM 15
param set FW_AIRSPD_MAX 20
param set FW_MAN_P_MAX 55
param set FW_MAN_R_MAX 55
param set FW_R_LIM 55
param set FW_WR_FF 0.2
param set FW_WR_I 0.2
param set FW_WR_IMAX 0.8
param set FW_WR_P 1
param set FW_W_RMAX 0
# set disarmed value for the ESC
param set PWM_DISARMED 1000
fi
set MIXER AAVVTWFF
# use PWM parameters for throttle channel
set PWM_OUT 5
set PWM_DISARMED p:PWM_DISARMED
set PWM_MIN p:PWM_MIN
set PWM_MAX p:PWM_MAX
+4
View File
@@ -564,6 +564,10 @@ then
then then
mavlink start -d /dev/ttyS2 -b 57600 -m osd -r 1000 mavlink start -d /dev/ttyS2 -b 57600 -m osd -r 1000
fi fi
if param compare SYS_COMPANION 257600
then
mavlink start -d /dev/ttyS2 -b 57600 -m magic -r 5000 -x
fi
# Sensors on the PWM interface bank # Sensors on the PWM interface bank
# clear pins 5 and 6 # clear pins 5 and 6
if param compare SENS_EN_LL40LS 1 if param compare SENS_EN_LL40LS 1
@@ -0,0 +1,96 @@
Aileron/rudder/elevator/throttle/wheel/flaps mixer for PX4FMU
=======================================================
This file defines mixers suitable for controlling a fixed wing aircraft with
aileron, rudder, elevator, throttle and steerable wheel controls using PX4FMU.
The configuration assumes the aileron servo(s) are connected to PX4FMU servo
output 0 and 1, the elevator to output 2, the rudder to output 3, the throttle
to output 4 and the wheel to output 5.
Inputs to the mixer come from channel group 0 (vehicle attitude), channels 0
(roll), 1 (pitch), 2 (yaw) and 3 (thrust) 4 (flaps) 6 (flaperon).
Aileron mixer (roll + flaperon)
---------------------------------
This mixer assumes that the aileron servos are set up correctly mechanically;
depending on the actual configuration it may be necessary to reverse the scaling
factors (to reverse the servo movement) and adjust the offset, scaling and
endpoints to suit.
M: 2
O: 10000 10000 0 -10000 10000
S: 0 0 10000 10000 0 -10000 10000
S: 0 6 10000 10000 0 -10000 10000
M: 2
O: 10000 10000 0 -10000 10000
S: 0 0 10000 10000 0 -10000 10000
S: 0 6 -10000 -10000 0 -10000 10000
Elevator mixer
------------
Two scalers total (output, roll).
This mixer assumes that the elevator servo is set up correctly mechanically;
depending on the actual configuration it may be necessary to reverse the scaling
factors (to reverse the servo movement) and adjust the offset, scaling and
endpoints to suit.
M: 1
O: 10000 10000 0 -10000 10000
S: 0 1 -10000 -10000 0 -10000 10000
Rudder mixer
------------
Two scalers total (output, yaw).
This mixer assumes that the rudder servo is set up correctly mechanically;
depending on the actual configuration it may be necessary to reverse the scaling
factors (to reverse the servo movement) and adjust the offset, scaling and
endpoints to suit.
M: 1
O: 10000 10000 0 -10000 10000
S: 0 2 10000 10000 0 -10000 10000
Motor speed mixer
-----------------
Two scalers total (output, thrust).
This mixer generates a full-range output (-1 to 1) from an input in the (0 - 1)
range. Inputs below zero are treated as zero.
M: 1
O: 10000 10000 0 -10000 10000
S: 0 3 0 20000 -10000 -10000 10000
Wheel mixer
------------
Two scalers total (output, yaw).
This mixer assumes that the wheel servo is set up correctly mechanically;
depending on the actual configuration it may be necessary to reverse the scaling
factors (to reverse the servo movement) and adjust the offset, scaling and
endpoints to suit.
M: 1
O: 10000 10000 0 -10000 10000
S: 0 2 10000 10000 0 -10000 10000
Flaps / gimbal / payload mixer for last three channels,
using the payload control group
-----------------------------------------------------
M: 1
O: 10000 10000 0 -10000 10000
S: 0 4 10000 10000 0 -10000 10000
M: 1
O: 10000 10000 0 -10000 10000
S: 2 0 10000 10000 0 -10000 10000
M: 1
O: 10000 10000 0 -10000 10000
S: 2 2 10000 10000 0 -10000 10000
@@ -0,0 +1,84 @@
Aileron/v-tail/throttle/wheel/flaps mixer for PX4FMU
=======================================================
This file defines mixers suitable for controlling a fixed wing aircraft with
aileron, v-tail (rudder, elevator), throttle, steerable wheel and flaps
using PX4FMU.
The configuration assumes the aileron servos are connected to PX4FMU servo
output 0 and 1, the tail servos to output 2 and 3, the throttle
to output 4, the wheel to output 5 and the flaps to output 6 and 7.
Inputs to the mixer come from channel group 0 (vehicle attitude), channels 0
(roll), 1 (pitch), 2 (yaw) and 3 (thrust) 4 (flaps) 6 (flaperon).
Aileron mixer (roll + flaperon)
---------------------------------
This mixer assumes that the aileron servos are set up correctly mechanically;
depending on the actual configuration it may be necessary to reverse the scaling
factors (to reverse the servo movement) and adjust the offset, scaling and
endpoints to suit.
M: 2
O: 10000 10000 0 -10000 10000
S: 0 0 10000 10000 0 -10000 10000
S: 0 6 10000 10000 0 -10000 10000
M: 2
O: 10000 10000 0 -10000 10000
S: 0 0 10000 10000 0 -10000 10000
S: 0 6 -10000 -10000 0 -10000 10000
V-tail mixers
-------------
Three scalers total (output, roll, pitch).
On the assumption that the two tail servos are physically reversed, the pitch
input is inverted between the two servos.
M: 2
O: 10000 10000 0 -10000 10000
S: 0 2 -7000 -7000 0 -10000 10000
S: 0 1 -8000 -8000 0 -10000 10000
M: 2
O: 10000 10000 0 -10000 10000
S: 0 2 -7000 -7000 0 -10000 10000
S: 0 1 8000 8000 0 -10000 10000
Motor speed mixer
-----------------
Two scalers total (output, thrust).
This mixer generates a full-range output (-1 to 1) from an input in the (0 - 1)
range. Inputs below zero are treated as zero.
M: 1
O: 10000 10000 0 -10000 10000
S: 0 3 0 20000 -10000 -10000 10000
Wheel mixer
------------
Two scalers total (output, yaw).
This mixer assumes that the wheel servo is set up correctly mechanically;
depending on the actual configuration it may be necessary to reverse the scaling
factors (to reverse the servo movement) and adjust the offset, scaling and
endpoints to suit.
M: 1
O: 10000 10000 0 -10000 10000
S: 0 2 -10000 -10000 0 -10000 10000
Flaps mixer
------------
Flap servos are physically reversed.
M: 1
O: 10000 10000 0 -10000 10000
S: 0 4 0 5000 -10000 -10000 10000
M: 1
O: 10000 10000 0 -10000 10000
S: 0 4 0 -5000 10000 -10000 10000
+5 -3
View File
@@ -17,7 +17,7 @@ for index,m in enumerate(raw_messages):
temp_list_floats = [] temp_list_floats = []
temp_list_uint64 = [] temp_list_uint64 = []
temp_list_bool = [] temp_list_bool = []
if("actuator_control" not in m and "pwm_input" not in m and "position_setpoint" not in m): if("pwm_input" not in m and "position_setpoint" not in m):
temp_list = [] temp_list = []
f = open(m,'r') f = open(m,'r')
for line in f.readlines(): for line in f.readlines():
@@ -55,9 +55,11 @@ for index,m in enumerate(raw_messages):
f.close() f.close()
(m_head, m_tail) = os.path.split(m) (m_head, m_tail) = os.path.split(m)
messages.append(m_tail.split('.')[0]) message = m_tail.split('.')[0]
if message != "actuator_controls":
messages.append(message)
message_elements.append(temp_list)
#messages.append(m.split('/')[-1].split('.')[0]) #messages.append(m.split('/')[-1].split('.')[0])
message_elements.append(temp_list)
num_messages = len(messages); num_messages = len(messages);
+35 -43
View File
@@ -15,7 +15,7 @@
<min>0</min> <min>0</min>
<max>1</max> <max>1</max>
</parameter> </parameter>
<parameter default="1" name="ctl_gain" type="FLOAT"> <parameter default="1" name="ctl_gain" type="FLOAT">
<short_desc>Speed (RPM) controller gain</short_desc> <short_desc>Speed (RPM) controller gain</short_desc>
<long_desc>Speed (RPM) controller gain. Determines controller <long_desc>Speed (RPM) controller gain. Determines controller
aggressiveness; units are amp-seconds per radian. Systems with aggressiveness; units are amp-seconds per radian. Systems with
@@ -24,59 +24,53 @@
decreased. Higher values result in faster response, but may result decreased. Higher values result in faster response, but may result
in oscillation and excessive overshoot. Lower values result in a in oscillation and excessive overshoot. Lower values result in a
slower, smoother response.</long_desc> slower, smoother response.</long_desc>
<unit>amp-seconds per radian</unit> <unit>amp-seconds per radian</unit>
<decimal>3</decimal> <decimal>3</decimal>
<min>0.00</min> <min>0.00</min>
<max>1.00</max> <max>1.00</max>
</parameter> </parameter>
<parameter default="3.5" name="ctl_hz_idle" type="FLOAT"> <parameter default="3.5" name="ctl_hz_idle" type="FLOAT">
<short_desc>Idle speed (e Hz)</short_desc> <short_desc>Idle speed (e Hz)</short_desc>
<long_desc>Idle speed (e Hz)</long_desc> <long_desc>Idle speed (e Hz)</long_desc>
<unit>Hertz</unit> <unit>Hertz</unit>
<decimal>3</decimal> <decimal>3</decimal>
<min>0.0</min> <min>0.0</min>
<max>100.0</max> <max>100.0</max>
</parameter> </parameter>
<parameter default="25" name="ctl_start_rate" type="INT32"> <parameter default="25" name="ctl_start_rate" type="INT32">
<short_desc>Spin-up rate (e Hz/s)</short_desc> <short_desc>Spin-up rate (e Hz/s)</short_desc>
<long_desc>Spin-up rate (e Hz/s)</long_desc> <long_desc>Spin-up rate (e Hz/s)</long_desc>
<unit>Hz/s</unit> <unit>Hz/s</unit>
<decimal></decimal>
<min>5</min> <min>5</min>
<max>1000</max> <max>1000</max>
</parameter> </parameter>
<parameter default="0" name="esc_index" type="INT32"> <parameter default="0" name="esc_index" type="INT32">
<short_desc>Index of this ESC in throttle command messages.</short_desc> <short_desc>Index of this ESC in throttle command messages.</short_desc>
<long_desc>Index of this ESC in throttle command messages.</long_desc> <long_desc>Index of this ESC in throttle command messages.</long_desc>
<unit>Index</unit> <unit>Index</unit>
<decimal></decimal>
<min>0</min> <min>0</min>
<max>15</max> <max>15</max>
</parameter> </parameter>
<parameter default="20034" name="id_ext_status" type="INT32"> <parameter default="20034" name="id_ext_status" type="INT32">
<short_desc>Extended status ID</short_desc> <short_desc>Extended status ID</short_desc>
<long_desc>Extended status ID</long_desc> <long_desc>Extended status ID</long_desc>
<unit></unit>
<decimal></decimal>
<min>1</min> <min>1</min>
<max>1023</max> <max>1000000</max>
</parameter> </parameter>
<parameter default="50000" name="int_ext_status" type="INT32"> <parameter default="50000" name="int_ext_status" type="INT32">
<short_desc>Extended status interval (µs)</short_desc> <short_desc>Extended status interval (µs)</short_desc>
<long_desc>Extended status interval (µs)</long_desc> <long_desc>Extended status interval (µs)</long_desc>
<unit>µs</unit> <unit>µs</unit>
<decimal></decimal>
<min>0</min> <min>0</min>
<max>1000000</max> <max>1000000</max>
</parameter> </parameter>
<parameter default="50000" name="int_status" type="INT32"> <parameter default="50000" name="int_status" type="INT32">
<short_desc>ESC status interval (µs)</short_desc> <short_desc>ESC status interval (µs)</short_desc>
<long_desc>ESC status interval (µs)</long_desc> <long_desc>ESC status interval (µs)</long_desc>
<unit>µs</unit> <unit>µs</unit>
<decimal></decimal>
<max>1000000</max> <max>1000000</max>
</parameter> </parameter>
<parameter default="12" name="mot_i_max" type="FLOAT"> <parameter default="12" name="mot_i_max" type="FLOAT">
<short_desc>Motor current limit in amps</short_desc> <short_desc>Motor current limit in amps</short_desc>
<long_desc>Motor current limit in amps. This determines the maximum <long_desc>Motor current limit in amps. This determines the maximum
current controller setpoint, as well as the maximum allowable current controller setpoint, as well as the maximum allowable
@@ -84,62 +78,60 @@
the continuous current rating listed in the motor’s specification the continuous current rating listed in the motor’s specification
sheet, or set equal to the motor’s specified continuous power sheet, or set equal to the motor’s specified continuous power
divided by the motor voltage limit.</long_desc> divided by the motor voltage limit.</long_desc>
<unit>Amps</unit> <unit>Amps</unit>
<decimal>3</decimal> <decimal>3</decimal>
<min>1</min> <min>1</min>
<max>80</max> <max>80</max>
</parameter> </parameter>
<parameter default="2300" name="mot_kv" type="INT32"> <parameter default="2300" name="mot_kv" type="INT32">
<short_desc>Motor Kv in RPM per volt</short_desc> <short_desc>Motor Kv in RPM per volt</short_desc>
<long_desc>Motor Kv in RPM per volt. This can be taken from the motor’s <long_desc>Motor Kv in RPM per volt. This can be taken from the motor’s
specification sheet; accuracy will help control performance but specification sheet; accuracy will help control performance but
some deviation from the specified value is acceptable.</long_desc> some deviation from the specified value is acceptable.</long_desc>
<unit>RPM/v</unit> <unit>RPM/v</unit>
<decimal>0</decimal>
<min>0</min> <min>0</min>
<max>100</max> <max>4000</max>
</parameter> </parameter>
<parameter default="0.0" name="mot_ls" type="FLOAT"> <parameter default="0.0" name="mot_ls" type="FLOAT">
<short_desc>READ ONLY: Motor inductance in henries.</short_desc> <short_desc>READ ONLY: Motor inductance in henries.</short_desc>
<long_desc>READ ONLY: Motor inductance in henries. This is measured on start-up.</long_desc> <long_desc>READ ONLY: Motor inductance in henries. This is measured on start-up.</long_desc>
<unit>henries</unit> <unit>henries</unit>
<decimal>3</decimal> <decimal>3</decimal>
</parameter> </parameter>
<parameter default="14" name="mot_num_poles" type="INT32"> <parameter default="14" name="mot_num_poles" type="INT32">
<short_desc>Number of motor poles.</short_desc> <short_desc>Number of motor poles.</short_desc>
<long_desc>Number of motor poles. Used to convert mechanical speeds to <long_desc>Number of motor poles. Used to convert mechanical speeds to
electrical speeds. This number should be taken from the motor’s electrical speeds. This number should be taken from the motor’s
specification sheet.</long_desc> specification sheet.</long_desc>
<unit>Poles</unit> <unit>Poles</unit>
<decimal></decimal>
<min>2</min> <min>2</min>
<max>40</max> <max>40</max>
</parameter> </parameter>
<parameter default="0.0" name="mot_rs" type="FLOAT"> <parameter default="0.0" name="mot_rs" type="FLOAT">
<short_desc>READ ONLY: Motor resistance in ohms</short_desc> <short_desc>READ ONLY: Motor resistance in ohms</short_desc>
<long_desc>READ ONLY: Motor resistance in ohms. This is measured on start-up. When <long_desc>READ ONLY: Motor resistance in ohms. This is measured on start-up. When
tuning a new motor, check that this value is approximately equal tuning a new motor, check that this value is approximately equal
to the value shown in the motor’s specification sheet.</long_desc> to the value shown in the motor’s specification sheet.</long_desc>
<unit>Ohms</unit> <unit>Ohms</unit>
<decimal>3</decimal> <decimal>3</decimal>
</parameter> </parameter>
<parameter default=".5" name="mot_v_accel" type="INT32"> <parameter default="0.5" name="mot_v_accel" type="FLOAT">
<short_desc>Acceleration limit (V)</short_desc> <short_desc>Acceleration limit (V)</short_desc>
<long_desc>Acceleration limit (V)</long_desc> <long_desc>Acceleration limit (V)</long_desc>
<unit>Volts</unit> <unit>Volts</unit>
<decimal>3</decimal> <decimal>3</decimal>
<min>0.01</min> <min>0.01</min>
<max>1.00</max> <max>1.00</max>
</parameter> </parameter>
<parameter default="14.8" name="mot_v_max" type="FLOAT"> <parameter default="14.8" name="mot_v_max" type="FLOAT">
<short_desc>Motor voltage limit in volts</short_desc> <short_desc>Motor voltage limit in volts</short_desc>
<long_desc>Motor voltage limit in volts. The current controller’s <long_desc>Motor voltage limit in volts. The current controller’s
commanded voltage will never exceed this value. Note that this may commanded voltage will never exceed this value. Note that this may
safely be above the nominal voltage of the motor; to determine the safely be above the nominal voltage of the motor; to determine the
actual motor voltage limit, divide the motor’s rated power by the actual motor voltage limit, divide the motor’s rated power by the
motor current limit.</long_desc> motor current limit.</long_desc>
<unit>Volts</unit> <unit>Volts</unit>
<decimal>3</decimal> <decimal>3</decimal>
<min>0</min> <min>0</min>
</parameter> </parameter>
</group> </group>
+1 -1
View File
@@ -130,7 +130,7 @@ def main():
# Output to XML file # Output to XML file
if args.xml: if args.xml:
print("Creating XML file " + args.xml) print("Creating XML file " + args.xml)
out = xmlout.XMLOutput(param_groups, args.board, args.inject_xml) out = xmlout.XMLOutput(param_groups, args.board, os.path.join(args.src_path, args.inject_xml))
out.Save(args.xml) out.Save(args.xml)
# Output to DokuWiki tables # Output to DokuWiki tables
+4 -4
View File
@@ -56,8 +56,8 @@ then
export GAZEBO_PLUGIN_PATH=${GAZEBO_PLUGIN_PATH}:$curr_dir/Tools/sitl_gazebo/Build export GAZEBO_PLUGIN_PATH=${GAZEBO_PLUGIN_PATH}:$curr_dir/Tools/sitl_gazebo/Build
# Set the model path so Gazebo finds the airframes # Set the model path so Gazebo finds the airframes
export GAZEBO_MODEL_PATH=${GAZEBO_MODEL_PATH}:$curr_dir/Tools/sitl_gazebo/models export GAZEBO_MODEL_PATH=${GAZEBO_MODEL_PATH}:$curr_dir/Tools/sitl_gazebo/models
# Disable online model lookup since this is quite experimental and unstable # The next line would disable online model lookup, can be commented in, in case of unstable behaviour.
export GAZEBO_MODEL_DATABASE_URI="" # export GAZEBO_MODEL_DATABASE_URI=""
export SITL_GAZEBO_PATH=$curr_dir/Tools/sitl_gazebo export SITL_GAZEBO_PATH=$curr_dir/Tools/sitl_gazebo
mkdir -p Tools/sitl_gazebo/Build mkdir -p Tools/sitl_gazebo/Build
cd Tools/sitl_gazebo/Build cd Tools/sitl_gazebo/Build
@@ -88,9 +88,9 @@ then
ddd --debugger gdb --args mainapp ../../../../${rc_script}_${program} ddd --debugger gdb --args mainapp ../../../../${rc_script}_${program}
elif [ "$debugger" == "valgrind" ] elif [ "$debugger" == "valgrind" ]
then then
valgrind ./mainapp ../../../../${rc_script}_${program} valgrind ./mainapp ../../../../${rc_script}_${program}_${model}
else else
./mainapp ../../../../${rc_script}_${program} ./mainapp ../../../../${rc_script}_${program}_${model}
fi fi
if [ "$program" == "jmavsim" ] if [ "$program" == "jmavsim" ]
@@ -111,6 +111,8 @@ set(config_module_list
lib/geo_lookup lib/geo_lookup
lib/conversion lib/conversion
lib/launchdetection lib/launchdetection
lib/terrain_estimation
lib/runway_takeoff
platforms/nuttx platforms/nuttx
# had to add for cmake, not sure why wasn't in original config # had to add for cmake, not sure why wasn't in original config
@@ -118,6 +118,8 @@ set(config_module_list
lib/geo_lookup lib/geo_lookup
lib/conversion lib/conversion
lib/launchdetection lib/launchdetection
lib/terrain_estimation
lib/runway_takeoff
platforms/nuttx platforms/nuttx
# had to add for cmake, not sure why wasn't in original config # had to add for cmake, not sure why wasn't in original config
+2
View File
@@ -38,6 +38,8 @@ set(config_module_list
lib/geo lib/geo
lib/geo_lookup lib/geo_lookup
lib/conversion lib/conversion
lib/terrain_estimation
lib/runway_takeoff
platforms/common platforms/common
platforms/posix/px4_layer platforms/posix/px4_layer
+2
View File
@@ -56,6 +56,8 @@ set(config_module_list
lib/geo lib/geo
lib/geo_lookup lib/geo_lookup
lib/launchdetection lib/launchdetection
lib/terrain_estimation
lib/runway_takeoff
) )
set(config_extra_builtin_cmds set(config_extra_builtin_cmds
+2
View File
@@ -47,6 +47,8 @@ set(config_module_list
lib/geo lib/geo
lib/geo_lookup lib/geo_lookup
lib/conversion lib/conversion
lib/terrain_estimation
lib/runway_takeoff
modules/controllib modules/controllib
# #
+2
View File
@@ -70,6 +70,8 @@ set(config_module_list
lib/geo lib/geo
lib/geo_lookup lib/geo_lookup
lib/conversion lib/conversion
lib/terrain_estimation
lib/runway_takeoff
# #
# QuRT port # QuRT port
+2
View File
@@ -52,6 +52,8 @@ set(config_module_list
lib/geo_lookup lib/geo_lookup
lib/conversion lib/conversion
lib/ecl lib/ecl
lib/terrain_estimation
lib/runway_takeoff
# #
# QuRT port # QuRT port
+3
View File
@@ -5,6 +5,9 @@ uint8 INDEX_PITCH = 1
uint8 INDEX_YAW = 2 uint8 INDEX_YAW = 2
uint8 INDEX_THROTTLE = 3 uint8 INDEX_THROTTLE = 3
uint8 INDEX_FLAPS = 4 uint8 INDEX_FLAPS = 4
uint8 INDEX_SPOILERS = 5
uint8 INDEX_AIRBRAKES = 6
uint8 INDEX_LANDING_GEAR = 7
uint8 GROUP_INDEX_ATTITUDE = 0 uint8 GROUP_INDEX_ATTITUDE = 0
uint64 timestamp uint64 timestamp
uint64 timestamp_sample # the timestamp the data this control response is based on was sampled uint64 timestamp_sample # the timestamp the data this control response is based on was sampled
+1
View File
@@ -16,3 +16,4 @@ float32[4] q # Attitude Quaternion
float32 roll_rate # Roll body angular rate (rad/s, x forward/y right/z down) float32 roll_rate # Roll body angular rate (rad/s, x forward/y right/z down)
float32 pitch_rate # Pitch body angular rate (rad/s, x forward/y right/z down) float32 pitch_rate # Pitch body angular rate (rad/s, x forward/y right/z down)
float32 yaw_rate # Yaw body angular rate (rad/s, x forward/y right/z down) float32 yaw_rate # Yaw body angular rate (rad/s, x forward/y right/z down)
float32 horz_acc_mag # Magnitude of the horizontal acceleration
+1
View File
@@ -3,3 +3,4 @@ float32 turn_distance # the optimal distance to a waypoint to switch to the nex
float32 landing_horizontal_slope_displacement float32 landing_horizontal_slope_displacement
float32 landing_slope_angle_rad float32 landing_slope_angle_rad
float32 landing_flare_length float32 landing_flare_length
bool abort_landing
+4
View File
@@ -21,3 +21,7 @@ float32 thrust # Thrust in Newton the power system should generate
bool roll_reset_integral # Reset roll integral part (navigation logic change) bool roll_reset_integral # Reset roll integral part (navigation logic change)
bool pitch_reset_integral # Reset pitch integral part (navigation logic change) bool pitch_reset_integral # Reset pitch integral part (navigation logic change)
bool yaw_reset_integral # Reset yaw integral part (navigation logic change) bool yaw_reset_integral # Reset yaw integral part (navigation logic change)
bool fw_control_yaw # control heading with rudder (used for auto takeoff on runway)
bool apply_flaps
+3
View File
@@ -120,6 +120,8 @@ bool in_transition_mode
bool condition_battery_voltage_valid bool condition_battery_voltage_valid
bool condition_system_in_air_restore # true if we can restore in mid air bool condition_system_in_air_restore # true if we can restore in mid air
bool condition_system_sensors_initialized bool condition_system_sensors_initialized
bool condition_system_prearm_error_reported # true if errors have already been reported
bool condition_system_hotplug_timeout # true if the hotplug sensor search is over
bool condition_system_returned_to_home bool condition_system_returned_to_home
bool condition_auto_mission_available bool condition_auto_mission_available
bool condition_global_position_valid # set to true by the commander app if the quality of the position estimate is good enough to use it for navigation bool condition_global_position_valid # set to true by the commander app if the quality of the position estimate is good enough to use it for navigation
@@ -179,3 +181,4 @@ bool circuit_breaker_engaged_power_check
bool circuit_breaker_engaged_airspd_check bool circuit_breaker_engaged_airspd_check
bool circuit_breaker_engaged_enginefailure_check bool circuit_breaker_engaged_enginefailure_check
bool circuit_breaker_engaged_gpsfailure_check bool circuit_breaker_engaged_gpsfailure_check
bool cb_usb
@@ -0,0 +1,64 @@
uorb start
simulator start -s
param load
param set MAV_TYPE 20
param set MC_PITCHRATE_P 0.3
param set MC_ROLLRATE_P 0.3
param set MC_YAW_P 2.0
param set MC_YAWRATE_P 0.35
param set VT_TYPE 0
param set SYS_AUTOSTART 4010
param set SYS_RESTART_TYPE 2
dataman start
param set CAL_GYRO0_ID 2293760
param set CAL_ACC0_ID 1376256
param set CAL_ACC1_ID 1310720
param set CAL_MAG0_ID 196608
param set CAL_GYRO0_XOFF 0.01
param set CAL_ACC0_XOFF 0.01
param set CAL_ACC0_YOFF -0.01
param set CAL_ACC0_ZOFF 0.01
param set CAL_ACC0_XSCALE 1.01
param set CAL_ACC0_YSCALE 1.01
param set CAL_ACC0_ZSCALE 1.01
param set CAL_ACC1_XOFF 0.01
param set CAL_MAG0_XOFF 0.01
param set MPC_XY_P 0.15
param set MPC_XY_VEL_P 0.05
param set MPC_XY_VEL_D 0.005
param set MPC_XY_FF 0.1
param set SENS_BOARD_ROT 8
param set COM_RC_IN_MODE 2
rgbled start
tone_alarm start
gyrosim start
accelsim start
barosim start
adcsim start
gpssim start
measairspeedsim start
pwm_out_sim mode_pwm
sleep 1
sensors start
commander start
land_detector start multicopter
navigator start
attitude_estimator_q start
position_estimator_inav start
vtol_att_control start
mc_pos_control start
mc_att_control start
fw_pos_control_l1 start
fw_att_control start
mixer load /dev/pwm_output0 ../../../../ROMFS/px4fmu_common/mixers/quad_x_vtol.main.mix
mavlink start -u 14556 -r 2000000
mavlink stream -r 80 -s POSITION_TARGET_LOCAL_NED -u 14556
mavlink stream -r 80 -s LOCAL_POSITION_NED -u 14556
mavlink stream -r 80 -s GLOBAL_POSITION_INT -u 14556
mavlink stream -r 80 -s ATTITUDE -u 14556
mavlink stream -r 80 -s ATTITUDE_TARGET -u 14556
mavlink stream -r 20 -s RC_CHANNELS -u 14556
mavlink stream -r 250 -s HIGHRES_IMU -u 14556
mavlink stream -r 10 -s OPTICAL_FLOW_RAD -u 14556
mavlink boot_complete
sdlog2 start -r 100 -e -t -a
@@ -82,6 +82,9 @@ __BEGIN_DECLS
#define GPIO_SPI_CS_GYRO (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_2MHz|GPIO_OUTPUT_SET|GPIO_PORTE|GPIO_PIN3) #define GPIO_SPI_CS_GYRO (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_2MHz|GPIO_OUTPUT_SET|GPIO_PORTE|GPIO_PIN3)
#define GPIO_SPI_CS_BARO (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_2MHz|GPIO_OUTPUT_SET|GPIO_PORTE|GPIO_PIN4) #define GPIO_SPI_CS_BARO (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_2MHz|GPIO_OUTPUT_SET|GPIO_PORTE|GPIO_PIN4)
/* SPI4--Ramtron */
#define PX4_SPI_BUS_RAMTRON 4
/* Nominal chip selects for devices on SPI bus #3 */ /* Nominal chip selects for devices on SPI bus #3 */
#define PX4_SPIDEV_ACCEL_MAG 0 #define PX4_SPIDEV_ACCEL_MAG 0
#define PX4_SPIDEV_GYRO 1 #define PX4_SPIDEV_GYRO 1
@@ -113,6 +113,7 @@ __BEGIN_DECLS
#define GPIO_SPI_CS_EXT3 (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|GPIO_OUTPUT_SET|GPIO_PORTC|GPIO_PIN13) #define GPIO_SPI_CS_EXT3 (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_50MHz|GPIO_OUTPUT_SET|GPIO_PORTC|GPIO_PIN13)
#define PX4_SPI_BUS_SENSORS 1 #define PX4_SPI_BUS_SENSORS 1
#define PX4_SPI_BUS_RAMTRON 2
#define PX4_SPI_BUS_EXT 4 #define PX4_SPI_BUS_EXT 4
/* Use these in place of the spi_dev_e enumeration to select a specific SPI device on SPI1 */ /* Use these in place of the spi_dev_e enumeration to select a specific SPI device on SPI1 */
+1 -1
View File
@@ -548,7 +548,7 @@ PWMSim::control_callback(uintptr_t handle,
const actuator_controls_s *controls = (actuator_controls_s *)handle; const actuator_controls_s *controls = (actuator_controls_s *)handle;
if (_armed) { if (_armed) {
input = controls->control[control_index]; input = controls[control_group].control[control_index];
} else { } else {
/* clamp actuator to zero if not armed */ /* clamp actuator to zero if not armed */
+4
View File
@@ -1469,6 +1469,10 @@ PX4FMU::sensor_reset(int ms)
stm32_gpiowrite(GPIO_SPI_CS_BARO, 1); stm32_gpiowrite(GPIO_SPI_CS_BARO, 1);
stm32_gpiowrite(GPIO_SPI_CS_MPU, 1); stm32_gpiowrite(GPIO_SPI_CS_MPU, 1);
stm32_configgpio(GPIO_SPI1_SCK);
stm32_configgpio(GPIO_SPI1_MISO);
stm32_configgpio(GPIO_SPI1_MOSI);
// // XXX bring up the EXTI pins again // // XXX bring up the EXTI pins again
// stm32_configgpio(GPIO_GYRO_DRDY); // stm32_configgpio(GPIO_GYRO_DRDY);
// stm32_configgpio(GPIO_MAG_DRDY); // stm32_configgpio(GPIO_MAG_DRDY);
+2 -2
View File
@@ -1780,8 +1780,8 @@ PX4IO::io_get_raw_rc_input(rc_input_values &input_rc)
/* get RSSI from input channel */ /* get RSSI from input channel */
if (_rssi_pwm_chan > 0 && _rssi_pwm_chan <= input_rc_s::RC_INPUT_MAX_CHANNELS && _rssi_pwm_max - _rssi_pwm_min != 0) { if (_rssi_pwm_chan > 0 && _rssi_pwm_chan <= input_rc_s::RC_INPUT_MAX_CHANNELS && _rssi_pwm_max - _rssi_pwm_min != 0) {
int rssi = (input_rc.values[_rssi_pwm_chan - 1] - _rssi_pwm_min) / int rssi = ((input_rc.values[_rssi_pwm_chan - 1] - _rssi_pwm_min) * 100) /
((_rssi_pwm_max - _rssi_pwm_min) / 100); (_rssi_pwm_max - _rssi_pwm_min);
rssi = rssi > 100 ? 100 : rssi; rssi = rssi > 100 ? 100 : rssi;
rssi = rssi < 0 ? 0 : rssi; rssi = rssi < 0 ? 0 : rssi;
input_rc.rssi = rssi; input_rc.rssi = rssi;
+1 -1
View File
@@ -36,7 +36,7 @@ add_dependencies(run_config mainapp)
foreach(viewer none jmavsim gazebo) foreach(viewer none jmavsim gazebo)
foreach(debugger none gdb lldb ddd valgrind) foreach(debugger none gdb lldb ddd valgrind)
foreach(model none iris vtol) foreach(model none iris tailsitter)
if (debugger STREQUAL "none") if (debugger STREQUAL "none")
if (model STREQUAL "none") if (model STREQUAL "none")
set(_targ_name "${viewer}") set(_targ_name "${viewer}")
+12 -12
View File
@@ -106,10 +106,10 @@ __EXPORT void mavlink_vasprintf(int _fd, int severity, const char *fmt, ...);
* @param _fd A file descriptor returned from open(MAVLINK_LOG_DEVICE, 0); * @param _fd A file descriptor returned from open(MAVLINK_LOG_DEVICE, 0);
* @param _text The text to log; * @param _text The text to log;
*/ */
#define mavlink_and_console_log_emergency(_fd, _text, ...) mavlink_vasprintf(_fd, MAVLINK_IOC_SEND_TEXT_EMERGENCY, _text, ##__VA_ARGS__); \ #define mavlink_and_console_log_emergency(_fd, _text, ...) do { mavlink_vasprintf(_fd, MAVLINK_IOC_SEND_TEXT_EMERGENCY, _text, ##__VA_ARGS__); \
fprintf(stderr, "telem> "); \ fprintf(stderr, "telem> "); \
fprintf(stderr, _text, ##__VA_ARGS__); \ fprintf(stderr, _text, ##__VA_ARGS__); \
fprintf(stderr, "\n"); fprintf(stderr, "\n"); } while(0);
/** /**
* Send a mavlink critical message and print to console. * Send a mavlink critical message and print to console.
@@ -117,10 +117,10 @@ __EXPORT void mavlink_vasprintf(int _fd, int severity, const char *fmt, ...);
* @param _fd A file descriptor returned from open(MAVLINK_LOG_DEVICE, 0); * @param _fd A file descriptor returned from open(MAVLINK_LOG_DEVICE, 0);
* @param _text The text to log; * @param _text The text to log;
*/ */
#define mavlink_and_console_log_critical(_fd, _text, ...) mavlink_vasprintf(_fd, MAVLINK_IOC_SEND_TEXT_CRITICAL, _text, ##__VA_ARGS__); \ #define mavlink_and_console_log_critical(_fd, _text, ...) do { mavlink_vasprintf(_fd, MAVLINK_IOC_SEND_TEXT_CRITICAL, _text, ##__VA_ARGS__); \
fprintf(stderr, "telem> "); \ fprintf(stderr, "telem> "); \
fprintf(stderr, _text, ##__VA_ARGS__); \ fprintf(stderr, _text, ##__VA_ARGS__); \
fprintf(stderr, "\n"); fprintf(stderr, "\n"); } while(0);
/** /**
* Send a mavlink emergency message and print to console. * Send a mavlink emergency message and print to console.
@@ -128,10 +128,10 @@ __EXPORT void mavlink_vasprintf(int _fd, int severity, const char *fmt, ...);
* @param _fd A file descriptor returned from open(MAVLINK_LOG_DEVICE, 0); * @param _fd A file descriptor returned from open(MAVLINK_LOG_DEVICE, 0);
* @param _text The text to log; * @param _text The text to log;
*/ */
#define mavlink_and_console_log_info(_fd, _text, ...) mavlink_vasprintf(_fd, MAVLINK_IOC_SEND_TEXT_INFO, _text, ##__VA_ARGS__); \ #define mavlink_and_console_log_info(_fd, _text, ...) do { mavlink_vasprintf(_fd, MAVLINK_IOC_SEND_TEXT_INFO, _text, ##__VA_ARGS__); \
fprintf(stderr, "telem> "); \ fprintf(stderr, "telem> "); \
fprintf(stderr, _text, ##__VA_ARGS__); \ fprintf(stderr, _text, ##__VA_ARGS__); \
fprintf(stderr, "\n"); fprintf(stderr, "\n"); } while(0);
struct mavlink_logmessage { struct mavlink_logmessage {
char text[MAVLINK_LOG_MAXLEN + 1]; char text[MAVLINK_LOG_MAXLEN + 1];
+1
View File
@@ -39,6 +39,7 @@ px4_add_module(
attitude_fw/ecl_pitch_controller.cpp attitude_fw/ecl_pitch_controller.cpp
attitude_fw/ecl_roll_controller.cpp attitude_fw/ecl_roll_controller.cpp
attitude_fw/ecl_yaw_controller.cpp attitude_fw/ecl_yaw_controller.cpp
attitude_fw/ecl_wheel_controller.cpp
l1/ecl_l1_pos_controller.cpp l1/ecl_l1_pos_controller.cpp
validation/data_validator.cpp validation/data_validator.cpp
validation/data_validator_group.cpp validation/data_validator_group.cpp
+2
View File
@@ -75,6 +75,8 @@ struct ECL_ControlData {
float airspeed_max; float airspeed_max;
float airspeed; float airspeed;
float scaler; float scaler;
float groundspeed;
float groundspeed_scaler;
bool lock_integrator; bool lock_integrator;
}; };
@@ -0,0 +1,153 @@
/****************************************************************************
*
* Copyright (c) 2013 Estimation and Control Library (ECL). All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name ECL nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file ecl_wheel_controller.cpp
* Implementation of a simple PID wheel controller for heading tracking.
*
* Authors and acknowledgements in header.
*/
#include "ecl_wheel_controller.h"
#include <stdint.h>
#include <float.h>
#include <geo/geo.h>
#include <ecl/ecl.h>
#include <mathlib/mathlib.h>
#include <systemlib/err.h>
#include <ecl/ecl.h>
ECL_WheelController::ECL_WheelController() :
ECL_Controller("wheel")
{
}
ECL_WheelController::~ECL_WheelController()
{
}
float ECL_WheelController::control_bodyrate(const struct ECL_ControlData &ctl_data)
{
/* Do not calculate control signal with bad inputs */
if (!(PX4_ISFINITE(ctl_data.yaw_rate) &&
PX4_ISFINITE(ctl_data.groundspeed) &&
PX4_ISFINITE(ctl_data.groundspeed_scaler))) {
perf_count(_nonfinite_input_perf);
return math::constrain(_last_output, -1.0f, 1.0f);
}
/* get the usual dt estimate */
uint64_t dt_micros = ecl_elapsed_time(&_last_run);
_last_run = ecl_absolute_time();
float dt = (float)dt_micros * 1e-6f;
/* lock integral for long intervals */
bool lock_integrator = ctl_data.lock_integrator;
if (dt_micros > 500000) {
lock_integrator = true;
}
/* input conditioning */
float min_speed = 1.0f;
/* Calculate body angular rate error */
_rate_error = _rate_setpoint - ctl_data.yaw_rate; //body angular rate error
if (!lock_integrator && _k_i > 0.0f && ctl_data.groundspeed > min_speed) {
float id = _rate_error * dt * ctl_data.groundspeed_scaler;
/*
* anti-windup: do not allow integrator to increase if actuator is at limit
*/
if (_last_output < -1.0f) {
/* only allow motion to center: increase value */
id = math::max(id, 0.0f);
} else if (_last_output > 1.0f) {
/* only allow motion to center: decrease value */
id = math::min(id, 0.0f);
}
_integrator += id;
}
/* integrator limit */
//xxx: until start detection is available: integral part in control signal is limited here
float integrator_constrained = math::constrain(_integrator * _k_i, -_integrator_max, _integrator_max);
/* Apply PI rate controller and store non-limited output */
_last_output = _rate_setpoint * _k_ff * ctl_data.groundspeed_scaler +
_rate_error * _k_p * ctl_data.groundspeed_scaler * ctl_data.groundspeed_scaler +
integrator_constrained;
/*warnx("wheel: _last_output: %.4f, _integrator: %.4f, scaler %.4f",
(double)_last_output, (double)_integrator, (double)ctl_data.groundspeed_scaler);*/
return math::constrain(_last_output, -1.0f, 1.0f);
}
float ECL_WheelController::control_attitude(const struct ECL_ControlData &ctl_data)
{
/* Do not calculate control signal with bad inputs */
if (!(PX4_ISFINITE(ctl_data.yaw_setpoint) &&
PX4_ISFINITE(ctl_data.yaw))) {
perf_count(_nonfinite_input_perf);
warnx("not controlling wheel");
return _rate_setpoint;
}
/* Calculate the error */
float yaw_error = ctl_data.yaw_setpoint - ctl_data.yaw;
/* shortest angle (wrap around) */
yaw_error = (float)fmod((float)fmod((yaw_error + M_PI_F), M_TWOPI_F) + M_TWOPI_F, M_TWOPI_F) - M_PI_F;
/*warnx("yaw_error: %.4f", (double)yaw_error);*/
/* Apply P controller: rate setpoint from current error and time constant */
_rate_setpoint = yaw_error / _tc;
/* limit the rate */
if (_max_rate > 0.01f) {
if (_rate_setpoint > 0.0f) {
_rate_setpoint = (_rate_setpoint > _max_rate) ? _max_rate : _rate_setpoint;
} else {
_rate_setpoint = (_rate_setpoint < -_max_rate) ? -_max_rate : _rate_setpoint;
}
}
return _rate_setpoint;
}
@@ -0,0 +1,70 @@
/****************************************************************************
*
* Copyright (c) 2013 Estimation and Control Library (ECL). All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name ECL nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file ecl_wheel_controller.h
* Definition of a simple orthogonal coordinated turn yaw PID controller.
*
* @author Lorenz Meier <lm@inf.ethz.ch>
* @author Thomas Gubler <thomasgubler@gmail.com>
* @author Andreas Antener <andreas@uaventure.com>
*
* Acknowledgements:
*
* The control design is based on a design
* by Paul Riseborough and Andrew Tridgell, 2013,
* which in turn is based on initial work of
* Jonathan Challinger, 2012.
*/
#ifndef ECL_HEADING_CONTROLLER_H
#define ECL_HEADING_CONTROLLER_H
#include <stdbool.h>
#include <stdint.h>
#include "ecl_controller.h"
class __EXPORT ECL_WheelController :
public ECL_Controller
{
public:
ECL_WheelController();
~ECL_WheelController();
float control_attitude(const struct ECL_ControlData &ctl_data);
float control_bodyrate(const struct ECL_ControlData &ctl_data);
};
#endif // ECL_HEADING_CONTROLLER_H
+5 -4
View File
@@ -76,14 +76,15 @@ public:
_coordinated_method = coordinated_method; _coordinated_method = coordinated_method;
} }
protected:
float _coordinated_min_speed;
enum { enum {
COORD_METHOD_OPEN = 0, COORD_METHOD_OPEN = 0,
COORD_METHOD_CLOSEACC = 1, COORD_METHOD_CLOSEACC = 1
}; };
protected:
float _coordinated_min_speed;
float _max_rate;
int32_t _coordinated_method; int32_t _coordinated_method;
float control_bodyrate_impl(const struct ECL_ControlData &ctl_data); float control_bodyrate_impl(const struct ECL_ControlData &ctl_data);
+26 -19
View File
@@ -43,6 +43,7 @@
#include <ecl/ecl.h> #include <ecl/ecl.h>
DataValidator::DataValidator(DataValidator *prev_sibling) : DataValidator::DataValidator(DataValidator *prev_sibling) :
_error_mask(ERROR_FLAG_NO_ERROR),
_time_last(0), _time_last(0),
_timeout_interval(20000), _timeout_interval(20000),
_event_count(0), _event_count(0),
@@ -111,39 +112,45 @@ DataValidator::put(uint64_t timestamp, float val[3], uint64_t error_count_in, in
float float
DataValidator::confidence(uint64_t timestamp) DataValidator::confidence(uint64_t timestamp)
{ {
float ret = 1.0f;
/* check if we have any data */ /* check if we have any data */
if (_time_last == 0) { if (_time_last == 0) {
return 0.0f; _error_mask |= ERROR_FLAG_NO_DATA;
ret = 0.0f;
} }
/* check error count limit */ /* timed out - that's it */
if (_error_count > NORETURN_ERRCOUNT) { if (timestamp - _time_last > _timeout_interval) {
return 0.0f; _error_mask |= ERROR_FLAG_TIMEOUT;
ret = 0.0f;
} }
/* we got the exact same sensor value N times in a row */ /* we got the exact same sensor value N times in a row */
if (_value_equal_count > VALUE_EQUAL_COUNT_MAX) { if (_value_equal_count > VALUE_EQUAL_COUNT_MAX) {
return 0.0f; _error_mask |= ERROR_FLAG_STALE_DATA;
ret = 0.0f;
} }
/* timed out - that's it */ /* check error count limit */
if (timestamp - _time_last > _timeout_interval) { if (_error_count > NORETURN_ERRCOUNT) {
return 0.0f; _error_mask |= ERROR_FLAG_HIGH_ERRCOUNT;
ret = 0.0f;
} }
/* cap error density counter at window size */ /* cap error density counter at window size */
if (_error_density > ERROR_DENSITY_WINDOW) { if (_error_density > ERROR_DENSITY_WINDOW) {
_error_mask |= ERROR_FLAG_HIGH_ERRDENSITY;
_error_density = ERROR_DENSITY_WINDOW; _error_density = ERROR_DENSITY_WINDOW;
} }
/* return local error density for last N measurements */ /* no critical errors */
return 1.0f - (_error_density / ERROR_DENSITY_WINDOW); if(ret > 0.0f) {
} /* return local error density for last N measurements */
ret = 1.0f - (_error_density / ERROR_DENSITY_WINDOW);
int }
DataValidator::priority()
{ return ret;
return _priority;
} }
void void
+23 -1
View File
@@ -91,7 +91,18 @@ public:
* Get the priority of this validator * Get the priority of this validator
* @return the stored priority * @return the stored priority
*/ */
int priority(); int priority() { return (_priority); }
/**
* Get the error state of this validator
* @return the bitmask with the error status
*/
uint32_t state() { return (_error_mask); }
/**
* Reset the error state of this validator
*/
void reset_state() { _error_mask = ERROR_FLAG_NO_ERROR; }
/** /**
* Get the RMS values of this validator * Get the RMS values of this validator
@@ -111,9 +122,20 @@ public:
* @param timeout_interval_us The timeout interval in microseconds * @param timeout_interval_us The timeout interval in microseconds
*/ */
void set_timeout(uint64_t timeout_interval_us) { _timeout_interval = timeout_interval_us; } void set_timeout(uint64_t timeout_interval_us) { _timeout_interval = timeout_interval_us; }
/**
* Data validator error states
*/
static constexpr uint32_t ERROR_FLAG_NO_ERROR = (0x00000000U);
static constexpr uint32_t ERROR_FLAG_NO_DATA = (0x00000001U);
static constexpr uint32_t ERROR_FLAG_STALE_DATA = (0x00000001U << 1);
static constexpr uint32_t ERROR_FLAG_TIMEOUT = (0x00000001U << 2);
static constexpr uint32_t ERROR_FLAG_HIGH_ERRCOUNT = (0x00000001U << 3);
static constexpr uint32_t ERROR_FLAG_HIGH_ERRDENSITY = (0x00000001U << 4);
private: private:
static const unsigned _dimensions = 3; static const unsigned _dimensions = 3;
uint32_t _error_mask; /**< sensor error state */
uint64_t _time_last; /**< last timestamp */ uint64_t _time_last; /**< last timestamp */
uint64_t _timeout_interval; /**< interval in which the datastream times out in us */ uint64_t _timeout_interval; /**< interval in which the datastream times out in us */
uint64_t _event_count; /**< total data counter */ uint64_t _event_count; /**< total data counter */
@@ -138,11 +138,13 @@ DataValidatorGroup::get_best(uint64_t timestamp, int *index)
bool true_failsafe = true; bool true_failsafe = true;
/* check wether the switch was a failsafe or preferring a higher priority sensor */ /* check whether the switch was a failsafe or preferring a higher priority sensor */
if (pre_check_prio != -1 && pre_check_prio < max_priority && if (pre_check_prio != -1 && pre_check_prio < max_priority &&
fabsf(pre_check_confidence - max_confidence) < 0.1f) { fabsf(pre_check_confidence - max_confidence) < 0.1f) {
/* this is not a failover */ /* this is not a failover */
true_failsafe = false; true_failsafe = false;
/* reset error flags, this is likely a hotplug sensor coming online late */
best->reset_state();
} }
/* if we're no initialized, initialize the bookkeeping but do not count a failsafe */ /* if we're no initialized, initialize the bookkeeping but do not count a failsafe */
@@ -199,17 +201,25 @@ void
DataValidatorGroup::print() DataValidatorGroup::print()
{ {
/* print the group's state */ /* print the group's state */
ECL_INFO("validator: best: %d, prev best: %d, failsafe: %s (# %u)", ECL_INFO("validator: best: %d, prev best: %d, failsafe: %s (%u events)",
_curr_best, _prev_best, (_toggle_count > 0) ? "YES" : "NO", _curr_best, _prev_best, (_toggle_count > 0) ? "YES" : "NO",
_toggle_count); _toggle_count);
DataValidator *next = _first; DataValidator *next = _first;
unsigned i = 0; unsigned i = 0;
while (next != nullptr) { while (next != nullptr) {
if (next->used()) { if (next->used()) {
ECL_INFO("sensor #%u, prio: %d", i, next->priority()); uint32_t flags = next->state();
ECL_INFO("sensor #%u, prio: %d, state:%s%s%s%s%s%s", i, next->priority(),
((flags & DataValidator::ERROR_FLAG_NO_DATA) ? " NO_DATA" : ""),
((flags & DataValidator::ERROR_FLAG_STALE_DATA) ? " STALE_DATA" : ""),
((flags & DataValidator::ERROR_FLAG_TIMEOUT) ? " DATA_TIMEOUT" : ""),
((flags & DataValidator::ERROR_FLAG_HIGH_ERRCOUNT) ? " HIGH_ERRCOUNT" : ""),
((flags & DataValidator::ERROR_FLAG_HIGH_ERRDENSITY) ? " HIGH_ERRDENSITY" : ""),
((flags == DataValidator::ERROR_FLAG_NO_ERROR) ? " OK" : ""));
next->print(); next->print();
} }
next = next->sibling(); next = next->sibling();
@@ -222,3 +232,35 @@ DataValidatorGroup::failover_count()
{ {
return _toggle_count; return _toggle_count;
} }
int
DataValidatorGroup::failover_index()
{
DataValidator *next = _first;
unsigned i = 0;
while (next != nullptr) {
if (next->used() && (next->state() != DataValidator::ERROR_FLAG_NO_ERROR) && (i == (unsigned)_prev_best)) {
return i;
}
next = next->sibling();
i++;
}
return -1;
}
uint32_t
DataValidatorGroup::failover_state()
{
DataValidator *next = _first;
unsigned i = 0;
while (next != nullptr) {
if (next->used() && (next->state() != DataValidator::ERROR_FLAG_NO_ERROR) && (i == (unsigned)_prev_best)) {
return next->state();
}
next = next->sibling();
i++;
}
return DataValidator::ERROR_FLAG_NO_ERROR;
}
@@ -80,6 +80,20 @@ public:
* @return the number of failovers * @return the number of failovers
*/ */
unsigned failover_count(); unsigned failover_count();
/**
* Get the index of the failed sensor in the group
*
* @return index of the failed sensor
*/
int failover_index();
/**
* Get the error state of the failed sensor in the group
*
* @return bitmask with erro states of the failed sensor
*/
uint32_t failover_state();
/** /**
* Print the validator value * Print the validator value
+35
View File
@@ -298,6 +298,41 @@ __EXPORT float get_distance_to_next_waypoint(double lat_now, double lon_now, dou
return CONSTANTS_RADIUS_OF_EARTH * c; return CONSTANTS_RADIUS_OF_EARTH * c;
} }
__EXPORT void create_waypoint_from_line_and_dist(double lat_A, double lon_A, double lat_B, double lon_B, float dist,
double *lat_target, double *lon_target)
{
if (fabsf(dist) < FLT_EPSILON) {
*lat_target = lat_A;
*lon_target = lon_A;
} else if (dist >= FLT_EPSILON) {
float heading = get_bearing_to_next_waypoint(lat_A, lon_A, lat_B, lon_B);
waypoint_from_heading_and_distance(lat_A, lon_A, heading, dist, lat_target, lon_target);
} else {
float heading = get_bearing_to_next_waypoint(lat_A, lon_A, lat_B, lon_B);
heading = _wrap_2pi(heading + M_PI_F);
waypoint_from_heading_and_distance(lat_A, lon_A, heading, dist, lat_target, lon_target);
}
}
__EXPORT void waypoint_from_heading_and_distance(double lat_start, double lon_start, float bearing, float dist,
double *lat_target, double *lon_target)
{
bearing = _wrap_2pi(bearing);
double radius_ratio = (double)(fabs(dist) / CONSTANTS_RADIUS_OF_EARTH);
double lat_start_rad = lat_start * M_DEG_TO_RAD;
double lon_start_rad = lon_start * M_DEG_TO_RAD;
*lat_target = asin(sin(lat_start_rad) * cos(radius_ratio) + cos(lat_start_rad) * sin(radius_ratio) * cos((
double)bearing));
*lon_target = lon_start_rad + atan2(sin((double)bearing) * sin(radius_ratio) * cos(lat_start_rad),
cos(radius_ratio) - sin(lat_start_rad) * sin(*lat_target));
*lat_target *= M_RAD_TO_DEG;
*lon_target *= M_RAD_TO_DEG;
}
__EXPORT float get_bearing_to_next_waypoint(double lat_now, double lon_now, double lat_next, double lon_next) __EXPORT float get_bearing_to_next_waypoint(double lat_now, double lon_now, double lat_next, double lon_next)
{ {
double lat_now_rad = lat_now * M_DEG_TO_RAD; double lat_now_rad = lat_now * M_DEG_TO_RAD;
+30
View File
@@ -236,6 +236,36 @@ __EXPORT int globallocalconverter_getref(double *lat_0, double *lon_0, float *al
*/ */
__EXPORT float get_distance_to_next_waypoint(double lat_now, double lon_now, double lat_next, double lon_next); __EXPORT float get_distance_to_next_waypoint(double lat_now, double lon_now, double lat_next, double lon_next);
/**
* Creates a new waypoint C on the line of two given waypoints (A, B) at certain distance
* from waypoint A
*
* @param lat_A waypoint A latitude in degrees (47.1234567°, not 471234567°)
* @param lon_A waypoint A longitude in degrees (8.1234567°, not 81234567°)
* @param lat_B waypoint B latitude in degrees (47.1234567°, not 471234567°)
* @param lon_B waypoint B longitude in degrees (8.1234567°, not 81234567°)
* @param dist distance of target waypoint from waypoint A in meters (can be negative)
* @param lat_target latitude of target waypoint C in degrees (47.1234567°, not 471234567°)
* @param lon_target longitude of target waypoint C in degrees (47.1234567°, not 471234567°)
*/
__EXPORT void create_waypoint_from_line_and_dist(double lat_A, double lon_A, double lat_B, double lon_B, float dist,
double *lat_target, double *lon_target);
/**
* Creates a waypoint from given waypoint, distance and bearing
* see http://www.movable-type.co.uk/scripts/latlong.html
*
* @param lat_start latitude of starting waypoint in degrees (47.1234567°, not 471234567°)
* @param lon_start longitude of starting waypoint in degrees (8.1234567°, not 81234567°)
* @param bearing in rad
* @param distance in meters
* @param lat_target latitude of target waypoint in degrees (47.1234567°, not 471234567°)
* @param lon_target longitude of target waypoint in degrees (47.1234567°, not 471234567°)
*/
__EXPORT void waypoint_from_heading_and_distance(double lat_start, double lon_start, float bearing, float dist,
double *lat_target, double *lon_target);
/** /**
* Returns the bearing to the next waypoint in radians. * Returns the bearing to the next waypoint in radians.
* *
+43
View File
@@ -0,0 +1,43 @@
############################################################################
#
# Copyright (c) 2015 PX4 Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name PX4 nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
px4_add_module(
MODULE lib__runway_takeoff
COMPILE_FLAGS
-Os
SRCS
RunwayTakeoff.cpp
runway_takeoff_params.c
DEPENDS
platforms__common
)
# vim: set noet ft=cmake fenc=utf-8 ff=unix :
+286
View File
@@ -0,0 +1,286 @@
/****************************************************************************
*
* Copyright (c) 2015 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file RunwayTakeoff.cpp
* Runway takeoff handling for fixed-wing UAVs with steerable wheels.
*
* @author Roman Bapst <roman@px4.io>
* @author Andreas Antener <andreas@uaventure.com>
*/
#include <stdbool.h>
#include <stdint.h>
#include <math.h>
#include "RunwayTakeoff.h"
#include <controllib/blocks.hpp>
#include <controllib/block/BlockParam.hpp>
#include <mavlink/mavlink_log.h>
#include <mathlib/mathlib.h>
namespace runwaytakeoff
{
RunwayTakeoff::RunwayTakeoff() :
SuperBlock(NULL, "RWTO"),
_state(),
_initialized(false),
_initialized_time(0),
_init_yaw(0),
_climbout(false),
_throttle_ramp_time(2 * 1e6),
_start_wp(),
_runway_takeoff_enabled(this, "TKOFF"),
_heading_mode(this, "HDG"),
_nav_alt(this, "NAV_ALT"),
_takeoff_throttle(this, "MAX_THR"),
_runway_pitch_sp(this, "PSP"),
_max_takeoff_pitch(this, "MAX_PITCH"),
_max_takeoff_roll(this, "MAX_ROLL"),
_min_airspeed_scaling(this, "AIRSPD_SCL"),
_airspeed_min(this, "FW_AIRSPD_MIN", false),
_climbout_diff(this, "FW_CLMBOUT_DIFF", false)
{
updateParams();
}
RunwayTakeoff::~RunwayTakeoff()
{
}
void RunwayTakeoff::init(float yaw, double current_lat, double current_lon)
{
_init_yaw = yaw;
_initialized = true;
_state = RunwayTakeoffState::THROTTLE_RAMP;
_initialized_time = hrt_absolute_time();
_climbout = true; // this is true until climbout is finished
_start_wp(0) = (float)current_lat;
_start_wp(1) = (float)current_lon;
}
void RunwayTakeoff::update(float airspeed, float alt_agl,
double current_lat, double current_lon, int mavlink_fd)
{
switch (_state) {
case RunwayTakeoffState::THROTTLE_RAMP:
if (hrt_elapsed_time(&_initialized_time) > _throttle_ramp_time) {
_state = RunwayTakeoffState::CLAMPED_TO_RUNWAY;
}
break;
case RunwayTakeoffState::CLAMPED_TO_RUNWAY:
if (airspeed > _airspeed_min.get() * _min_airspeed_scaling.get()) {
_state = RunwayTakeoffState::TAKEOFF;
mavlink_log_info(mavlink_fd, "#Takeoff airspeed reached");
}
break;
case RunwayTakeoffState::TAKEOFF:
if (alt_agl > _nav_alt.get()) {
_state = RunwayTakeoffState::CLIMBOUT;
/*
* If we started in heading hold mode, move the navigation start WP to the current location now.
* The navigator will take this as starting point to navigate towards the takeoff WP.
*/
if (_heading_mode.get() == 0) {
_start_wp(0) = (float)current_lat;
_start_wp(1) = (float)current_lon;
}
mavlink_log_info(mavlink_fd, "#Climbout");
}
break;
case RunwayTakeoffState::CLIMBOUT:
if (alt_agl > _climbout_diff.get()) {
_climbout = false;
_state = RunwayTakeoffState::FLY;
mavlink_log_info(mavlink_fd, "#Navigating to waypoint");
}
break;
default:
break;
}
}
/*
* Returns true as long as we're below navigation altitude
*/
bool RunwayTakeoff::controlYaw()
{
// keep controlling yaw directly until we start navigation
return _state < RunwayTakeoffState::CLIMBOUT;
}
/*
* Returns pitch setpoint to use.
*
* Limited (parameter) as long as the plane is on runway. Otherwise
* use the one from TECS
*/
float RunwayTakeoff::getPitch(float tecsPitch)
{
if (_state <= RunwayTakeoffState::CLAMPED_TO_RUNWAY) {
return math::radians(_runway_pitch_sp.get());
}
return tecsPitch;
}
/*
* Returns the roll setpoint to use.
*/
float RunwayTakeoff::getRoll(float navigatorRoll)
{
// until we have enough ground clearance, set roll to 0
if (_state < RunwayTakeoffState::CLIMBOUT) {
return 0.0f;
}
// allow some roll during climbout
else if (_state < RunwayTakeoffState::FLY) {
return math::constrain(navigatorRoll,
math::radians(-_max_takeoff_roll.get()),
math::radians(_max_takeoff_roll.get()));
}
return navigatorRoll;
}
/*
* Returns the yaw setpoint to use.
*
* In heading hold mode (_heading_mode == 0), it returns initial yaw as long as it's on the
* runway. When it has enough ground clearance we start navigation towards WP.
*/
float RunwayTakeoff::getYaw(float navigatorYaw)
{
if (_heading_mode.get() == 0 && _state < RunwayTakeoffState::CLIMBOUT) {
return _init_yaw;
} else {
return navigatorYaw;
}
}
/*
* Returns the throttle setpoint to use.
*
* Ramps up in the beginning, until it lifts off the runway it is set to
* parameter value, then it returns the TECS throttle.
*/
float RunwayTakeoff::getThrottle(float tecsThrottle)
{
switch (_state) {
case RunwayTakeoffState::THROTTLE_RAMP: {
float throttle = hrt_elapsed_time(&_initialized_time) / (float)_throttle_ramp_time *
_takeoff_throttle.get();
return throttle < _takeoff_throttle.get() ?
throttle :
_takeoff_throttle.get();
}
case RunwayTakeoffState::CLAMPED_TO_RUNWAY:
return _takeoff_throttle.get();
default:
return tecsThrottle;
}
}
bool RunwayTakeoff::resetIntegrators()
{
// reset integrators if we're still on runway
return _state < RunwayTakeoffState::TAKEOFF;
}
/*
* Returns the minimum pitch for TECS to use.
*
* In climbout we either want what was set on the waypoint (sp_min) but at least
* the climbtout minimum pitch (parameter).
* Otherwise use the minimum that is enforced generally (parameter).
*/
float RunwayTakeoff::getMinPitch(float sp_min, float climbout_min, float min)
{
if (_state < RunwayTakeoffState::FLY) {
return math::max(sp_min, climbout_min);
}
else {
return min;
}
}
/*
* Returns the maximum pitch for TECS to use.
*
* Limited by parameter (if set) until climbout is done.
*/
float RunwayTakeoff::getMaxPitch(float max)
{
// use max pitch from parameter if set (> 0.1)
if (_state < RunwayTakeoffState::FLY && _max_takeoff_pitch.get() > 0.1f) {
return _max_takeoff_pitch.get();
}
else {
return max;
}
}
/*
* Returns the "previous" (start) WP for navigation.
*/
math::Vector<2> RunwayTakeoff::getStartWP()
{
return _start_wp;
}
void RunwayTakeoff::reset()
{
_initialized = false;
_state = RunwayTakeoffState::THROTTLE_RAMP;
}
}
+121
View File
@@ -0,0 +1,121 @@
/****************************************************************************
*
* Copyright (c) 2015 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file RunwayTakeoff.h
* Runway takeoff handling for fixed-wing UAVs with steerable wheels.
*
* @author Roman Bapst <roman@px4.io>
* @author Andreas Antener <andreas@uaventure.com>
*/
#ifndef RUNWAYTAKEOFF_H
#define RUNWAYTAKEOFF_H
#include <stdbool.h>
#include <stdint.h>
#include <math.h>
#include <drivers/drv_hrt.h>
#include <controllib/blocks.hpp>
#include <controllib/block/BlockParam.hpp>
#include <mavlink/mavlink_log.h>
#include <mathlib/mathlib.h>
namespace runwaytakeoff
{
enum RunwayTakeoffState {
THROTTLE_RAMP = 0, /**< ramping up throttle */
CLAMPED_TO_RUNWAY = 1, /**< clamped to runway, controlling yaw directly (wheel or rudder) */
TAKEOFF = 2, /**< taking off, get ground clearance, roll 0 */
CLIMBOUT = 3, /**< climbout to safe height before navigation, roll limited */
FLY = 4 /**< fly towards takeoff waypoint */
};
class __EXPORT RunwayTakeoff : public control::SuperBlock
{
public:
RunwayTakeoff();
~RunwayTakeoff();
void init(float yaw, double current_lat, double current_lon);
void update(float airspeed, float alt_agl, double current_lat, double current_lon, int mavlink_fd);
RunwayTakeoffState getState() { return _state; };
bool isInitialized() { return _initialized; };
bool runwayTakeoffEnabled() { return (bool)_runway_takeoff_enabled.get(); };
float getMinAirspeedScaling() { return _min_airspeed_scaling.get(); };
float getInitYaw() { return _init_yaw; };
bool controlYaw();
bool climbout() { return _climbout; };
float getPitch(float tecsPitch);
float getRoll(float navigatorRoll);
float getYaw(float navigatorYaw);
float getThrottle(float tecsThrottle);
bool resetIntegrators();
float getMinPitch(float sp_min, float climbout_min, float min);
float getMaxPitch(float max);
math::Vector<2> getStartWP();
void reset();
protected:
private:
/** state variables **/
RunwayTakeoffState _state;
bool _initialized;
hrt_abstime _initialized_time;
float _init_yaw;
bool _climbout;
unsigned _throttle_ramp_time;
math::Vector<2> _start_wp;
/** parameters **/
control::BlockParamInt _runway_takeoff_enabled;
control::BlockParamInt _heading_mode;
control::BlockParamFloat _nav_alt;
control::BlockParamFloat _takeoff_throttle;
control::BlockParamFloat _runway_pitch_sp;
control::BlockParamFloat _max_takeoff_pitch;
control::BlockParamFloat _max_takeoff_roll;
control::BlockParamFloat _min_airspeed_scaling;
control::BlockParamFloat _airspeed_min;
control::BlockParamFloat _climbout_diff;
};
}
#endif // RUNWAYTAKEOFF_H
@@ -0,0 +1,137 @@
/****************************************************************************
*
* Copyright (c) 2015 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file runway_takeoff_params.c
*
* Parameters for runway takeoff
*
* @author Andreas Antener <andreas@uaventure.com>
*/
#include <px4_config.h>
#include <systemlib/param/param.h>
/**
* Enable or disable runway takeoff with landing gear
*
* 0: disabled, 1: enabled
*
* @min 0
* @max 1
* @group Runway Takeoff
*/
PARAM_DEFINE_INT32(RWTO_TKOFF, 0);
/**
* Specifies which heading should be held during runnway takeoff.
*
* 0: airframe heading, 1: heading towards takeoff waypoint
*
* @min 0
* @max 1
* @group Runway Takeoff
*/
PARAM_DEFINE_INT32(RWTO_HDG, 0);
/**
* Altitude AGL at which we have enough ground clearance to allow some roll.
* Until RWTO_NAV_ALT is reached the plane is held level and only
* rudder is used to keep the heading (see RWTO_HDG). This should be below
* FW_CLMBOUT_DIFF if FW_CLMBOUT_DIFF > 0.
*
* @unit m
* @min 0.0
* @max 100.0
* @group Runway Takeoff
*/
PARAM_DEFINE_FLOAT(RWTO_NAV_ALT, 5.0);
/**
* Max throttle during runway takeoff.
* (Can be used to test taxi on runway)
*
* @min 0.0
* @max 1.0
* @group Runway Takeoff
*/
PARAM_DEFINE_FLOAT(RWTO_MAX_THR, 1.0);
/**
* Pitch setpoint during taxi / before takeoff airspeed is reached.
* A taildragger with stearable wheel might need to pitch up
* a little to keep it's wheel on the ground before airspeed
* to takeoff is reached.
*
* @unit deg
* @min 0.0
* @max 20.0
* @group Runway Takeoff
*/
PARAM_DEFINE_FLOAT(RWTO_PSP, 0.0);
/**
* Max pitch during takeoff.
* Fixed-wing settings are used if set to 0. Note that there is also a minimum
* pitch of 10 degrees during takeoff, so this must be larger if set.
*
* @unit deg
* @min 0.0
* @max 60.0
* @group Runway Takeoff
*/
PARAM_DEFINE_FLOAT(RWTO_MAX_PITCH, 20.0);
/**
* Max roll during climbout.
* Roll is limited during climbout to ensure enough lift and prevents aggressive
* navigation before we're on a safe height.
*
* @unit deg
* @min 0.0
* @max 60.0
* @group Runway Takeoff
*/
PARAM_DEFINE_FLOAT(RWTO_MAX_ROLL, 25.0);
/**
* Min. airspeed scaling factor for takeoff.
* Pitch up will be commanded when the following airspeed is reached:
* FW_AIRSPD_MIN * RWTO_AIRSPD_SCL
*
* @min 0.0
* @max 2.0
* @group Runway Takeoff
*/
PARAM_DEFINE_FLOAT(RWTO_AIRSPD_SCL, 1.3);
+42
View File
@@ -0,0 +1,42 @@
############################################################################
#
# Copyright (c) 2015 PX4 Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name PX4 nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
px4_add_module(
MODULE lib__terrain_estimation
COMPILE_FLAGS
-Os
SRCS
terrain_estimator.cpp
DEPENDS
platforms__common
)
# vim: set noet ft=cmake fenc=utf-8 ff=unix :
@@ -0,0 +1,201 @@
/****************************************************************************
*
* Copyright (c) 2015 Roman Bapst. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file terrain_estimator.cpp
* A terrain estimation kalman filter.
*/
#include "terrain_estimator.h"
#define DISTANCE_TIMEOUT 100000 // time in usec after which laser is considered dead
TerrainEstimator::TerrainEstimator() :
_distance_last(0.0f),
_terrain_valid(false),
_time_last_distance(0),
_time_last_gps(0)
{
memset(&_x._data[0], 0, sizeof(_x._data));
_u_z = 0.0f;
_P.setIdentity();
}
bool TerrainEstimator::is_distance_valid(float distance)
{
if (distance > 40.0f || distance < 0.00001f) {
return false;
} else {
return true;
}
}
void TerrainEstimator::predict(float dt, const struct vehicle_attitude_s *attitude,
const struct sensor_combined_s *sensor,
const struct distance_sensor_s *distance)
{
if (attitude->R_valid) {
matrix::Matrix<float, 3, 3> R_att(attitude->R);
matrix::Vector<float, 3> a(&sensor->accelerometer_m_s2[0]);
matrix::Vector<float, 3> u;
u = R_att * a;
_u_z = u(2) + 9.81f; // compensate for gravity
} else {
_u_z = 0.0f;
}
// dynamics matrix
matrix::Matrix<float, n_x, n_x> A;
A.setZero();
A(0, 1) = 1;
A(1, 2) = 1;
// input matrix
matrix::Matrix<float, n_x, 1> B;
B.setZero();
B(1, 0) = 1;
// input noise variance
float R = 0.135f;
// process noise convariance
matrix::Matrix<float, n_x, n_x> Q;
Q(0, 0) = 0;
Q(1, 1) = 0;
// do prediction
matrix::Vector<float, n_x> dx = (A * _x) * dt;
dx(1) += B(1, 0) * _u_z * dt;
// propagate state and covariance matrix
_x += dx;
_P += (A * _P + _P * A.transpose() +
B * R * B.transpose() + Q) * dt;
}
void TerrainEstimator::measurement_update(uint64_t time_ref, const struct vehicle_gps_position_s *gps,
const struct distance_sensor_s *distance,
const struct vehicle_attitude_s *attitude)
{
// terrain estimate is invalid if we have range sensor timeout
if (time_ref - distance->timestamp > DISTANCE_TIMEOUT) {
_terrain_valid = false;
}
if (distance->timestamp > _time_last_distance) {
float d = distance->current_distance;
matrix::Matrix<float, 1, n_x> C;
C(0, 0) = -1; // measured altitude,
float R = 0.009f;
matrix::Vector<float, 1> y;
y(0) = d * cosf(attitude->roll) * cosf(attitude->pitch);
// residual
matrix::Matrix<float, 1, 1> S_I = (C * _P * C.transpose());
S_I(0, 0) += R;
S_I = matrix::inv<float, 1> (S_I);
matrix::Vector<float, 1> r = y - C * _x;
matrix::Matrix<float, n_x, 1> K = _P * C.transpose() * S_I;
// some sort of outlayer rejection
if (fabsf(distance->current_distance - _distance_last) < 1.0f) {
_x += K * r;
_P -= K * C * _P;
}
// if the current and the last range measurement are bad then we consider the terrain
// estimate to be invalid
if (!is_distance_valid(distance->current_distance) && !is_distance_valid(_distance_last)) {
_terrain_valid = false;
} else {
_terrain_valid = true;
}
_time_last_distance = distance->timestamp;
_distance_last = distance->current_distance;
}
if (gps->timestamp_position > _time_last_gps && gps->fix_type >= 3) {
matrix::Matrix<float, 1, n_x> C;
C(0, 1) = 1;
float R = 0.056f;
matrix::Vector<float, 1> y;
y(0) = gps->vel_d_m_s;
// residual
matrix::Matrix<float, 1, 1> S_I = (C * _P * C.transpose());
S_I(0, 0) += R;
S_I = matrix::inv<float, 1>(S_I);
matrix::Vector<float, 1> r = y - C * _x;
matrix::Matrix<float, n_x, 1> K = _P * C.transpose() * S_I;
_x += K * r;
_P -= K * C * _P;
_time_last_gps = gps->timestamp_position;
}
// reinitialise filter if we find bad data
bool reinit = false;
for (int i = 0; i < n_x; i++) {
if (!PX4_ISFINITE(_x(i))) {
reinit = true;
}
}
for (int i = 0; i < n_x; i++) {
for (int j = 0; j < n_x; j++) {
if (!PX4_ISFINITE(_P(i, j))) {
reinit = true;
}
}
}
if (reinit) {
memset(&_x._data[0], 0, sizeof(_x._data));
_P.setZero();
_P(0, 0) = _P(1, 1) = _P(2, 2) = 0.1f;
}
}
@@ -0,0 +1,100 @@
/****************************************************************************
*
* Copyright (c) 2015 Roman Bapst. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file terrain_estimator.h
*/
#include <lib/mathlib/mathlib.h>
#include "matrix/Matrix.hpp"
#include <uORB/topics/sensor_combined.h>
#include <uORB/topics/vehicle_gps_position.h>
#include <uORB/topics/vehicle_attitude.h>
#include <uORB/topics/distance_sensor.h>
/*
* This class can be used to estimate distance to the ground using a laser range finder.
* It's assumed that the laser points down vertically if the vehicle is in it's neutral pose.
* The predict(...) function will do a state prediciton based on accelerometer inputs. It also
* considers accelerometer bias.
* The measurement_update(...) function does a measurement update based on range finder and gps
* velocity measurements. Both functions should always be called together when there is new
* acceleration data available.
* The is_valid() function provides information whether the estimate is valid.
*/
class __EXPORT TerrainEstimator
{
public:
TerrainEstimator();
~TerrainEstimator() {};
bool is_valid() {return _terrain_valid;}
float get_distance_to_ground() {return -_x(0);}
float get_velocity() {return _x(1);};
void predict(float dt, const struct vehicle_attitude_s *attitude, const struct sensor_combined_s *sensor,
const struct distance_sensor_s *distance);
void measurement_update(uint64_t time_ref, const struct vehicle_gps_position_s *gps,
const struct distance_sensor_s *distance,
const struct vehicle_attitude_s *attitude);
private:
enum {n_x = 3};
float _distance_last;
bool _terrain_valid;
// kalman filter variables
matrix::Vector<float, n_x> _x; // state: ground distance, velocity, accel bias in z direction
float _u_z; // acceleration in earth z direction
matrix::Matrix<float, 3, 3> _P; // covariance matrix
// timestamps
uint64_t _time_last_distance;
uint64_t _time_last_gps;
/*
struct {
float var_acc_z;
float var_p_z;
float var_p_vz;
float var_lidar;
float var_gps_vz;
} _params;
*/
bool is_distance_valid(float distance);
};
@@ -348,10 +348,17 @@ void AttitudeEstimatorQ::task_main()
_voter_gyro.put(i, sensors.gyro_timestamp[i], &gyro[0], sensors.gyro_errcount[i], sensors.gyro_priority[i]); _voter_gyro.put(i, sensors.gyro_timestamp[i], &gyro[0], sensors.gyro_errcount[i], sensors.gyro_priority[i]);
} }
_voter_accel.put(i, sensors.accelerometer_timestamp[i], &sensors.accelerometer_m_s2[i * 3], /* ignore empty fields */
sensors.accelerometer_errcount[i], sensors.accelerometer_priority[i]); if (sensors.accelerometer_timestamp[i] > 0) {
_voter_mag.put(i, sensors.magnetometer_timestamp[i], &sensors.magnetometer_ga[i * 3], _voter_accel.put(i, sensors.accelerometer_timestamp[i], &sensors.accelerometer_m_s2[i * 3],
sensors.magnetometer_errcount[i], sensors.magnetometer_priority[i]); sensors.accelerometer_errcount[i], sensors.accelerometer_priority[i]);
}
/* ignore empty fields */
if (sensors.magnetometer_timestamp[i] > 0) {
_voter_mag.put(i, sensors.magnetometer_timestamp[i], &sensors.magnetometer_ga[i * 3],
sensors.magnetometer_errcount[i], sensors.magnetometer_priority[i]);
}
} }
int best_gyro, best_accel, best_mag; int best_gyro, best_accel, best_mag;
@@ -369,12 +376,48 @@ void AttitudeEstimatorQ::task_main()
_data_good = true; _data_good = true;
if (!_failsafe && (_voter_gyro.failover_count() > 0 || if (!_failsafe) {
_voter_accel.failover_count() > 0 || uint32_t flags = DataValidator::ERROR_FLAG_NO_ERROR;
_voter_mag.failover_count() > 0)) {
_failsafe = true; if (_voter_gyro.failover_count() > 0) {
mavlink_and_console_log_emergency(_mavlink_fd, "SENSOR FAILSAFE! RETURN TO LAND IMMEDIATELY"); _failsafe = true;
flags = _voter_gyro.failover_state();
mavlink_and_console_log_emergency(_mavlink_fd, "Gyro #%i failure :%s%s%s%s%s!",
_voter_gyro.failover_index(),
((flags & DataValidator::ERROR_FLAG_NO_DATA) ? " No data" : ""),
((flags & DataValidator::ERROR_FLAG_STALE_DATA) ? " Stale data" : ""),
((flags & DataValidator::ERROR_FLAG_TIMEOUT) ? " Data timeout" : ""),
((flags & DataValidator::ERROR_FLAG_HIGH_ERRCOUNT) ? " High error count" : ""),
((flags & DataValidator::ERROR_FLAG_HIGH_ERRDENSITY) ? " High error density" : ""));
}
if (_voter_accel.failover_count() > 0) {
_failsafe = true;
flags = _voter_accel.failover_state();
mavlink_and_console_log_emergency(_mavlink_fd, "Accel #%i failure :%s%s%s%s%s!",
_voter_accel.failover_index(),
((flags & DataValidator::ERROR_FLAG_NO_DATA) ? " No data" : ""),
((flags & DataValidator::ERROR_FLAG_STALE_DATA) ? " Stale data" : ""),
((flags & DataValidator::ERROR_FLAG_TIMEOUT) ? " Data timeout" : ""),
((flags & DataValidator::ERROR_FLAG_HIGH_ERRCOUNT) ? " High error count" : ""),
((flags & DataValidator::ERROR_FLAG_HIGH_ERRDENSITY) ? " High error density" : ""));
}
if (_voter_mag.failover_count() > 0) {
_failsafe = true;
flags = _voter_mag.failover_state();
mavlink_and_console_log_emergency(_mavlink_fd, "Mag #%i failure :%s%s%s%s%s!",
_voter_mag.failover_index(),
((flags & DataValidator::ERROR_FLAG_NO_DATA) ? " No data" : ""),
((flags & DataValidator::ERROR_FLAG_STALE_DATA) ? " Stale data" : ""),
((flags & DataValidator::ERROR_FLAG_TIMEOUT) ? " Data timeout" : ""),
((flags & DataValidator::ERROR_FLAG_HIGH_ERRCOUNT) ? " High error count" : ""),
((flags & DataValidator::ERROR_FLAG_HIGH_ERRDENSITY) ? " High error density" : ""));
}
if (_failsafe) {
mavlink_and_console_log_emergency(_mavlink_fd, "SENSOR FAILSAFE! RETURN TO LAND IMMEDIATELY");
}
} }
if (!_vibration_warning && (_voter_gyro.get_vibration_factor(curr_time) > _vibration_warning_threshold || if (!_vibration_warning && (_voter_gyro.get_vibration_factor(curr_time) > _vibration_warning_threshold ||
+1 -1
View File
@@ -37,7 +37,7 @@ endif()
px4_add_module( px4_add_module(
MODULE modules__commander MODULE modules__commander
MAIN commander MAIN commander
STACK 1200 STACK 4096
COMPILE_FLAGS COMPILE_FLAGS
${MODULE_CFLAGS} ${MODULE_CFLAGS}
-Os -Os
+75 -35
View File
@@ -116,7 +116,7 @@ static int check_calibration(DevHandle &h, const char* param_template, int &devi
return !calibration_found; return !calibration_found;
} }
static bool magnometerCheck(int mavlink_fd, unsigned instance, bool optional, int &device_id) static bool magnometerCheck(int mavlink_fd, unsigned instance, bool optional, int &device_id, bool report_fail)
{ {
bool success = true; bool success = true;
@@ -127,8 +127,10 @@ static bool magnometerCheck(int mavlink_fd, unsigned instance, bool optional, in
if (!h.isValid()) { if (!h.isValid()) {
if (!optional) { if (!optional) {
mavlink_and_console_log_critical(mavlink_fd, if (report_fail) {
mavlink_and_console_log_critical(mavlink_fd,
"PREFLIGHT FAIL: NO MAG SENSOR #%u", instance); "PREFLIGHT FAIL: NO MAG SENSOR #%u", instance);
}
} }
return false; return false;
@@ -137,8 +139,10 @@ static bool magnometerCheck(int mavlink_fd, unsigned instance, bool optional, in
int ret = check_calibration(h, "CAL_MAG%u_ID", device_id); int ret = check_calibration(h, "CAL_MAG%u_ID", device_id);
if (ret) { if (ret) {
mavlink_and_console_log_critical(mavlink_fd, if (report_fail) {
mavlink_and_console_log_critical(mavlink_fd,
"PREFLIGHT FAIL: MAG #%u UNCALIBRATED", instance); "PREFLIGHT FAIL: MAG #%u UNCALIBRATED", instance);
}
success = false; success = false;
goto out; goto out;
} }
@@ -146,8 +150,10 @@ static bool magnometerCheck(int mavlink_fd, unsigned instance, bool optional, in
ret = h.ioctl(MAGIOCSELFTEST, 0); ret = h.ioctl(MAGIOCSELFTEST, 0);
if (ret != OK) { if (ret != OK) {
mavlink_and_console_log_critical(mavlink_fd, if (report_fail) {
mavlink_and_console_log_critical(mavlink_fd,
"PREFLIGHT FAIL: MAG #%u SELFTEST FAILED", instance); "PREFLIGHT FAIL: MAG #%u SELFTEST FAILED", instance);
}
success = false; success = false;
goto out; goto out;
} }
@@ -157,7 +163,7 @@ out:
return success; return success;
} }
static bool accelerometerCheck(int mavlink_fd, unsigned instance, bool optional, bool dynamic, int &device_id) static bool accelerometerCheck(int mavlink_fd, unsigned instance, bool optional, bool dynamic, int &device_id, bool report_fail)
{ {
bool success = true; bool success = true;
@@ -168,8 +174,10 @@ static bool accelerometerCheck(int mavlink_fd, unsigned instance, bool optional,
if (!h.isValid()) { if (!h.isValid()) {
if (!optional) { if (!optional) {
mavlink_and_console_log_critical(mavlink_fd, if (report_fail) {
mavlink_and_console_log_critical(mavlink_fd,
"PREFLIGHT FAIL: NO ACCEL SENSOR #%u", instance); "PREFLIGHT FAIL: NO ACCEL SENSOR #%u", instance);
}
} }
return false; return false;
@@ -178,8 +186,10 @@ static bool accelerometerCheck(int mavlink_fd, unsigned instance, bool optional,
int ret = check_calibration(h, "CAL_ACC%u_ID", device_id); int ret = check_calibration(h, "CAL_ACC%u_ID", device_id);
if (ret) { if (ret) {
mavlink_and_console_log_critical(mavlink_fd, if (report_fail) {
mavlink_and_console_log_critical(mavlink_fd,
"PREFLIGHT FAIL: ACCEL #%u UNCALIBRATED", instance); "PREFLIGHT FAIL: ACCEL #%u UNCALIBRATED", instance);
}
success = false; success = false;
goto out; goto out;
} }
@@ -187,8 +197,10 @@ static bool accelerometerCheck(int mavlink_fd, unsigned instance, bool optional,
ret = h.ioctl(ACCELIOCSELFTEST, 0); ret = h.ioctl(ACCELIOCSELFTEST, 0);
if (ret != OK) { if (ret != OK) {
mavlink_and_console_log_critical(mavlink_fd, if (report_fail) {
mavlink_and_console_log_critical(mavlink_fd,
"PREFLIGHT FAIL: ACCEL #%u SELFTEST FAILED", instance); "PREFLIGHT FAIL: ACCEL #%u SELFTEST FAILED", instance);
}
success = false; success = false;
goto out; goto out;
} }
@@ -204,13 +216,17 @@ static bool accelerometerCheck(int mavlink_fd, unsigned instance, bool optional,
float accel_magnitude = sqrtf(acc.x * acc.x + acc.y * acc.y + acc.z * acc.z); float accel_magnitude = sqrtf(acc.x * acc.x + acc.y * acc.y + acc.z * acc.z);
if (accel_magnitude < 4.0f || accel_magnitude > 15.0f /* m/s^2 */) { if (accel_magnitude < 4.0f || accel_magnitude > 15.0f /* m/s^2 */) {
mavlink_and_console_log_critical(mavlink_fd, "PREFLIGHT FAIL: ACCEL RANGE, hold still on arming"); if (report_fail) {
mavlink_and_console_log_critical(mavlink_fd, "PREFLIGHT FAIL: ACCEL RANGE, hold still on arming");
}
/* this is frickin' fatal */ /* this is frickin' fatal */
success = false; success = false;
goto out; goto out;
} }
} else { } else {
mavlink_log_critical(mavlink_fd, "PREFLIGHT FAIL: ACCEL READ"); if (report_fail) {
mavlink_and_console_log_critical(mavlink_fd, "PREFLIGHT FAIL: ACCEL READ");
}
/* this is frickin' fatal */ /* this is frickin' fatal */
success = false; success = false;
goto out; goto out;
@@ -223,7 +239,7 @@ out:
return success; return success;
} }
static bool gyroCheck(int mavlink_fd, unsigned instance, bool optional, int &device_id) static bool gyroCheck(int mavlink_fd, unsigned instance, bool optional, int &device_id, bool report_fail)
{ {
bool success = true; bool success = true;
@@ -234,8 +250,10 @@ static bool gyroCheck(int mavlink_fd, unsigned instance, bool optional, int &dev
if (!h.isValid()) { if (!h.isValid()) {
if (!optional) { if (!optional) {
mavlink_and_console_log_critical(mavlink_fd, if (report_fail) {
mavlink_and_console_log_critical(mavlink_fd,
"PREFLIGHT FAIL: NO GYRO SENSOR #%u", instance); "PREFLIGHT FAIL: NO GYRO SENSOR #%u", instance);
}
} }
return false; return false;
@@ -244,8 +262,10 @@ static bool gyroCheck(int mavlink_fd, unsigned instance, bool optional, int &dev
int ret = check_calibration(h, "CAL_GYRO%u_ID", device_id); int ret = check_calibration(h, "CAL_GYRO%u_ID", device_id);
if (ret) { if (ret) {
mavlink_and_console_log_critical(mavlink_fd, if (report_fail) {
mavlink_and_console_log_critical(mavlink_fd,
"PREFLIGHT FAIL: GYRO #%u UNCALIBRATED", instance); "PREFLIGHT FAIL: GYRO #%u UNCALIBRATED", instance);
}
success = false; success = false;
goto out; goto out;
} }
@@ -253,8 +273,10 @@ static bool gyroCheck(int mavlink_fd, unsigned instance, bool optional, int &dev
ret = h.ioctl(GYROIOCSELFTEST, 0); ret = h.ioctl(GYROIOCSELFTEST, 0);
if (ret != OK) { if (ret != OK) {
mavlink_and_console_log_critical(mavlink_fd, if (report_fail) {
mavlink_and_console_log_critical(mavlink_fd,
"PREFLIGHT FAIL: GYRO #%u SELFTEST FAILED", instance); "PREFLIGHT FAIL: GYRO #%u SELFTEST FAILED", instance);
}
success = false; success = false;
goto out; goto out;
} }
@@ -264,7 +286,7 @@ out:
return success; return success;
} }
static bool baroCheck(int mavlink_fd, unsigned instance, bool optional, int &device_id) static bool baroCheck(int mavlink_fd, unsigned instance, bool optional, int &device_id, bool report_fail)
{ {
bool success = true; bool success = true;
@@ -275,8 +297,10 @@ static bool baroCheck(int mavlink_fd, unsigned instance, bool optional, int &dev
if (!h.isValid()) { if (!h.isValid()) {
if (!optional) { if (!optional) {
mavlink_and_console_log_critical(mavlink_fd, if (report_fail) {
mavlink_and_console_log_critical(mavlink_fd,
"PREFLIGHT FAIL: NO BARO SENSOR #%u", instance); "PREFLIGHT FAIL: NO BARO SENSOR #%u", instance);
}
} }
return false; return false;
@@ -300,7 +324,7 @@ static bool baroCheck(int mavlink_fd, unsigned instance, bool optional, int &dev
return success; return success;
} }
static bool airspeedCheck(int mavlink_fd, bool optional) static bool airspeedCheck(int mavlink_fd, bool optional, bool report_fail)
{ {
bool success = true; bool success = true;
int ret; int ret;
@@ -310,13 +334,17 @@ static bool airspeedCheck(int mavlink_fd, bool optional)
if ((ret = orb_copy(ORB_ID(airspeed), fd, &airspeed)) || if ((ret = orb_copy(ORB_ID(airspeed), fd, &airspeed)) ||
(hrt_elapsed_time(&airspeed.timestamp) > (500 * 1000))) { (hrt_elapsed_time(&airspeed.timestamp) > (500 * 1000))) {
mavlink_and_console_log_critical(mavlink_fd, "PREFLIGHT FAIL: AIRSPEED SENSOR MISSING"); if (report_fail) {
mavlink_and_console_log_critical(mavlink_fd, "PREFLIGHT FAIL: AIRSPEED SENSOR MISSING");
}
success = false; success = false;
goto out; goto out;
} }
if (fabsf(airspeed.indicated_airspeed_m_s) > 6.0f) { if (fabsf(airspeed.indicated_airspeed_m_s) > 6.0f) {
mavlink_and_console_log_critical(mavlink_fd, "AIRSPEED WARNING: WIND OR CALIBRATION ISSUE"); if (report_fail) {
mavlink_and_console_log_critical(mavlink_fd, "AIRSPEED WARNING: WIND OR CALIBRATION ISSUE");
}
// XXX do not make this fatal yet // XXX do not make this fatal yet
} }
@@ -325,7 +353,7 @@ out:
return success; return success;
} }
static bool gnssCheck(int mavlink_fd) static bool gnssCheck(int mavlink_fd, bool report_fail)
{ {
bool success = true; bool success = true;
@@ -347,8 +375,10 @@ static bool gnssCheck(int mavlink_fd)
} }
//Report failure to detect module //Report failure to detect module
if(!success) { if (!success) {
mavlink_and_console_log_critical(mavlink_fd, "PREFLIGHT FAIL: GPS RECEIVER MISSING"); if (report_fail) {
mavlink_and_console_log_critical(mavlink_fd, "PREFLIGHT FAIL: GPS RECEIVER MISSING");
}
} }
px4_close(gpsSub); px4_close(gpsSub);
@@ -356,7 +386,7 @@ static bool gnssCheck(int mavlink_fd)
} }
bool preflightCheck(int mavlink_fd, bool checkMag, bool checkAcc, bool checkGyro, bool preflightCheck(int mavlink_fd, bool checkMag, bool checkAcc, bool checkGyro,
bool checkBaro, bool checkAirspeed, bool checkRC, bool checkGNSS, bool checkDynamic) bool checkBaro, bool checkAirspeed, bool checkRC, bool checkGNSS, bool checkDynamic, bool reportFailures)
{ {
bool failed = false; bool failed = false;
@@ -371,7 +401,7 @@ bool preflightCheck(int mavlink_fd, bool checkMag, bool checkAcc, bool checkGyro
bool required = (i < max_mandatory_mag_count); bool required = (i < max_mandatory_mag_count);
int device_id = -1; int device_id = -1;
if (!magnometerCheck(mavlink_fd, i, !required, device_id) && required) { if (!magnometerCheck(mavlink_fd, i, !required, device_id, reportFailures) && required) {
failed = true; failed = true;
} }
@@ -382,7 +412,9 @@ bool preflightCheck(int mavlink_fd, bool checkMag, bool checkAcc, bool checkGyro
/* check if the primary device is present */ /* check if the primary device is present */
if (!prime_found && prime_id != 0) { if (!prime_found && prime_id != 0) {
mavlink_log_critical(mavlink_fd, "warning: primary compass not operational"); if (reportFailures) {
mavlink_and_console_log_critical(mavlink_fd, "Warning: Primary compass not found");
}
failed = true; failed = true;
} }
} }
@@ -398,7 +430,7 @@ bool preflightCheck(int mavlink_fd, bool checkMag, bool checkAcc, bool checkGyro
bool required = (i < max_mandatory_accel_count); bool required = (i < max_mandatory_accel_count);
int device_id = -1; int device_id = -1;
if (!accelerometerCheck(mavlink_fd, i, !required, checkDynamic, device_id) && required) { if (!accelerometerCheck(mavlink_fd, i, !required, checkDynamic, device_id, reportFailures) && required) {
failed = true; failed = true;
} }
@@ -409,7 +441,9 @@ bool preflightCheck(int mavlink_fd, bool checkMag, bool checkAcc, bool checkGyro
/* check if the primary device is present */ /* check if the primary device is present */
if (!prime_found && prime_id != 0) { if (!prime_found && prime_id != 0) {
mavlink_log_critical(mavlink_fd, "warning: primary accelerometer not operational"); if (reportFailures) {
mavlink_and_console_log_critical(mavlink_fd, "Warning: Primary accelerometer not found");
}
failed = true; failed = true;
} }
} }
@@ -425,7 +459,7 @@ bool preflightCheck(int mavlink_fd, bool checkMag, bool checkAcc, bool checkGyro
bool required = (i < max_mandatory_gyro_count); bool required = (i < max_mandatory_gyro_count);
int device_id = -1; int device_id = -1;
if (!gyroCheck(mavlink_fd, i, !required, device_id) && required) { if (!gyroCheck(mavlink_fd, i, !required, device_id, reportFailures) && required) {
failed = true; failed = true;
} }
@@ -436,7 +470,9 @@ bool preflightCheck(int mavlink_fd, bool checkMag, bool checkAcc, bool checkGyro
/* check if the primary device is present */ /* check if the primary device is present */
if (!prime_found && prime_id != 0) { if (!prime_found && prime_id != 0) {
mavlink_log_critical(mavlink_fd, "warning: primary gyro not operational"); if (reportFailures) {
mavlink_and_console_log_critical(mavlink_fd, "Warning: Primary gyro not found");
}
failed = true; failed = true;
} }
} }
@@ -452,7 +488,7 @@ bool preflightCheck(int mavlink_fd, bool checkMag, bool checkAcc, bool checkGyro
bool required = (i < max_mandatory_baro_count); bool required = (i < max_mandatory_baro_count);
int device_id = -1; int device_id = -1;
if (!baroCheck(mavlink_fd, i, !required, device_id) && required) { if (!baroCheck(mavlink_fd, i, !required, device_id, reportFailures) && required) {
failed = true; failed = true;
} }
@@ -464,29 +500,33 @@ bool preflightCheck(int mavlink_fd, bool checkMag, bool checkAcc, bool checkGyro
// TODO there is no logic in place to calibrate the primary baro yet // TODO there is no logic in place to calibrate the primary baro yet
// // check if the primary device is present // // check if the primary device is present
if (!prime_found && prime_id != 0) { if (!prime_found && prime_id != 0) {
mavlink_log_critical(mavlink_fd, "warning: primary barometer not operational"); if (reportFailures) {
mavlink_and_console_log_critical(mavlink_fd, "warning: primary barometer not operational");
}
failed = true; failed = true;
} }
} }
/* ---- AIRSPEED ---- */ /* ---- AIRSPEED ---- */
if (checkAirspeed) { if (checkAirspeed) {
if (!airspeedCheck(mavlink_fd, true)) { if (!airspeedCheck(mavlink_fd, true, reportFailures)) {
failed = true; failed = true;
} }
} }
/* ---- RC CALIBRATION ---- */ /* ---- RC CALIBRATION ---- */
if (checkRC) { if (checkRC) {
if (rc_calibration_check(mavlink_fd) != OK) { if (rc_calibration_check(mavlink_fd, reportFailures) != OK) {
mavlink_log_critical(mavlink_fd, "RC calibration check failed"); if (reportFailures) {
mavlink_and_console_log_critical(mavlink_fd, "RC calibration check failed");
}
failed = true; failed = true;
} }
} }
/* ---- Global Navigation Satellite System receiver ---- */ /* ---- Global Navigation Satellite System receiver ---- */
if (checkGNSS) { if (checkGNSS) {
if(!gnssCheck(mavlink_fd)) { if (!gnssCheck(mavlink_fd, reportFailures)) {
failed = true; failed = true;
} }
} }
+1 -1
View File
@@ -67,7 +67,7 @@ namespace Commander
* true if the GNSS receiver should be checked * true if the GNSS receiver should be checked
**/ **/
bool preflightCheck(int mavlink_fd, bool checkMag, bool checkAcc, bool preflightCheck(int mavlink_fd, bool checkMag, bool checkAcc,
bool checkGyro, bool checkBaro, bool checkAirspeed, bool checkRC, bool checkGNSS, bool checkDynamic = false); bool checkGyro, bool checkBaro, bool checkAirspeed, bool checkRC, bool checkGNSS, bool checkDynamic, bool reportFailures = false);
const unsigned max_mandatory_gyro_count = 1; const unsigned max_mandatory_gyro_count = 1;
const unsigned max_optional_gyro_count = 3; const unsigned max_optional_gyro_count = 3;
+20 -20
View File
@@ -68,7 +68,7 @@ static const char *sensor_name = "dpress";
static void feedback_calibration_failed(int mavlink_fd) static void feedback_calibration_failed(int mavlink_fd)
{ {
sleep(5); sleep(5);
mavlink_log_critical(mavlink_fd, CAL_QGC_FAILED_MSG, sensor_name); mavlink_and_console_log_critical(mavlink_fd, CAL_QGC_FAILED_MSG, sensor_name);
} }
int do_airspeed_calibration(int mavlink_fd) int do_airspeed_calibration(int mavlink_fd)
@@ -78,7 +78,7 @@ int do_airspeed_calibration(int mavlink_fd)
const unsigned maxcount = 2400; const unsigned maxcount = 2400;
/* give directions */ /* give directions */
mavlink_log_info(mavlink_fd, CAL_QGC_STARTED_MSG, sensor_name); mavlink_and_console_log_info(mavlink_fd, CAL_QGC_STARTED_MSG, sensor_name);
const unsigned calibration_count = (maxcount * 2) / 3; const unsigned calibration_count = (maxcount * 2) / 3;
@@ -101,7 +101,7 @@ int do_airspeed_calibration(int mavlink_fd)
paramreset_successful = true; paramreset_successful = true;
} else { } else {
mavlink_log_critical(mavlink_fd, "[cal] airspeed offset zero failed"); mavlink_and_console_log_critical(mavlink_fd, "[cal] airspeed offset zero failed");
} }
px4_close(fd); px4_close(fd);
@@ -115,18 +115,18 @@ int do_airspeed_calibration(int mavlink_fd)
float analog_scaling = 0.0f; float analog_scaling = 0.0f;
param_get(param_find("SENS_DPRES_ANSC"), &(analog_scaling)); param_get(param_find("SENS_DPRES_ANSC"), &(analog_scaling));
if (fabsf(analog_scaling) < 0.1f) { if (fabsf(analog_scaling) < 0.1f) {
mavlink_log_critical(mavlink_fd, "[cal] No airspeed sensor, see http://px4.io/help/aspd"); mavlink_and_console_log_critical(mavlink_fd, "[cal] No airspeed sensor, see http://px4.io/help/aspd");
goto error_return; goto error_return;
} }
/* set scaling offset parameter */ /* set scaling offset parameter */
if (param_set(param_find("SENS_DPRES_OFF"), &(diff_pres_offset))) { if (param_set(param_find("SENS_DPRES_OFF"), &(diff_pres_offset))) {
mavlink_log_critical(mavlink_fd, CAL_ERROR_SET_PARAMS_MSG); mavlink_and_console_log_critical(mavlink_fd, CAL_ERROR_SET_PARAMS_MSG, 1);
goto error_return; goto error_return;
} }
} }
mavlink_log_critical(mavlink_fd, "[cal] Ensure sensor is not measuring wind"); mavlink_and_console_log_critical(mavlink_fd, "[cal] Ensure sensor is not measuring wind");
usleep(500 * 1000); usleep(500 * 1000);
while (calibration_counter < calibration_count) { while (calibration_counter < calibration_count) {
@@ -149,7 +149,7 @@ int do_airspeed_calibration(int mavlink_fd)
calibration_counter++; calibration_counter++;
if (calibration_counter % (calibration_count / 20) == 0) { if (calibration_counter % (calibration_count / 20) == 0) {
mavlink_log_info(mavlink_fd, CAL_QGC_PROGRESS_MSG, (calibration_counter * 80) / calibration_count); mavlink_and_console_log_info(mavlink_fd, CAL_QGC_PROGRESS_MSG, (calibration_counter * 80) / calibration_count);
} }
} else if (poll_ret == 0) { } else if (poll_ret == 0) {
@@ -167,14 +167,14 @@ int do_airspeed_calibration(int mavlink_fd)
airscale.offset_pa = diff_pres_offset; airscale.offset_pa = diff_pres_offset;
if (fd_scale > 0) { if (fd_scale > 0) {
if (OK != px4_ioctl(fd_scale, AIRSPEEDIOCSSCALE, (long unsigned int)&airscale)) { if (OK != px4_ioctl(fd_scale, AIRSPEEDIOCSSCALE, (long unsigned int)&airscale)) {
mavlink_log_critical(mavlink_fd, "[cal] airspeed offset update failed"); mavlink_and_console_log_critical(mavlink_fd, "[cal] airspeed offset update failed");
} }
px4_close(fd_scale); px4_close(fd_scale);
} }
if (param_set(param_find("SENS_DPRES_OFF"), &(diff_pres_offset))) { if (param_set(param_find("SENS_DPRES_OFF"), &(diff_pres_offset))) {
mavlink_log_critical(mavlink_fd, CAL_ERROR_SET_PARAMS_MSG); mavlink_and_console_log_critical(mavlink_fd, CAL_ERROR_SET_PARAMS_MSG, 1);
goto error_return; goto error_return;
} }
@@ -183,7 +183,7 @@ int do_airspeed_calibration(int mavlink_fd)
if (save_ret != 0) { if (save_ret != 0) {
warn("WARNING: auto-save of params to storage failed"); warn("WARNING: auto-save of params to storage failed");
mavlink_log_critical(mavlink_fd, CAL_ERROR_SAVE_PARAMS_MSG); mavlink_and_console_log_critical(mavlink_fd, CAL_ERROR_SAVE_PARAMS_MSG);
goto error_return; goto error_return;
} }
@@ -192,12 +192,12 @@ int do_airspeed_calibration(int mavlink_fd)
goto error_return; goto error_return;
} }
mavlink_log_critical(mavlink_fd, "[cal] Offset of %d Pascal", (int)diff_pres_offset); mavlink_and_console_log_critical(mavlink_fd, "[cal] Offset of %d Pascal", (int)diff_pres_offset);
/* wait 500 ms to ensure parameter propagated through the system */ /* wait 500 ms to ensure parameter propagated through the system */
usleep(500 * 1000); usleep(500 * 1000);
mavlink_log_critical(mavlink_fd, "[cal] Create airflow now"); mavlink_and_console_log_critical(mavlink_fd, "[cal] Create airflow now");
calibration_counter = 0; calibration_counter = 0;
@@ -222,7 +222,7 @@ int do_airspeed_calibration(int mavlink_fd)
if (fabsf(diff_pres.differential_pressure_raw_pa) < 50.0f) { if (fabsf(diff_pres.differential_pressure_raw_pa) < 50.0f) {
if (calibration_counter % 500 == 0) { if (calibration_counter % 500 == 0) {
mavlink_log_info(mavlink_fd, "[cal] Create air pressure! (got %d, wanted: 50 Pa)", mavlink_and_console_log_info(mavlink_fd, "[cal] Create air pressure! (got %d, wanted: 50 Pa)",
(int)diff_pres.differential_pressure_raw_pa); (int)diff_pres.differential_pressure_raw_pa);
} }
continue; continue;
@@ -230,26 +230,26 @@ int do_airspeed_calibration(int mavlink_fd)
/* do not allow negative values */ /* do not allow negative values */
if (diff_pres.differential_pressure_raw_pa < 0.0f) { if (diff_pres.differential_pressure_raw_pa < 0.0f) {
mavlink_log_info(mavlink_fd, "[cal] Negative pressure difference detected (%d Pa)", mavlink_and_console_log_info(mavlink_fd, "[cal] Negative pressure difference detected (%d Pa)",
(int)diff_pres.differential_pressure_raw_pa); (int)diff_pres.differential_pressure_raw_pa);
mavlink_log_info(mavlink_fd, "[cal] Swap static and dynamic ports!"); mavlink_and_console_log_info(mavlink_fd, "[cal] Swap static and dynamic ports!");
/* the user setup is wrong, wipe the calibration to force a proper re-calibration */ /* the user setup is wrong, wipe the calibration to force a proper re-calibration */
diff_pres_offset = 0.0f; diff_pres_offset = 0.0f;
if (param_set(param_find("SENS_DPRES_OFF"), &(diff_pres_offset))) { if (param_set(param_find("SENS_DPRES_OFF"), &(diff_pres_offset))) {
mavlink_log_critical(mavlink_fd, CAL_ERROR_SET_PARAMS_MSG); mavlink_and_console_log_critical(mavlink_fd, CAL_ERROR_SET_PARAMS_MSG, 1);
goto error_return; goto error_return;
} }
/* save */ /* save */
mavlink_log_info(mavlink_fd, CAL_QGC_PROGRESS_MSG, 0); mavlink_and_console_log_info(mavlink_fd, CAL_QGC_PROGRESS_MSG, 0);
(void)param_save_default(); (void)param_save_default();
feedback_calibration_failed(mavlink_fd); feedback_calibration_failed(mavlink_fd);
goto error_return; goto error_return;
} else { } else {
mavlink_log_info(mavlink_fd, "[cal] Positive pressure: OK (%d Pa)", mavlink_and_console_log_info(mavlink_fd, "[cal] Positive pressure: OK (%d Pa)",
(int)diff_pres.differential_pressure_raw_pa); (int)diff_pres.differential_pressure_raw_pa);
break; break;
} }
@@ -266,9 +266,9 @@ int do_airspeed_calibration(int mavlink_fd)
goto error_return; goto error_return;
} }
mavlink_log_info(mavlink_fd, CAL_QGC_PROGRESS_MSG, 100); mavlink_and_console_log_info(mavlink_fd, CAL_QGC_PROGRESS_MSG, 100);
mavlink_log_info(mavlink_fd, CAL_QGC_DONE_MSG, sensor_name); mavlink_and_console_log_info(mavlink_fd, CAL_QGC_DONE_MSG, sensor_name);
tune_neutral(true); tune_neutral(true);
normal_return: normal_return:
+71 -27
View File
@@ -148,6 +148,8 @@ static constexpr uint8_t COMMANDER_MAX_GPS_NOISE = 60; /**< Maximum percentage
#define OFFBOARD_TIMEOUT 500000 #define OFFBOARD_TIMEOUT 500000
#define DIFFPRESS_TIMEOUT 2000000 #define DIFFPRESS_TIMEOUT 2000000
#define HOTPLUG_SENS_TIMEOUT (8 * 1000 * 1000) /**< wait for hotplug sensors to come online for upto 10 seconds */
#define PRINT_INTERVAL 5000000 #define PRINT_INTERVAL 5000000
#define PRINT_MODE_REJECT_INTERVAL 10000000 #define PRINT_MODE_REJECT_INTERVAL 10000000
@@ -299,7 +301,7 @@ int commander_main(int argc, char *argv[])
daemon_task = px4_task_spawn_cmd("commander", daemon_task = px4_task_spawn_cmd("commander",
SCHED_DEFAULT, SCHED_DEFAULT,
SCHED_PRIORITY_MAX - 40, SCHED_PRIORITY_MAX - 40,
3500, 3600,
commander_thread_main, commander_thread_main,
(char * const *)&argv[0]); (char * const *)&argv[0]);
@@ -360,6 +362,8 @@ int commander_main(int argc, char *argv[])
calib_ret = do_level_calibration(mavlink_fd); calib_ret = do_level_calibration(mavlink_fd);
} else if (!strcmp(argv[2], "esc")) { } else if (!strcmp(argv[2], "esc")) {
calib_ret = do_esc_calibration(mavlink_fd, &armed); calib_ret = do_esc_calibration(mavlink_fd, &armed);
} else if (!strcmp(argv[2], "airspeed")) {
calib_ret = do_airspeed_calibration(mavlink_fd);
} else { } else {
warnx("argument %s unsupported.", argv[2]); warnx("argument %s unsupported.", argv[2]);
} }
@@ -377,23 +381,31 @@ int commander_main(int argc, char *argv[])
if (!strcmp(argv[1], "check")) { if (!strcmp(argv[1], "check")) {
int mavlink_fd_local = px4_open(MAVLINK_LOG_DEVICE, 0); int mavlink_fd_local = px4_open(MAVLINK_LOG_DEVICE, 0);
int checkres = prearm_check(&status, mavlink_fd_local); int checkres = 0;
checkres = preflight_check(&status, mavlink_fd_local, false, true);
warnx("Preflight check: %s", (checkres == 0) ? "OK" : "FAILED");
checkres = preflight_check(&status, mavlink_fd_local, true, true);
warnx("Prearm check: %s", (checkres == 0) ? "OK" : "FAILED");
px4_close(mavlink_fd_local); px4_close(mavlink_fd_local);
warnx("FINAL RESULT: %s", (checkres == 0) ? "OK" : "FAILED");
return 0; return 0;
} }
if (!strcmp(argv[1], "arm")) { if (!strcmp(argv[1], "arm")) {
int mavlink_fd_local = px4_open(MAVLINK_LOG_DEVICE, 0); int mavlink_fd_local = px4_open(MAVLINK_LOG_DEVICE, 0);
arm_disarm(true, mavlink_fd_local, "command line"); if (TRANSITION_CHANGED == arm_disarm(true, mavlink_fd_local, "command line")) {
warnx("note: not updating home position on commandline arming!"); warnx("note: not updating home position on commandline arming!");
} else {
warnx("arming failed");
}
px4_close(mavlink_fd_local); px4_close(mavlink_fd_local);
return 0; return 0;
} }
if (!strcmp(argv[1], "disarm")) { if (!strcmp(argv[1], "disarm")) {
int mavlink_fd_local = px4_open(MAVLINK_LOG_DEVICE, 0); int mavlink_fd_local = px4_open(MAVLINK_LOG_DEVICE, 0);
arm_disarm(false, mavlink_fd_local, "command line"); if (TRANSITION_DENIED == arm_disarm(false, mavlink_fd_local, "command line")) {
warnx("rejected disarm");
}
px4_close(mavlink_fd_local); px4_close(mavlink_fd_local);
return 0; return 0;
} }
@@ -891,6 +903,7 @@ int commander_thread_main(int argc, char *argv[])
/* not yet initialized */ /* not yet initialized */
commander_initialized = false; commander_initialized = false;
bool sensor_fail_tune_played = false;
bool arm_tune_played = false; bool arm_tune_played = false;
bool was_landed = true; bool was_landed = true;
bool was_armed = false; bool was_armed = false;
@@ -1020,6 +1033,9 @@ int commander_thread_main(int argc, char *argv[])
// XXX for now just set sensors as initialized // XXX for now just set sensors as initialized
status.condition_system_sensors_initialized = true; status.condition_system_sensors_initialized = true;
status.condition_system_prearm_error_reported = false;
status.condition_system_hotplug_timeout = false;
status.counter++; status.counter++;
status.timestamp = hrt_absolute_time(); status.timestamp = hrt_absolute_time();
@@ -1101,7 +1117,7 @@ int commander_thread_main(int argc, char *argv[])
bool updated = false; bool updated = false;
rc_calibration_check(mavlink_fd); rc_calibration_check(mavlink_fd, true);
/* Subscribe to safety topic */ /* Subscribe to safety topic */
int safety_sub = orb_subscribe(ORB_ID(safety)); int safety_sub = orb_subscribe(ORB_ID(safety));
@@ -1243,6 +1259,7 @@ int commander_thread_main(int argc, char *argv[])
// Run preflight check // Run preflight check
int32_t rc_in_off = 0; int32_t rc_in_off = 0;
bool hotplug_timeout = hrt_elapsed_time(&commander_boot_timestamp) > HOTPLUG_SENS_TIMEOUT;
param_get(_param_autostart_id, &autostart_id); param_get(_param_autostart_id, &autostart_id);
param_get(_param_rc_in_off, &rc_in_off); param_get(_param_rc_in_off, &rc_in_off);
status.rc_input_mode = rc_in_off; status.rc_input_mode = rc_in_off;
@@ -1251,14 +1268,10 @@ int commander_thread_main(int argc, char *argv[])
status.condition_system_sensors_initialized = false; status.condition_system_sensors_initialized = false;
set_tune_override(TONE_STARTUP_TUNE); //normal boot tune set_tune_override(TONE_STARTUP_TUNE); //normal boot tune
} else { } else {
status.condition_system_sensors_initialized = Commander::preflightCheck(mavlink_fd, true, true, true, true, // sensor diagnostics done continiously, not just at boot so don't warn about any issues just yet
checkAirspeed, (status.rc_input_mode == vehicle_status_s::RC_IN_MODE_DEFAULT), !status.circuit_breaker_engaged_gpsfailure_check); status.condition_system_sensors_initialized = Commander::preflightCheck(mavlink_fd, true, true, true, true,
if (!status.condition_system_sensors_initialized) { checkAirspeed, (status.rc_input_mode == vehicle_status_s::RC_IN_MODE_DEFAULT), !status.circuit_breaker_engaged_gpsfailure_check, false);
set_tune_override(TONE_GPS_WARNING_TUNE); //sensor fail tune
}
else {
set_tune_override(TONE_STARTUP_TUNE); //normal boot tune set_tune_override(TONE_STARTUP_TUNE); //normal boot tune
}
} }
commander_boot_timestamp = hrt_absolute_time(); commander_boot_timestamp = hrt_absolute_time();
@@ -1291,7 +1304,7 @@ int commander_thread_main(int argc, char *argv[])
/* initialize low priority thread */ /* initialize low priority thread */
pthread_attr_t commander_low_prio_attr; pthread_attr_t commander_low_prio_attr;
pthread_attr_init(&commander_low_prio_attr); pthread_attr_init(&commander_low_prio_attr);
pthread_attr_setstacksize(&commander_low_prio_attr, 2600); pthread_attr_setstacksize(&commander_low_prio_attr, 2880);
struct sched_param param; struct sched_param param;
(void)pthread_attr_getschedparam(&commander_low_prio_attr, &param); (void)pthread_attr_getschedparam(&commander_low_prio_attr, &param);
@@ -1354,11 +1367,11 @@ int commander_thread_main(int argc, char *argv[])
if (map_mode_sw == 0 && map_mode_sw != map_mode_sw_new && map_mode_sw_new < input_rc_s::RC_INPUT_MAX_CHANNELS && map_mode_sw_new > 0) { if (map_mode_sw == 0 && map_mode_sw != map_mode_sw_new && map_mode_sw_new < input_rc_s::RC_INPUT_MAX_CHANNELS && map_mode_sw_new > 0) {
status.condition_system_sensors_initialized = Commander::preflightCheck(mavlink_fd, true, true, true, true, checkAirspeed, status.condition_system_sensors_initialized = Commander::preflightCheck(mavlink_fd, true, true, true, true, checkAirspeed,
!(status.rc_input_mode == vehicle_status_s::RC_IN_MODE_OFF), !status.circuit_breaker_engaged_gpsfailure_check); !(status.rc_input_mode == vehicle_status_s::RC_IN_MODE_OFF), !status.circuit_breaker_engaged_gpsfailure_check, hotplug_timeout);
} }
/* re-check RC calibration */ /* re-check RC calibration */
rc_calibration_check(mavlink_fd); rc_calibration_check(mavlink_fd, true);
} }
/* Safety parameters */ /* Safety parameters */
@@ -1446,6 +1459,8 @@ int commander_thread_main(int argc, char *argv[])
!armed.armed) { !armed.armed) {
bool chAirspeed = false; bool chAirspeed = false;
bool hotplug_timeout = hrt_elapsed_time(&commander_boot_timestamp) > HOTPLUG_SENS_TIMEOUT;
/* Perform airspeed check only if circuit breaker is not /* Perform airspeed check only if circuit breaker is not
* engaged and it's not a rotary wing */ * engaged and it's not a rotary wing */
if (!status.circuit_breaker_engaged_airspd_check && !status.is_rotary_wing) { if (!status.circuit_breaker_engaged_airspd_check && !status.is_rotary_wing) {
@@ -1456,11 +1471,11 @@ int commander_thread_main(int argc, char *argv[])
if (is_hil_setup(autostart_id)) { if (is_hil_setup(autostart_id)) {
/* HIL configuration: check only RC input */ /* HIL configuration: check only RC input */
(void)Commander::preflightCheck(mavlink_fd, false, false, false, false, false, (void)Commander::preflightCheck(mavlink_fd, false, false, false, false, false,
!(status.rc_input_mode == vehicle_status_s::RC_IN_MODE_OFF), false); !(status.rc_input_mode == vehicle_status_s::RC_IN_MODE_OFF), false, true);
} else { } else {
/* check sensors also */ /* check sensors also */
(void)Commander::preflightCheck(mavlink_fd, true, true, true, true, chAirspeed, (void)Commander::preflightCheck(mavlink_fd, true, true, true, true, chAirspeed,
!(status.rc_input_mode == vehicle_status_s::RC_IN_MODE_OFF), !status.circuit_breaker_engaged_gpsfailure_check); !(status.rc_input_mode == vehicle_status_s::RC_IN_MODE_OFF), !status.circuit_breaker_engaged_gpsfailure_check, hotplug_timeout);
} }
} }
@@ -1686,10 +1701,10 @@ int commander_thread_main(int argc, char *argv[])
status_changed = true; status_changed = true;
if (status.condition_landed) { if (status.condition_landed) {
mavlink_log_critical(mavlink_fd, "LANDING DETECTED"); mavlink_and_console_log_info(mavlink_fd, "LANDING DETECTED");
} else { } else {
mavlink_log_critical(mavlink_fd, "TAKEOFF DETECTED"); mavlink_and_console_log_info(mavlink_fd, "TAKEOFF DETECTED");
} }
} }
@@ -2177,11 +2192,17 @@ int commander_thread_main(int argc, char *argv[])
if (telemetry_lost[i] && if (telemetry_lost[i] &&
hrt_elapsed_time(&telemetry_last_dl_loss[i]) > datalink_regain_timeout * 1e6) { hrt_elapsed_time(&telemetry_last_dl_loss[i]) > datalink_regain_timeout * 1e6) {
/* only report a regain */ /* report a regain */
if (telemetry_last_dl_loss[i] > 0) { if (telemetry_last_dl_loss[i] > 0) {
mavlink_and_console_log_info(mavlink_fd, "data link #%i regained", i); mavlink_and_console_log_info(mavlink_fd, "data link #%i regained", i);
} else if (telemetry_last_dl_loss[i] == 0) {
/* new link */
} }
/* got link again or new */
status.condition_system_prearm_error_reported = false;
status_changed = true;
telemetry_lost[i] = false; telemetry_lost[i] = false;
have_link = true; have_link = true;
@@ -2414,7 +2435,7 @@ int commander_thread_main(int argc, char *argv[])
} else { } else {
set_tune(TONE_STOP_TUNE); set_tune(TONE_STOP_TUNE);
} }
/* reset arm_tune_played when disarmed */ /* reset arm_tune_played when disarmed */
if (!armed.armed || (safety.safety_switch_available && !safety.safety_off)) { if (!armed.armed || (safety.safety_switch_available && !safety.safety_off)) {
@@ -2425,6 +2446,21 @@ int commander_thread_main(int argc, char *argv[])
arm_tune_played = false; arm_tune_played = false;
} }
/* play sensor failure tunes if we already waited for hotplug sensors to come up and failed */
hotplug_timeout = hrt_elapsed_time(&commander_boot_timestamp) > HOTPLUG_SENS_TIMEOUT;
if (!sensor_fail_tune_played && (!status.condition_system_sensors_initialized && hotplug_timeout)) {
set_tune_override(TONE_GPS_WARNING_TUNE);
sensor_fail_tune_played = true;
status_changed = true;
}
/* update timeout flag */
if(!(hotplug_timeout == status.condition_system_hotplug_timeout)) {
status.condition_system_hotplug_timeout = hotplug_timeout;
status_changed = true;
}
counter++; counter++;
@@ -2482,6 +2518,8 @@ get_circuit_breaker_params()
{ {
status.circuit_breaker_engaged_power_check = status.circuit_breaker_engaged_power_check =
circuit_breaker_enabled("CBRK_SUPPLY_CHK", CBRK_SUPPLY_CHK_KEY); circuit_breaker_enabled("CBRK_SUPPLY_CHK", CBRK_SUPPLY_CHK_KEY);
status.cb_usb =
circuit_breaker_enabled("CBRK_USB_CHK", CBRK_USB_CHK_KEY);
status.circuit_breaker_engaged_airspd_check = status.circuit_breaker_engaged_airspd_check =
circuit_breaker_enabled("CBRK_AIRSPD_CHK", CBRK_AIRSPD_CHK_KEY); circuit_breaker_enabled("CBRK_AIRSPD_CHK", CBRK_AIRSPD_CHK_KEY);
status.circuit_breaker_engaged_enginefailure_check = status.circuit_breaker_engaged_enginefailure_check =
@@ -2508,19 +2546,24 @@ control_status_leds(vehicle_status_s *status_local, const actuator_armed_s *actu
/* driving rgbled */ /* driving rgbled */
if (changed) { if (changed) {
bool set_normal_color = false; bool set_normal_color = false;
bool hotplug_timeout = hrt_elapsed_time(&commander_boot_timestamp) > HOTPLUG_SENS_TIMEOUT;
/* set mode */ /* set mode */
if (status_local->arming_state == vehicle_status_s::ARMING_STATE_ARMED) { if (status_local->arming_state == vehicle_status_s::ARMING_STATE_ARMED) {
rgbled_set_mode(RGBLED_MODE_ON); rgbled_set_mode(RGBLED_MODE_ON);
set_normal_color = true; set_normal_color = true;
} else if (status_local->arming_state == vehicle_status_s::ARMING_STATE_ARMED_ERROR || !status.condition_system_sensors_initialized) { } else if (status_local->arming_state == vehicle_status_s::ARMING_STATE_ARMED_ERROR || (!status.condition_system_sensors_initialized && hotplug_timeout)) {
rgbled_set_mode(RGBLED_MODE_BLINK_FAST); rgbled_set_mode(RGBLED_MODE_BLINK_FAST);
rgbled_set_color(RGBLED_COLOR_RED); rgbled_set_color(RGBLED_COLOR_RED);
} else if (status_local->arming_state == vehicle_status_s::ARMING_STATE_STANDBY) { } else if (status_local->arming_state == vehicle_status_s::ARMING_STATE_STANDBY) {
rgbled_set_mode(RGBLED_MODE_BREATHE); rgbled_set_mode(RGBLED_MODE_BREATHE);
set_normal_color = true; set_normal_color = true;
} else if (!status.condition_system_sensors_initialized && !hotplug_timeout) {
rgbled_set_mode(RGBLED_MODE_BREATHE);
set_normal_color = true;
} else { // STANDBY_ERROR and other states } else { // STANDBY_ERROR and other states
rgbled_set_mode(RGBLED_MODE_BLINK_NORMAL); rgbled_set_mode(RGBLED_MODE_BLINK_NORMAL);
@@ -2536,7 +2579,7 @@ control_status_leds(vehicle_status_s *status_local, const actuator_armed_s *actu
} else if (status_local->battery_warning == vehicle_status_s::VEHICLE_BATTERY_WARNING_CRITICAL) { } else if (status_local->battery_warning == vehicle_status_s::VEHICLE_BATTERY_WARNING_CRITICAL) {
rgbled_set_color(RGBLED_COLOR_RED); rgbled_set_color(RGBLED_COLOR_RED);
} else { } else {
if (status_local->condition_home_position_valid) { if (status_local->condition_home_position_valid && status_local->condition_global_position_valid) {
rgbled_set_color(RGBLED_COLOR_GREEN); rgbled_set_color(RGBLED_COLOR_GREEN);
} else { } else {
@@ -3197,6 +3240,7 @@ void *commander_low_prio_loop(void *arg)
// so this would be prone to false negatives. // so this would be prone to false negatives.
bool checkAirspeed = false; bool checkAirspeed = false;
bool hotplug_timeout = hrt_elapsed_time(&commander_boot_timestamp) > HOTPLUG_SENS_TIMEOUT;
/* Perform airspeed check only if circuit breaker is not /* Perform airspeed check only if circuit breaker is not
* engaged and it's not a rotary wing */ * engaged and it's not a rotary wing */
if (!status.circuit_breaker_engaged_airspd_check && !status.is_rotary_wing) { if (!status.circuit_breaker_engaged_airspd_check && !status.is_rotary_wing) {
@@ -3204,7 +3248,7 @@ void *commander_low_prio_loop(void *arg)
} }
status.condition_system_sensors_initialized = Commander::preflightCheck(mavlink_fd, true, true, true, true, checkAirspeed, status.condition_system_sensors_initialized = Commander::preflightCheck(mavlink_fd, true, true, true, true, checkAirspeed,
!(status.rc_input_mode == vehicle_status_s::RC_IN_MODE_OFF), !status.circuit_breaker_engaged_gpsfailure_check); !(status.rc_input_mode == vehicle_status_s::RC_IN_MODE_OFF), !status.circuit_breaker_engaged_gpsfailure_check, hotplug_timeout);
arming_state_transition(&status, &safety, vehicle_status_s::ARMING_STATE_STANDBY, &armed, false /* fRunPreArmChecks */, mavlink_fd); arming_state_transition(&status, &safety, vehicle_status_s::ARMING_STATE_STANDBY, &armed, false /* fRunPreArmChecks */, mavlink_fd);
+14
View File
@@ -55,6 +55,7 @@
* @group Radio Calibration * @group Radio Calibration
* @min -0.25 * @min -0.25
* @max 0.25 * @max 0.25
* @decimal 2
*/ */
PARAM_DEFINE_FLOAT(TRIM_ROLL, 0.0f); PARAM_DEFINE_FLOAT(TRIM_ROLL, 0.0f);
@@ -69,6 +70,7 @@ PARAM_DEFINE_FLOAT(TRIM_ROLL, 0.0f);
* @group Radio Calibration * @group Radio Calibration
* @min -0.25 * @min -0.25
* @max 0.25 * @max 0.25
* @decimal 2
*/ */
PARAM_DEFINE_FLOAT(TRIM_PITCH, 0.0f); PARAM_DEFINE_FLOAT(TRIM_PITCH, 0.0f);
@@ -83,6 +85,7 @@ PARAM_DEFINE_FLOAT(TRIM_PITCH, 0.0f);
* @group Radio Calibration * @group Radio Calibration
* @min -0.25 * @min -0.25
* @max 0.25 * @max 0.25
* @decimal 2
*/ */
PARAM_DEFINE_FLOAT(TRIM_YAW, 0.0f); PARAM_DEFINE_FLOAT(TRIM_YAW, 0.0f);
@@ -93,6 +96,7 @@ PARAM_DEFINE_FLOAT(TRIM_YAW, 0.0f);
* *
* @group Battery Calibration * @group Battery Calibration
* @unit V * @unit V
* @decimal 2
*/ */
PARAM_DEFINE_FLOAT(BAT_V_EMPTY, 3.4f); PARAM_DEFINE_FLOAT(BAT_V_EMPTY, 3.4f);
@@ -103,6 +107,7 @@ PARAM_DEFINE_FLOAT(BAT_V_EMPTY, 3.4f);
* *
* @group Battery Calibration * @group Battery Calibration
* @unit V * @unit V
* @decimal 2
*/ */
PARAM_DEFINE_FLOAT(BAT_V_CHARGED, 4.2f); PARAM_DEFINE_FLOAT(BAT_V_CHARGED, 4.2f);
@@ -115,6 +120,8 @@ PARAM_DEFINE_FLOAT(BAT_V_CHARGED, 4.2f);
* @group Battery Calibration * @group Battery Calibration
* @unit V * @unit V
* @min 0.0 * @min 0.0
* @max 1.5
* @decimal 2
*/ */
PARAM_DEFINE_FLOAT(BAT_V_LOAD_DROP, 0.07f); PARAM_DEFINE_FLOAT(BAT_V_LOAD_DROP, 0.07f);
@@ -137,6 +144,7 @@ PARAM_DEFINE_INT32(BAT_N_CELLS, 3);
* *
* @group Battery Calibration * @group Battery Calibration
* @unit mA * @unit mA
* @decimal 0
*/ */
PARAM_DEFINE_FLOAT(BAT_CAPACITY, -1.0f); PARAM_DEFINE_FLOAT(BAT_CAPACITY, -1.0f);
@@ -184,6 +192,7 @@ PARAM_DEFINE_INT32(COM_DL_REG_T, 0);
* @group Commander * @group Commander
* @min 0.0 * @min 0.0
* @max 1.0 * @max 1.0
* @decimal 1
*/ */
PARAM_DEFINE_FLOAT(COM_EF_THROT, 0.5f); PARAM_DEFINE_FLOAT(COM_EF_THROT, 0.5f);
@@ -196,6 +205,7 @@ PARAM_DEFINE_FLOAT(COM_EF_THROT, 0.5f);
* @min 0.0 * @min 0.0
* @max 30.0 * @max 30.0
* @unit ampere * @unit ampere
* @decimal 2
*/ */
PARAM_DEFINE_FLOAT(COM_EF_C2T, 5.0f); PARAM_DEFINE_FLOAT(COM_EF_C2T, 5.0f);
@@ -209,6 +219,7 @@ PARAM_DEFINE_FLOAT(COM_EF_C2T, 5.0f);
* @unit second * @unit second
* @min 0.0 * @min 0.0
* @max 60.0 * @max 60.0
* @decimal 1
*/ */
PARAM_DEFINE_FLOAT(COM_EF_TIME, 10.0f); PARAM_DEFINE_FLOAT(COM_EF_TIME, 10.0f);
@@ -221,6 +232,7 @@ PARAM_DEFINE_FLOAT(COM_EF_TIME, 10.0f);
* @unit second * @unit second
* @min 0 * @min 0
* @max 35 * @max 35
* @decimal 1
*/ */
PARAM_DEFINE_FLOAT(COM_RC_LOSS_T, 0.5f); PARAM_DEFINE_FLOAT(COM_RC_LOSS_T, 0.5f);
@@ -233,6 +245,7 @@ PARAM_DEFINE_FLOAT(COM_RC_LOSS_T, 0.5f);
* @unit meter * @unit meter
* @min 2 * @min 2
* @max 15 * @max 15
* @decimal 2
*/ */
PARAM_DEFINE_FLOAT(COM_HOME_H_T, 5.0f); PARAM_DEFINE_FLOAT(COM_HOME_H_T, 5.0f);
@@ -245,6 +258,7 @@ PARAM_DEFINE_FLOAT(COM_HOME_H_T, 5.0f);
* @unit meter * @unit meter
* @min 5 * @min 5
* @max 25 * @max 25
* @decimal 2
*/ */
PARAM_DEFINE_FLOAT(COM_HOME_V_T, 10.0f); PARAM_DEFINE_FLOAT(COM_HOME_V_T, 10.0f);
+11 -11
View File
@@ -122,7 +122,7 @@ static calibrate_return gyro_calibration_worker(int cancel_sub, void* data)
} }
if (s == 0 && calibration_counter[0] % (calibration_count / 20) == 0) { if (s == 0 && calibration_counter[0] % (calibration_count / 20) == 0) {
mavlink_log_info(worker_data->mavlink_fd, CAL_QGC_PROGRESS_MSG, (calibration_counter[0] * 100) / calibration_count); mavlink_and_console_log_info(worker_data->mavlink_fd, CAL_QGC_PROGRESS_MSG, (calibration_counter[0] * 100) / calibration_count);
} }
} }
@@ -131,14 +131,14 @@ static calibrate_return gyro_calibration_worker(int cancel_sub, void* data)
} }
if (poll_errcount > 1000) { if (poll_errcount > 1000) {
mavlink_log_critical(worker_data->mavlink_fd, CAL_ERROR_SENSOR_MSG); mavlink_and_console_log_critical(worker_data->mavlink_fd, CAL_ERROR_SENSOR_MSG);
return calibrate_return_error; return calibrate_return_error;
} }
} }
for (unsigned s = 0; s < max_gyros; s++) { for (unsigned s = 0; s < max_gyros; s++) {
if (worker_data->device_id[s] != 0 && calibration_counter[s] < calibration_count / 2) { if (worker_data->device_id[s] != 0 && calibration_counter[s] < calibration_count / 2) {
mavlink_log_critical(worker_data->mavlink_fd, "[cal] ERROR: missing data, sensor %d", s) mavlink_and_console_log_critical(worker_data->mavlink_fd, "[cal] ERROR: missing data, sensor %d", s)
return calibrate_return_error; return calibrate_return_error;
} }
@@ -155,7 +155,7 @@ int do_gyro_calibration(int mavlink_fd)
int res = OK; int res = OK;
gyro_worker_data_t worker_data = {}; gyro_worker_data_t worker_data = {};
mavlink_log_info(mavlink_fd, CAL_QGC_STARTED_MSG, sensor_name); mavlink_and_console_log_info(mavlink_fd, CAL_QGC_STARTED_MSG, sensor_name);
worker_data.mavlink_fd = mavlink_fd; worker_data.mavlink_fd = mavlink_fd;
@@ -179,7 +179,7 @@ int do_gyro_calibration(int mavlink_fd)
(void)sprintf(str, "CAL_GYRO%u_ID", s); (void)sprintf(str, "CAL_GYRO%u_ID", s);
res = param_set_no_notification(param_find(str), &(worker_data.device_id[s])); res = param_set_no_notification(param_find(str), &(worker_data.device_id[s]));
if (res != OK) { if (res != OK) {
mavlink_log_critical(mavlink_fd, "[cal] Unable to reset CAL_GYRO%u_ID", s); mavlink_and_console_log_critical(mavlink_fd, "[cal] Unable to reset CAL_GYRO%u_ID", s);
return ERROR; return ERROR;
} }
@@ -193,7 +193,7 @@ int do_gyro_calibration(int mavlink_fd)
px4_close(fd); px4_close(fd);
if (res != OK) { if (res != OK) {
mavlink_log_critical(mavlink_fd, CAL_ERROR_RESET_CAL_MSG, s); mavlink_and_console_log_critical(mavlink_fd, CAL_ERROR_RESET_CAL_MSG, s);
return ERROR; return ERROR;
} }
} }
@@ -238,7 +238,7 @@ int do_gyro_calibration(int mavlink_fd)
float zdiff = worker_data.gyro_report_0.z - worker_data.gyro_scale[0].z_offset; float zdiff = worker_data.gyro_report_0.z - worker_data.gyro_scale[0].z_offset;
/* maximum allowable calibration error in radians */ /* maximum allowable calibration error in radians */
const float maxoff = 0.0055f; const float maxoff = 0.01f;
if (!PX4_ISFINITE(worker_data.gyro_scale[0].x_offset) || if (!PX4_ISFINITE(worker_data.gyro_scale[0].x_offset) ||
!PX4_ISFINITE(worker_data.gyro_scale[0].y_offset) || !PX4_ISFINITE(worker_data.gyro_scale[0].y_offset) ||
@@ -302,7 +302,7 @@ int do_gyro_calibration(int mavlink_fd)
px4_close(fd); px4_close(fd);
if (res != OK) { if (res != OK) {
mavlink_log_critical(mavlink_fd, CAL_ERROR_APPLY_CAL_MSG); mavlink_and_console_log_critical(mavlink_fd, CAL_ERROR_APPLY_CAL_MSG, 1);
} }
} }
} }
@@ -325,7 +325,7 @@ int do_gyro_calibration(int mavlink_fd)
res = param_save_default(); res = param_save_default();
if (res != OK) { if (res != OK) {
mavlink_log_critical(mavlink_fd, CAL_ERROR_SAVE_PARAMS_MSG); mavlink_and_console_log_critical(mavlink_fd, CAL_ERROR_SAVE_PARAMS_MSG);
} }
} }
@@ -333,9 +333,9 @@ int do_gyro_calibration(int mavlink_fd)
usleep(200000); usleep(200000);
if (res == OK) { if (res == OK) {
mavlink_log_info(mavlink_fd, CAL_QGC_DONE_MSG, sensor_name); mavlink_and_console_log_info(mavlink_fd, CAL_QGC_DONE_MSG, sensor_name);
} else { } else {
mavlink_log_info(mavlink_fd, CAL_QGC_FAILED_MSG, sensor_name); mavlink_and_console_log_info(mavlink_fd, CAL_QGC_FAILED_MSG, sensor_name);
} }
/* give this message enough time to propagate */ /* give this message enough time to propagate */
+46 -24
View File
@@ -97,8 +97,6 @@ static const char * const state_names[vehicle_status_s::ARMING_STATE_MAX] = {
"ARMING_STATE_IN_AIR_RESTORE", "ARMING_STATE_IN_AIR_RESTORE",
}; };
static bool sensor_feedback_provided = false;
transition_result_t transition_result_t
arming_state_transition(struct vehicle_status_s *status, ///< current vehicle status arming_state_transition(struct vehicle_status_s *status, ///< current vehicle status
const struct safety_s *safety, ///< current safety settings const struct safety_s *safety, ///< current safety settings
@@ -126,10 +124,20 @@ arming_state_transition(struct vehicle_status_s *status, ///< current vehicle s
*/ */
int prearm_ret = OK; int prearm_ret = OK;
/* only perform the check if we have to */ /* only perform the pre-arm check if we have to */
if (fRunPreArmChecks && new_arming_state == vehicle_status_s::ARMING_STATE_ARMED if (fRunPreArmChecks && new_arming_state == vehicle_status_s::ARMING_STATE_ARMED
&& status->hil_state == vehicle_status_s::HIL_STATE_OFF) { && status->hil_state == vehicle_status_s::HIL_STATE_OFF) {
prearm_ret = prearm_check(status, mavlink_fd);
prearm_ret = preflight_check(status, mavlink_fd, true /* pre-arm */ );
}
/* re-run the pre-flight check as long as sensors are failing */
if (!status->condition_system_sensors_initialized
&& (new_arming_state == vehicle_status_s::ARMING_STATE_ARMED ||
new_arming_state == vehicle_status_s::ARMING_STATE_STANDBY)
&& status->hil_state == vehicle_status_s::HIL_STATE_OFF) {
prearm_ret = preflight_check(status, mavlink_fd, false /* pre-flight */);
status->condition_system_sensors_initialized = !prearm_ret;
} }
/* /*
@@ -175,7 +183,7 @@ arming_state_transition(struct vehicle_status_s *status, ///< current vehicle s
// Fail transition if we need safety switch press // Fail transition if we need safety switch press
} else if (safety->safety_switch_available && !safety->safety_off) { } else if (safety->safety_switch_available && !safety->safety_off) {
mavlink_log_critical(mavlink_fd, "NOT ARMING: Press safety switch first!"); mavlink_and_console_log_critical(mavlink_fd, "NOT ARMING: Press safety switch first!");
feedback_provided = true; feedback_provided = true;
valid_transition = false; valid_transition = false;
} }
@@ -200,10 +208,10 @@ arming_state_transition(struct vehicle_status_s *status, ///< current vehicle s
feedback_provided = true; feedback_provided = true;
valid_transition = false; valid_transition = false;
} else if (status->avionics_power_rail_voltage < 4.9f) { } else if (status->avionics_power_rail_voltage < 4.9f) {
mavlink_log_critical(mavlink_fd, "CAUTION: Avionics power low: %6.2f Volt", (double)status->avionics_power_rail_voltage); mavlink_and_console_log_critical(mavlink_fd, "CAUTION: Avionics power low: %6.2f Volt", (double)status->avionics_power_rail_voltage);
feedback_provided = true; feedback_provided = true;
} else if (status->avionics_power_rail_voltage > 5.4f) { } else if (status->avionics_power_rail_voltage > 5.4f) {
mavlink_log_critical(mavlink_fd, "CAUTION: Avionics power high: %6.2f Volt", (double)status->avionics_power_rail_voltage); mavlink_and_console_log_critical(mavlink_fd, "CAUTION: Avionics power high: %6.2f Volt", (double)status->avionics_power_rail_voltage);
feedback_provided = true; feedback_provided = true;
} }
} }
@@ -247,9 +255,11 @@ arming_state_transition(struct vehicle_status_s *status, ///< current vehicle s
(new_arming_state == vehicle_status_s::ARMING_STATE_STANDBY) && (new_arming_state == vehicle_status_s::ARMING_STATE_STANDBY) &&
(status->arming_state != vehicle_status_s::ARMING_STATE_STANDBY_ERROR) && (status->arming_state != vehicle_status_s::ARMING_STATE_STANDBY_ERROR) &&
(!status->condition_system_sensors_initialized)) { (!status->condition_system_sensors_initialized)) {
if (!sensor_feedback_provided || (new_arming_state == vehicle_status_s::ARMING_STATE_ARMED)) { if ((!status->condition_system_prearm_error_reported &&
status->condition_system_hotplug_timeout) ||
(new_arming_state == vehicle_status_s::ARMING_STATE_ARMED)) {
mavlink_and_console_log_critical(mavlink_fd, "Not ready to fly: Sensors need inspection"); mavlink_and_console_log_critical(mavlink_fd, "Not ready to fly: Sensors need inspection");
sensor_feedback_provided = true; status->condition_system_prearm_error_reported = true;
} }
feedback_provided = true; feedback_provided = true;
valid_transition = false; valid_transition = false;
@@ -265,8 +275,9 @@ arming_state_transition(struct vehicle_status_s *status, ///< current vehicle s
/* reset feedback state */ /* reset feedback state */
if (status->arming_state != vehicle_status_s::ARMING_STATE_STANDBY_ERROR && if (status->arming_state != vehicle_status_s::ARMING_STATE_STANDBY_ERROR &&
status->arming_state != vehicle_status_s::ARMING_STATE_INIT &&
valid_transition) { valid_transition) {
sensor_feedback_provided = false; status->condition_system_prearm_error_reported = false;
} }
/* end of atomic state update */ /* end of atomic state update */
@@ -384,7 +395,7 @@ transition_result_t hil_state_transition(hil_state_t new_state, orb_advert_t sta
switch (new_state) { switch (new_state) {
case vehicle_status_s::HIL_STATE_OFF: case vehicle_status_s::HIL_STATE_OFF:
/* we're in HIL and unexpected things can happen if we disable HIL now */ /* we're in HIL and unexpected things can happen if we disable HIL now */
mavlink_log_critical(mavlink_fd, "Not switching off HIL (safety)"); mavlink_and_console_log_critical(mavlink_fd, "Not switching off HIL (safety)");
ret = TRANSITION_DENIED; ret = TRANSITION_DENIED;
break; break;
@@ -457,7 +468,7 @@ transition_result_t hil_state_transition(hil_state_t new_state, orb_advert_t sta
closedir(d); closedir(d);
ret = TRANSITION_CHANGED; ret = TRANSITION_CHANGED;
mavlink_log_critical(mavlink_fd, "Switched to ON hil state"); mavlink_and_console_log_critical(mavlink_fd, "Switched to ON hil state");
} else { } else {
/* failed opening dir */ /* failed opening dir */
@@ -518,11 +529,11 @@ transition_result_t hil_state_transition(hil_state_t new_state, orb_advert_t sta
} }
ret = TRANSITION_CHANGED; ret = TRANSITION_CHANGED;
mavlink_log_critical(mavlink_fd, "Switched to ON hil state"); mavlink_and_console_log_critical(mavlink_fd, "Switched to ON hil state");
#endif #endif
} else { } else {
mavlink_log_critical(mavlink_fd, "Not switching to HIL when armed"); mavlink_and_console_log_critical(mavlink_fd, "Not switching to HIL when armed");
ret = TRANSITION_DENIED; ret = TRANSITION_DENIED;
} }
break; break;
@@ -759,24 +770,35 @@ bool set_nav_state(struct vehicle_status_s *status, const bool data_link_loss_en
return status->nav_state != nav_state_old; return status->nav_state != nav_state_old;
} }
int prearm_check(const struct vehicle_status_s *status, const int mavlink_fd) int preflight_check(struct vehicle_status_s *status, const int mavlink_fd, bool prearm, bool force_report)
{ {
/* at this point this equals the preflight check, but might add additional /*
* quantities later.
*/ */
bool reportFailures = force_report || (!status->condition_system_prearm_error_reported &&
status->condition_system_hotplug_timeout);
bool checkAirspeed = false; bool checkAirspeed = false;
/* Perform airspeed check only if circuit breaker is not /* Perform airspeed check only if circuit breaker is not
* engaged and it's not a rotary wing */ * engaged and it's not a rotary wing */
if (!status->circuit_breaker_engaged_airspd_check && !status->is_rotary_wing) { if (!status->circuit_breaker_engaged_airspd_check && (!status->is_rotary_wing || status->is_vtol)) {
checkAirspeed = true; checkAirspeed = true;
} }
bool prearm_ok = Commander::preflightCheck(mavlink_fd, true, true, true, true, checkAirspeed, !(status->rc_input_mode == vehicle_status_s::RC_IN_MODE_OFF), !status->circuit_breaker_engaged_gpsfailure_check, true); bool preflight_ok = Commander::preflightCheck(mavlink_fd, true, true, true, true,
checkAirspeed, !(status->rc_input_mode == vehicle_status_s::RC_IN_MODE_OFF),
if (status->usb_connected) { !status->circuit_breaker_engaged_gpsfailure_check, true, reportFailures);
prearm_ok = false;
mavlink_log_critical(mavlink_fd, "NOT ARMING: Flying with USB connected prohibited"); if (!status->cb_usb && status->usb_connected && prearm) {
preflight_ok = false;
if (reportFailures) {
mavlink_and_console_log_critical(mavlink_fd, "NOT ARMING: Flying with USB connected prohibited");
}
} }
return !prearm_ok; /* report once, then set the flag */
if (mavlink_fd >= 0 && reportFailures && !preflight_ok) {
status->condition_system_prearm_error_reported = true;
}
return !preflight_ok;
} }
+1 -1
View File
@@ -65,6 +65,6 @@ transition_result_t hil_state_transition(hil_state_t new_state, orb_advert_t sta
bool set_nav_state(struct vehicle_status_s *status, const bool data_link_loss_enabled, const bool mission_finished, const bool stay_in_failsafe); bool set_nav_state(struct vehicle_status_s *status, const bool data_link_loss_enabled, const bool mission_finished, const bool stay_in_failsafe);
int prearm_check(const struct vehicle_status_s *status, const int mavlink_fd); int preflight_check(struct vehicle_status_s *status, const int mavlink_fd, bool prearm, bool force_report=false);
#endif /* STATE_MACHINE_HELPER_H_ */ #endif /* STATE_MACHINE_HELPER_H_ */
@@ -69,6 +69,7 @@
#include <mathlib/math/filter/LowPassFilter2p.hpp> #include <mathlib/math/filter/LowPassFilter2p.hpp>
#include <geo/geo.h> #include <geo/geo.h>
#include <terrain_estimation/terrain_estimator.h>
#include <systemlib/perf_counter.h> #include <systemlib/perf_counter.h>
#include <lib/ecl/validation/data_validator_group.h> #include <lib/ecl/validation/data_validator_group.h>
#include "estimator_22states.h" #include "estimator_22states.h"
@@ -278,6 +279,8 @@ private:
AttPosEKF *_ekf; AttPosEKF *_ekf;
TerrainEstimator *_terrain_estimator;
/* Low pass filter for attitude rates */ /* Low pass filter for attitude rates */
math::LowPassFilter2p _LP_att_P; math::LowPassFilter2p _LP_att_P;
math::LowPassFilter2p _LP_att_Q; math::LowPassFilter2p _LP_att_Q;
@@ -212,6 +212,7 @@ AttitudePositionEstimatorEKF::AttitudePositionEstimatorEKF() :
_parameters{}, _parameters{},
_parameter_handles{}, _parameter_handles{},
_ekf(nullptr), _ekf(nullptr),
_terrain_estimator(nullptr),
_LP_att_P(250.0f, 20.0f), _LP_att_P(250.0f, 20.0f),
_LP_att_Q(250.0f, 20.0f), _LP_att_Q(250.0f, 20.0f),
@@ -219,6 +220,8 @@ AttitudePositionEstimatorEKF::AttitudePositionEstimatorEKF() :
{ {
_voter_mag.set_timeout(200000); _voter_mag.set_timeout(200000);
_terrain_estimator = new TerrainEstimator();
_parameter_handles.vel_delay_ms = param_find("PE_VEL_DELAY_MS"); _parameter_handles.vel_delay_ms = param_find("PE_VEL_DELAY_MS");
_parameter_handles.pos_delay_ms = param_find("PE_POS_DELAY_MS"); _parameter_handles.pos_delay_ms = param_find("PE_POS_DELAY_MS");
_parameter_handles.height_delay_ms = param_find("PE_HGT_DELAY_MS"); _parameter_handles.height_delay_ms = param_find("PE_HGT_DELAY_MS");
@@ -267,7 +270,7 @@ AttitudePositionEstimatorEKF::~AttitudePositionEstimatorEKF()
} }
} while (_estimator_task != -1); } while (_estimator_task != -1);
} }
delete _terrain_estimator;
delete _ekf; delete _ekf;
estimator::g_estimator = nullptr; estimator::g_estimator = nullptr;
@@ -697,6 +700,10 @@ void AttitudePositionEstimatorEKF::task_main()
// Run EKF data fusion steps // Run EKF data fusion steps
updateSensorFusion(_gpsIsGood, _newDataMag, _newRangeData, _newHgtData, _newAdsData); updateSensorFusion(_gpsIsGood, _newDataMag, _newRangeData, _newHgtData, _newAdsData);
// Run separate terrain estimator
_terrain_estimator->predict(_ekf->dtIMU, &_att, &_sensor_combined, &_distance);
_terrain_estimator->measurement_update(hrt_absolute_time(), &_gps, &_distance, &_att);
// Publish attitude estimations // Publish attitude estimations
publishAttitude(); publishAttitude();
@@ -997,9 +1004,12 @@ void AttitudePositionEstimatorEKF::publishGlobalPosition()
} }
/* terrain altitude */ /* terrain altitude */
_global_pos.terrain_alt = _ekf->hgtRef - _ekf->flowStates[1]; if (_terrain_estimator->is_valid()) {
_global_pos.terrain_alt_valid = (_distance_last_valid > 0) && _global_pos.terrain_alt = _global_pos.alt - _terrain_estimator->get_distance_to_ground();
(hrt_elapsed_time(&_distance_last_valid) < 20 * 1000 * 1000); _global_pos.terrain_alt_valid = true;
} else {
_global_pos.terrain_alt_valid = false;
}
_global_pos.yaw = _local_pos.yaw; _global_pos.yaw = _local_pos.yaw;
@@ -82,6 +82,7 @@
#include <ecl/attitude_fw/ecl_pitch_controller.h> #include <ecl/attitude_fw/ecl_pitch_controller.h>
#include <ecl/attitude_fw/ecl_roll_controller.h> #include <ecl/attitude_fw/ecl_roll_controller.h>
#include <ecl/attitude_fw/ecl_yaw_controller.h> #include <ecl/attitude_fw/ecl_yaw_controller.h>
#include <ecl/attitude_fw/ecl_wheel_controller.h>
#include <platforms/px4_defines.h> #include <platforms/px4_defines.h>
/** /**
@@ -160,6 +161,10 @@ private:
bool _setpoint_valid; /**< flag if the position control setpoint is valid */ bool _setpoint_valid; /**< flag if the position control setpoint is valid */
bool _debug; /**< if set to true, print debug output */ bool _debug; /**< if set to true, print debug output */
float _flaps_cmd_last;
float _flaperons_cmd_last;
struct { struct {
float tconst; float tconst;
float p_p; float p_p;
@@ -181,6 +186,11 @@ private:
float y_coordinated_min_speed; float y_coordinated_min_speed;
int32_t y_coordinated_method; int32_t y_coordinated_method;
float y_rmax; float y_rmax;
float w_p;
float w_i;
float w_ff;
float w_integrator_max;
float w_rmax;
float airspeed_min; float airspeed_min;
float airspeed_trim; float airspeed_trim;
@@ -196,6 +206,9 @@ private:
float man_roll_max; /**< Max Roll in rad */ float man_roll_max; /**< Max Roll in rad */
float man_pitch_max; /**< Max Pitch in rad */ float man_pitch_max; /**< Max Pitch in rad */
float flaps_scale; /**< Scale factor for flaps */
float flaperon_scale; /**< Scale factor for flaperons */
int vtol_type; /**< VTOL type: 0 = tailsitter, 1 = tiltrotor */ int vtol_type; /**< VTOL type: 0 = tailsitter, 1 = tiltrotor */
} _parameters; /**< local copies of interesting parameters */ } _parameters; /**< local copies of interesting parameters */
@@ -222,6 +235,11 @@ private:
param_t y_coordinated_min_speed; param_t y_coordinated_min_speed;
param_t y_coordinated_method; param_t y_coordinated_method;
param_t y_rmax; param_t y_rmax;
param_t w_p;
param_t w_i;
param_t w_ff;
param_t w_integrator_max;
param_t w_rmax;
param_t airspeed_min; param_t airspeed_min;
param_t airspeed_trim; param_t airspeed_trim;
@@ -235,6 +253,9 @@ private:
param_t man_roll_max; param_t man_roll_max;
param_t man_pitch_max; param_t man_pitch_max;
param_t flaps_scale;
param_t flaperon_scale;
param_t vtol_type; param_t vtol_type;
} _parameter_handles; /**< handles for interesting parameters */ } _parameter_handles; /**< handles for interesting parameters */
@@ -248,6 +269,7 @@ private:
ECL_RollController _roll_ctrl; ECL_RollController _roll_ctrl;
ECL_PitchController _pitch_ctrl; ECL_PitchController _pitch_ctrl;
ECL_YawController _yaw_ctrl; ECL_YawController _yaw_ctrl;
ECL_WheelController _wheel_ctrl;
/** /**
@@ -345,7 +367,9 @@ FixedwingAttitudeControl::FixedwingAttitudeControl() :
_nonfinite_output_perf(perf_alloc(PC_COUNT, "fw att control nonfinite output")), _nonfinite_output_perf(perf_alloc(PC_COUNT, "fw att control nonfinite output")),
/* states */ /* states */
_setpoint_valid(false), _setpoint_valid(false),
_debug(false) _debug(false),
_flaps_cmd_last(0),
_flaperons_cmd_last(0)
{ {
/* safely initialize structs */ /* safely initialize structs */
_ctrl_state = {}; _ctrl_state = {};
@@ -380,6 +404,12 @@ FixedwingAttitudeControl::FixedwingAttitudeControl() :
_parameter_handles.y_integrator_max = param_find("FW_YR_IMAX"); _parameter_handles.y_integrator_max = param_find("FW_YR_IMAX");
_parameter_handles.y_rmax = param_find("FW_Y_RMAX"); _parameter_handles.y_rmax = param_find("FW_Y_RMAX");
_parameter_handles.w_p = param_find("FW_WR_P");
_parameter_handles.w_i = param_find("FW_WR_I");
_parameter_handles.w_ff = param_find("FW_WR_FF");
_parameter_handles.w_integrator_max = param_find("FW_WR_IMAX");
_parameter_handles.w_rmax = param_find("FW_W_RMAX");
_parameter_handles.airspeed_min = param_find("FW_AIRSPD_MIN"); _parameter_handles.airspeed_min = param_find("FW_AIRSPD_MIN");
_parameter_handles.airspeed_trim = param_find("FW_AIRSPD_TRIM"); _parameter_handles.airspeed_trim = param_find("FW_AIRSPD_TRIM");
_parameter_handles.airspeed_max = param_find("FW_AIRSPD_MAX"); _parameter_handles.airspeed_max = param_find("FW_AIRSPD_MAX");
@@ -396,6 +426,9 @@ FixedwingAttitudeControl::FixedwingAttitudeControl() :
_parameter_handles.man_roll_max = param_find("FW_MAN_R_MAX"); _parameter_handles.man_roll_max = param_find("FW_MAN_R_MAX");
_parameter_handles.man_pitch_max = param_find("FW_MAN_P_MAX"); _parameter_handles.man_pitch_max = param_find("FW_MAN_P_MAX");
_parameter_handles.flaps_scale = param_find("FW_FLAPS_SCL");
_parameter_handles.flaperon_scale = param_find("FW_FLAPERON_SCL");
_parameter_handles.vtol_type = param_find("VT_TYPE"); _parameter_handles.vtol_type = param_find("VT_TYPE");
/* fetch initial parameter values */ /* fetch initial parameter values */
@@ -458,6 +491,12 @@ FixedwingAttitudeControl::parameters_update()
param_get(_parameter_handles.y_coordinated_method, &(_parameters.y_coordinated_method)); param_get(_parameter_handles.y_coordinated_method, &(_parameters.y_coordinated_method));
param_get(_parameter_handles.y_rmax, &(_parameters.y_rmax)); param_get(_parameter_handles.y_rmax, &(_parameters.y_rmax));
param_get(_parameter_handles.w_p, &(_parameters.w_p));
param_get(_parameter_handles.w_i, &(_parameters.w_i));
param_get(_parameter_handles.w_ff, &(_parameters.w_ff));
param_get(_parameter_handles.w_integrator_max, &(_parameters.w_integrator_max));
param_get(_parameter_handles.w_rmax, &(_parameters.w_rmax));
param_get(_parameter_handles.airspeed_min, &(_parameters.airspeed_min)); param_get(_parameter_handles.airspeed_min, &(_parameters.airspeed_min));
param_get(_parameter_handles.airspeed_trim, &(_parameters.airspeed_trim)); param_get(_parameter_handles.airspeed_trim, &(_parameters.airspeed_trim));
param_get(_parameter_handles.airspeed_max, &(_parameters.airspeed_max)); param_get(_parameter_handles.airspeed_max, &(_parameters.airspeed_max));
@@ -474,6 +513,9 @@ FixedwingAttitudeControl::parameters_update()
_parameters.man_roll_max = math::radians(_parameters.man_roll_max); _parameters.man_roll_max = math::radians(_parameters.man_roll_max);
_parameters.man_pitch_max = math::radians(_parameters.man_pitch_max); _parameters.man_pitch_max = math::radians(_parameters.man_pitch_max);
param_get(_parameter_handles.flaps_scale, &_parameters.flaps_scale);
param_get(_parameter_handles.flaperon_scale, &_parameters.flaperon_scale);
param_get(_parameter_handles.vtol_type, &_parameters.vtol_type); param_get(_parameter_handles.vtol_type, &_parameters.vtol_type);
/* pitch control parameters */ /* pitch control parameters */
@@ -502,6 +544,13 @@ FixedwingAttitudeControl::parameters_update()
_yaw_ctrl.set_coordinated_method(_parameters.y_coordinated_method); _yaw_ctrl.set_coordinated_method(_parameters.y_coordinated_method);
_yaw_ctrl.set_max_rate(math::radians(_parameters.y_rmax)); _yaw_ctrl.set_max_rate(math::radians(_parameters.y_rmax));
/* wheel control parameters */
_wheel_ctrl.set_k_p(_parameters.w_p);
_wheel_ctrl.set_k_i(_parameters.w_i);
_wheel_ctrl.set_k_ff(_parameters.w_ff);
_wheel_ctrl.set_integrator_max(_parameters.w_integrator_max);
_wheel_ctrl.set_max_rate(math::radians(_parameters.w_rmax));
return OK; return OK;
} }
@@ -751,6 +800,10 @@ FixedwingAttitudeControl::task_main()
vehicle_status_poll(); vehicle_status_poll();
// the position controller will not emit attitude setpoints in some modes
// we need to make sure that this flag is reset
_att_sp.fw_control_yaw = _att_sp.fw_control_yaw && _vcontrol_mode.flag_control_auto_enabled;
/* lock integrator until control is started */ /* lock integrator until control is started */
bool lock_integrator; bool lock_integrator;
@@ -778,9 +831,53 @@ FixedwingAttitudeControl::task_main()
/* default flaps to center */ /* default flaps to center */
float flaps_control = 0.0f; float flaps_control = 0.0f;
static float delta_flaps = 0;
/* map flaps by default to manual if valid */ /* map flaps by default to manual if valid */
if (PX4_ISFINITE(_manual.flaps)) { if (PX4_ISFINITE(_manual.flaps) && _vcontrol_mode.flag_control_manual_enabled) {
flaps_control = _manual.flaps; flaps_control = 0.5f * (_manual.flaps + 1.0f ) * _parameters.flaps_scale;
} else if (_vcontrol_mode.flag_control_auto_enabled) {
flaps_control = _att_sp.apply_flaps ? 1.0f * _parameters.flaps_scale : 0.0f;
}
// move the actual control value continuous with time
static hrt_abstime t_flaps_changed = 0;
if (fabsf(flaps_control - _flaps_cmd_last) > 0.01f) {
t_flaps_changed = hrt_absolute_time();
delta_flaps = flaps_control - _flaps_cmd_last;
_flaps_cmd_last = flaps_control;
}
static float flaps_applied = 0.0f;
if (fabsf(flaps_applied - flaps_control) > 0.01f) {
flaps_applied = (flaps_control - delta_flaps) + (float)hrt_elapsed_time(&t_flaps_changed) * (delta_flaps) / 1000000;
}
/* default flaperon to center */
float flaperon = 0.0f;
static float delta_flaperon = 0.0f;
/* map flaperons by default to manual if valid */
if (PX4_ISFINITE(_manual.aux2) && _vcontrol_mode.flag_control_manual_enabled) {
flaperon = 0.5f * (_manual.aux2 + 1.0f) * _parameters.flaperon_scale;
} else if (_vcontrol_mode.flag_control_auto_enabled) {
flaperon = _att_sp.apply_flaps ? 1.0f * _parameters.flaperon_scale : 0.0f;
}
// move the actual control value continuous with time
static hrt_abstime t_flaperons_changed = 0;
if (fabsf(flaperon - _flaperons_cmd_last) > 0.01f) {
t_flaperons_changed = hrt_absolute_time();
delta_flaperon = flaperon - _flaperons_cmd_last;
_flaperons_cmd_last = flaperon;
}
static float flaperon_applied = 0.0f;
if (fabsf(flaperon_applied - flaperon) > 0.01f) {
flaperon_applied = (flaperon - delta_flaperon) + (float)hrt_elapsed_time(&t_flaperons_changed) * (delta_flaperon) / 1000000;
} }
/* decide if in stabilized or full manual control */ /* decide if in stabilized or full manual control */
@@ -806,11 +903,19 @@ FixedwingAttitudeControl::task_main()
* *
* Forcing the scaling to this value allows reasonable handheld tests. * Forcing the scaling to this value allows reasonable handheld tests.
*/ */
float airspeed_scaling = _parameters.airspeed_trim / ((airspeed < _parameters.airspeed_min) ? _parameters.airspeed_min : airspeed); float airspeed_scaling = _parameters.airspeed_trim / ((airspeed < _parameters.airspeed_min) ? _parameters.airspeed_min : airspeed);
/* Use min airspeed to calculate ground speed scaling region.
* Don't scale below gspd_scaling_trim
*/
float groundspeed = sqrtf(_global_pos.vel_n * _global_pos.vel_n +
_global_pos.vel_e * _global_pos.vel_e);
float gspd_scaling_trim = (_parameters.airspeed_min * 0.6f);
float groundspeed_scaler = gspd_scaling_trim / ((groundspeed < gspd_scaling_trim) ? gspd_scaling_trim : groundspeed);
float roll_sp = _parameters.rollsp_offset_rad; float roll_sp = _parameters.rollsp_offset_rad;
float pitch_sp = _parameters.pitchsp_offset_rad; float pitch_sp = _parameters.pitchsp_offset_rad;
float yaw_sp = 0.0f;
float yaw_manual = 0.0f; float yaw_manual = 0.0f;
float throttle_sp = 0.0f; float throttle_sp = 0.0f;
@@ -824,6 +929,7 @@ FixedwingAttitudeControl::task_main()
/* read in attitude setpoint from attitude setpoint uorb topic */ /* read in attitude setpoint from attitude setpoint uorb topic */
roll_sp = _att_sp.roll_body + _parameters.rollsp_offset_rad; roll_sp = _att_sp.roll_body + _parameters.rollsp_offset_rad;
pitch_sp = _att_sp.pitch_body + _parameters.pitchsp_offset_rad; pitch_sp = _att_sp.pitch_body + _parameters.pitchsp_offset_rad;
yaw_sp = _att_sp.yaw_body;
throttle_sp = _att_sp.thrust; throttle_sp = _att_sp.thrust;
/* reset integrals where needed */ /* reset integrals where needed */
@@ -835,6 +941,7 @@ FixedwingAttitudeControl::task_main()
} }
if (_att_sp.yaw_reset_integral) { if (_att_sp.yaw_reset_integral) {
_yaw_ctrl.reset_integrator(); _yaw_ctrl.reset_integrator();
_wheel_ctrl.reset_integrator();
} }
} else if (_vcontrol_mode.flag_control_velocity_enabled) { } else if (_vcontrol_mode.flag_control_velocity_enabled) {
@@ -860,6 +967,7 @@ FixedwingAttitudeControl::task_main()
} }
if (_att_sp.yaw_reset_integral) { if (_att_sp.yaw_reset_integral) {
_yaw_ctrl.reset_integrator(); _yaw_ctrl.reset_integrator();
_wheel_ctrl.reset_integrator();
} }
} else if (_vcontrol_mode.flag_control_altitude_enabled) { } else if (_vcontrol_mode.flag_control_altitude_enabled) {
@@ -879,6 +987,7 @@ FixedwingAttitudeControl::task_main()
} }
if (_att_sp.yaw_reset_integral) { if (_att_sp.yaw_reset_integral) {
_yaw_ctrl.reset_integrator(); _yaw_ctrl.reset_integrator();
_wheel_ctrl.reset_integrator();
} }
} else { } else {
/* /*
@@ -929,6 +1038,7 @@ FixedwingAttitudeControl::task_main()
_roll_ctrl.reset_integrator(); _roll_ctrl.reset_integrator();
_pitch_ctrl.reset_integrator(); _pitch_ctrl.reset_integrator();
_yaw_ctrl.reset_integrator(); _yaw_ctrl.reset_integrator();
_wheel_ctrl.reset_integrator();
} }
/* Prepare speed_body_u and speed_body_w */ /* Prepare speed_body_u and speed_body_w */
@@ -952,17 +1062,23 @@ FixedwingAttitudeControl::task_main()
control_input.acc_body_z = _accel.z; control_input.acc_body_z = _accel.z;
control_input.roll_setpoint = roll_sp; control_input.roll_setpoint = roll_sp;
control_input.pitch_setpoint = pitch_sp; control_input.pitch_setpoint = pitch_sp;
control_input.yaw_setpoint = yaw_sp;
control_input.airspeed_min = _parameters.airspeed_min; control_input.airspeed_min = _parameters.airspeed_min;
control_input.airspeed_max = _parameters.airspeed_max; control_input.airspeed_max = _parameters.airspeed_max;
control_input.airspeed = airspeed; control_input.airspeed = airspeed;
control_input.scaler = airspeed_scaling; control_input.scaler = airspeed_scaling;
control_input.lock_integrator = lock_integrator; control_input.lock_integrator = lock_integrator;
control_input.groundspeed = groundspeed;
control_input.groundspeed_scaler = groundspeed_scaler;
_yaw_ctrl.set_coordinated_method(_parameters.y_coordinated_method);
/* Run attitude controllers */ /* Run attitude controllers */
if (PX4_ISFINITE(roll_sp) && PX4_ISFINITE(pitch_sp)) { if (PX4_ISFINITE(roll_sp) && PX4_ISFINITE(pitch_sp)) {
_roll_ctrl.control_attitude(control_input); _roll_ctrl.control_attitude(control_input);
_pitch_ctrl.control_attitude(control_input); _pitch_ctrl.control_attitude(control_input);
_yaw_ctrl.control_attitude(control_input); //runs last, because is depending on output of roll and pitch attitude _yaw_ctrl.control_attitude(control_input); //runs last, because is depending on output of roll and pitch attitude
_wheel_ctrl.control_attitude(control_input);
/* Update input data for rate controllers */ /* Update input data for rate controllers */
control_input.roll_rate_setpoint = _roll_ctrl.get_desired_rate(); control_input.roll_rate_setpoint = _roll_ctrl.get_desired_rate();
@@ -1002,13 +1118,21 @@ FixedwingAttitudeControl::task_main()
} }
} }
float yaw_u = _yaw_ctrl.control_bodyrate(control_input); float yaw_u = 0.0f;
if (_att_sp.fw_control_yaw == true) {
yaw_u = _wheel_ctrl.control_bodyrate(control_input);
}
else {
yaw_u = _yaw_ctrl.control_bodyrate(control_input);
}
_actuators.control[2] = (PX4_ISFINITE(yaw_u)) ? yaw_u + _parameters.trim_yaw : _parameters.trim_yaw; _actuators.control[2] = (PX4_ISFINITE(yaw_u)) ? yaw_u + _parameters.trim_yaw : _parameters.trim_yaw;
/* add in manual rudder control */ /* add in manual rudder control */
_actuators.control[2] += yaw_manual; _actuators.control[2] += yaw_manual;
if (!PX4_ISFINITE(yaw_u)) { if (!PX4_ISFINITE(yaw_u)) {
_yaw_ctrl.reset_integrator(); _yaw_ctrl.reset_integrator();
_wheel_ctrl.reset_integrator();
perf_count(_nonfinite_output_perf); perf_count(_nonfinite_output_perf);
if (_debug && loop_counter % 10 == 0) { if (_debug && loop_counter % 10 == 0) {
warnx("yaw_u %.4f", (double)yaw_u); warnx("yaw_u %.4f", (double)yaw_u);
@@ -1059,9 +1183,9 @@ FixedwingAttitudeControl::task_main()
_actuators.control[actuator_controls_s::INDEX_THROTTLE] = _manual.z; _actuators.control[actuator_controls_s::INDEX_THROTTLE] = _manual.z;
} }
_actuators.control[actuator_controls_s::INDEX_FLAPS] = flaps_control; _actuators.control[actuator_controls_s::INDEX_FLAPS] = flaps_applied;
_actuators.control[5] = _manual.aux1; _actuators.control[5] = _manual.aux1;
_actuators.control[6] = _manual.aux2; _actuators.control[actuator_controls_s::INDEX_AIRBRAKES] = flaperon_applied;
_actuators.control[7] = _manual.aux3; _actuators.control[7] = _manual.aux3;
/* lazily publish the setpoint only once available */ /* lazily publish the setpoint only once available */
@@ -220,6 +220,55 @@ PARAM_DEFINE_FLOAT(FW_YR_IMAX, 0.2f);
*/ */
PARAM_DEFINE_FLOAT(FW_Y_RMAX, 0.0f); PARAM_DEFINE_FLOAT(FW_Y_RMAX, 0.0f);
/**
* Wheel steering rate proportional gain
*
* This defines how much the wheel steering input will be commanded depending on the
* current body angular rate error.
*
* @min 0.005
* @max 1.0
* @group FW Attitude Control
*/
PARAM_DEFINE_FLOAT(FW_WR_P, 0.5f);
/**
* Wheel steering rate integrator gain
*
* This gain defines how much control response will result out of a steady
* state error. It trims any constant error.
*
* @min 0.0
* @max 50.0
* @group FW Attitude Control
*/
PARAM_DEFINE_FLOAT(FW_WR_I, 0.1f);
/**
* Wheel steering rate integrator limit
*
* The portion of the integrator part in the control surface deflection is
* limited to this value
*
* @min 0.0
* @max 1.0
* @group FW Attitude Control
*/
PARAM_DEFINE_FLOAT(FW_WR_IMAX, 1.0f);
/**
* Maximum wheel steering rate
*
* This limits the maximum wheel steering rate the controller will output (in degrees per
* second). Setting a value of zero disables the limit.
*
* @unit deg/s
* @min 0.0
* @max 90.0
* @group FW Attitude Control
*/
PARAM_DEFINE_FLOAT(FW_W_RMAX, 0.0f);
/** /**
* Roll rate feed forward * Roll rate feed forward
* *
@@ -255,6 +304,17 @@ PARAM_DEFINE_FLOAT(FW_PR_FF, 0.5f);
*/ */
PARAM_DEFINE_FLOAT(FW_YR_FF, 0.3f); PARAM_DEFINE_FLOAT(FW_YR_FF, 0.3f);
/**
* Wheel steering rate feed forward
*
* Direct feed forward from rate setpoint to control surface output
*
* @min 0.0
* @max 10.0
* @group FW Attitude Control
*/
PARAM_DEFINE_FLOAT(FW_WR_FF, 0.2f);
/** /**
* Minimal speed for yaw coordination * Minimal speed for yaw coordination
* *
@@ -374,3 +434,21 @@ PARAM_DEFINE_FLOAT(FW_MAN_R_MAX, 45.0f);
* @group FW Attitude Control * @group FW Attitude Control
*/ */
PARAM_DEFINE_FLOAT(FW_MAN_P_MAX, 45.0f); PARAM_DEFINE_FLOAT(FW_MAN_P_MAX, 45.0f);
/**
* Scale factor for flaps
*
* @min 0.0
* @max 1.0
* @group FW Attitude Control
*/
PARAM_DEFINE_FLOAT(FW_FLAPS_SCL, 1.0f);
/**
* Scale factor for flaperons
*
* @min 0.0
* @max 1.0
* @group FW Attitude Control
*/
PARAM_DEFINE_FLOAT(FW_FLAPERON_SCL, 0.0f);
@@ -49,6 +49,7 @@
* *
* @author Lorenz Meier <lm@inf.ethz.ch> * @author Lorenz Meier <lm@inf.ethz.ch>
* @author Thomas Gubler <thomasgubler@gmail.com> * @author Thomas Gubler <thomasgubler@gmail.com>
* @author Andreas Antener <andreas@uaventure.com>
*/ */
#include <px4_config.h> #include <px4_config.h>
@@ -95,6 +96,7 @@
#include "landingslope.h" #include "landingslope.h"
#include "mtecs/mTecs.h" #include "mtecs/mTecs.h"
#include <platforms/px4_defines.h> #include <platforms/px4_defines.h>
#include <runway_takeoff/RunwayTakeoff.h>
static int _control_task = -1; /**< task handle for sensor task */ static int _control_task = -1; /**< task handle for sensor task */
#define HDG_HOLD_DIST_NEXT 3000.0f // initial distance of waypoint in front of plane in heading hold mode #define HDG_HOLD_DIST_NEXT 3000.0f // initial distance of waypoint in front of plane in heading hold mode
@@ -103,6 +105,7 @@ static int _control_task = -1; /**< task handle for sensor task */
#define HDG_HOLD_YAWRATE_THRESH 0.15f // max yawrate at which plane locks yaw for heading hold mode #define HDG_HOLD_YAWRATE_THRESH 0.15f // max yawrate at which plane locks yaw for heading hold mode
#define HDG_HOLD_MAN_INPUT_THRESH 0.01f // max manual roll input from user which does not change the locked heading #define HDG_HOLD_MAN_INPUT_THRESH 0.01f // max manual roll input from user which does not change the locked heading
#define TAKEOFF_IDLE 0.2f // idle speed for POSCTRL/ATTCTRL (when landed and throttle stick > 0) #define TAKEOFF_IDLE 0.2f // idle speed for POSCTRL/ATTCTRL (when landed and throttle stick > 0)
#define T_ALT_TIMEOUT 1 // time after which we abort landing if terrain estimate is not valid
static constexpr float THROTTLE_THRESH = 0.05f; ///< max throttle from user which will not lead to motors spinning up in altitude controlled modes static constexpr float THROTTLE_THRESH = 0.05f; ///< max throttle from user which will not lead to motors spinning up in altitude controlled modes
static constexpr float MANUAL_THROTTLE_CLIMBOUT_THRESH = 0.85f; ///< a throttle / pitch input above this value leads to the system switching to climbout mode static constexpr float MANUAL_THROTTLE_CLIMBOUT_THRESH = 0.85f; ///< a throttle / pitch input above this value leads to the system switching to climbout mode
@@ -194,9 +197,17 @@ private:
bool land_onslope; bool land_onslope;
bool land_useterrain; bool land_useterrain;
// landing relevant states
float _t_alt_prev_valid; //**< last terrain estimate which was valid */
hrt_abstime _time_last_t_alt; //*< time at which we had last valid terrain alt */
hrt_abstime _time_started_landing; //*< time at which landing started */
float height_flare; //*< estimated height to ground at which flare started */
bool _was_in_air; /**< indicated wether the plane was in the air in the previous interation*/ bool _was_in_air; /**< indicated wether the plane was in the air in the previous interation*/
hrt_abstime _time_went_in_air; /**< time at which the plane went in the air */ hrt_abstime _time_went_in_air; /**< time at which the plane went in the air */
runwaytakeoff::RunwayTakeoff _runway_takeoff;
/* takeoff/launch states */ /* takeoff/launch states */
LaunchDetectionResult launch_detection_state; LaunchDetectionResult launch_detection_state;
@@ -277,6 +288,7 @@ private:
float land_flare_pitch_min_deg; float land_flare_pitch_min_deg;
float land_flare_pitch_max_deg; float land_flare_pitch_max_deg;
int land_use_terrain_estimate; int land_use_terrain_estimate;
float land_airspeed_scale;
} _parameters; /**< local copies of interesting parameters */ } _parameters; /**< local copies of interesting parameters */
@@ -325,6 +337,7 @@ private:
param_t land_flare_pitch_min_deg; param_t land_flare_pitch_min_deg;
param_t land_flare_pitch_max_deg; param_t land_flare_pitch_max_deg;
param_t land_use_terrain_estimate; param_t land_use_terrain_estimate;
param_t land_airspeed_scale;
} _parameter_handles; /**< handles for interesting parameters */ } _parameter_handles; /**< handles for interesting parameters */
@@ -391,6 +404,11 @@ private:
*/ */
float get_terrain_altitude_landing(float land_setpoint_alt, const struct vehicle_global_position_s &global_pos); float get_terrain_altitude_landing(float land_setpoint_alt, const struct vehicle_global_position_s &global_pos);
/**
* Return the terrain estimate during takeoff or takeoff_alt if terrain estimate is not available
*/
float get_terrain_altitude_takeoff(float takeoff_alt, const struct vehicle_global_position_s &global_pos);
/** /**
* Check if we are in a takeoff situation * Check if we are in a takeoff situation
*/ */
@@ -519,8 +537,13 @@ FixedwingPositionControl::FixedwingPositionControl() :
land_motor_lim(false), land_motor_lim(false),
land_onslope(false), land_onslope(false),
land_useterrain(false), land_useterrain(false),
_t_alt_prev_valid(0),
_time_last_t_alt(0),
_time_started_landing(0),
height_flare(0.0f),
_was_in_air(false), _was_in_air(false),
_time_went_in_air(0), _time_went_in_air(0),
_runway_takeoff(),
launch_detection_state(LAUNCHDETECTION_RES_NONE), launch_detection_state(LAUNCHDETECTION_RES_NONE),
last_manual(false), last_manual(false),
landingslope(), landingslope(),
@@ -562,6 +585,7 @@ FixedwingPositionControl::FixedwingPositionControl() :
_parameter_handles.land_flare_pitch_min_deg = param_find("FW_FLARE_PMIN"); _parameter_handles.land_flare_pitch_min_deg = param_find("FW_FLARE_PMIN");
_parameter_handles.land_flare_pitch_max_deg = param_find("FW_FLARE_PMAX"); _parameter_handles.land_flare_pitch_max_deg = param_find("FW_FLARE_PMAX");
_parameter_handles.land_use_terrain_estimate= param_find("FW_LND_USETER"); _parameter_handles.land_use_terrain_estimate= param_find("FW_LND_USETER");
_parameter_handles.land_airspeed_scale = param_find("FW_AIRSPD_SCALE");
_parameter_handles.time_const = param_find("FW_T_TIME_CONST"); _parameter_handles.time_const = param_find("FW_T_TIME_CONST");
_parameter_handles.time_const_throt = param_find("FW_T_THRO_CONST"); _parameter_handles.time_const_throt = param_find("FW_T_THRO_CONST");
@@ -665,6 +689,7 @@ FixedwingPositionControl::parameters_update()
param_get(_parameter_handles.land_flare_pitch_min_deg, &(_parameters.land_flare_pitch_min_deg)); param_get(_parameter_handles.land_flare_pitch_min_deg, &(_parameters.land_flare_pitch_min_deg));
param_get(_parameter_handles.land_flare_pitch_max_deg, &(_parameters.land_flare_pitch_max_deg)); param_get(_parameter_handles.land_flare_pitch_max_deg, &(_parameters.land_flare_pitch_max_deg));
param_get(_parameter_handles.land_use_terrain_estimate, &(_parameters.land_use_terrain_estimate)); param_get(_parameter_handles.land_use_terrain_estimate, &(_parameters.land_use_terrain_estimate));
param_get(_parameter_handles.land_airspeed_scale, &(_parameters.land_airspeed_scale));
_l1_control.set_l1_damping(_parameters.l1_damping); _l1_control.set_l1_damping(_parameters.l1_damping);
_l1_control.set_l1_period(_parameters.l1_period); _l1_control.set_l1_period(_parameters.l1_period);
@@ -715,6 +740,8 @@ FixedwingPositionControl::parameters_update()
/* Update the mTecs */ /* Update the mTecs */
_mTecs.updateParams(); _mTecs.updateParams();
_runway_takeoff.updateParams();
return OK; return OK;
} }
@@ -947,9 +974,9 @@ float FixedwingPositionControl::get_terrain_altitude_landing(float land_setpoint
/* Decide if the terrain estimation can be used, once we switched to using the terrain we stick with it /* Decide if the terrain estimation can be used, once we switched to using the terrain we stick with it
* for the whole landing */ * for the whole landing */
if (_parameters.land_use_terrain_estimate && (global_pos.terrain_alt_valid || land_useterrain)) { if (_parameters.land_use_terrain_estimate && global_pos.terrain_alt_valid) {
if(!land_useterrain) { if(!land_useterrain) {
mavlink_log_info(_mavlink_fd, "#audio: Landing, using terrain estimate"); mavlink_log_info(_mavlink_fd, "Landing, using terrain estimate");
land_useterrain = true; land_useterrain = true;
} }
return global_pos.terrain_alt; return global_pos.terrain_alt;
@@ -958,6 +985,15 @@ float FixedwingPositionControl::get_terrain_altitude_landing(float land_setpoint
} }
} }
float FixedwingPositionControl::get_terrain_altitude_takeoff(float takeoff_alt, const struct vehicle_global_position_s &global_pos)
{
if (PX4_ISFINITE(global_pos.terrain_alt) && global_pos.terrain_alt_valid) {
return global_pos.terrain_alt;
}
return takeoff_alt;
}
bool FixedwingPositionControl::update_desired_altitude(float dt) bool FixedwingPositionControl::update_desired_altitude(float dt)
{ {
/* /*
@@ -1054,6 +1090,8 @@ FixedwingPositionControl::control_position(const math::Vector<2> &current_positi
bool setpoint = true; bool setpoint = true;
_att_sp.fw_control_yaw = false; // by default we don't want yaw to be contoller directly with rudder
_att_sp.apply_flaps = false; // by default we don't use flaps
float eas2tas = 1.0f; // XXX calculate actual number based on current measurements float eas2tas = 1.0f; // XXX calculate actual number based on current measurements
/* filter speed and altitude for controller */ /* filter speed and altitude for controller */
@@ -1171,19 +1209,39 @@ FixedwingPositionControl::control_position(const math::Vector<2> &current_positi
_att_sp.roll_body = _l1_control.nav_roll(); _att_sp.roll_body = _l1_control.nav_roll();
_att_sp.yaw_body = _l1_control.nav_bearing(); _att_sp.yaw_body = _l1_control.nav_bearing();
if (in_takeoff_situation()) { float alt_sp;
if (_nav_capabilities.abort_landing == true) {
// if we entered loiter due to an aborted landing, demand
// altitude setpoint well above landing waypoint
alt_sp = _pos_sp_triplet.current.alt + 2.0f * _parameters.climbout_diff;
} else {
// use altitude given by wapoint
alt_sp = _pos_sp_triplet.current.alt;
}
if (in_takeoff_situation() ||
((_global_pos.alt < _pos_sp_triplet.current.alt + _parameters.climbout_diff ) && _nav_capabilities.abort_landing == true)) {
/* limit roll motion to ensure enough lift */ /* limit roll motion to ensure enough lift */
_att_sp.roll_body = math::constrain(_att_sp.roll_body, math::radians(-15.0f), _att_sp.roll_body = math::constrain(_att_sp.roll_body, math::radians(-15.0f),
math::radians(15.0f)); math::radians(15.0f));
} }
tecs_update_pitch_throttle(_pos_sp_triplet.current.alt, calculate_target_airspeed(_parameters.airspeed_trim), eas2tas, tecs_update_pitch_throttle(alt_sp, calculate_target_airspeed(_parameters.airspeed_trim), eas2tas,
math::radians(_parameters.pitch_limit_min), math::radians(_parameters.pitch_limit_max), math::radians(_parameters.pitch_limit_min), math::radians(_parameters.pitch_limit_max),
_parameters.throttle_min, _parameters.throttle_max, _parameters.throttle_cruise, _parameters.throttle_min, _parameters.throttle_max, _parameters.throttle_cruise,
false, math::radians(_parameters.pitch_limit_min), _global_pos.alt, ground_speed); false, math::radians(_parameters.pitch_limit_min), _global_pos.alt, ground_speed);
} else if (pos_sp_triplet.current.type == position_setpoint_s::SETPOINT_TYPE_LAND) { } else if (pos_sp_triplet.current.type == position_setpoint_s::SETPOINT_TYPE_LAND) {
// apply full flaps for landings. this flag will also trigger the use of flaperons
// if they have been enabled using the corresponding parameter
_att_sp.apply_flaps = true;
// save time at which we started landing
if (_time_started_landing == 0) {
_time_started_landing = hrt_absolute_time();
}
float bearing_lastwp_currwp = get_bearing_to_next_waypoint(prev_wp(0), prev_wp(1), curr_wp(0), curr_wp(1)); float bearing_lastwp_currwp = get_bearing_to_next_waypoint(prev_wp(0), prev_wp(1), curr_wp(0), curr_wp(1));
float bearing_airplane_currwp = get_bearing_to_next_waypoint(current_position(0), current_position(1), curr_wp(0), curr_wp(1)); float bearing_airplane_currwp = get_bearing_to_next_waypoint(current_position(0), current_position(1), curr_wp(0), curr_wp(1));
@@ -1196,7 +1254,20 @@ FixedwingPositionControl::control_position(const math::Vector<2> &current_positi
wp_distance_save = 0.0f; wp_distance_save = 0.0f;
} }
//warnx("wp dist: %d, alt err: %d, noret: %s", (int)wp_distance, (int)altitude_error, (land_noreturn) ? "YES" : "NO"); // create virtual waypoint which is on the desired flight path but
// some distance behind landing waypoint. This will make sure that the plane
// will always follow the desired flight path even if we get close or past
// the landing waypoint
math::Vector<2> curr_wp_shifted;
double lat;
double lon;
create_waypoint_from_line_and_dist(pos_sp_triplet.current.lat, pos_sp_triplet.current.lon, pos_sp_triplet.previous.lat,pos_sp_triplet.previous.lon, -1000.0f, &lat, &lon);
curr_wp_shifted(0) = (float)lat;
curr_wp_shifted(1) = (float)lon;
// we want the plane to keep tracking the desired flight path until we start flaring
// if we go into heading hold mode earlier then we risk to be pushed away from the runway by cross winds
//if (land_noreturn_vertical) {
if (wp_distance < _parameters.land_heading_hold_horizontal_distance || land_noreturn_horizontal) { if (wp_distance < _parameters.land_heading_hold_horizontal_distance || land_noreturn_horizontal) {
/* heading hold, along the line connecting this and the last waypoint */ /* heading hold, along the line connecting this and the last waypoint */
@@ -1207,7 +1278,7 @@ FixedwingPositionControl::control_position(const math::Vector<2> &current_positi
} else { } else {
target_bearing = _yaw; target_bearing = _yaw;
} }
mavlink_log_info(_mavlink_fd, "#audio: Landing, heading hold"); mavlink_log_info(_mavlink_fd, "#Landing, heading hold");
} }
// warnx("NORET: %d, target_bearing: %d, yaw: %d", (int)land_noreturn_horizontal, (int)math::degrees(target_bearing), (int)math::degrees(_yaw)); // warnx("NORET: %d, target_bearing: %d, yaw: %d", (int)land_noreturn_horizontal, (int)math::degrees(target_bearing), (int)math::degrees(_yaw));
@@ -1236,12 +1307,45 @@ FixedwingPositionControl::control_position(const math::Vector<2> &current_positi
// XXX this could make a great param // XXX this could make a great param
float throttle_land = _parameters.throttle_min + (_parameters.throttle_max - _parameters.throttle_min) * 0.1f; float throttle_land = _parameters.throttle_min + (_parameters.throttle_max - _parameters.throttle_min) * 0.1f;
float airspeed_land = 1.3f * _parameters.airspeed_min; float airspeed_land = _parameters.land_airspeed_scale * _parameters.airspeed_min;
float airspeed_approach = 1.3f * _parameters.airspeed_min; float airspeed_approach = _parameters.land_airspeed_scale * _parameters.airspeed_min;
/* Get an estimate of the terrain altitude if available, otherwise terrain_alt will be /* Get an estimate of the terrain altitude if available, otherwise terrain_alt will be
* equal to _pos_sp_triplet.current.alt */ * equal to _pos_sp_triplet.current.alt */
float terrain_alt = get_terrain_altitude_landing(_pos_sp_triplet.current.alt, _global_pos); float terrain_alt;
if (_parameters.land_use_terrain_estimate) {
if (_global_pos.terrain_alt_valid) {
// all good, have valid terrain altitude
terrain_alt = _global_pos.terrain_alt;
_t_alt_prev_valid = terrain_alt;
_time_last_t_alt = hrt_absolute_time();
} else if (_time_last_t_alt == 0) {
// we have started landing phase but don't have valid terrain
// wait for some time, maybe we will soon get a valid estimate
// until then just use the altitude of the landing waypoint
if (hrt_elapsed_time(&_time_started_landing) < 10 * 1000 * 1000) {
terrain_alt = _pos_sp_triplet.current.alt;
} else {
// still no valid terrain, abort landing
terrain_alt = _pos_sp_triplet.current.alt;
_nav_capabilities.abort_landing = true;
}
} else if ((!_global_pos.terrain_alt_valid && hrt_elapsed_time(&_time_last_t_alt) < T_ALT_TIMEOUT * 1000 * 1000)
|| land_noreturn_vertical) {
// use previous terrain estimate for some time and hope to recover
// if we are already flaring (land_noreturn_vertical) then just
// go with the old estimate
terrain_alt = _t_alt_prev_valid;
} else {
// terrain alt was not valid for long time, abort landing
terrain_alt = _t_alt_prev_valid;
_nav_capabilities.abort_landing = true;
}
} else {
// no terrain estimation, just use landing waypoint altitude
terrain_alt = _pos_sp_triplet.current.alt;
}
/* Calculate distance (to landing waypoint) and altitude of last ordinary waypoint L */ /* Calculate distance (to landing waypoint) and altitude of last ordinary waypoint L */
float L_altitude_rel = _pos_sp_triplet.previous.valid ? float L_altitude_rel = _pos_sp_triplet.previous.valid ?
@@ -1264,11 +1368,15 @@ FixedwingPositionControl::control_position(const math::Vector<2> &current_positi
/* kill the throttle if param requests it */ /* kill the throttle if param requests it */
throttle_max = _parameters.throttle_max; throttle_max = _parameters.throttle_max;
/* enable direct yaw control using rudder/wheel */
_att_sp.yaw_body = target_bearing;
_att_sp.fw_control_yaw = true;
if (_global_pos.alt < terrain_alt + landingslope.motor_lim_relative_alt() || land_motor_lim) { if (_global_pos.alt < terrain_alt + landingslope.motor_lim_relative_alt() || land_motor_lim) {
throttle_max = math::min(throttle_max, _parameters.throttle_land_max); throttle_max = math::min(throttle_max, _parameters.throttle_land_max);
if (!land_motor_lim) { if (!land_motor_lim) {
land_motor_lim = true; land_motor_lim = true;
mavlink_log_info(_mavlink_fd, "#audio: Landing, limiting throttle"); mavlink_log_info(_mavlink_fd, "#Landing, limiting throttle");
} }
} }
@@ -1292,10 +1400,19 @@ FixedwingPositionControl::control_position(const math::Vector<2> &current_positi
land_motor_lim ? tecs_status_s::TECS_MODE_LAND_THROTTLELIM : tecs_status_s::TECS_MODE_LAND); land_motor_lim ? tecs_status_s::TECS_MODE_LAND_THROTTLELIM : tecs_status_s::TECS_MODE_LAND);
if (!land_noreturn_vertical) { if (!land_noreturn_vertical) {
mavlink_log_info(_mavlink_fd, "#audio: Landing, flaring"); // just started with the flaring phase
_att_sp.pitch_body = 0.0f;
height_flare = _global_pos.alt - terrain_alt;
mavlink_log_info(_mavlink_fd, "#Landing, flaring");
land_noreturn_vertical = true; land_noreturn_vertical = true;
} else {
if (_global_pos.vel_d > 0.1f) {
_att_sp.pitch_body = math::radians(_parameters.land_flare_pitch_min_deg) *
math::constrain((height_flare - (_global_pos.alt - terrain_alt)) / height_flare, 0.0f, 1.0f);
} else {
_att_sp.pitch_body = _att_sp.pitch_body;
}
} }
//warnx("Landing: flare, _global_pos.alt %.1f, flare_curve_alt %.1f, flare_curve_alt_last %.1f, flare_length %.1f, wp_distance %.1f", _global_pos.alt, flare_curve_alt, flare_curve_alt_last, flare_length, wp_distance);
flare_curve_alt_rel_last = flare_curve_alt_rel; flare_curve_alt_rel_last = flare_curve_alt_rel;
} else { } else {
@@ -1314,7 +1431,7 @@ FixedwingPositionControl::control_position(const math::Vector<2> &current_positi
/* stay on slope */ /* stay on slope */
altitude_desired_rel = landing_slope_alt_rel_desired; altitude_desired_rel = landing_slope_alt_rel_desired;
if (!land_onslope) { if (!land_onslope) {
mavlink_log_info(_mavlink_fd, "#audio: Landing, on slope"); mavlink_log_info(_mavlink_fd, "#Landing, on slope");
land_onslope = true; land_onslope = true;
} }
} else { } else {
@@ -1338,94 +1455,160 @@ FixedwingPositionControl::control_position(const math::Vector<2> &current_positi
} else if (pos_sp_triplet.current.type == position_setpoint_s::SETPOINT_TYPE_TAKEOFF) { } else if (pos_sp_triplet.current.type == position_setpoint_s::SETPOINT_TYPE_TAKEOFF) {
/* Perform launch detection */ if (_runway_takeoff.runwayTakeoffEnabled()) {
if (launchDetector.launchDetectionEnabled() && if (!_runway_takeoff.isInitialized()) {
launch_detection_state != LAUNCHDETECTION_RES_DETECTED_ENABLEMOTORS) { math::Quaternion q(&_ctrl_state.q[0]);
/* Inform user that launchdetection is running */ math::Vector<3> euler = q.to_euler();
static hrt_abstime last_sent = 0; _runway_takeoff.init(euler(2), _global_pos.lat, _global_pos.lon);
if(hrt_absolute_time() - last_sent > 4e6) {
mavlink_log_critical(_mavlink_fd, "Launchdetection running"); /* need this already before takeoff is detected
last_sent = hrt_absolute_time(); * doesn't matter if it gets reset when takeoff is detected eventually */
_takeoff_ground_alt = _global_pos.alt;
mavlink_log_info(_mavlink_fd, "#Takeoff on runway");
} }
/* Detect launch */ float terrain_alt = get_terrain_altitude_takeoff(_takeoff_ground_alt, _global_pos);
launchDetector.update(_sensor_combined.accelerometer_m_s2[0]);
/* update our copy of the launch detection state */ // update runway takeoff helper
launch_detection_state = launchDetector.getLaunchDetected(); _runway_takeoff.update(
} else { _ctrl_state.airspeed,
/* no takeoff detection --> fly */ _global_pos.alt - terrain_alt,
launch_detection_state = LAUNCHDETECTION_RES_DETECTED_ENABLEMOTORS; _global_pos.lat,
} _global_pos.lon,
_mavlink_fd);
/* Set control values depending on the detection state */ /*
if (launch_detection_state != LAUNCHDETECTION_RES_NONE) { * Update navigation: _runway_takeoff returns the start WP according to mode and phase.
/* Launch has been detected, hence we have to control the plane. */ * If we use the navigator heading or not is decided later.
*/
_l1_control.navigate_waypoints(_runway_takeoff.getStartWP(), curr_wp, current_position, ground_speed_2d);
_l1_control.navigate_waypoints(prev_wp, curr_wp, current_position, ground_speed_2d); // update tecs
_att_sp.roll_body = _l1_control.nav_roll(); float takeoff_pitch_max_deg = _runway_takeoff.getMaxPitch(_parameters.pitch_limit_max);
_att_sp.yaw_body = _l1_control.nav_bearing();
/* Select throttle: only in LAUNCHDETECTION_RES_DETECTED_ENABLEMOTORS we want to use
* full throttle, otherwise we use the preTakeOff Throttle */
float takeoff_throttle = launch_detection_state !=
LAUNCHDETECTION_RES_DETECTED_ENABLEMOTORS ?
launchDetector.getThrottlePreTakeoff() : _parameters.throttle_max;
/* select maximum pitch: the launchdetector may impose another limit for the pitch
* depending on the state of the launch */
float takeoff_pitch_max_deg = launchDetector.getPitchMax(_parameters.pitch_limit_max);
float takeoff_pitch_max_rad = math::radians(takeoff_pitch_max_deg); float takeoff_pitch_max_rad = math::radians(takeoff_pitch_max_deg);
/* apply minimum pitch and limit roll if target altitude is not within climbout_diff tecs_update_pitch_throttle(_pos_sp_triplet.current.alt,
* meters */ calculate_target_airspeed(
if (_parameters.climbout_diff > 0.001f && altitude_error > _parameters.climbout_diff) { _runway_takeoff.getMinAirspeedScaling() * _parameters.airspeed_min),
eas2tas,
math::radians(_parameters.pitch_limit_min),
takeoff_pitch_max_rad,
_parameters.throttle_min,
_parameters.throttle_max, // XXX should we also set runway_takeoff_throttle here?
_parameters.throttle_cruise,
_runway_takeoff.climbout(),
math::radians(_runway_takeoff.getMinPitch(
_pos_sp_triplet.current.pitch_min,
10.0f,
_parameters.pitch_limit_min)),
_global_pos.alt,
ground_speed,
tecs_status_s::TECS_MODE_TAKEOFF,
takeoff_pitch_max_deg != _parameters.pitch_limit_max);
/* enforce a minimum of 10 degrees pitch up on takeoff, or take parameter */ // assign values
tecs_update_pitch_throttle(_pos_sp_triplet.current.alt, _att_sp.roll_body = _runway_takeoff.getRoll(_l1_control.nav_roll());
calculate_target_airspeed(1.3f * _parameters.airspeed_min), _att_sp.yaw_body = _runway_takeoff.getYaw(_l1_control.nav_bearing());
eas2tas, _att_sp.fw_control_yaw = _runway_takeoff.controlYaw();
math::radians(_parameters.pitch_limit_min), _att_sp.pitch_body = _runway_takeoff.getPitch(_tecs.get_pitch_demand());
takeoff_pitch_max_rad,
_parameters.throttle_min, takeoff_throttle,
_parameters.throttle_cruise,
true,
math::max(math::radians(pos_sp_triplet.current.pitch_min),
math::radians(10.0f)),
_global_pos.alt,
ground_speed,
tecs_status_s::TECS_MODE_TAKEOFF,
takeoff_pitch_max_deg != _parameters.pitch_limit_max);
/* limit roll motion to ensure enough lift */ // reset integrals except yaw (which also counts for the wheel controller)
_att_sp.roll_body = math::constrain(_att_sp.roll_body, math::radians(-15.0f), _att_sp.roll_reset_integral = _runway_takeoff.resetIntegrators();
math::radians(15.0f)); _att_sp.pitch_reset_integral = _runway_takeoff.resetIntegrators();
/*warnx("yaw: %.4f, roll: %.4f, pitch: %.4f", (double)_att_sp.yaw_body,
(double)_att_sp.roll_body, (double)_att_sp.pitch_body);*/
} else {
tecs_update_pitch_throttle(_pos_sp_triplet.current.alt,
calculate_target_airspeed(_parameters.airspeed_trim),
eas2tas,
math::radians(_parameters.pitch_limit_min),
math::radians(_parameters.pitch_limit_max),
_parameters.throttle_min,
takeoff_throttle,
_parameters.throttle_cruise,
false,
math::radians(_parameters.pitch_limit_min),
_global_pos.alt,
ground_speed);
}
} else { } else {
/* Tell the attitude controller to stop integrating while we are waiting /* Perform launch detection */
* for the launch */ if (launchDetector.launchDetectionEnabled() &&
_att_sp.roll_reset_integral = true; launch_detection_state != LAUNCHDETECTION_RES_DETECTED_ENABLEMOTORS) {
_att_sp.pitch_reset_integral = true; /* Inform user that launchdetection is running */
_att_sp.yaw_reset_integral = true; static hrt_abstime last_sent = 0;
if(hrt_absolute_time() - last_sent > 4e6) {
mavlink_log_critical(_mavlink_fd, "#Launchdetection running");
last_sent = hrt_absolute_time();
}
/* Set default roll and pitch setpoints during detection phase */ /* Detect launch */
_att_sp.roll_body = 0.0f; launchDetector.update(_sensor_combined.accelerometer_m_s2[0]);
_att_sp.pitch_body = math::max(math::radians(pos_sp_triplet.current.pitch_min),
math::radians(10.0f)); /* update our copy of the launch detection state */
launch_detection_state = launchDetector.getLaunchDetected();
} else {
/* no takeoff detection --> fly */
launch_detection_state = LAUNCHDETECTION_RES_DETECTED_ENABLEMOTORS;
}
/* Set control values depending on the detection state */
if (launch_detection_state != LAUNCHDETECTION_RES_NONE) {
/* Launch has been detected, hence we have to control the plane. */
_l1_control.navigate_waypoints(prev_wp, curr_wp, current_position, ground_speed_2d);
_att_sp.roll_body = _l1_control.nav_roll();
_att_sp.yaw_body = _l1_control.nav_bearing();
/* Select throttle: only in LAUNCHDETECTION_RES_DETECTED_ENABLEMOTORS we want to use
* full throttle, otherwise we use the preTakeOff Throttle */
float takeoff_throttle = launch_detection_state !=
LAUNCHDETECTION_RES_DETECTED_ENABLEMOTORS ?
launchDetector.getThrottlePreTakeoff() : _parameters.throttle_max;
/* select maximum pitch: the launchdetector may impose another limit for the pitch
* depending on the state of the launch */
float takeoff_pitch_max_deg = launchDetector.getPitchMax(_parameters.pitch_limit_max);
float takeoff_pitch_max_rad = math::radians(takeoff_pitch_max_deg);
/* apply minimum pitch and limit roll if target altitude is not within climbout_diff
* meters */
if (_parameters.climbout_diff > 0.001f && altitude_error > _parameters.climbout_diff) {
/* enforce a minimum of 10 degrees pitch up on takeoff, or take parameter */
tecs_update_pitch_throttle(_pos_sp_triplet.current.alt,
calculate_target_airspeed(1.3f * _parameters.airspeed_min),
eas2tas,
math::radians(_parameters.pitch_limit_min),
takeoff_pitch_max_rad,
_parameters.throttle_min, takeoff_throttle,
_parameters.throttle_cruise,
true,
math::max(math::radians(_pos_sp_triplet.current.pitch_min),
math::radians(10.0f)),
_global_pos.alt,
ground_speed,
tecs_status_s::TECS_MODE_TAKEOFF,
takeoff_pitch_max_deg != _parameters.pitch_limit_max);
/* limit roll motion to ensure enough lift */
_att_sp.roll_body = math::constrain(_att_sp.roll_body, math::radians(-15.0f),
math::radians(15.0f));
} else {
tecs_update_pitch_throttle(_pos_sp_triplet.current.alt,
calculate_target_airspeed(_parameters.airspeed_trim),
eas2tas,
math::radians(_parameters.pitch_limit_min),
math::radians(_parameters.pitch_limit_max),
_parameters.throttle_min,
takeoff_throttle,
_parameters.throttle_cruise,
false,
math::radians(_parameters.pitch_limit_min),
_global_pos.alt,
ground_speed);
}
} else {
/* Tell the attitude controller to stop integrating while we are waiting
* for the launch */
_att_sp.roll_reset_integral = true;
_att_sp.pitch_reset_integral = true;
_att_sp.yaw_reset_integral = true;
/* Set default roll and pitch setpoints during detection phase */
_att_sp.roll_body = 0.0f;
_att_sp.pitch_body = math::max(math::radians(pos_sp_triplet.current.pitch_min),
math::radians(10.0f));
}
} }
} }
@@ -1620,9 +1803,16 @@ FixedwingPositionControl::control_position(const math::Vector<2> &current_positi
/** MANUAL FLIGHT **/ /** MANUAL FLIGHT **/
/* reset hold altitude */ // reset hold altitude
_hold_alt = _global_pos.alt; _hold_alt = _global_pos.alt;
// reset terrain estimation relevant values
_time_started_landing = 0;
_time_last_t_alt = 0;
// reset lading abort state
_nav_capabilities.abort_landing = false;
/* no flight mode applies, do not publish an attitude setpoint */ /* no flight mode applies, do not publish an attitude setpoint */
setpoint = false; setpoint = false;
@@ -1637,15 +1827,26 @@ FixedwingPositionControl::control_position(const math::Vector<2> &current_positi
if (_vehicle_status.engine_failure || _vehicle_status.engine_failure_cmd) { if (_vehicle_status.engine_failure || _vehicle_status.engine_failure_cmd) {
/* Set thrust to 0 to minimize damage */ /* Set thrust to 0 to minimize damage */
_att_sp.thrust = 0.0f; _att_sp.thrust = 0.0f;
} else if (_control_mode_current == FW_POSCTRL_MODE_AUTO && // launchdetector only available in auto } else if (_control_mode_current == FW_POSCTRL_MODE_AUTO && // launchdetector only available in auto
pos_sp_triplet.current.type == position_setpoint_s::SETPOINT_TYPE_TAKEOFF && pos_sp_triplet.current.type == position_setpoint_s::SETPOINT_TYPE_TAKEOFF &&
launch_detection_state != LAUNCHDETECTION_RES_DETECTED_ENABLEMOTORS) { launch_detection_state != LAUNCHDETECTION_RES_DETECTED_ENABLEMOTORS &&
!_runway_takeoff.runwayTakeoffEnabled()) {
/* making sure again that the correct thrust is used, /* making sure again that the correct thrust is used,
* without depending on library calls for safety reasons */ * without depending on library calls for safety reasons */
_att_sp.thrust = launchDetector.getThrottlePreTakeoff(); _att_sp.thrust = launchDetector.getThrottlePreTakeoff();
} else if (_control_mode_current == FW_POSCTRL_MODE_AUTO &&
pos_sp_triplet.current.type == position_setpoint_s::SETPOINT_TYPE_TAKEOFF &&
_runway_takeoff.runwayTakeoffEnabled()) {
_att_sp.thrust = _runway_takeoff.getThrottle(
math::min(_mTecs.getEnabled() ? _mTecs.getThrottleSetpoint() :
_tecs.get_throttle_demand(), throttle_max));
} else if (_control_mode_current == FW_POSCTRL_MODE_AUTO && } else if (_control_mode_current == FW_POSCTRL_MODE_AUTO &&
pos_sp_triplet.current.type == position_setpoint_s::SETPOINT_TYPE_IDLE) { pos_sp_triplet.current.type == position_setpoint_s::SETPOINT_TYPE_IDLE) {
_att_sp.thrust = 0.0f; _att_sp.thrust = 0.0f;
} else { } else {
/* Copy thrust and pitch values from tecs */ /* Copy thrust and pitch values from tecs */
if (_vehicle_status.condition_landed && if (_vehicle_status.condition_landed &&
@@ -1663,9 +1864,13 @@ FixedwingPositionControl::control_position(const math::Vector<2> &current_positi
/* During a takeoff waypoint while waiting for launch the pitch sp is set /* During a takeoff waypoint while waiting for launch the pitch sp is set
* already (not by tecs) */ * already (not by tecs) */
if (!(_control_mode_current == FW_POSCTRL_MODE_AUTO && if (!(_control_mode_current == FW_POSCTRL_MODE_AUTO && (
pos_sp_triplet.current.type == position_setpoint_s::SETPOINT_TYPE_TAKEOFF && (pos_sp_triplet.current.type == position_setpoint_s::SETPOINT_TYPE_TAKEOFF &&
launch_detection_state == LAUNCHDETECTION_RES_NONE)) { (launch_detection_state == LAUNCHDETECTION_RES_NONE ||
_runway_takeoff.runwayTakeoffEnabled())) ||
(pos_sp_triplet.current.type == position_setpoint_s::SETPOINT_TYPE_LAND &&
land_noreturn_vertical))
)) {
_att_sp.pitch_body = _mTecs.getEnabled() ? _mTecs.getPitchSetpoint() : _tecs.get_pitch_demand(); _att_sp.pitch_body = _mTecs.getEnabled() ? _mTecs.getPitchSetpoint() : _tecs.get_pitch_demand();
} }
@@ -1825,6 +2030,7 @@ void FixedwingPositionControl::reset_takeoff_state()
{ {
launch_detection_state = LAUNCHDETECTION_RES_NONE; launch_detection_state = LAUNCHDETECTION_RES_NONE;
launchDetector.reset(); launchDetector.reset();
_runway_takeoff.reset();
} }
void FixedwingPositionControl::reset_landing_state() void FixedwingPositionControl::reset_landing_state()
@@ -443,3 +443,15 @@ PARAM_DEFINE_FLOAT(FW_FLARE_PMIN, 2.5f);
* *
*/ */
PARAM_DEFINE_FLOAT(FW_FLARE_PMAX, 15.0f); PARAM_DEFINE_FLOAT(FW_FLARE_PMAX, 15.0f);
/**
* Takeoff and landing airspeed scale factor
*
* Multiplying this factor with the minimum airspeed of the plane
* gives the target airspeed for takeoff and landing approach.
*
* @min 1.0
* @max 1.5
* @group L1 Control
*/
PARAM_DEFINE_FLOAT(FW_AIRSPD_SCALE, 1.3f);
+8 -1
View File
@@ -1523,6 +1523,9 @@ Mavlink::task_main(int argc, char *argv[])
} else if (strcmp(myoptarg, "osd") == 0) { } else if (strcmp(myoptarg, "osd") == 0) {
_mode = MAVLINK_MODE_OSD; _mode = MAVLINK_MODE_OSD;
} else if (strcmp(myoptarg, "magic") == 0) {
_mode = MAVLINK_MODE_MAGIC;
} else if (strcmp(myoptarg, "config") == 0) { } else if (strcmp(myoptarg, "config") == 0) {
_mode = MAVLINK_MODE_CONFIG; _mode = MAVLINK_MODE_CONFIG;
} }
@@ -1709,7 +1712,7 @@ Mavlink::task_main(int argc, char *argv[])
configure_stream("SYSTEM_TIME", 1.0f); configure_stream("SYSTEM_TIME", 1.0f);
configure_stream("TIMESYNC", 10.0f); configure_stream("TIMESYNC", 10.0f);
configure_stream("ACTUATOR_CONTROL_TARGET0", 10.0f); configure_stream("ACTUATOR_CONTROL_TARGET0", 10.0f);
/* camera trigger is rate limited at the source, do not limit here */ //camera trigger is rate limited at the source, do not limit here
configure_stream("CAMERA_TRIGGER", 500.0f); configure_stream("CAMERA_TRIGGER", 500.0f);
configure_stream("EXTENDED_SYS_STATE", 2.0f); configure_stream("EXTENDED_SYS_STATE", 2.0f);
break; break;
@@ -1729,6 +1732,10 @@ Mavlink::task_main(int argc, char *argv[])
configure_stream("EXTENDED_SYS_STATE", 1.0f); configure_stream("EXTENDED_SYS_STATE", 1.0f);
break; break;
case MAVLINK_MODE_MAGIC:
//stream nothing
break;
case MAVLINK_MODE_CONFIG: case MAVLINK_MODE_CONFIG:
// Enable a number of interesting streams we want via USB // Enable a number of interesting streams we want via USB
configure_stream("SYS_STATUS", 1.0f); configure_stream("SYS_STATUS", 1.0f);
+1
View File
@@ -149,6 +149,7 @@ public:
MAVLINK_MODE_CUSTOM, MAVLINK_MODE_CUSTOM,
MAVLINK_MODE_ONBOARD, MAVLINK_MODE_ONBOARD,
MAVLINK_MODE_OSD, MAVLINK_MODE_OSD,
MAVLINK_MODE_MAGIC,
MAVLINK_MODE_CONFIG MAVLINK_MODE_CONFIG
}; };
+1 -1
View File
@@ -52,7 +52,7 @@
* @unit meters * @unit meters
* @group Mission * @group Mission
*/ */
PARAM_DEFINE_FLOAT(MIS_TAKEOFF_ALT, 10.0f); PARAM_DEFINE_FLOAT(MIS_TAKEOFF_ALT, 2.5f);
/** /**
* Enable persistent onboard mission storage * Enable persistent onboard mission storage
+2 -4
View File
@@ -135,7 +135,7 @@ public:
struct vehicle_gps_position_s* get_gps_position() { return &_gps_pos; } struct vehicle_gps_position_s* get_gps_position() { return &_gps_pos; }
struct sensor_combined_s* get_sensor_combined() { return &_sensor_combined; } struct sensor_combined_s* get_sensor_combined() { return &_sensor_combined; }
struct home_position_s* get_home_position() { return &_home_pos; } struct home_position_s* get_home_position() { return &_home_pos; }
bool home_position_valid() { return _home_position_set; } bool home_position_valid() { return (_home_pos.timestamp > 0); }
struct position_setpoint_triplet_s* get_position_setpoint_triplet() { return &_pos_sp_triplet; } struct position_setpoint_triplet_s* get_position_setpoint_triplet() { return &_pos_sp_triplet; }
struct mission_result_s* get_mission_result() { return &_mission_result; } struct mission_result_s* get_mission_result() { return &_mission_result; }
struct geofence_result_s* get_geofence_result() { return &_geofence_result; } struct geofence_result_s* get_geofence_result() { return &_geofence_result; }
@@ -205,8 +205,6 @@ private:
geofence_result_s _geofence_result; geofence_result_s _geofence_result;
vehicle_attitude_setpoint_s _att_sp; vehicle_attitude_setpoint_s _att_sp;
bool _home_position_set;
bool _mission_item_valid; /**< flags if the current mission item is valid */ bool _mission_item_valid; /**< flags if the current mission item is valid */
int _mission_instance_count; /**< instance count for the current mission */ int _mission_instance_count; /**< instance count for the current mission */
@@ -257,7 +255,7 @@ private:
/** /**
* Retrieve home position * Retrieve home position
*/ */
void home_position_update(); void home_position_update(bool force=false);
/** /**
* Retreive navigation capabilities * Retreive navigation capabilities
+14 -12
View File
@@ -126,7 +126,6 @@ Navigator::Navigator() :
_pos_sp_triplet{}, _pos_sp_triplet{},
_mission_result{}, _mission_result{},
_att_sp{}, _att_sp{},
_home_position_set(false),
_mission_item_valid(false), _mission_item_valid(false),
_mission_instance_count(0), _mission_instance_count(0),
_loop_perf(perf_alloc(PC_ELAPSED, "navigator")), _loop_perf(perf_alloc(PC_ELAPSED, "navigator")),
@@ -206,17 +205,13 @@ Navigator::sensor_combined_update()
} }
void void
Navigator::home_position_update() Navigator::home_position_update(bool force)
{ {
bool updated = false; bool updated = false;
orb_check(_home_pos_sub, &updated); orb_check(_home_pos_sub, &updated);
if (updated) { if (updated || force) {
orb_copy(ORB_ID(home_position), _home_pos_sub, &_home_pos); orb_copy(ORB_ID(home_position), _home_pos_sub, &_home_pos);
if (_home_pos.timestamp > 0) {
_home_position_set = true;
}
} }
} }
@@ -298,7 +293,7 @@ Navigator::task_main()
global_position_update(); global_position_update();
gps_position_update(); gps_position_update();
sensor_combined_update(); sensor_combined_update();
home_position_update(); home_position_update(true);
navigation_capabilities_update(); navigation_capabilities_update();
params_update(); params_update();
@@ -408,7 +403,7 @@ Navigator::task_main()
if (have_geofence_position_data && if (have_geofence_position_data &&
(_geofence.getGeofenceAction() != geofence_result_s::GF_ACTION_NONE) && (_geofence.getGeofenceAction() != geofence_result_s::GF_ACTION_NONE) &&
(hrt_elapsed_time(&last_geofence_check) > GEOFENCE_CHECK_INTERVAL)) { (hrt_elapsed_time(&last_geofence_check) > GEOFENCE_CHECK_INTERVAL)) {
bool inside = _geofence.inside(_global_pos, _gps_pos, _sensor_combined.baro_alt_meter[0], _home_pos, _home_position_set); bool inside = _geofence.inside(_global_pos, _gps_pos, _sensor_combined.baro_alt_meter[0], _home_pos, home_position_valid());
last_geofence_check = hrt_absolute_time(); last_geofence_check = hrt_absolute_time();
have_geofence_position_data = false; have_geofence_position_data = false;
@@ -445,8 +440,15 @@ Navigator::task_main()
_can_loiter_at_sp = false; _can_loiter_at_sp = false;
break; break;
case vehicle_status_s::NAVIGATION_STATE_AUTO_MISSION: case vehicle_status_s::NAVIGATION_STATE_AUTO_MISSION:
_pos_sp_triplet_published_invalid_once = false; if (_nav_caps.abort_landing) {
_navigation_mode = &_mission; // pos controller aborted landing, requests loiter
// above landing waypoint
_navigation_mode = &_loiter;
_pos_sp_triplet_published_invalid_once = false;
} else {
_pos_sp_triplet_published_invalid_once = false;
_navigation_mode = &_mission;
}
break; break;
case vehicle_status_s::NAVIGATION_STATE_AUTO_LOITER: case vehicle_status_s::NAVIGATION_STATE_AUTO_LOITER:
_pos_sp_triplet_published_invalid_once = false; _pos_sp_triplet_published_invalid_once = false;
@@ -489,7 +491,7 @@ Navigator::task_main()
} }
/* iterate through navigation modes and set active/inactive for each */ /* iterate through navigation modes and set active/inactive for each */
for(unsigned int i = 0; i < NAVIGATOR_MODE_ARRAY_SIZE; i++) { for (unsigned int i = 0; i < NAVIGATOR_MODE_ARRAY_SIZE; i++) {
_navigation_mode_array[i]->run(_navigation_mode == _navigation_mode_array[i]); _navigation_mode_array[i]->run(_navigation_mode == _navigation_mode_array[i]);
} }
@@ -31,7 +31,7 @@
# #
############################################################################ ############################################################################
if(${OS} STREQUAL "nuttx") if(${OS} STREQUAL "nuttx")
list(APPEND MODULE_CFLAGS -Wframe-larger-than=3890) list(APPEND MODULE_CFLAGS -Wframe-larger-than=4000)
endif() endif()
px4_add_module( px4_add_module(
MODULE modules__position_estimator_inav MODULE modules__position_estimator_inav
@@ -586,8 +586,6 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
/* set this flag if flow should be accurate according to current velocity and attitude rate estimate */ /* set this flag if flow should be accurate according to current velocity and attitude rate estimate */
flow_accurate = fabsf(body_v_est[1] / flow_dist - att.rollspeed) < max_flow && flow_accurate = fabsf(body_v_est[1] / flow_dist - att.rollspeed) < max_flow &&
fabsf(body_v_est[0] / flow_dist + att.pitchspeed) < max_flow; fabsf(body_v_est[0] / flow_dist + att.pitchspeed) < max_flow;
//this flag is not working -->
flow_accurate = true; //already checked if flow_q > 0.3
/*calculate offset of flow-gyro using already calibrated gyro from autopilot*/ /*calculate offset of flow-gyro using already calibrated gyro from autopilot*/
@@ -840,7 +838,7 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
} else if (t > ref_init_start + ref_init_delay) { } else if (t > ref_init_start + ref_init_delay) {
ref_inited = true; ref_inited = true;
/* set position estimate to (0, 0, 0), use GPS velocity for XY */ /* set position estimate to (0, 0, 0), use GPS velocity for XY */
x_est[0] = 0.0f; x_est[0] = 0.0f;
x_est[1] = gps.vel_n_m_s; x_est[1] = gps.vel_n_m_s;
@@ -953,9 +951,15 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
t_prev = t; t_prev = t;
/* increase EPH/EPV on each step */ /* increase EPH/EPV on each step */
if (eph < 0.000001f) { //get case where eph is 0 -> would stay 0
eph = 0.001;
}
if (eph < max_eph_epv) { if (eph < max_eph_epv) {
eph *= 1.0f + dt; eph *= 1.0f + dt;
} }
if (epv < 0.000001f) { //get case where epv is 0 -> would stay 0
epv = 0.001;
}
if (epv < max_eph_epv) { if (epv < max_eph_epv) {
epv += 0.005f * dt; // add 1m to EPV each 200s (baro drift) epv += 0.005f * dt; // add 1m to EPV each 200s (baro drift)
} }
@@ -968,9 +972,13 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
bool use_vision_z = vision_valid && params.w_z_vision_p > MIN_VALID_W; bool use_vision_z = vision_valid && params.w_z_vision_p > MIN_VALID_W;
/* use MOCAP if it's valid and has a valid weight parameter */ /* use MOCAP if it's valid and has a valid weight parameter */
bool use_mocap = mocap_valid && params.w_mocap_p > MIN_VALID_W; bool use_mocap = mocap_valid && params.w_mocap_p > MIN_VALID_W;
if(params.disable_mocap) { //disable mocap if fake gps is used
use_mocap = false;
}
/* use flow if it's valid and (accurate or no GPS available) */ /* use flow if it's valid and (accurate or no GPS available) */
bool use_flow = flow_valid && (flow_accurate || !use_gps_xy); bool use_flow = flow_valid && (flow_accurate || !use_gps_xy);
bool can_estimate_xy = (eph < max_eph_epv) || use_gps_xy || use_flow || use_vision_xy || use_mocap; bool can_estimate_xy = (eph < max_eph_epv) || use_gps_xy || use_flow || use_vision_xy || use_mocap;
bool dist_bottom_valid = (t < lidar_valid_time + lidar_valid_timeout); bool dist_bottom_valid = (t < lidar_valid_time + lidar_valid_timeout);
@@ -1166,7 +1174,6 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
inertial_filter_correct(corr_flow[0], dt, x_est, 1, params.w_xy_flow * w_flow); inertial_filter_correct(corr_flow[0], dt, x_est, 1, params.w_xy_flow * w_flow);
inertial_filter_correct(corr_flow[1], dt, y_est, 1, params.w_xy_flow * w_flow); inertial_filter_correct(corr_flow[1], dt, y_est, 1, params.w_xy_flow * w_flow);
//mavlink_log_info(mavlink_fd, "w_flow = %2.4f\t w_xy_flow = %2.4f\n", (double)w_flow, (double)params.w_xy_flow);
} }
if (use_gps_xy) { if (use_gps_xy) {
@@ -1264,6 +1271,7 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
buf_ptr = 0; buf_ptr = 0;
} }
/* publish local position */ /* publish local position */
local_pos.xy_valid = can_estimate_xy; local_pos.xy_valid = can_estimate_xy;
local_pos.v_xy_valid = can_estimate_xy; local_pos.v_xy_valid = can_estimate_xy;
@@ -158,10 +158,10 @@ PARAM_DEFINE_FLOAT(INAV_W_XY_VIS_V, 0.0f);
* Weight (cutoff frequency) for optical flow (velocity) measurements. * Weight (cutoff frequency) for optical flow (velocity) measurements.
* *
* @min 0.0 * @min 0.0
* @max 30.0 * @max 10.0
* @group Position Estimator INAV * @group Position Estimator INAV
*/ */
PARAM_DEFINE_FLOAT(INAV_W_XY_FLOW, 10.0f); PARAM_DEFINE_FLOAT(INAV_W_XY_FLOW, 9.0f);
/** /**
* XY axis weight for resetting velocity * XY axis weight for resetting velocity
@@ -313,6 +313,17 @@ PARAM_DEFINE_FLOAT(INAV_FLOW_DIST_X, 0.0f);
*/ */
PARAM_DEFINE_FLOAT(INAV_FLOW_DIST_Y, 0.0f); PARAM_DEFINE_FLOAT(INAV_FLOW_DIST_Y, 0.0f);
/**
* Disable mocap (set 0 if using fake gps)
*
* Disable mocap
*
* @min 0
* @max 1
* @group Position Estimator INAV
*/
PARAM_DEFINE_FLOAT(INAV_DISAB_MOCAP, 0);
/** /**
* Disable vision input * Disable vision input
* *
@@ -364,6 +375,7 @@ int inav_parameters_init(struct position_estimator_inav_param_handles *h)
h->delay_gps = param_find("INAV_DELAY_GPS"); h->delay_gps = param_find("INAV_DELAY_GPS");
h->flow_module_offset_x = param_find("INAV_FLOW_DIST_X"); h->flow_module_offset_x = param_find("INAV_FLOW_DIST_X");
h->flow_module_offset_y = param_find("INAV_FLOW_DIST_Y"); h->flow_module_offset_y = param_find("INAV_FLOW_DIST_Y");
h->disable_mocap = param_find("INAV_DISAB_MOCAP");
return 0; return 0;
} }
@@ -394,6 +406,7 @@ int inav_parameters_update(const struct position_estimator_inav_param_handles *h
param_get(h->delay_gps, &(p->delay_gps)); param_get(h->delay_gps, &(p->delay_gps));
param_get(h->flow_module_offset_x, &(p->flow_module_offset_x)); param_get(h->flow_module_offset_x, &(p->flow_module_offset_x));
param_get(h->flow_module_offset_y, &(p->flow_module_offset_y)); param_get(h->flow_module_offset_y, &(p->flow_module_offset_y));
param_get(h->disable_mocap, &(p->disable_mocap));
return 0; return 0;
} }
@@ -67,6 +67,7 @@ struct position_estimator_inav_params {
float delay_gps; float delay_gps;
float flow_module_offset_x; float flow_module_offset_x;
float flow_module_offset_y; float flow_module_offset_y;
int32_t disable_mocap;
}; };
struct position_estimator_inav_param_handles { struct position_estimator_inav_param_handles {
@@ -95,6 +96,7 @@ struct position_estimator_inav_param_handles {
param_t delay_gps; param_t delay_gps;
param_t flow_module_offset_x; param_t flow_module_offset_x;
param_t flow_module_offset_y; param_t flow_module_offset_y;
param_t disable_mocap;
}; };
#define CBRK_NO_VISION_KEY 328754 #define CBRK_NO_VISION_KEY 328754
+1 -1
View File
@@ -425,7 +425,6 @@ int create_log_dir()
mkdir_ret = mkdir(log_dir, S_IRWXU | S_IRWXG | S_IRWXO); mkdir_ret = mkdir(log_dir, S_IRWXU | S_IRWXG | S_IRWXO);
if (mkdir_ret == 0) { if (mkdir_ret == 0) {
warnx("log dir created: %s", log_dir);
break; break;
} else if (errno != EEXIST) { } else if (errno != EEXIST) {
@@ -1677,6 +1676,7 @@ int sdlog2_thread_main(int argc, char *argv[])
log_msg.msg_type = LOG_RC_MSG; log_msg.msg_type = LOG_RC_MSG;
/* Copy only the first 8 channels of 14 */ /* Copy only the first 8 channels of 14 */
memcpy(log_msg.body.log_RC.channel, buf.rc.channels, sizeof(log_msg.body.log_RC.channel)); memcpy(log_msg.body.log_RC.channel, buf.rc.channels, sizeof(log_msg.body.log_RC.channel));
log_msg.body.log_RC.rssi = buf.rc.rssi;
log_msg.body.log_RC.channel_count = buf.rc.channel_count; log_msg.body.log_RC.channel_count = buf.rc.channel_count;
log_msg.body.log_RC.signal_lost = buf.rc.signal_lost; log_msg.body.log_RC.signal_lost = buf.rc.signal_lost;
LOGBUFFER_WRITE_AND_COUNT(RC); LOGBUFFER_WRITE_AND_COUNT(RC);
+2 -1
View File
@@ -189,6 +189,7 @@ struct log_STAT_s {
#define LOG_RC_MSG 11 #define LOG_RC_MSG 11
struct log_RC_s { struct log_RC_s {
float channel[8]; float channel[8];
uint8_t rssi;
uint8_t channel_count; uint8_t channel_count;
uint8_t signal_lost; uint8_t signal_lost;
}; };
@@ -532,7 +533,7 @@ static const struct log_format_s log_formats[] = {
LOG_FORMAT(STAT, "BBBfBBf", "MainState,ArmS,Failsafe,BatRem,BatWarn,Landed,Load"), LOG_FORMAT(STAT, "BBBfBBf", "MainState,ArmS,Failsafe,BatRem,BatWarn,Landed,Load"),
LOG_FORMAT(VTOL, "f", "Arsp"), LOG_FORMAT(VTOL, "f", "Arsp"),
LOG_FORMAT(CTS, "fffffff", "Vx_b,Vy_b,Vz_b,Vinf,P,Q,R"), LOG_FORMAT(CTS, "fffffff", "Vx_b,Vy_b,Vz_b,Vinf,P,Q,R"),
LOG_FORMAT(RC, "ffffffffBB", "Ch0,Ch1,Ch2,Ch3,Ch4,Ch5,Ch6,Ch7,Count,SignalLost"), LOG_FORMAT(RC, "ffffffffBBB", "Ch0,Ch1,Ch2,Ch3,Ch4,Ch5,Ch6,Ch7,RSSI,Count,SignalLost"),
LOG_FORMAT(OUT0, "ffffffff", "Out0,Out1,Out2,Out3,Out4,Out5,Out6,Out7"), LOG_FORMAT(OUT0, "ffffffff", "Out0,Out1,Out2,Out3,Out4,Out5,Out6,Out7"),
LOG_FORMAT(AIRS, "fff", "IndSpeed,TrueSpeed,AirTemp"), LOG_FORMAT(AIRS, "fff", "IndSpeed,TrueSpeed,AirTemp"),
LOG_FORMAT(ARSP, "fff", "RollRateSP,PitchRateSP,YawRateSP"), LOG_FORMAT(ARSP, "fff", "RollRateSP,PitchRateSP,YawRateSP"),
+2 -2
View File
@@ -80,7 +80,7 @@ void Simulator::pack_actuator_message(mavlink_hil_controls_t &actuator_msg)
// for now we only support quadrotors // for now we only support quadrotors
unsigned n = 4; unsigned n = 4;
if (_vehicle_status.is_rotary_wing) { if (_vehicle_status.is_rotary_wing || _vehicle_status.is_vtol) {
for (unsigned i = 0; i < 8; i++) { for (unsigned i = 0; i < 8; i++) {
if (_actuators.output[i] > PWM_LOWEST_MIN / 2) { if (_actuators.output[i] > PWM_LOWEST_MIN / 2) {
if (i < n) { if (i < n) {
@@ -113,7 +113,7 @@ void Simulator::pack_actuator_message(mavlink_hil_controls_t &actuator_msg)
actuator_msg.time_usec = hrt_absolute_time(); actuator_msg.time_usec = hrt_absolute_time();
actuator_msg.roll_ailerons = out[0]; actuator_msg.roll_ailerons = out[0];
actuator_msg.pitch_elevator = _vehicle_status.is_rotary_wing ? out[1] : -out[1]; actuator_msg.pitch_elevator = (_vehicle_status.is_rotary_wing || _vehicle_status.is_vtol) ? out[1] : -out[1];
actuator_msg.yaw_rudder = out[2]; actuator_msg.yaw_rudder = out[2];
actuator_msg.throttle = out[3]; actuator_msg.throttle = out[3];
actuator_msg.aux1 = out[4]; actuator_msg.aux1 = out[4];
+1
View File
@@ -56,6 +56,7 @@
#define CBRK_FLIGHTTERM_KEY 121212 #define CBRK_FLIGHTTERM_KEY 121212
#define CBRK_ENGINEFAIL_KEY 284953 #define CBRK_ENGINEFAIL_KEY 284953
#define CBRK_GPSFAIL_KEY 240024 #define CBRK_GPSFAIL_KEY 240024
#define CBRK_USB_CHK_KEY 197848
#include <stdbool.h> #include <stdbool.h>
@@ -147,3 +147,16 @@ PARAM_DEFINE_INT32(CBRK_GPSFAIL, 240024);
* @group Circuit Breaker * @group Circuit Breaker
*/ */
PARAM_DEFINE_INT32(CBRK_BUZZER, 0); PARAM_DEFINE_INT32(CBRK_BUZZER, 0);
/**
* Circuit breaker for USB link check
*
* Setting this parameter to 197848 will disable the USB connected
* checks in the commander.
* WARNING: ENABLING THIS CIRCUIT BREAKER IS AT OWN RISK
*
* @min 0
* @max 197848
* @group Circuit Breaker
*/
PARAM_DEFINE_INT32(CBRK_USB_CHK, 0);
+28 -11
View File
@@ -52,7 +52,7 @@
#define RC_INPUT_MAP_UNMAPPED 0 #define RC_INPUT_MAP_UNMAPPED 0
int rc_calibration_check(int mavlink_fd) int rc_calibration_check(int mavlink_fd, bool report_fail)
{ {
char nbuf[20]; char nbuf[20];
@@ -74,7 +74,8 @@ int rc_calibration_check(int mavlink_fd)
param_t map_parm = param_find(rc_map_mandatory[j]); param_t map_parm = param_find(rc_map_mandatory[j]);
if (map_parm == PARAM_INVALID) { if (map_parm == PARAM_INVALID) {
mavlink_log_critical(mavlink_fd, "RC ERR: PARAM %s MISSING", rc_map_mandatory[j]); if (report_fail) { mavlink_and_console_log_critical(mavlink_fd, "RC ERR: PARAM %s MISSING", rc_map_mandatory[j]); }
/* give system time to flush error message in case there are more */ /* give system time to flush error message in case there are more */
usleep(100000); usleep(100000);
map_fail_count++; map_fail_count++;
@@ -86,14 +87,16 @@ int rc_calibration_check(int mavlink_fd)
param_get(map_parm, &mapping); param_get(map_parm, &mapping);
if (mapping > RC_INPUT_MAX_CHANNELS) { if (mapping > RC_INPUT_MAX_CHANNELS) {
mavlink_log_critical(mavlink_fd, "RC ERR: %s >= # CHANS", rc_map_mandatory[j]); if (report_fail) { mavlink_and_console_log_critical(mavlink_fd, "RC ERR: %s >= # CHANS", rc_map_mandatory[j]); }
/* give system time to flush error message in case there are more */ /* give system time to flush error message in case there are more */
usleep(100000); usleep(100000);
map_fail_count++; map_fail_count++;
} }
if (mapping == 0) { if (mapping == 0) {
mavlink_log_critical(mavlink_fd, "RC ERR: Mandatory %s is unmapped", rc_map_mandatory[j]); if (report_fail) { mavlink_and_console_log_critical(mavlink_fd, "RC ERR: Mandatory %s is unmapped", rc_map_mandatory[j]); }
/* give system time to flush error message in case there are more */ /* give system time to flush error message in case there are more */
usleep(100000); usleep(100000);
map_fail_count++; map_fail_count++;
@@ -144,35 +147,44 @@ int rc_calibration_check(int mavlink_fd)
/* assert min..center..max ordering */ /* assert min..center..max ordering */
if (param_min < RC_INPUT_LOWEST_MIN_US) { if (param_min < RC_INPUT_LOWEST_MIN_US) {
count++; count++;
mavlink_log_critical(mavlink_fd, "RC ERR: RC_%d_MIN < %u", i + 1, RC_INPUT_LOWEST_MIN_US);
if (report_fail) { mavlink_and_console_log_critical(mavlink_fd, "RC ERR: RC_%d_MIN < %u", i + 1, RC_INPUT_LOWEST_MIN_US); }
/* give system time to flush error message in case there are more */ /* give system time to flush error message in case there are more */
usleep(100000); usleep(100000);
} }
if (param_max > RC_INPUT_HIGHEST_MAX_US) { if (param_max > RC_INPUT_HIGHEST_MAX_US) {
count++; count++;
mavlink_log_critical(mavlink_fd, "RC ERR: RC_%d_MAX > %u", i + 1, RC_INPUT_HIGHEST_MAX_US);
if (report_fail) { mavlink_and_console_log_critical(mavlink_fd, "RC ERR: RC_%d_MAX > %u", i + 1, RC_INPUT_HIGHEST_MAX_US); }
/* give system time to flush error message in case there are more */ /* give system time to flush error message in case there are more */
usleep(100000); usleep(100000);
} }
if (param_trim < param_min) { if (param_trim < param_min) {
count++; count++;
mavlink_log_critical(mavlink_fd, "RC ERR: RC_%d_TRIM < MIN (%d/%d)", i + 1, (int)param_trim, (int)param_min);
if (report_fail) { mavlink_and_console_log_critical(mavlink_fd, "RC ERR: RC_%d_TRIM < MIN (%d/%d)", i + 1, (int)param_trim, (int)param_min); }
/* give system time to flush error message in case there are more */ /* give system time to flush error message in case there are more */
usleep(100000); usleep(100000);
} }
if (param_trim > param_max) { if (param_trim > param_max) {
count++; count++;
mavlink_log_critical(mavlink_fd, "RC ERR: RC_%d_TRIM > MAX (%d/%d)", i + 1, (int)param_trim, (int)param_max);
if (report_fail) { mavlink_and_console_log_critical(mavlink_fd, "RC ERR: RC_%d_TRIM > MAX (%d/%d)", i + 1, (int)param_trim, (int)param_max); }
/* give system time to flush error message in case there are more */ /* give system time to flush error message in case there are more */
usleep(100000); usleep(100000);
} }
/* assert deadzone is sane */ /* assert deadzone is sane */
if (param_dz > RC_INPUT_MAX_DEADZONE_US) { if (param_dz > RC_INPUT_MAX_DEADZONE_US) {
mavlink_log_critical(mavlink_fd, "RC ERR: RC_%d_DZ > %u", i + 1, RC_INPUT_MAX_DEADZONE_US); if (report_fail) { mavlink_and_console_log_critical(mavlink_fd, "RC ERR: RC_%d_DZ > %u", i + 1, RC_INPUT_MAX_DEADZONE_US); }
/* give system time to flush error message in case there are more */ /* give system time to flush error message in case there are more */
usleep(100000); usleep(100000);
count++; count++;
@@ -187,8 +199,13 @@ int rc_calibration_check(int mavlink_fd)
if (channels_failed) { if (channels_failed) {
sleep(2); sleep(2);
mavlink_and_console_log_critical(mavlink_fd, "%d config error%s for %d RC channel%s.", total_fail_count,
(total_fail_count > 1) ? "s" : "", channels_failed, (channels_failed > 1) ? "s" : ""); if (report_fail) {
mavlink_and_console_log_critical(mavlink_fd, "%d config error%s for %d RC channel%s.",
total_fail_count,
(total_fail_count > 1) ? "s" : "", channels_failed, (channels_failed > 1) ? "s" : "");
}
usleep(100000); usleep(100000);
} }
+1 -1
View File
@@ -47,6 +47,6 @@ __BEGIN_DECLS
* @return 0 / OK if RC calibration is ok, index + 1 of the first * @return 0 / OK if RC calibration is ok, index + 1 of the first
* channel that failed else (so 1 == first channel failed) * channel that failed else (so 1 == first channel failed)
*/ */
__EXPORT int rc_calibration_check(int mavlink_fd); __EXPORT int rc_calibration_check(int mavlink_fd, bool report_fail);
__END_DECLS __END_DECLS
-3
View File
@@ -37,15 +37,12 @@ set(UAVCAN_PLATFORM stm32 CACHE STRING "uavcan platform")
string(TOUPPER "${OS}" OS_UPPER) string(TOUPPER "${OS}" OS_UPPER)
add_definitions( add_definitions(
-DUAVCAN_CPP_VERSION=UAVCAN_CPP03 -DUAVCAN_CPP_VERSION=UAVCAN_CPP03
-DUAVCAN_MAX_NETWORK_SIZE_HINT=16
-DUAVCAN_MEM_POOL_BLOCK_SIZE=48 -DUAVCAN_MEM_POOL_BLOCK_SIZE=48
-DUAVCAN_NO_ASSERTIONS -DUAVCAN_NO_ASSERTIONS
-DUAVCAN_PLATFORM=stm32 -DUAVCAN_PLATFORM=stm32
-DUAVCAN_STM32_${OS_UPPER}=1 -DUAVCAN_STM32_${OS_UPPER}=1
-DUAVCAN_STM32_NUM_IFACES=2 -DUAVCAN_STM32_NUM_IFACES=2
-DUAVCAN_STM32_TIMER_NUMBER=5 -DUAVCAN_STM32_TIMER_NUMBER=5
-DUAVCAN_USE_CPP03=ON
-DUAVCAN_USE_EXTERNAL_SNPRINT
) )
add_subdirectory(libuavcan EXCLUDE_FROM_ALL) add_subdirectory(libuavcan EXCLUDE_FROM_ALL)
+73
View File
@@ -0,0 +1,73 @@
/****************************************************************************
*
* Copyright (C) 2015 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @author Pavel Kirienko <pavel.kirienko@gmail.com>
*/
#pragma once
#include <systemlib/err.h>
#include <uavcan/uavcan.hpp>
#include <uavcan/helpers/heap_based_pool_allocator.hpp>
// TODO: Entire UAVCAN application should be moved into a namespace later; this is the first step.
namespace uavcan_node
{
struct AllocatorSynchronizer
{
const ::irqstate_t state = ::irqsave();
~AllocatorSynchronizer() { ::irqrestore(state); }
};
struct Allocator : public uavcan::HeapBasedPoolAllocator<uavcan::MemPoolBlockSize, AllocatorSynchronizer>
{
static constexpr unsigned CapacitySoftLimit = 250;
static constexpr unsigned CapacityHardLimit = 500;
Allocator() :
uavcan::HeapBasedPoolAllocator<uavcan::MemPoolBlockSize, AllocatorSynchronizer>(CapacitySoftLimit, CapacityHardLimit)
{ }
~Allocator()
{
if (getNumAllocatedBlocks() > 0)
{
warnx("UAVCAN LEAKS MEMORY: %u BLOCKS (%u BYTES) LOST",
getNumAllocatedBlocks(), getNumAllocatedBlocks() * uavcan::MemPoolBlockSize);
}
}
};
}
+4 -11
View File
@@ -44,7 +44,7 @@ UavcanBarometerBridge::UavcanBarometerBridge(uavcan::INode &node) :
UavcanCDevSensorBridgeBase("uavcan_baro", "/dev/uavcan/baro", BARO_BASE_DEVICE_PATH, ORB_ID(sensor_baro)), UavcanCDevSensorBridgeBase("uavcan_baro", "/dev/uavcan/baro", BARO_BASE_DEVICE_PATH, ORB_ID(sensor_baro)),
_sub_air_pressure_data(node), _sub_air_pressure_data(node),
_sub_air_temperature_data(node), _sub_air_temperature_data(node),
_reports(nullptr) _reports(2, sizeof(baro_report))
{ } { }
int UavcanBarometerBridge::init() int UavcanBarometerBridge::init()
@@ -55,13 +55,6 @@ int UavcanBarometerBridge::init()
return res; return res;
} }
/* allocate basic report buffers */
_reports = new ringbuffer::RingBuffer(2, sizeof(baro_report));
if (_reports == nullptr) {
return -1;
}
res = _sub_air_pressure_data.start(AirPressureCbBinder(this, &UavcanBarometerBridge::air_pressure_sub_cb)); res = _sub_air_pressure_data.start(AirPressureCbBinder(this, &UavcanBarometerBridge::air_pressure_sub_cb));
if (res < 0) { if (res < 0) {
@@ -91,7 +84,7 @@ ssize_t UavcanBarometerBridge::read(struct file *filp, char *buffer, size_t bufl
} }
while (count--) { while (count--) {
if (_reports->get(baro_buf)) { if (_reports.get(baro_buf)) {
ret += sizeof(*baro_buf); ret += sizeof(*baro_buf);
baro_buf++; baro_buf++;
} }
@@ -132,7 +125,7 @@ int UavcanBarometerBridge::ioctl(struct file *filp, int cmd, unsigned long arg)
irqstate_t flags = irqsave(); irqstate_t flags = irqsave();
if (!_reports->resize(arg)) { if (!_reports.resize(arg)) {
irqrestore(flags); irqrestore(flags);
return -ENOMEM; return -ENOMEM;
} }
@@ -186,7 +179,7 @@ void UavcanBarometerBridge::air_pressure_sub_cb(const
report.altitude = (((std::pow((p / p1), (-(a * R) / g))) * T1) - T1) / a; report.altitude = (((std::pow((p / p1), (-(a * R) / g))) * T1) - T1) / a;
// add to the ring buffer // add to the ring buffer
_reports->force(&report); _reports.force(&report);
publish(msg.getSrcNodeID().get(), &report); publish(msg.getSrcNodeID().get(), &report);
} }
+3 -1
View File
@@ -76,8 +76,10 @@ private:
uavcan::Subscriber<uavcan::equipment::air_data::StaticPressure, AirPressureCbBinder> _sub_air_pressure_data; uavcan::Subscriber<uavcan::equipment::air_data::StaticPressure, AirPressureCbBinder> _sub_air_pressure_data;
uavcan::Subscriber<uavcan::equipment::air_data::StaticTemperature, AirTemperatureCbBinder> _sub_air_temperature_data; uavcan::Subscriber<uavcan::equipment::air_data::StaticTemperature, AirTemperatureCbBinder> _sub_air_temperature_data;
ringbuffer::RingBuffer _reports;
unsigned _msl_pressure = 101325; unsigned _msl_pressure = 101325;
ringbuffer::RingBuffer *_reports;
float last_temperature_kelvin = 0.0f; float last_temperature_kelvin = 0.0f;
}; };
+50 -6
View File
@@ -77,7 +77,7 @@
UavcanNode *UavcanNode::_instance; UavcanNode *UavcanNode::_instance;
UavcanNode::UavcanNode(uavcan::ICanDriver &can_driver, uavcan::ISystemClock &system_clock) : UavcanNode::UavcanNode(uavcan::ICanDriver &can_driver, uavcan::ISystemClock &system_clock) :
CDev("uavcan", UAVCAN_DEVICE_PATH), CDev("uavcan", UAVCAN_DEVICE_PATH),
_node(can_driver, system_clock), _node(can_driver, system_clock, _pool_allocator),
_node_mutex(), _node_mutex(),
_esc_controller(_node), _esc_controller(_node),
_time_sync_master(_node), _time_sync_master(_node),
@@ -144,10 +144,9 @@ UavcanNode::~UavcanNode()
} while (_task != -1); } while (_task != -1);
} }
/* clean up the alternate device node */ (void)::close(_armed_sub);
// unregister_driver(PWM_OUTPUT_DEVICE_PATH); (void)::close(_test_motor_sub);
(void)::close(_actuator_direct_sub);
::close(_armed_sub);
// Removing the sensor bridges // Removing the sensor bridges
auto br = _sensor_bridges.getHead(); auto br = _sensor_bridges.getHead();
@@ -166,6 +165,10 @@ UavcanNode::~UavcanNode()
pthread_mutex_destroy(&_node_mutex); pthread_mutex_destroy(&_node_mutex);
px4_sem_destroy(&_server_command_sem); px4_sem_destroy(&_server_command_sem);
// Is it allowed to delete it like that?
if (_mixers != nullptr) {
delete _mixers;
}
} }
int UavcanNode::getHardwareVersion(uavcan::protocol::HardwareVersion &hwver) int UavcanNode::getHardwareVersion(uavcan::protocol::HardwareVersion &hwver)
@@ -965,6 +968,8 @@ int UavcanNode::run()
} }
} }
(void)::close(busevent_fd);
teardown(); teardown();
warnx("exiting."); warnx("exiting.");
@@ -1119,6 +1124,33 @@ UavcanNode::print_info()
(void)pthread_mutex_lock(&_node_mutex); (void)pthread_mutex_lock(&_node_mutex);
// Memory status
printf("Pool allocator status:\n");
printf("\tCapacity hard/soft: %u/%u blocks\n",
_pool_allocator.getBlockCapacityHardLimit(), _pool_allocator.getBlockCapacity());
printf("\tReserved: %u blocks\n", _pool_allocator.getNumReservedBlocks());
printf("\tAllocated: %u blocks\n", _pool_allocator.getNumAllocatedBlocks());
// UAVCAN node perfcounters
printf("UAVCAN node status:\n");
printf("\tInternal failures: %llu\n", _node.getInternalFailureCount());
printf("\tTransfer errors: %llu\n", _node.getDispatcher().getTransferPerfCounter().getErrorCount());
printf("\tRX transfers: %llu\n", _node.getDispatcher().getTransferPerfCounter().getRxTransferCount());
printf("\tTX transfers: %llu\n", _node.getDispatcher().getTransferPerfCounter().getTxTransferCount());
// CAN driver status
for (unsigned i = 0; i < _node.getDispatcher().getCanIOManager().getCanDriver().getNumIfaces(); i++) {
printf("CAN%u status:\n", unsigned(i + 1));
auto iface = _node.getDispatcher().getCanIOManager().getCanDriver().getIface(i);
printf("\tHW errors: %llu\n", iface->getErrorCount());
auto iface_perf_cnt = _node.getDispatcher().getCanIOManager().getIfacePerfCounters(i);
printf("\tIO errors: %llu\n", iface_perf_cnt.errors);
printf("\tRX frames: %llu\n", iface_perf_cnt.frames_rx);
printf("\tTX frames: %llu\n", iface_perf_cnt.frames_tx);
}
// ESC mixer status // ESC mixer status
printf("ESC actuators control groups: sub: %u / req: %u / fds: %u\n", printf("ESC actuators control groups: sub: %u / req: %u / fds: %u\n",
(unsigned)_groups_subscribed, (unsigned)_groups_required, _poll_fds_num); (unsigned)_groups_subscribed, (unsigned)_groups_required, _poll_fds_num);
@@ -1169,13 +1201,20 @@ UavcanNode::print_info()
(void)pthread_mutex_unlock(&_node_mutex); (void)pthread_mutex_unlock(&_node_mutex);
} }
void UavcanNode::shrink()
{
(void)pthread_mutex_lock(&_node_mutex);
_pool_allocator.shrink();
(void)pthread_mutex_unlock(&_node_mutex);
}
/* /*
* App entry point * App entry point
*/ */
static void print_usage() static void print_usage()
{ {
warnx("usage: \n" warnx("usage: \n"
"\tuavcan {start [fw]|status|stop [all|fw]|arm|disarm|update fw|param [set|get|list|save] nodeid [name] [value]|reset nodeid}"); "\tuavcan {start [fw]|status|stop [all|fw]|shrink|arm|disarm|update fw|param [set|get|list|save] nodeid [name] [value]|reset nodeid}");
} }
extern "C" __EXPORT int uavcan_main(int argc, char *argv[]); extern "C" __EXPORT int uavcan_main(int argc, char *argv[]);
@@ -1251,6 +1290,11 @@ int uavcan_main(int argc, char *argv[])
::exit(0); ::exit(0);
} }
if (!std::strcmp(argv[1], "shrink")) {
inst->shrink();
::exit(0);
}
if (!std::strcmp(argv[1], "arm")) { if (!std::strcmp(argv[1], "arm")) {
inst->arm_actuators(true); inst->arm_actuators(true);
::exit(0); ::exit(0);
+10 -6
View File
@@ -36,6 +36,7 @@
#include <px4_config.h> #include <px4_config.h>
#include <uavcan_stm32/uavcan_stm32.hpp> #include <uavcan_stm32/uavcan_stm32.hpp>
#include <uavcan/helpers/heap_based_pool_allocator.hpp>
#include <uavcan/protocol/global_time_sync_master.hpp> #include <uavcan/protocol/global_time_sync_master.hpp>
#include <uavcan/protocol/global_time_sync_slave.hpp> #include <uavcan/protocol/global_time_sync_slave.hpp>
#include <uavcan/protocol/param/GetSet.hpp> #include <uavcan/protocol/param/GetSet.hpp>
@@ -55,6 +56,7 @@
#include "sensors/sensor_bridge.hpp" #include "sensors/sensor_bridge.hpp"
#include "uavcan_servers.hpp" #include "uavcan_servers.hpp"
#include "allocator.hpp"
/** /**
* @file uavcan_main.hpp * @file uavcan_main.hpp
@@ -78,9 +80,8 @@ class UavcanNode : public device::CDev
static constexpr unsigned FramePerSecond = MaxBitRatePerSec / bitPerFrame; static constexpr unsigned FramePerSecond = MaxBitRatePerSec / bitPerFrame;
static constexpr unsigned FramePerMSecond = ((FramePerSecond / 1000) + 1); static constexpr unsigned FramePerMSecond = ((FramePerSecond / 1000) + 1);
static constexpr unsigned PollTimeoutMs = 10; static constexpr unsigned PollTimeoutMs = 3;
static constexpr unsigned MemPoolSize = 64 * uavcan::MemPoolBlockSize;
/* /*
* This memory is reserved for uavcan to use for queuing CAN frames. * This memory is reserved for uavcan to use for queuing CAN frames.
* At 1Mbit there is approximately one CAN frame every 145 uS. * At 1Mbit there is approximately one CAN frame every 145 uS.
@@ -97,7 +98,6 @@ class UavcanNode : public device::CDev
static constexpr unsigned StackSize = 1800; static constexpr unsigned StackSize = 1800;
public: public:
typedef uavcan::Node<MemPoolSize> Node;
typedef uavcan_stm32::CanInitHelper<RxQueueLenPerIface> CanInitHelper; typedef uavcan_stm32::CanInitHelper<RxQueueLenPerIface> CanInitHelper;
enum eServerAction {None, Start, Stop, CheckFW , Busy}; enum eServerAction {None, Start, Stop, CheckFW , Busy};
@@ -109,7 +109,7 @@ public:
static int start(uavcan::NodeID node_id, uint32_t bitrate); static int start(uavcan::NodeID node_id, uint32_t bitrate);
Node &get_node() { return _node; } uavcan::Node<> &get_node() { return _node; }
// TODO: move the actuator mixing stuff into the ESC controller class // TODO: move the actuator mixing stuff into the ESC controller class
static int control_callback(uintptr_t handle, uint8_t control_group, uint8_t control_index, float &input); static int control_callback(uintptr_t handle, uint8_t control_group, uint8_t control_index, float &input);
@@ -121,6 +121,8 @@ public:
void print_info(); void print_info();
void shrink();
static UavcanNode *instance() { return _instance; } static UavcanNode *instance() { return _instance; }
static int getHardwareVersion(uavcan::protocol::HardwareVersion &hwver); static int getHardwareVersion(uavcan::protocol::HardwareVersion &hwver);
int fw_server(eServerAction action); int fw_server(eServerAction action);
@@ -130,8 +132,8 @@ public:
int set_param(int remote_node_id, const char *name, char *value); int set_param(int remote_node_id, const char *name, char *value);
int get_param(int remote_node_id, const char *name); int get_param(int remote_node_id, const char *name);
int reset_node(int remote_node_id); int reset_node(int remote_node_id);
private:
private:
void fill_node_info(); void fill_node_info();
int init(uavcan::NodeID node_id); int init(uavcan::NodeID node_id);
void node_spin_once(); void node_spin_once();
@@ -167,7 +169,9 @@ private:
static UavcanNode *_instance; ///< singleton pointer static UavcanNode *_instance; ///< singleton pointer
Node _node; ///< library instance uavcan_node::Allocator _pool_allocator;
uavcan::Node<> _node; ///< library instance
pthread_mutex_t _node_mutex; pthread_mutex_t _node_mutex;
px4_sem_t _server_command_sem; px4_sem_t _server_command_sem;
UavcanEscController _esc_controller; UavcanEscController _esc_controller;
+12 -9
View File
@@ -85,8 +85,8 @@
UavcanServers *UavcanServers::_instance; UavcanServers *UavcanServers::_instance;
UavcanServers::UavcanServers(uavcan::INode &main_node) : UavcanServers::UavcanServers(uavcan::INode &main_node) :
_subnode_thread(-1), _subnode_thread(-1),
_vdriver(NumIfaces, uavcan_stm32::SystemClock::instance()), _vdriver(NumIfaces, uavcan_stm32::SystemClock::instance(), main_node.getAllocator(), VirtualIfaceBlockAllocationQuota),
_subnode(_vdriver, uavcan_stm32::SystemClock::instance()), _subnode(_vdriver, uavcan_stm32::SystemClock::instance(), main_node.getAllocator()),
_main_node(main_node), _main_node(main_node),
_tracer(), _tracer(),
_storage_backend(), _storage_backend(),
@@ -141,13 +141,14 @@ int UavcanServers::stop()
return -1; return -1;
} }
_instance = nullptr; if (server->_subnode_thread) {
warnx("stopping fw srv thread...");
if (server->_subnode_thread != -1) { server->_subnode_thread_should_exit = true;
pthread_cancel(server->_subnode_thread); (void)pthread_join(server->_subnode_thread, NULL);
pthread_join(server->_subnode_thread, NULL);
} }
_instance = nullptr;
server->_main_node.getDispatcher().removeRxFrameListener(); server->_main_node.getDispatcher().removeRxFrameListener();
delete server; delete server;
@@ -334,7 +335,7 @@ pthread_addr_t UavcanServers::run(pthread_addr_t)
memset(_esc_enumeration_ids, 0, sizeof(_esc_enumeration_ids)); memset(_esc_enumeration_ids, 0, sizeof(_esc_enumeration_ids));
_esc_enumeration_index = 0; _esc_enumeration_index = 0;
while (1) { while (!_subnode_thread_should_exit) {
if (_check_fw == true) { if (_check_fw == true) {
_check_fw = false; _check_fw = false;
@@ -554,7 +555,9 @@ pthread_addr_t UavcanServers::run(pthread_addr_t)
} }
} }
warnx("exiting."); _subnode_thread_should_exit = false;
warnx("exiting");
return (pthread_addr_t) 0; return (pthread_addr_t) 0;
} }
+6 -21
View File
@@ -81,24 +81,10 @@ class UavcanServers
{ {
static constexpr unsigned NumIfaces = 1; // UAVCAN_STM32_NUM_IFACES static constexpr unsigned NumIfaces = 1; // UAVCAN_STM32_NUM_IFACES
static constexpr unsigned MemPoolSize = 64 * uavcan::MemPoolBlockSize;
static constexpr unsigned MaxCanFramesPerTransfer = 63;
/**
* This number is based on the worst case max number of frames per interface. With
* MemPoolBlockSize set at 48 this is 6048 Bytes.
*
* The servers can be forced to use the primary interface only, this can be achieved simply by passing
* 1 instead of UAVCAN_STM32_NUM_IFACES into the constructor of the virtual CAN driver.
*/
static constexpr unsigned QueuePoolSize =
(NumIfaces * uavcan::MemPoolBlockSize * MaxCanFramesPerTransfer);
static constexpr unsigned StackSize = 6000; static constexpr unsigned StackSize = 6000;
static constexpr unsigned Priority = 120; static constexpr unsigned Priority = 120;
typedef uavcan::SubNode<MemPoolSize> SubNode; static constexpr unsigned VirtualIfaceBlockAllocationQuota = 80;
public: public:
UavcanServers(uavcan::INode &main_node); UavcanServers(uavcan::INode &main_node);
@@ -108,7 +94,7 @@ public:
static int start(uavcan::INode &main_node); static int start(uavcan::INode &main_node);
static int stop(); static int stop();
SubNode &get_node() { return _subnode; } uavcan::SubNode<> &get_node() { return _subnode; }
static UavcanServers *instance() { return _instance; } static UavcanServers *instance() { return _instance; }
@@ -124,6 +110,7 @@ public:
private: private:
pthread_t _subnode_thread; pthread_t _subnode_thread;
pthread_mutex_t _subnode_mutex; pthread_mutex_t _subnode_mutex;
volatile bool _subnode_thread_should_exit = false;
int init(); int init();
@@ -131,12 +118,10 @@ private:
static UavcanServers *_instance; ///< singleton pointer static UavcanServers *_instance; ///< singleton pointer
typedef VirtualCanDriver<QueuePoolSize> vCanDriver; VirtualCanDriver _vdriver;
vCanDriver _vdriver; uavcan::SubNode<> _subnode;
uavcan::INode &_main_node;
uavcan::SubNode<MemPoolSize> _subnode; ///< library instance
uavcan::INode &_main_node; ///< library instance
uavcan_posix::dynamic_node_id_server::FileEventTracer _tracer; uavcan_posix::dynamic_node_id_server::FileEventTracer _tracer;
uavcan_posix::dynamic_node_id_server::FileStorageBackend _storage_backend; uavcan_posix::dynamic_node_id_server::FileStorageBackend _storage_backend;
@@ -114,6 +114,14 @@ public:
uavcan::IsDynamicallyAllocatable<Item>::check(); uavcan::IsDynamicallyAllocatable<Item>::check();
} }
~Queue()
{
while (!isEmpty())
{
pop();
}
}
bool isEmpty() const { return list_.isEmpty(); } bool isEmpty() const { return list_.isEmpty(); }
/** /**
@@ -329,11 +337,7 @@ public:
/** /**
* Objects of this class are owned by the sub-node thread. * Objects of this class are owned by the sub-node thread.
* This class does not use heap memory. * This class does not use heap memory.
* @tparam SharedMemoryPoolSize Amount of memory, in bytes, that will be statically allocated for the
* memory pool that will be shared across all interfaces for RX/TX queues.
* Typically this value should be no less than 4K per interface.
*/ */
template <unsigned SharedMemoryPoolSize>
class VirtualCanDriver : public uavcan::ICanDriver, class VirtualCanDriver : public uavcan::ICanDriver,
public uavcan::IRxFrameListener, public uavcan::IRxFrameListener,
public ITxQueueInjector, public ITxQueueInjector,
@@ -400,9 +404,8 @@ class VirtualCanDriver : public uavcan::ICanDriver,
} }
}; };
Event event_; ///< Used to unblock the select() call when IO happens. Event event_; ///< Used to unblock the select() call when IO happens.
pthread_mutex_t driver_mutex_; ///< Shared across all ifaces pthread_mutex_t driver_mutex_; ///< Shared across all ifaces
uavcan::PoolAllocator<SharedMemoryPoolSize, uavcan::MemPoolBlockSize> allocator_; ///< Shared across all ifaces
uavcan::LazyConstructor<VirtualCanIface> ifaces_[uavcan::MaxCanIfaces]; uavcan::LazyConstructor<VirtualCanIface> ifaces_[uavcan::MaxCanIfaces];
const unsigned num_ifaces_; const unsigned num_ifaces_;
uavcan::ISystemClock &clock_; uavcan::ISystemClock &clock_;
@@ -476,7 +479,10 @@ class VirtualCanDriver : public uavcan::ICanDriver,
} }
public: public:
VirtualCanDriver(unsigned arg_num_ifaces, uavcan::ISystemClock &system_clock) : VirtualCanDriver(unsigned arg_num_ifaces,
uavcan::ISystemClock &system_clock,
uavcan::IPoolAllocator& allocator,
unsigned virtual_iface_block_allocation_quota) :
num_ifaces_(arg_num_ifaces), num_ifaces_(arg_num_ifaces),
clock_(system_clock) clock_(system_clock)
{ {
@@ -485,15 +491,11 @@ public:
assert(num_ifaces_ > 0 && num_ifaces_ <= uavcan::MaxCanIfaces); assert(num_ifaces_ > 0 && num_ifaces_ <= uavcan::MaxCanIfaces);
const unsigned quota_per_iface = allocator_.getNumBlocks() / num_ifaces_; const unsigned quota_per_queue = virtual_iface_block_allocation_quota; // 2x overcommit
const unsigned quota_per_queue = quota_per_iface; // 2x overcommit
UAVCAN_TRACE("VirtualCanDriver", "Total blocks: %u, quota per queue: %u",
unsigned(allocator_.getNumBlocks()), unsigned(quota_per_queue));
for (unsigned i = 0; i < num_ifaces_; i++) { for (unsigned i = 0; i < num_ifaces_; i++) {
ifaces_[i].template construct<uavcan::IPoolAllocator &, uavcan::ISystemClock &, ifaces_[i].construct<uavcan::IPoolAllocator&, uavcan::ISystemClock&, pthread_mutex_t&,
pthread_mutex_t &, unsigned>(allocator_, clock_, driver_mutex_, quota_per_queue); unsigned>(allocator, clock_, driver_mutex_, quota_per_queue);
} }
} }
+1 -1
View File
@@ -154,7 +154,7 @@ void Standard::update_vtol_state()
} else if (_vtol_schedule.flight_mode == TRANSITION_TO_FW) { } else if (_vtol_schedule.flight_mode == TRANSITION_TO_FW) {
// continue the transition to fw mode while monitoring airspeed for a final switch to fw mode // continue the transition to fw mode while monitoring airspeed for a final switch to fw mode
if (_airspeed->true_airspeed_m_s >= _params_standard.airspeed_trans) { if (_airspeed->true_airspeed_m_s >= _params_standard.airspeed_trans || !_armed->armed) {
_vtol_schedule.flight_mode = FW_MODE; _vtol_schedule.flight_mode = FW_MODE;
// we can turn off the multirotor motors now // we can turn off the multirotor motors now
_flag_enable_mc_motors = false; _flag_enable_mc_motors = false;
+2 -1
View File
@@ -205,7 +205,8 @@ void Tiltrotor::update_vtol_state()
case TRANSITION_FRONT_P1: case TRANSITION_FRONT_P1:
// check if we have reached airspeed to switch to fw mode // check if we have reached airspeed to switch to fw mode
if (_airspeed->true_airspeed_m_s >= _params_tiltrotor.airspeed_trans) { // also allow switch if we are not armed for the sake of bench testing
if (_airspeed->true_airspeed_m_s >= _params_tiltrotor.airspeed_trans || !_armed->armed) {
_vtol_schedule.flight_mode = TRANSITION_FRONT_P2; _vtol_schedule.flight_mode = TRANSITION_FRONT_P2;
_vtol_schedule.transition_start = hrt_absolute_time(); _vtol_schedule.transition_start = hrt_absolute_time();
} }
@@ -690,6 +690,7 @@ int vtol_att_control_main(int argc, char *argv[])
return 1; return 1;
} }
return 0;
} }
if (!strcmp(argv[1], "stop")) { if (!strcmp(argv[1], "stop")) {
@@ -99,9 +99,9 @@ using namespace DriverFramework;
// Product Name Product Revision // Product Name Product Revision
#define GYROSIMES_REV_C4 0x14 #define GYROSIMES_REV_C4 0x14
#define GYROSIM_ACCEL_DEFAULT_RATE 1000 #define GYROSIM_ACCEL_DEFAULT_RATE 400
#define GYROSIM_GYRO_DEFAULT_RATE 1000 #define GYROSIM_GYRO_DEFAULT_RATE 400
#define GYROSIM_ONE_G 9.80665f #define GYROSIM_ONE_G 9.80665f

Some files were not shown because too many files have changed in this diff Show More