2020-03-06 06:30:17 -04:00
-- This script allows for best effort return for quadplanes
-- on loss of forward motor
-- When an engine failure is detected (RPM and Vibration values drop below a certain threshold), the aircraft will:
-- Send a warning ground station
-- Start prioritizing airspeed completely
-- Glide back towards the home location or rally point, monitoring the distance away from the point as well as Altitude.
-- If the aircraft drops below a predetermined minimum altitude, QLAND mode is engaged and the aircraft lands at its current position.
-- If the aircraft arrives within Q_FW_LND_APR_RAD of the return point before dropping below the minimum altitude, it should loiter down to the minimum altitude before switching to QRTL and landing.
2024-05-03 15:22:25 -03:00
---@diagnostic disable: cast-local-type
2022-04-30 00:12:03 -03:00
-- setup param block for VTOL failsafe params
local PARAM_TABLE_KEY = 77
local PARAM_TABLE_PREFIX = " VTFS_ "
assert ( param : add_table ( PARAM_TABLE_KEY , PARAM_TABLE_PREFIX , 4 ) , ' could not add param table ' )
-- add a parameter and bind it to a variable
function bind_add_param ( name , idx , default_value )
assert ( param : add_param ( PARAM_TABLE_KEY , idx , name , default_value ) , string.format ( ' could not add param %s ' , name ) )
2022-09-12 20:39:03 -03:00
return Parameter ( PARAM_TABLE_PREFIX .. name )
2022-04-30 00:12:03 -03:00
end
2020-03-06 06:30:17 -04:00
-- consider engine stopped when vibe is low and RPM low for more than 4s
2022-04-30 00:12:03 -03:00
ENGINE_STOPPED_MS = bind_add_param ( ' ENG_STOP_MS ' , 1 , 4000 )
2020-03-06 06:30:17 -04:00
-- RPM threshold below which engine may be stopped
2022-04-30 00:12:03 -03:00
RPM_LOW_THRESH = bind_add_param ( ' RPM_THRESH ' , 2 , 500 )
2020-03-06 06:30:17 -04:00
-- vibration threshold below which engine may be stopped
2022-04-30 00:12:03 -03:00
VIBE_LOW_THRESH = bind_add_param ( ' VIBE_LOW ' , 3 , 2 )
2020-03-06 06:30:17 -04:00
-- altitude threshold for QLAND
2022-04-30 00:12:03 -03:00
LOW_ALT_THRESH = bind_add_param ( ' LOW_ALT ' , 4 , 70 )
2020-03-06 06:30:17 -04:00
-- time when engine stopped
local engine_stop_ms = - 1
local engine_stopped = false
-- have we triggered failsafe? Only trigger once
local triggered_failsafe = false
-- flight mode numbers for plane
local MODE_AUTO = 10
local MODE_RTL = 11
local MODE_QLAND = 20
local MODE_QRTL = 21
-- update engine running status
function check_engine ( )
if not arming : is_armed ( ) then
engine_stopped = false
engine_stop_ms = - 1
return true
end
local rpm = RPM : get_rpm ( 0 )
local vibe = ahrs : get_vibration ( ) : length ( )
-- if either RPM is high or vibe is high then assume engine is running
2022-04-30 00:12:03 -03:00
if ( rpm and ( rpm > RPM_LOW_THRESH : get ( ) ) ) or ( vibe > VIBE_LOW_THRESH : get ( ) ) then
2020-03-06 06:30:17 -04:00
-- engine is definately running
engine_stop_ms = - 1
if engine_stopped then
-- notify user engine has started
gcs : send_text ( 0 , " Engine: STARTED " )
engine_stopped = false
end
return true
end
local now = millis ( )
if engine_stop_ms == - 1 then
-- start timeout period
engine_stop_ms = now
return true
end
2022-04-30 00:12:03 -03:00
if now - engine_stop_ms < ENGINE_STOPPED_MS : get ( ) then
2020-03-06 06:30:17 -04:00
return false
end
-- engine has been stopped for ENGINE_STOPPED_MS milliseconds, notify user
if not engine_stopped then
engine_stopped = true
gcs : send_text ( 0 , " Engine: STOPPED " )
end
return engine_stopped
end
-- trigger failsafe function
function trigger_failsafe ( )
if param : get ( ' RTL_AUTOLAND ' ) == 2 then
-- we don't want to do the mission based autoland, so disable
-- RTL_AUTOLAND
param : set ( ' RTL_AUTOLAND ' , 0 )
end
if param : get ( ' TECS_SPDWEIGHT ' ) < 2 then
-- force airspeed priority
param : set ( ' TECS_SPDWEIGHT ' , 2 )
end
-- trigger an RTL to start bringing the vehicle home
-- it will automatically go to the nearest rally point if set or go to home
-- if no rally point available within the RALLY_LIMIT_KM
vehicle : set_mode ( MODE_RTL )
end
-- check if we should switch to QLAND
function check_qland ( )
local target = vehicle : get_target_location ( )
2022-01-20 19:42:41 -04:00
local pos = ahrs : get_location ( )
2020-03-06 06:30:17 -04:00
if not target or not pos then
-- we can't estimate distance
return
end
local dist = target : get_distance ( pos )
local terrain_height = terrain : height_above_terrain ( true )
local threshold = param : get ( ' Q_FW_LND_APR_RAD ' )
2022-04-30 00:12:03 -03:00
if dist < threshold and ( terrain_height and ( terrain_height < LOW_ALT_THRESH : get ( ) ) ) then
2020-03-06 06:30:17 -04:00
gcs : send_text ( 0 , " Failsafe: LANDING QRTL " )
vehicle : set_mode ( MODE_QRTL )
2022-04-30 00:12:03 -03:00
elseif terrain_height and terrain_height < LOW_ALT_THRESH : get ( ) then
2020-03-06 06:30:17 -04:00
gcs : send_text ( 0 , " Failsafe: LANDING QLAND " )
vehicle : set_mode ( MODE_QLAND )
end
end
function update ( )
-- check engine status
check_engine ( )
-- if armed and in AUTO mode then consider triggering failsafe
if engine_stopped and vehicle : get_mode ( ) == MODE_AUTO and arming : is_armed ( ) and not triggered_failsafe then
triggered_failsafe = true
trigger_failsafe ( )
gcs : send_text ( 0 , " Failsafe: TRIGGERED " )
end
if not engine_stopped and triggered_failsafe then
triggered_failsafe = false
gcs : send_text ( 0 , " Failsafe: RECOVERED " )
end
if triggered_failsafe and vehicle : get_mode ( ) == MODE_RTL then
check_qland ( )
end
-- run at 5Hz
return update , 200
end
-- start running update loop
return update ( )