mirror of
https://github.com/ArduPilot/ardupilot
synced 2025-01-08 17:08:28 -04:00
AP_Scripting: removed old aerobatics system
This commit is contained in:
parent
bf34bea4d6
commit
8c671c8b29
@ -1,324 +0,0 @@
|
||||
-- loops and returns on switch
|
||||
|
||||
TRICK_NUMBER = 10 -- selector number recognized to execute trick, change as desired
|
||||
-- number of loops controlled by AERO_RPT_COUNT, if 0 it will do an immelman instead, trick returns control after executing even if trick id remains 10
|
||||
|
||||
local target_vel -- trick specific global variables
|
||||
local loop_stage
|
||||
|
||||
-------------------------------------------------------------------
|
||||
-- do not change anything unless noted
|
||||
|
||||
local running = false
|
||||
local not_bound = true
|
||||
local initial_yaw_deg = 0
|
||||
local initial_height = 0
|
||||
local repeat_count
|
||||
|
||||
-- constrain a value between limits
|
||||
function constrain(v, vmin, vmax)
|
||||
if v < vmin then
|
||||
v = vmin
|
||||
end
|
||||
if v > vmax then
|
||||
v = vmax
|
||||
end
|
||||
return v
|
||||
end
|
||||
|
||||
|
||||
function wrap_360(angle) --function returns positive angle modulo360, -710 in returns 10, -10 returns +350
|
||||
local res = math.fmod(angle, 360.0)
|
||||
if res < 0 then
|
||||
res = res + 360.0
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
function wrap_180(angle)
|
||||
local res = wrap_360(angle)
|
||||
if res > 180 then
|
||||
res = res - 360
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
-- roll angle error 180 wrap to cope with errors while in inverted segments
|
||||
function roll_angle_error_wrap(roll_angle_error)
|
||||
if math.abs(roll_angle_error) > 180 then
|
||||
if roll_angle_error > 0 then
|
||||
roll_angle_error = roll_angle_error - 360
|
||||
else
|
||||
roll_angle_error= roll_angle_error +360
|
||||
end
|
||||
end
|
||||
return roll_angle_error
|
||||
end
|
||||
|
||||
--roll controller to keep wings level in earth frame. if arg is 0 then level is at only 0 deg, otherwise its at 180/-180 roll also for loops
|
||||
function earth_frame_wings_level(arg)
|
||||
local roll_deg = math.deg(ahrs:get_roll())
|
||||
local roll_angle_error = 0.0
|
||||
if (roll_deg > 90 or roll_deg < -90) and arg ~= 0 then
|
||||
roll_angle_error = 180 - roll_deg
|
||||
else
|
||||
roll_angle_error = - roll_deg
|
||||
end
|
||||
return roll_angle_error_wrap(roll_angle_error)/(RLL2SRV_TCONST:get())
|
||||
end
|
||||
|
||||
-- constrain rates to rate controller call
|
||||
function _set_target_throttle_rate_rpy(throttle,roll_rate, pitch_rate, yaw_rate)
|
||||
local r_rate = constrain(roll_rate,-RATE_MAX:get(),RATE_MAX:get())
|
||||
local p_rate = constrain(pitch_rate,-RATE_MAX:get(),RATE_MAX:get())
|
||||
vehicle:set_target_throttle_rate_rpy(throttle, r_rate, p_rate, yaw_rate)
|
||||
end
|
||||
|
||||
-- a PI controller implemented as a Lua object
|
||||
local function PI_controller(kP,kI,iMax)
|
||||
-- the new instance. You can put public variables inside this self
|
||||
-- declaration if you want to
|
||||
local self = {}
|
||||
|
||||
-- private fields as locals
|
||||
local _kP = kP or 0.0
|
||||
local _kI = kI or 0.0
|
||||
local _kD = kD or 0.0
|
||||
local _iMax = iMax
|
||||
local _last_t = nil
|
||||
local _I = 0
|
||||
local _P = 0
|
||||
local _total = 0
|
||||
local _counter = 0
|
||||
local _target = 0
|
||||
local _current = 0
|
||||
|
||||
-- update the controller.
|
||||
function self.update(target, current)
|
||||
local now = millis():tofloat() * 0.001
|
||||
if not _last_t then
|
||||
_last_t = now
|
||||
end
|
||||
local dt = now - _last_t
|
||||
_last_t = now
|
||||
local err = target - current
|
||||
_counter = _counter + 1
|
||||
|
||||
local P = _kP * err
|
||||
_I = _I + _kI * err * dt
|
||||
if _iMax then
|
||||
_I = constrain(_I, -_iMax, iMax)
|
||||
end
|
||||
local I = _I
|
||||
local ret = P + I
|
||||
|
||||
_target = target
|
||||
_current = current
|
||||
_P = P
|
||||
_total = ret
|
||||
return ret
|
||||
end
|
||||
|
||||
-- reset integrator to an initial value
|
||||
function self.reset(integrator)
|
||||
_I = integrator
|
||||
end
|
||||
|
||||
function self.set_I(I)
|
||||
_kI = I
|
||||
end
|
||||
|
||||
function self.set_P(P)
|
||||
_kP = P
|
||||
end
|
||||
|
||||
function self.set_Imax(Imax)
|
||||
_iMax = Imax
|
||||
end
|
||||
|
||||
-- log the controller internals
|
||||
function self.log(name, add_total)
|
||||
-- allow for an external addition to total
|
||||
logger:write(name,'Targ,Curr,P,I,Total,Add','ffffff',_target,_current,_P,_I,_total,add_total)
|
||||
end
|
||||
-- return the instance
|
||||
return self
|
||||
end
|
||||
|
||||
local function height_controller(kP_param,kI_param,KnifeEdge_param,Imax)
|
||||
local self = {}
|
||||
local kP = kP_param
|
||||
local kI = kI_param
|
||||
local KnifeEdge = KnifeEdge_param
|
||||
local PI = PI_controller(kP:get(), kI:get(), Imax)
|
||||
|
||||
function self.update(target)
|
||||
local target_pitch = PI.update(initial_height, ahrs:get_position():alt()*0.01)
|
||||
local roll_rad = ahrs:get_roll()
|
||||
local ke_add = math.abs(math.sin(roll_rad)) * KnifeEdge:get()
|
||||
target_pitch = target_pitch + ke_add
|
||||
PI.log("HPI", ke_add)
|
||||
return constrain(target_pitch,-45,45)
|
||||
end
|
||||
|
||||
function self.reset()
|
||||
PI.reset(math.max(math.deg(ahrs:get_pitch()), 3.0))
|
||||
PI.set_P(kP:get())
|
||||
PI.set_I(kI:get())
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
-- a controller to target a zero pitch angle and zero heading change, used in a roll
|
||||
-- output is a body frame pitch rate, with convergence over time tconst in seconds
|
||||
function pitch_controller(target_pitch_deg, target_yaw_deg, tconst)
|
||||
local roll_deg = math.deg(ahrs:get_roll())
|
||||
local pitch_deg = math.deg(ahrs:get_pitch())
|
||||
local yaw_deg = math.deg(ahrs:get_yaw())
|
||||
|
||||
-- get earth frame pitch and yaw rates
|
||||
local ef_pitch_rate = (target_pitch_deg - pitch_deg) / tconst
|
||||
local ef_yaw_rate = wrap_180(target_yaw_deg - yaw_deg) / tconst
|
||||
|
||||
local bf_pitch_rate = math.sin(math.rad(roll_deg)) * ef_yaw_rate + math.cos(math.rad(roll_deg)) * ef_pitch_rate
|
||||
local bf_yaw_rate = math.cos(math.rad(roll_deg)) * ef_yaw_rate - math.sin(math.rad(roll_deg)) * ef_pitch_rate
|
||||
return bf_pitch_rate, bf_yaw_rate
|
||||
end
|
||||
|
||||
-- a controller for throttle to account for pitch
|
||||
function throttle_controller()
|
||||
local pitch_rad = ahrs:get_pitch()
|
||||
local thr_ff = THR_PIT_FF:get()
|
||||
local throttle = TRIM_THROTTLE:get() + math.sin(pitch_rad) * thr_ff
|
||||
return constrain(throttle, TRIM_THROTTLE:get(), 100.0)
|
||||
end
|
||||
function bind_param(name)
|
||||
local p = Parameter()
|
||||
if p:init(name) then
|
||||
not_bound = false
|
||||
return p
|
||||
else
|
||||
not_bound = true
|
||||
end
|
||||
end
|
||||
|
||||
-- recover entry altitude
|
||||
function recover_alt()
|
||||
local target_pitch = height_PI.update(initial_height)
|
||||
local pitch_rate, yaw_rate = pitch_controller(target_pitch, initial_yaw_deg, PITCH_TCONST:get())
|
||||
throttle = throttle_controller()
|
||||
return throttle, pitch_rate, yaw_rate
|
||||
end
|
||||
----------------------------------------------------------------------------------------------
|
||||
--every trick needs an init, change as needed...to bind the AERO params it uses(which will depend on the trick), and setup PID controllers used by script
|
||||
|
||||
function init()
|
||||
HGT_P = bind_param("AERO_HGT_P") -- height P gain, required for height controller
|
||||
HGT_I = bind_param("AERO_HGT_I") -- height I gain, required for height controller
|
||||
HGT_KE_BIAS = bind_param("AERO_HGT_KE_BIAS") -- height knifeedge addition for pitch
|
||||
THR_PIT_FF = bind_param("AERO_THR_PIT_FF") -- throttle FF from pitch
|
||||
TRIM_THROTTLE = bind_param("TRIM_THROTTLE") --usually required for any trick
|
||||
TRIM_ARSPD_CM = bind_param("TRIM_ARSPD_CM") --usually required for any trick
|
||||
RATE_MAX = bind_param("AERO_RATE_MAX")
|
||||
RLL2SRV_TCONST = bind_param("RLL2SRV_TCONST") --usually required for any trick
|
||||
PITCH_TCONST = bind_param("PTCH2SRV_TCONST") --usually required for any trick
|
||||
TRICK_ID = bind_param("AERO_TRICK_ID") --- required for any trick
|
||||
TRICK_RAT = bind_param("AERO_TRICK_RAT") --usually required for any trick
|
||||
RPT_COUNT = bind_param("AERO_RPT_COUNT") --repeat count for trick
|
||||
if not_bound then
|
||||
gcs:send_text(0,string.format("Not bound yet"))
|
||||
return init, 100
|
||||
else
|
||||
gcs:send_text(0,string.format("Params bound,Trick %.0f loaded", TRICK_NUMBER))
|
||||
height_PI = height_controller(HGT_P, HGT_I, HGT_KE_BIAS, 20.0) -- this trick needs this height PID controller setup to hold height during the trick
|
||||
loop_stage = 0
|
||||
return update, 50
|
||||
end
|
||||
end
|
||||
-----------------------------------------------------------------------------------------------
|
||||
--every trick will have its own do_trick function to perform the trick...this will change totally for each different trick
|
||||
|
||||
function do_loop(arg1)
|
||||
-- do one loop with controllable pitch rate arg1 is pitch rate, arg2 number of loops, 0 indicates 1/2 cuban8 reversa
|
||||
local throttle = throttle_controller()
|
||||
local pitch_deg = math.deg(ahrs:get_pitch())
|
||||
local roll_deg = math.deg(ahrs:get_roll())
|
||||
local vel = ahrs:get_velocity_NED():length()
|
||||
local pitch_rate = arg1
|
||||
local yaw_rate = 0
|
||||
pitch_rate = pitch_rate * (1+ 2*((vel/target_vel)-1)) --increase/decrease rate based on velocity to round loop
|
||||
pitch_rate = constrain(pitch_rate,.5 * arg1, 3 * arg1)
|
||||
if loop_stage == 0 then
|
||||
if pitch_deg > 60 then
|
||||
loop_stage = 1
|
||||
end
|
||||
elseif loop_stage == 1 then
|
||||
if (math.abs(roll_deg) < 90 and pitch_deg > -5 and pitch_deg < 5 and repeat_count > 0) then
|
||||
-- we're done with loop
|
||||
gcs:send_text(0, string.format("Finished loop p=%.1f", pitch_deg))
|
||||
loop_stage = 2 --now recover stage
|
||||
repeat_count = repeat_count - 1
|
||||
elseif (math.abs(roll_deg) > 90 and pitch_deg > -5 and pitch_deg < 5 and repeat_count <= 0) then
|
||||
gcs:send_text(0, string.format("Finished return p=%.1f", pitch_deg))
|
||||
loop_stage = 2 --now recover stage
|
||||
repeat_count = repeat_count - 1
|
||||
initial_yaw_deg = math.deg(ahrs:get_yaw())
|
||||
end
|
||||
elseif loop_stage == 2 then
|
||||
-- recover alt if above or below start and terminate
|
||||
|
||||
if repeat_count > 0 then
|
||||
--yaw_rate = 0
|
||||
loop_stage = 0
|
||||
elseif math.abs(ahrs:get_position():alt()*0.01 - initial_height) > 3 then
|
||||
|
||||
throttle, pitch_rate, yaw_rate = recover_alt()
|
||||
else
|
||||
running = false
|
||||
gcs:send_text(0, string.format("Recovered entry alt"))
|
||||
TRICK_ID:set(0)
|
||||
return
|
||||
end
|
||||
end
|
||||
throttle = throttle_controller()
|
||||
if loop_stage == 2 or loop_stage == 0 then level_type = 0 else level_type = 1 end
|
||||
if math.abs(pitch_deg) > 85 and math.abs(pitch_deg) < 95 then
|
||||
roll_rate = 0
|
||||
else
|
||||
roll_rate = earth_frame_wings_level(level_type)
|
||||
end
|
||||
_set_target_throttle_rate_rpy(throttle, roll_rate, pitch_rate, yaw_rate)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------
|
||||
--trick should noramlly only have to change the notification text in this routine,initialize trick specific variables, and any parameters needing to be passed to do_trick(..)
|
||||
|
||||
function update()
|
||||
if (TRICK_ID:get() == TRICK_NUMBER) then
|
||||
local current_mode = vehicle:get_mode()
|
||||
if arming:is_armed() and running == false then
|
||||
if not vehicle:nav_scripting_enable(current_mode) then
|
||||
return update, 50
|
||||
end
|
||||
running = true
|
||||
initial_height = ahrs:get_position():alt()*0.01
|
||||
initial_yaw_deg = math.deg(ahrs:get_yaw())
|
||||
height_PI.reset()
|
||||
repeat_count = RPT_COUNT:get()
|
||||
-----------------------------------------------trick specific
|
||||
loop_stage = 0
|
||||
target_vel = ahrs:get_velocity_NED():length()
|
||||
gcs:send_text(0, string.format("Loop/Return")) --change announcement as appropriate for trick
|
||||
-------------------------------------------------------
|
||||
elseif running == true then
|
||||
do_loop(TRICK_RAT:get()) -- change arguments as appropriate for trick
|
||||
end
|
||||
else
|
||||
running = false
|
||||
end
|
||||
return update, 50
|
||||
end
|
||||
|
||||
return init,1000
|
||||
|
@ -1,243 +0,0 @@
|
||||
-- knife edge on switch
|
||||
|
||||
TRICK_NUMBER = 5 -- selector number recognized to execute trick, change as desired
|
||||
-- knife-edge angle set by AERO_TRICK_ANG, active for as long as trick id = 5
|
||||
-------------------------------------------------------------------
|
||||
-- do not change anything below unless noted
|
||||
|
||||
local running = false
|
||||
local not_bound = true
|
||||
local initial_yaw_deg = 0
|
||||
local initial_height = 0
|
||||
local repeat_count
|
||||
|
||||
-- constrain a value between limits
|
||||
function constrain(v, vmin, vmax)
|
||||
if v < vmin then
|
||||
v = vmin
|
||||
end
|
||||
if v > vmax then
|
||||
v = vmax
|
||||
end
|
||||
return v
|
||||
end
|
||||
|
||||
|
||||
function wrap_360(angle) --function returns positive angle modulo360, -710 in returns 10, -10 returns +350
|
||||
local res = math.fmod(angle, 360.0)
|
||||
if res < 0 then
|
||||
res = res + 360.0
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
function wrap_180(angle)
|
||||
local res = wrap_360(angle)
|
||||
if res > 180 then
|
||||
res = res - 360
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
-- a PI controller implemented as a Lua object
|
||||
local function PI_controller(kP,kI,iMax)
|
||||
-- the new instance. You can put public variables inside this self
|
||||
-- declaration if you want to
|
||||
local self = {}
|
||||
|
||||
-- private fields as locals
|
||||
local _kP = kP or 0.0
|
||||
local _kI = kI or 0.0
|
||||
local _kD = kD or 0.0
|
||||
local _iMax = iMax
|
||||
local _last_t = nil
|
||||
local _I = 0
|
||||
local _P = 0
|
||||
local _total = 0
|
||||
local _counter = 0
|
||||
local _target = 0
|
||||
local _current = 0
|
||||
|
||||
-- update the controller.
|
||||
function self.update(target, current)
|
||||
local now = millis():tofloat() * 0.001
|
||||
if not _last_t then
|
||||
_last_t = now
|
||||
end
|
||||
local dt = now - _last_t
|
||||
_last_t = now
|
||||
local err = target - current
|
||||
_counter = _counter + 1
|
||||
|
||||
local P = _kP * err
|
||||
_I = _I + _kI * err * dt
|
||||
if _iMax then
|
||||
_I = constrain(_I, -_iMax, iMax)
|
||||
end
|
||||
local I = _I
|
||||
local ret = P + I
|
||||
|
||||
_target = target
|
||||
_current = current
|
||||
_P = P
|
||||
_total = ret
|
||||
return ret
|
||||
end
|
||||
|
||||
-- reset integrator to an initial value
|
||||
function self.reset(integrator)
|
||||
_I = integrator
|
||||
end
|
||||
|
||||
function self.set_I(I)
|
||||
_kI = I
|
||||
end
|
||||
|
||||
function self.set_P(P)
|
||||
_kP = P
|
||||
end
|
||||
|
||||
function self.set_Imax(Imax)
|
||||
_iMax = Imax
|
||||
end
|
||||
|
||||
-- log the controller internals
|
||||
function self.log(name, add_total)
|
||||
-- allow for an external addition to total
|
||||
logger:write(name,'Targ,Curr,P,I,Total,Add','ffffff',_target,_current,_P,_I,_total,add_total)
|
||||
end
|
||||
-- return the instance
|
||||
return self
|
||||
end
|
||||
|
||||
local function height_controller(kP_param,kI_param,KnifeEdge_param,Imax)
|
||||
local self = {}
|
||||
local kP = kP_param
|
||||
local kI = kI_param
|
||||
local KnifeEdge = KnifeEdge_param
|
||||
local PI = PI_controller(kP:get(), kI:get(), Imax)
|
||||
|
||||
function self.update(target)
|
||||
local target_pitch = PI.update(initial_height, ahrs:get_position():alt()*0.01)
|
||||
local roll_rad = ahrs:get_roll()
|
||||
local ke_add = math.abs(math.sin(roll_rad)) * KnifeEdge:get()
|
||||
target_pitch = target_pitch + ke_add
|
||||
PI.log("HPI", ke_add)
|
||||
return constrain(target_pitch,-45,45)
|
||||
end
|
||||
|
||||
function self.reset()
|
||||
PI.reset(math.max(math.deg(ahrs:get_pitch()), 3.0))
|
||||
PI.set_P(kP:get())
|
||||
PI.set_I(kI:get())
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
-- a controller to target a zero pitch angle and zero heading change, used in a roll
|
||||
-- output is a body frame pitch rate, with convergence over time tconst in seconds
|
||||
function pitch_controller(target_pitch_deg, target_yaw_deg, tconst)
|
||||
local roll_deg = math.deg(ahrs:get_roll())
|
||||
local pitch_deg = math.deg(ahrs:get_pitch())
|
||||
local yaw_deg = math.deg(ahrs:get_yaw())
|
||||
|
||||
-- get earth frame pitch and yaw rates
|
||||
local ef_pitch_rate = (target_pitch_deg - pitch_deg) / tconst
|
||||
local ef_yaw_rate = wrap_180(target_yaw_deg - yaw_deg) / tconst
|
||||
|
||||
local bf_pitch_rate = math.sin(math.rad(roll_deg)) * ef_yaw_rate + math.cos(math.rad(roll_deg)) * ef_pitch_rate
|
||||
local bf_yaw_rate = math.cos(math.rad(roll_deg)) * ef_yaw_rate - math.sin(math.rad(roll_deg)) * ef_pitch_rate
|
||||
return bf_pitch_rate, bf_yaw_rate
|
||||
end
|
||||
|
||||
-- a controller for throttle to account for pitch
|
||||
function throttle_controller()
|
||||
local pitch_rad = ahrs:get_pitch()
|
||||
local thr_ff = THR_PIT_FF:get()
|
||||
local throttle = TRIM_THROTTLE:get() + math.sin(pitch_rad) * thr_ff
|
||||
return constrain(throttle, TRIM_THROTTLE:get(), 100.0)
|
||||
end
|
||||
|
||||
function bind_param(name)
|
||||
local p = Parameter()
|
||||
if not p:init(name) then
|
||||
not_bound = true
|
||||
end
|
||||
return p
|
||||
end
|
||||
----------------------------------------------------------------------------------------------
|
||||
--every trick needs an init, change as needed...to bind the AERO params it uses(which will depend on the trick), and setup PID controllers used by script
|
||||
|
||||
function init()
|
||||
not_bound = false
|
||||
HGT_P = bind_param("AERO_HGT_P") -- height P gain, required for height controller
|
||||
HGT_I = bind_param("AERO_HGT_I") -- height I gain, required for height controller
|
||||
HGT_KE_BIAS = bind_param("AERO_HGT_KE_BIAS") -- height knifeedge addition for pitch
|
||||
THR_PIT_FF = bind_param("AERO_THR_PIT_FF") -- throttle FF from pitch
|
||||
TRIM_THROTTLE = bind_param("TRIM_THROTTLE") --usually required for any trick
|
||||
TRIM_ARSPD_CM = bind_param("TRIM_ARSPD_CM") --usually required for any trick
|
||||
RLL2SRV_TCONST = bind_param("RLL2SRV_TCONST") --usually required for any trick
|
||||
PITCH_TCONST = bind_param("PTCH2SRV_TCONST") --usually required for any trick
|
||||
KE_ANG = bind_param("AERO_TRICK_ANG") --this particulat trick needs a target angle for the knife-edge its doing
|
||||
TRICK_ID = bind_param("AERO_TRICK_ID") --- required for any trick
|
||||
RPT_COUNT = bind_param("AERO_RPT_COUNT") -- if trick can repeat
|
||||
if not_bound then
|
||||
gcs:send_text(0,string.format("Not bound yet"))
|
||||
return init, 100
|
||||
else
|
||||
gcs:send_text(0,string.format("Params bound,Trick %.0f loaded", TRICK_NUMBER))
|
||||
height_PI = height_controller(HGT_P, HGT_I, HGT_KE_BIAS, 20.0) -- this trick needs this height PID controller setup to hold height during the trick
|
||||
return update, 1000
|
||||
end
|
||||
end
|
||||
-----------------------------------------------------------------------------------------------
|
||||
--every trick will have its own do_trick function to perform the trick...this will change totally for each different trick
|
||||
|
||||
function do_trick(arg1)
|
||||
-- arg1 is angle +/-180
|
||||
local roll_deg = math.deg(ahrs:get_roll())
|
||||
local roll_angle_error = (arg1 - roll_deg)
|
||||
if math.abs(roll_angle_error) > 180 then
|
||||
if roll_angle_error > 0 then
|
||||
roll_angle_error = roll_angle_error - 360
|
||||
else
|
||||
roll_angle_error= roll_angle_error +360
|
||||
end
|
||||
end
|
||||
local roll_rate = roll_angle_error/(RLL2SRV_TCONST:get())
|
||||
local target_pitch = height_PI.update(initial_height)
|
||||
local pitch_rate, yaw_rate = pitch_controller(target_pitch, initial_yaw_deg, PITCH_TCONST:get())
|
||||
local throttle = throttle_controller()
|
||||
vehicle:set_target_throttle_rate_rpy(throttle, roll_rate, pitch_rate, yaw_rate)
|
||||
return
|
||||
end
|
||||
-------------------------------------------------------------------------------------------
|
||||
--trick should noramlly only have to change the notification text in this routine,initialize trick specific variables, and any parameters needing to be passed to do_trick(..)
|
||||
|
||||
function update()
|
||||
if (TRICK_ID:get() == TRICK_NUMBER) then
|
||||
local current_mode = vehicle:get_mode()
|
||||
if arming:is_armed() and running == false then
|
||||
if not vehicle:nav_scripting_enable(current_mode) then
|
||||
return update, 50
|
||||
end
|
||||
running = true
|
||||
initial_height = ahrs:get_position():alt()*0.01
|
||||
initial_yaw_deg = math.deg(ahrs:get_yaw())
|
||||
height_PI.reset()
|
||||
repeat_count = RPT_COUNT:get() --not used in this trick, knife-edge on as long as mode does not change or sw is not lowered
|
||||
-----------------------------------------------trick specific
|
||||
gcs:send_text(0, string.format("%d Knife edge", KE_ANG:get())) --change announcement as appropriate for trick
|
||||
----------------------------------------------------------
|
||||
elseif running == true then
|
||||
do_trick(KE_ANG:get()) -- change arguments as appropriate for trick
|
||||
end
|
||||
else
|
||||
running = false
|
||||
end
|
||||
return update, 50
|
||||
end
|
||||
|
||||
return init,1000
|
||||
|
@ -1,22 +0,0 @@
|
||||
Aerobatics via an RC switch
|
||||
===========================
|
||||
|
||||
this requires the lua_trick_selector.lua script
|
||||
additional individual trick scripts can then be selectively executed via a switch
|
||||
|
||||
RCx_OPTION switch 300 is the activations switch to execute a trick
|
||||
RCx_OPTION switch 301 selects a trick from up to 10 trick scripts to execute
|
||||
|
||||
included as templates are two tricks: any angle knife-edge and a loop/return
|
||||
|
||||
activation switch when high will start the trick, which may self terminate (loop/return example), or continue indefinitely (knige-edge) until switch is low, when switched from low to mid and held for 0.5 second, the trick number selected by the selection channel is announced
|
||||
|
||||
trick is aborted if:
|
||||
- activation switch is returned low
|
||||
- flight mode changes
|
||||
- script hangs, ie does not call the set_target_throttle_rpy(..) function every 50ms
|
||||
- trick selection is moved to 0 (low)
|
||||
|
||||
Only modes defined in the nav_scripting_enable(mode) function call can enable scripting control and current flight mode must match the "mode" argument
|
||||
|
||||
Note: for tricks like knifedges which normally are indefinite(could modify this trick for a fixed duration, instead, though) until activation switch is set back low or mode is changed, the exit is totally dependent upon the mode being re-entered....for example, returning to FBWA can result in a change of heading as FBWA re-establishes level depending on knife-edge angle (90 deg has worst heading shift upon FBWA recovery), ACRO shows no change of attitude,CRUISE will re-establish track to last CRUISE target update, etc.
|
@ -1,59 +0,0 @@
|
||||
-- master control script for selecting aerobatics scripts
|
||||
-- the two rc channels below must be assigned
|
||||
|
||||
local scripting_rc_activation = assert(rc:find_channel_for_option(300), 'no sw assigned for trick activation') -- trick script selection channel
|
||||
local scripting_rc_selection = assert(rc:find_channel_for_option(301), 'no switch assigned for trick selection') -- trick script activation channel (low:off/stop, mid:report trick ID to GCS, high:do trick
|
||||
|
||||
local trick_id = 0 --current trick ID, 0 means no trick, placing any number into the AERO_TRICK_ID param below means execute a script that recognizes it as its trick ID
|
||||
|
||||
local sw_current = scripting_rc_activation:norm_input() --current position of scripting_rc_activation switch -1 to 1
|
||||
local sw_last = sw_current -- last position of scripting scripting_rc_activation switch
|
||||
|
||||
-- setup param block for aerobatics, reserving 30 params beginning with AERO_
|
||||
local PARAM_TABLE_KEY = 72
|
||||
assert(param:add_table(PARAM_TABLE_KEY, "AERO_", 30), 'could not add param table')
|
||||
|
||||
-- this control script uses AERO_TRICK_ID to report the selected trick number from the scripting_rc_selection rc channel
|
||||
assert(param:add_param(PARAM_TABLE_KEY, 1, 'TRICK_ID', 0), 'could not add param1') -- trick IDs for switch activation
|
||||
assert(param:add_param(PARAM_TABLE_KEY, 2, 'RPT_COUNT', 0), 'could not add param2') -- trick repeats
|
||||
assert(param:add_param(PARAM_TABLE_KEY, 3, 'RATE_MAX', 120), 'could not add param3') -- max rates applied to axes(like ACRO rate param)
|
||||
assert(param:add_param(PARAM_TABLE_KEY, 4, 'HGT_P', 1), 'could not add param4') -- height P gain
|
||||
assert(param:add_param(PARAM_TABLE_KEY, 5, 'HGT_I', 2), 'could not add param5') -- height I gain
|
||||
assert(param:add_param(PARAM_TABLE_KEY, 6, 'HGT_KE_BIAS', 20), 'could not add param6') --height knife-edge addition for pitch
|
||||
assert(param:add_param(PARAM_TABLE_KEY, 7, 'THR_PIT_FF', 80), 'could not add param67') --throttle FF from pitch
|
||||
assert(param:add_param(PARAM_TABLE_KEY, 8, 'SPD_P', 5), 'could not add param8') -- speed P gain
|
||||
assert(param:add_param(PARAM_TABLE_KEY, 9, 'SPD_I', 25), 'could not add param9') -- speed I gain
|
||||
assert(param:add_param(PARAM_TABLE_KEY, 10, 'TRICK_ANG', 90), 'could not add param10') -- knife-edge angle,etc.
|
||||
assert(param:add_param(PARAM_TABLE_KEY, 11, 'TRICK_RAT', 90), 'could not add param11') -- used for trick loop rate, axial roll rates, etc
|
||||
|
||||
|
||||
local trick_id = Parameter("AERO_TRICK_ID")
|
||||
local sw_last = 0
|
||||
local sw_current = 0
|
||||
local last_selection = 0
|
||||
function update()
|
||||
local trick_selection = math.floor(5 * (scripting_rc_selection:norm_input_ignore_trim() +1)) -- produces range of 0 to 10 for selecting trick ID
|
||||
if trick_selection == 0 then -- anytime trick selection is zero force trick ID to 0, another way to terminate tricks
|
||||
trick_id:set(trick_selection)
|
||||
end
|
||||
sw_current = scripting_rc_activation:norm_input_ignore_trim()
|
||||
if sw_current == sw_last then
|
||||
if sw_current > -0.25 and sw_current < 0.75 and last_selection ~= trick_selection then
|
||||
gcs:send_text(0, string.format("Current trick ID = %.0f",trick_selection))
|
||||
last_selection = trick_selection
|
||||
end
|
||||
return update, 500
|
||||
else
|
||||
if sw_current < -0.25 then
|
||||
trick_id:set(0)
|
||||
elseif sw_current > 0.75 and arming:is_armed() then --setting trick ID to non-zero should be recognized by trick with that ID to init and execute
|
||||
trick_id:set(trick_selection)
|
||||
elseif sw_last < -0.25 and sw_current > -0.25 and sw_current < 0.75 then
|
||||
gcs:send_text(0, string.format("Current trick ID = %.0f",trick_selection))
|
||||
end
|
||||
sw_last = sw_current
|
||||
return update, 500
|
||||
end
|
||||
end
|
||||
|
||||
return update, 50
|
Loading…
Reference in New Issue
Block a user