Background for this LUA script:
Our “Flebatron”, a high speed flying wing glider designed and built by @Matzito (Matthias Möller) to explore dynamic sailing, had its successful maiden flight last week. On the one hand, we were pleased with the good glide range, on the other hand, we were concerned about the long distance in ground effect required for landing:
So we decided to use Crowflaps as a kind of airbrake. Crow flaps usually work by adjusting ailerons and flaps in opposite directions and not ailerons and elevators as installed in our gilder:
The Arduplane Crow mixer therefore cannot work. That’s why this LUA script was created. Also differential spoiler were impemented and the gain values for crow and spoiler function (separately for aileron and elevator) can be comfortably set by 4 new parameters between 0 and 100%.
--[[ Crowflaps with differential spoilers for delta-wing glider with elevator and aileron on each wing
Separate gain settings for elevator and aileron each for crow and spoiler function.
Many thanks to Peter Hall for pointing me out the SRV_Channels:get/set_output_scaled lua-commands
The following servooutputs should be set:
SERVO1_FUNCTION = 94 (Script 1) left aileron
SERVO1_FUNCTION = 95 (Script 2) right aileron
SERVO3_FUNCTION = 96 (Script 3) left elevator
SERVO3_FUNCTION = 97 (Script 4) right elevator
The following new parameters should be set via groundcontrolstation
(values between 0 and 100 %)
GAIN_AIL_CROW
GAIN_AIL_SPOIL
GAIN_ELE_CROW
GAIN_ELE_SPOIL
--]]
local UPDATE_RATE_HZ = 25
local MESSAGE = 6
local PARAM_TABLE_KEY = 99 -- unique index value between 0 and 200
-- create custom parameter set
local function add_params(key, prefix, tbl)
assert(param:add_table(key, prefix, #tbl), string.format('Could not add %s param table.', prefix))
for num = 1, #tbl do
assert(param:add_param(key, num, tbl[num][1], tbl[num][2]), string.format('Could not add %s%s.', prefix, tbl[num][1]))
end
end
-- arming:arm() -- only for glider if throttlestick is used as flapinput
-- Create parameters
add_params(PARAM_TABLE_KEY, 'GAIN_', {
-- { name, default value },
{ 'AIL_CROW', 80 },
{ 'ELE_CROW', 80 },
{ 'AIL_SPOIL', 40 },
{ 'ELE_SPOIL', 40 }
})
-- Bind parameters
function bind_param(name)
local p = Parameter()
assert(p:init(name), string.format('could not find %s parameter', name))
return p
end
local GAIN_Aileron_Crow = bind_param("GAIN_AIL_CROW")
local GAIN_Elevator_Crow = bind_param("GAIN_ELE_CROW")
local GAIN_Aileron_Spoil = bind_param("GAIN_AIL_SPOIL")
local GAIN_Elevator_Spoil = bind_param("GAIN_ELE_SPOIL")
-- servo outputs
local K_AILERON = 4
local K_ELEVATOR = 19
local K_RUDDER = 21
local K_THROTTLE = 70
local K_FLAP = 2
local K_SCRIPTING1 = 94 -- for left aileron servo
local K_SCRIPTING2 = 95 -- for right aileron servo
local K_SCRIPTING3 = 96 -- for left elevator servo
local K_SCRIPTING4 = 97 -- for right elevator servo
local vmin = -4500
local vmax = 4500
-- get time in seconds since boot
-- only used for debugging
function get_time()
return millis():tofloat() * 0.001
end
local last_warning = get_time()
-- constrain a value between limits
function constrain(v)
if v < vmin then
v = vmin
end
if v > vmax then
v = vmax
end
return v
end
function update()
-- local cflaps = SRV_Channels:get_output_scaled(K_THROTTLE) -- 0 - 100
local cflaps = SRV_Channels:get_output_scaled(K_FLAP) -- -0 - 100
cflaps = (cflaps-100) * 45 -- scale throttel to 4500
local aileron = SRV_Channels:get_output_scaled(K_AILERON) -- -4500 to +4500
local elevator = SRV_Channels:get_output_scaled(K_ELEVATOR) -- -4500 to +4500
local rudder = SRV_Channels:get_output_scaled(K_RUDDER) -- -4500 to +4500
local GAC = GAIN_Aileron_Crow:get()/100
local GAS = GAIN_Aileron_Spoil:get()/100
local GES = GAIN_Elevator_Spoil:get()/100
local GEC = GAIN_Elevator_Crow:get()/100
-- Crow Mixer:
elevator = constrain(elevator - (cflaps * GEC ))
local aileron_l = constrain(aileron - (cflaps * GAC ))
local aileron_r = constrain(aileron + (cflaps * GAC ))
local elevator_l = elevator
local elevator_r = elevator
-- Spoiler Mixer
if rudder > 0 then
elevator_l = constrain(elevator_l - (rudder * GES))
aileron_l = constrain(aileron_l + (rudder * GAS ))
else
elevator_r = constrain(elevator_r - (rudder * GES ))
aileron_r = constrain(aileron_r + (rudder * GAS))
end
--servooutput:
SRV_Channels:set_output_scaled(K_SCRIPTING1, aileron_l)
SRV_Channels:set_output_scaled(K_SCRIPTING2, aileron_r)
SRV_Channels:set_output_scaled(K_SCRIPTING3, elevator_l)
SRV_Channels:set_output_scaled(K_SCRIPTING4, elevator_r)
-- only used for debugging:
--[[if get_time() > last_warning + 4 then
gcs:send_text(MESSAGE, cflaps)
last_warning = get_time()
end
--]]
return update, 1000/UPDATE_RATE_HZ
end
gcs:send_text(MESSAGE, "Crow lua is running")
return update()
Thanks to everyone who contributed to the implementation of Ardupilot’s LUA script capability and to those who created the LUA script examples, and especially to @iampete Peter Hall for
pointing me to the crucial LUA script command (SRV_Channels:get/set_output_scaled) for this script.
I hope that the script is self-explanatory for those interested. Servos are connected according to the picture above. Also servo functions for aileron, elevator, rudder and flaps have to be connected to free servo outputs, due to their values have to be read in by SRV_Channels:get_output_scaled().
Rolf