Vehicles/Rdd2/RateControlAllocator.mo
Download original .moGitHub source
Documentation: Vehicles.Rdd2.RateControlAllocator
within Vehicles.Rdd2;
// SPDX-License-Identifier: Apache-2.0
block RateControlAllocator
"Sampled body-rate control and motor allocation task"
import Interfaces = Vehicles.Rdd2.ControllerInterfaces;
parameter Real samplePeriod(unit = "s") = 0.000625;
parameter Real inertia[3] = {
0.02166666666666667,
0.02166666666666667,
0.04000000000000001};
parameter Real rateGain[3] = {20.0, 20.0, 10.0};
parameter Real maximumBodyMoment_Nm[3] = {2.6, 2.6, 0.30}
"Conservative requested-moment bounds before allocation";
parameter Real thrustCoefficient = 8.54858e-6
"Rotor thrust coefficient [N/(rad/s)^2]";
parameter Real maxMotorSpeed(unit = "rad/s") = 1100.0;
parameter Vehicles.Rdd2.RotorGeometry rotorGeometry =
Vehicles.Rdd2.RotorGeometry()
"Airframe geometry, fixed at code generation; geometry changes recompile
through calibration rather than tuning the allocation at runtime"
annotation(Evaluate = true);
parameter Real wrenchToRotorThrust[4, 4] =
Control.Multirotor.Allocation.quadrotorWrenchToThrust(
rotorGeometry.positionBodyFlu_m,
rotorGeometry.yawMomentPerThrust_m);
Interfaces.RateControlInput inputSignal;
Interfaces.MotorCommands commands;
protected
discrete Real unboundedMomentBodyFlu_Nm[3](each start = 0.0);
discrete Real momentBodyFlu_Nm[3](each start = 0.0);
discrete Real allocatedMotorCommand[4](each start = 0.0, each fixed = true);
equation
commands.motor = if inputSignal.armed then
allocatedMotorCommand
else
zeros(4);
initial algorithm
assert(inertia[1] > 0.0 and inertia[2] > 0.0 and inertia[3] > 0.0,
"Every body inertia must be positive");
assert(rateGain[1] >= 0.0 and rateGain[2] >= 0.0 and rateGain[3] >= 0.0,
"Every body-rate gain must be nonnegative");
assert(thrustCoefficient > 0.0,
"Every rotor thrust coefficient must be positive");
assert(maxMotorSpeed > 0.0,
"Every maximum rotor speed must be positive");
algorithm
when sample(0.0, samplePeriod) then
unboundedMomentBodyFlu_Nm := Control.Multirotor.RateLoop.bodyMoment(
inputSignal.angularVelocityCommandFlu_rad_s,
inputSignal.angularVelocityMeasuredFlu_rad_s,
inertia,
rateGain);
momentBodyFlu_Nm := {
MathUtilities.clip(unboundedMomentBodyFlu_Nm[1],
-maximumBodyMoment_Nm[1], maximumBodyMoment_Nm[1]),
MathUtilities.clip(unboundedMomentBodyFlu_Nm[2],
-maximumBodyMoment_Nm[2], maximumBodyMoment_Nm[2]),
MathUtilities.clip(unboundedMomentBodyFlu_Nm[3],
-maximumBodyMoment_Nm[3], maximumBodyMoment_Nm[3])};
allocatedMotorCommand := Control.Multirotor.Allocation.rotorCommands(
4,
inputSignal.thrust_N,
momentBodyFlu_Nm,
wrenchToRotorThrust,
fill(thrustCoefficient, 4),
fill(maxMotorSpeed, 4));
end when;
annotation(Documentation(info = "<html>
<p>This block owns the fast RTOS task boundary. It samples the outer-loop
body-rate and thrust command, computes body moment in the shared FLU
convention, and allocates the result to the four motors.</p>
<p>The model intentionally retains vector and matrix equations. Rumoca
lowers those equations to bounded scalar Production Code; the source model
remains compact and auditable.</p>
</html>"));
end RateControlAllocator;