mirror of
https://github.com/ArduPilot/ardupilot.git
synced 2026-02-04 21:14:59 -06:00
227 lines
6.7 KiB
Lua
227 lines
6.7 KiB
Lua
--[[
|
|
a dynamic motor mixer for an X8 coax multicopter with co-rotating
|
|
motors on each of the arms
|
|
|
|
adds parameters for a multiplier for top and bottom layer motors
|
|
--]]
|
|
|
|
local PARAM_TABLE_KEY = 105
|
|
local PARAM_TABLE_PREFIX = "MOT_X8C_"
|
|
|
|
-- add a parameter and bind it to a variable
|
|
local 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))
|
|
-- use the old style of param constructor to be compatible with very old ArduPilot versions (tested on 4.2.x)
|
|
local p = Parameter()
|
|
p:init(PARAM_TABLE_PREFIX .. name)
|
|
return p;
|
|
end
|
|
|
|
-- Setup Parameters
|
|
assert(param:add_table(PARAM_TABLE_KEY, PARAM_TABLE_PREFIX, 6), 'X8-corotating: could not add param table')
|
|
|
|
local MAV_SEVERITY = {EMERGENCY=0, ALERT=1, CRITICAL=2, ERROR=3, WARNING=4, NOTICE=5, INFO=6, DEBUG=7}
|
|
|
|
--[[
|
|
// @Param: X8C_TOPMUL
|
|
// @DisplayName: X8C Top Layer Multiplier
|
|
// @Description: Multiplier for the top layer motors
|
|
// @Range: 0 1
|
|
// @User: Standard
|
|
--]]
|
|
local X8C_TOPMUL = bind_add_param('TOPMUL', 1, 1.0)
|
|
|
|
--[[
|
|
// @Param: X8C_BOTMUL
|
|
// @DisplayName: X8C Bottom Layer Multiplier
|
|
// @Description: Multiplier for the bottom layer motors
|
|
// @Range: 0 1
|
|
// @User: Standard
|
|
--]]
|
|
local X8C_BOTMUL = bind_add_param('BOTMUL', 2, 1.0)
|
|
|
|
--[[
|
|
// @Param: X8C_ORDER
|
|
// @DisplayName: X8C motor ordering
|
|
// @Description: Selecting between old and clockwise X8 ordering
|
|
// @Values: 0:OldOrdering, 1:ClockwiseOrdering
|
|
// @User: Standard
|
|
--]]
|
|
local X8C_ORDER = bind_add_param('ORDER', 3, 0)
|
|
|
|
local CCW = 1
|
|
local CW = -1
|
|
|
|
local FRAME_NAME = "X8-corotating"
|
|
|
|
--[[
|
|
motors array for X8 with co-rotating motors, using old X8 ordering
|
|
--]]
|
|
local Motors_old_order = {
|
|
{ name = "Motor 1", test_order = 1, Xpos = 1, Ypos = 1, rotation = CCW, layer=2 },
|
|
{ name = "Motor 2", test_order = 7, Xpos = 1, Ypos = -1, rotation = CW, layer=2 },
|
|
{ name = "Motor 3", test_order = 5, Xpos = -1, Ypos = -1, rotation = CCW, layer=2 },
|
|
{ name = "Motor 4", test_order = 3, Xpos = -1, Ypos = 1, rotation = CW, layer=2 },
|
|
{ name = "Motor 5", test_order = 8, Xpos = 1, Ypos = -1, rotation = CW, layer=1 },
|
|
{ name = "Motor 6", test_order = 2, Xpos = 1, Ypos = 1, rotation = CCW, layer=1 },
|
|
{ name = "Motor 7", test_order = 4, Xpos = -1, Ypos = 1, rotation = CW, layer=1 },
|
|
{ name = "Motor 8", test_order = 6, Xpos = -1, Ypos = -1, rotation = CCW, layer=1 }
|
|
}
|
|
|
|
--[[
|
|
motors array for X8 with co-rotating motors, using clockwise X8 ordering
|
|
--]]
|
|
local Motors_cw_order = {
|
|
{ name = "Motor 1", test_order = 1, Xpos = 1, Ypos = 1, rotation = CCW, layer=2 },
|
|
{ name = "Motor 2", test_order = 2, Xpos = 1, Ypos = 1, rotation = CCW, layer=1 },
|
|
{ name = "Motor 3", test_order = 3, Xpos = -1, Ypos = 1, rotation = CW, layer=2 },
|
|
{ name = "Motor 4", test_order = 4, Xpos = -1, Ypos = 1, rotation = CW, layer=1 },
|
|
{ name = "Motor 5", test_order = 5, Xpos = -1, Ypos = -1, rotation = CCW, layer=2 },
|
|
{ name = "Motor 6", test_order = 6, Xpos = -1, Ypos = -1, rotation = CCW, layer=1 },
|
|
{ name = "Motor 7", test_order = 7, Xpos = 1, Ypos = -1, rotation = CW, layer=2 },
|
|
{ name = "Motor 8", test_order = 8, Xpos = 1, Ypos = -1, rotation = CW, layer=1 }
|
|
}
|
|
|
|
if X8C_ORDER:get() == 0 then
|
|
Motors = Motors_old_order
|
|
else
|
|
Motors = Motors_cw_order
|
|
FRAME_NAME = "X8-corotating-cw"
|
|
end
|
|
|
|
local num_motors = #Motors
|
|
|
|
--[[
|
|
add the motors to the Motors_dynamic object
|
|
--]]
|
|
for i = 1, num_motors do
|
|
local test_order = Motors[i].test_order
|
|
Motors_dynamic:add_motor(i-1, test_order)
|
|
end
|
|
|
|
-- create a motor factor table
|
|
factors = motor_factor_table()
|
|
|
|
--[[
|
|
multiplier for a layer, to account for the parameters
|
|
--]]
|
|
local function layer_multiplier(motor_num)
|
|
local layer = Motors[motor_num].layer
|
|
if layer == 2 then
|
|
return X8C_TOPMUL:get()
|
|
elseif layer == 1 then
|
|
return X8C_BOTMUL:get()
|
|
else
|
|
return 1.0
|
|
end
|
|
end
|
|
|
|
--[[
|
|
when we setup the roll, pitch and yaw factors we normalise them to a maximum
|
|
of 0.5, which is what is expected by the motor mixer
|
|
--]]
|
|
|
|
--[[
|
|
setup the roll factors
|
|
--]]
|
|
local function setup_roll_factors()
|
|
-- find the highest absolute value of Ypos
|
|
local max_y = 0
|
|
for i = 1, num_motors do
|
|
max_y = math.max(math.abs(Motors[i].Ypos), max_y)
|
|
end
|
|
if max_y == 0 then
|
|
max_y = 1 -- prevent division by zero
|
|
end
|
|
-- set the roll factors based on the Xpos of each motor
|
|
-- positive Ypos means roll left, negative Ypos means roll right
|
|
for i = 1, num_motors do
|
|
local Ypos = Motors[i].Ypos
|
|
local roll_factor = -(Ypos / max_y) * 0.5 * layer_multiplier(i)
|
|
factors:roll(i-1, roll_factor)
|
|
end
|
|
end
|
|
|
|
--[[
|
|
setup the pitch factors
|
|
--]]
|
|
local function setup_pitch_factors()
|
|
-- find the highest absolute value of Ypos
|
|
local max_x = 0
|
|
for i = 1, num_motors do
|
|
max_x = math.max(math.abs(Motors[i].Xpos), max_x)
|
|
end
|
|
if max_x == 0 then
|
|
max_x = 1 -- prevent division by zero
|
|
end
|
|
-- set the roll factors based on the Ypos of each motor
|
|
-- positive Xpos means pitch up, negative Xpos means pitch down
|
|
for i = 1, num_motors do
|
|
local Xpos = Motors[i].Xpos
|
|
local pitch_factor = (Xpos / max_x) * 0.5 * layer_multiplier(i)
|
|
factors:pitch(i-1, pitch_factor)
|
|
end
|
|
end
|
|
|
|
--[[
|
|
setup the yaw factors
|
|
--]]
|
|
local function setup_yaw_factors()
|
|
-- set the yaw factors based on the rotation of each motor
|
|
for i = 1, num_motors do
|
|
local rotation = Motors[i].rotation
|
|
factors:yaw(i-1, rotation * 0.5 * layer_multiplier(i))
|
|
end
|
|
end
|
|
|
|
--[[
|
|
setup the thrust factors
|
|
--]]
|
|
local function setup_thrust_factors()
|
|
for i = 1, num_motors do
|
|
factors:throttle(i-1, 1.0 * layer_multiplier(i))
|
|
end
|
|
end
|
|
|
|
--[[
|
|
setup throttle factors
|
|
--]]
|
|
local function update_factors()
|
|
if X8C_ORDER:get() == 0 then
|
|
Motors = Motors_old_order
|
|
else
|
|
Motors = Motors_cw_order
|
|
end
|
|
setup_roll_factors()
|
|
setup_pitch_factors()
|
|
setup_yaw_factors()
|
|
setup_thrust_factors()
|
|
Motors_dynamic:load_factors(factors)
|
|
end
|
|
|
|
update_factors()
|
|
|
|
assert(Motors_dynamic:init(num_motors), string.format("Failed to init %s", FRAME_NAME))
|
|
|
|
motors:set_frame_string(FRAME_NAME)
|
|
|
|
local last_top_layer_mul = X8C_TOPMUL:get()
|
|
local last_bot_layer_mul = X8C_BOTMUL:get()
|
|
local last_order = X8C_ORDER:get()
|
|
|
|
local function update()
|
|
if last_top_layer_mul ~= X8C_TOPMUL:get() or
|
|
last_bot_layer_mul ~= X8C_BOTMUL:get() or
|
|
last_order ~= X8C_ORDER:get() then
|
|
last_top_layer_mul = X8C_TOPMUL:get()
|
|
last_bot_layer_mul = X8C_BOTMUL:get()
|
|
last_order = X8C_ORDER:get()
|
|
update_factors()
|
|
end
|
|
return update, 200
|
|
end
|
|
|
|
gcs:send_text(MAV_SEVERITY.INFO, string.format("Loaded frame %s", FRAME_NAME))
|
|
|
|
return update,200
|