initial control allocation support

- control allocation module with multirotor, VTOL standard, and tiltrotor support
 - angular_velocity_controller
 - See https://github.com/PX4/PX4-Autopilot/pull/13351 for details

Co-authored-by: Silvan Fuhrer <silvan@auterion.com>
Co-authored-by: Roman Bapst <bapstroman@gmail.com>
This commit is contained in:
Julien Lecoeur
2021-01-10 11:30:23 -05:00
committed by Daniel Agar
parent fc6b61dad1
commit 343cf5603e
68 changed files with 6129 additions and 17 deletions
@@ -0,0 +1,116 @@
/****************************************************************************
*
* Copyright (c) 2020 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file ActuatorEffectiveness.hpp
*
* Interface for Actuator Effectiveness
*
* @author Julien Lecoeur <julien.lecoeur@gmail.com>
*/
#pragma once
#include <ControlAllocation/ControlAllocation.hpp>
#include <matrix/matrix/math.hpp>
#include <uORB/topics/vehicle_actuator_setpoint.h>
class ActuatorEffectiveness
{
public:
ActuatorEffectiveness() = default;
virtual ~ActuatorEffectiveness() = default;
static constexpr uint8_t NUM_ACTUATORS = ControlAllocation::NUM_ACTUATORS;
static constexpr uint8_t NUM_AXES = ControlAllocation::NUM_AXES;
enum class FlightPhase {
HOVER_FLIGHT = 0,
FORWARD_FLIGHT = 1,
TRANSITION_HF_TO_FF = 2,
TRANSITION_FF_TO_HF = 3
};
/**
* Update effectiveness matrix
*
* @return True if the effectiveness matrix has changed
*/
virtual bool update() = 0;
/**
* Set the current flight phase
*
* @param Flight phase
*/
virtual void setFlightPhase(const FlightPhase &flight_phase)
{
_flight_phase = flight_phase;
};
/**
* Get the control effectiveness matrix
*
* @return Effectiveness matrix
*/
const matrix::Matrix<float, NUM_AXES, NUM_ACTUATORS> &getEffectivenessMatrix() const
{
return _effectiveness;
};
/**
* Get the actuator trims
*
* @return Actuator trims
*/
const matrix::Vector<float, NUM_ACTUATORS> &getActuatorTrim() const
{
return _trim;
};
/**
* Get the current flight phase
*
* @return Flight phase
*/
const FlightPhase &getFlightPhase() const
{
return _flight_phase;
};
protected:
matrix::Matrix<float, NUM_AXES, NUM_ACTUATORS> _effectiveness; //< Effectiveness matrix
matrix::Vector<float, NUM_ACTUATORS> _trim; //< Actuator trim
FlightPhase _flight_phase{FlightPhase::HOVER_FLIGHT}; //< Current flight phase
};
@@ -0,0 +1,201 @@
/****************************************************************************
*
* Copyright (c) 2020 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file ActuatorEffectivenessMultirotor.hpp
*
* Actuator effectiveness computed from rotors position and orientation
*
* @author Julien Lecoeur <julien.lecoeur@gmail.com>
*/
#include "ActuatorEffectivenessMultirotor.hpp"
ActuatorEffectivenessMultirotor::ActuatorEffectivenessMultirotor():
ModuleParams(nullptr)
{
parameters_updated();
}
bool
ActuatorEffectivenessMultirotor::update()
{
bool updated = false;
// Check if parameters have changed
if (_parameter_update_sub.updated()) {
// clear update
parameter_update_s param_update;
_parameter_update_sub.copy(&param_update);
updateParams();
parameters_updated();
updated = true;
}
return updated;
}
matrix::Matrix<float, ActuatorEffectivenessMultirotor::NUM_AXES, ActuatorEffectivenessMultirotor::NUM_ACTUATORS>
ActuatorEffectivenessMultirotor::computeEffectivenessMatrix(MultirotorGeometry geometry)
{
matrix::Matrix<float, ActuatorEffectivenessMultirotor::NUM_AXES, ActuatorEffectivenessMultirotor::NUM_ACTUATORS>
effectiveness;
for (size_t i = 0; i < NUM_ROTORS_MAX; i++) {
// Get rotor axis
matrix::Vector3f axis(
geometry.rotors[i].axis_x,
geometry.rotors[i].axis_y,
geometry.rotors[i].axis_z
);
// Normalize axis
float axis_norm = axis.norm();
if (axis_norm > FLT_EPSILON) {
axis /= axis_norm;
} else {
// Bad axis definition, ignore this rotor
continue;
}
// Get rotor position
matrix::Vector3f position(
geometry.rotors[i].position_x,
geometry.rotors[i].position_y,
geometry.rotors[i].position_z
);
// Get coefficients
float ct = geometry.rotors[i].thrust_coef;
float km = geometry.rotors[i].moment_ratio;
// Compute thrust generated by this rotor
matrix::Vector3f thrust = ct * axis;
// Compute moment generated by this rotor
matrix::Vector3f moment = ct * position.cross(axis) - ct * km * axis;
// Fill corresponding items in effectiveness matrix
for (size_t j = 0; j < 3; j++) {
effectiveness(j, i) = moment(j);
effectiveness(j + 3, i) = thrust(j);
}
}
return effectiveness;
}
void
ActuatorEffectivenessMultirotor::parameters_updated()
{
// Get multirotor geometry
MultirotorGeometry geometry = {};
geometry.rotors[0].position_x = _param_ca_mc_r0_px.get();
geometry.rotors[0].position_y = _param_ca_mc_r0_py.get();
geometry.rotors[0].position_z = _param_ca_mc_r0_pz.get();
geometry.rotors[0].axis_x = _param_ca_mc_r0_ax.get();
geometry.rotors[0].axis_y = _param_ca_mc_r0_ay.get();
geometry.rotors[0].axis_z = _param_ca_mc_r0_az.get();
geometry.rotors[0].thrust_coef = _param_ca_mc_r0_ct.get();
geometry.rotors[0].moment_ratio = _param_ca_mc_r0_km.get();
geometry.rotors[1].position_x = _param_ca_mc_r1_px.get();
geometry.rotors[1].position_y = _param_ca_mc_r1_py.get();
geometry.rotors[1].position_z = _param_ca_mc_r1_pz.get();
geometry.rotors[1].axis_x = _param_ca_mc_r1_ax.get();
geometry.rotors[1].axis_y = _param_ca_mc_r1_ay.get();
geometry.rotors[1].axis_z = _param_ca_mc_r1_az.get();
geometry.rotors[1].thrust_coef = _param_ca_mc_r1_ct.get();
geometry.rotors[1].moment_ratio = _param_ca_mc_r1_km.get();
geometry.rotors[2].position_x = _param_ca_mc_r2_px.get();
geometry.rotors[2].position_y = _param_ca_mc_r2_py.get();
geometry.rotors[2].position_z = _param_ca_mc_r2_pz.get();
geometry.rotors[2].axis_x = _param_ca_mc_r2_ax.get();
geometry.rotors[2].axis_y = _param_ca_mc_r2_ay.get();
geometry.rotors[2].axis_z = _param_ca_mc_r2_az.get();
geometry.rotors[2].thrust_coef = _param_ca_mc_r2_ct.get();
geometry.rotors[2].moment_ratio = _param_ca_mc_r2_km.get();
geometry.rotors[3].position_x = _param_ca_mc_r3_px.get();
geometry.rotors[3].position_y = _param_ca_mc_r3_py.get();
geometry.rotors[3].position_z = _param_ca_mc_r3_pz.get();
geometry.rotors[3].axis_x = _param_ca_mc_r3_ax.get();
geometry.rotors[3].axis_y = _param_ca_mc_r3_ay.get();
geometry.rotors[3].axis_z = _param_ca_mc_r3_az.get();
geometry.rotors[3].thrust_coef = _param_ca_mc_r3_ct.get();
geometry.rotors[3].moment_ratio = _param_ca_mc_r3_km.get();
geometry.rotors[4].position_x = _param_ca_mc_r4_px.get();
geometry.rotors[4].position_y = _param_ca_mc_r4_py.get();
geometry.rotors[4].position_z = _param_ca_mc_r4_pz.get();
geometry.rotors[4].axis_x = _param_ca_mc_r4_ax.get();
geometry.rotors[4].axis_y = _param_ca_mc_r4_ay.get();
geometry.rotors[4].axis_z = _param_ca_mc_r4_az.get();
geometry.rotors[4].thrust_coef = _param_ca_mc_r4_ct.get();
geometry.rotors[4].moment_ratio = _param_ca_mc_r4_km.get();
geometry.rotors[5].position_x = _param_ca_mc_r5_px.get();
geometry.rotors[5].position_y = _param_ca_mc_r5_py.get();
geometry.rotors[5].position_z = _param_ca_mc_r5_pz.get();
geometry.rotors[5].axis_x = _param_ca_mc_r5_ax.get();
geometry.rotors[5].axis_y = _param_ca_mc_r5_ay.get();
geometry.rotors[5].axis_z = _param_ca_mc_r5_az.get();
geometry.rotors[5].thrust_coef = _param_ca_mc_r5_ct.get();
geometry.rotors[5].moment_ratio = _param_ca_mc_r5_km.get();
geometry.rotors[6].position_x = _param_ca_mc_r6_px.get();
geometry.rotors[6].position_y = _param_ca_mc_r6_py.get();
geometry.rotors[6].position_z = _param_ca_mc_r6_pz.get();
geometry.rotors[6].axis_x = _param_ca_mc_r6_ax.get();
geometry.rotors[6].axis_y = _param_ca_mc_r6_ay.get();
geometry.rotors[6].axis_z = _param_ca_mc_r6_az.get();
geometry.rotors[6].thrust_coef = _param_ca_mc_r6_ct.get();
geometry.rotors[6].moment_ratio = _param_ca_mc_r6_km.get();
geometry.rotors[7].position_x = _param_ca_mc_r7_px.get();
geometry.rotors[7].position_y = _param_ca_mc_r7_py.get();
geometry.rotors[7].position_z = _param_ca_mc_r7_pz.get();
geometry.rotors[7].axis_x = _param_ca_mc_r7_ax.get();
geometry.rotors[7].axis_y = _param_ca_mc_r7_ay.get();
geometry.rotors[7].axis_z = _param_ca_mc_r7_az.get();
geometry.rotors[7].thrust_coef = _param_ca_mc_r7_ct.get();
geometry.rotors[7].moment_ratio = _param_ca_mc_r7_km.get();
// Compute effectiveness matrix
_effectiveness = computeEffectivenessMatrix(geometry);
}
@@ -0,0 +1,163 @@
/****************************************************************************
*
* Copyright (c) 2020 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file ActuatorEffectivenessMultirotor.hpp
*
* Actuator effectiveness computed from rotors position and orientation
*
* @author Julien Lecoeur <julien.lecoeur@gmail.com>
*/
#pragma once
#include "ActuatorEffectiveness.hpp"
#include <px4_platform_common/module_params.h>
#include <uORB/Subscription.hpp>
#include <uORB/topics/parameter_update.h>
class ActuatorEffectivenessMultirotor: public ModuleParams, public ActuatorEffectiveness
{
public:
ActuatorEffectivenessMultirotor();
virtual ~ActuatorEffectivenessMultirotor() = default;
/**
* Update effectiveness matrix
*
* @return True if the effectiveness matrix has changed
*/
virtual bool update() override;
static constexpr int NUM_ROTORS_MAX = 8;
typedef struct {
float position_x;
float position_y;
float position_z;
float axis_x;
float axis_y;
float axis_z;
float thrust_coef;
float moment_ratio;
} RotorGeometry;
typedef struct {
RotorGeometry rotors[NUM_ROTORS_MAX];
} MultirotorGeometry;
static matrix::Matrix<float, NUM_AXES, NUM_ACTUATORS> computeEffectivenessMatrix(MultirotorGeometry);
private:
/**
* initialize some vectors/matrices from parameters
*/
void parameters_updated();
uORB::Subscription _parameter_update_sub{ORB_ID(parameter_update)}; /**< parameter updates subscription */
DEFINE_PARAMETERS(
(ParamFloat<px4::params::CA_MC_R0_PX>) _param_ca_mc_r0_px,
(ParamFloat<px4::params::CA_MC_R0_PY>) _param_ca_mc_r0_py,
(ParamFloat<px4::params::CA_MC_R0_PZ>) _param_ca_mc_r0_pz,
(ParamFloat<px4::params::CA_MC_R0_AX>) _param_ca_mc_r0_ax,
(ParamFloat<px4::params::CA_MC_R0_AY>) _param_ca_mc_r0_ay,
(ParamFloat<px4::params::CA_MC_R0_AZ>) _param_ca_mc_r0_az,
(ParamFloat<px4::params::CA_MC_R0_CT>) _param_ca_mc_r0_ct,
(ParamFloat<px4::params::CA_MC_R0_KM>) _param_ca_mc_r0_km,
(ParamFloat<px4::params::CA_MC_R1_PX>) _param_ca_mc_r1_px,
(ParamFloat<px4::params::CA_MC_R1_PY>) _param_ca_mc_r1_py,
(ParamFloat<px4::params::CA_MC_R1_PZ>) _param_ca_mc_r1_pz,
(ParamFloat<px4::params::CA_MC_R1_AX>) _param_ca_mc_r1_ax,
(ParamFloat<px4::params::CA_MC_R1_AY>) _param_ca_mc_r1_ay,
(ParamFloat<px4::params::CA_MC_R1_AZ>) _param_ca_mc_r1_az,
(ParamFloat<px4::params::CA_MC_R1_CT>) _param_ca_mc_r1_ct,
(ParamFloat<px4::params::CA_MC_R1_KM>) _param_ca_mc_r1_km,
(ParamFloat<px4::params::CA_MC_R2_PX>) _param_ca_mc_r2_px,
(ParamFloat<px4::params::CA_MC_R2_PY>) _param_ca_mc_r2_py,
(ParamFloat<px4::params::CA_MC_R2_PZ>) _param_ca_mc_r2_pz,
(ParamFloat<px4::params::CA_MC_R2_AX>) _param_ca_mc_r2_ax,
(ParamFloat<px4::params::CA_MC_R2_AY>) _param_ca_mc_r2_ay,
(ParamFloat<px4::params::CA_MC_R2_AZ>) _param_ca_mc_r2_az,
(ParamFloat<px4::params::CA_MC_R2_CT>) _param_ca_mc_r2_ct,
(ParamFloat<px4::params::CA_MC_R2_KM>) _param_ca_mc_r2_km,
(ParamFloat<px4::params::CA_MC_R3_PX>) _param_ca_mc_r3_px,
(ParamFloat<px4::params::CA_MC_R3_PY>) _param_ca_mc_r3_py,
(ParamFloat<px4::params::CA_MC_R3_PZ>) _param_ca_mc_r3_pz,
(ParamFloat<px4::params::CA_MC_R3_AX>) _param_ca_mc_r3_ax,
(ParamFloat<px4::params::CA_MC_R3_AY>) _param_ca_mc_r3_ay,
(ParamFloat<px4::params::CA_MC_R3_AZ>) _param_ca_mc_r3_az,
(ParamFloat<px4::params::CA_MC_R3_CT>) _param_ca_mc_r3_ct,
(ParamFloat<px4::params::CA_MC_R3_KM>) _param_ca_mc_r3_km,
(ParamFloat<px4::params::CA_MC_R4_PX>) _param_ca_mc_r4_px,
(ParamFloat<px4::params::CA_MC_R4_PY>) _param_ca_mc_r4_py,
(ParamFloat<px4::params::CA_MC_R4_PZ>) _param_ca_mc_r4_pz,
(ParamFloat<px4::params::CA_MC_R4_AX>) _param_ca_mc_r4_ax,
(ParamFloat<px4::params::CA_MC_R4_AY>) _param_ca_mc_r4_ay,
(ParamFloat<px4::params::CA_MC_R4_AZ>) _param_ca_mc_r4_az,
(ParamFloat<px4::params::CA_MC_R4_CT>) _param_ca_mc_r4_ct,
(ParamFloat<px4::params::CA_MC_R4_KM>) _param_ca_mc_r4_km,
(ParamFloat<px4::params::CA_MC_R5_PX>) _param_ca_mc_r5_px,
(ParamFloat<px4::params::CA_MC_R5_PY>) _param_ca_mc_r5_py,
(ParamFloat<px4::params::CA_MC_R5_PZ>) _param_ca_mc_r5_pz,
(ParamFloat<px4::params::CA_MC_R5_AX>) _param_ca_mc_r5_ax,
(ParamFloat<px4::params::CA_MC_R5_AY>) _param_ca_mc_r5_ay,
(ParamFloat<px4::params::CA_MC_R5_AZ>) _param_ca_mc_r5_az,
(ParamFloat<px4::params::CA_MC_R5_CT>) _param_ca_mc_r5_ct,
(ParamFloat<px4::params::CA_MC_R5_KM>) _param_ca_mc_r5_km,
(ParamFloat<px4::params::CA_MC_R6_PX>) _param_ca_mc_r6_px,
(ParamFloat<px4::params::CA_MC_R6_PY>) _param_ca_mc_r6_py,
(ParamFloat<px4::params::CA_MC_R6_PZ>) _param_ca_mc_r6_pz,
(ParamFloat<px4::params::CA_MC_R6_AX>) _param_ca_mc_r6_ax,
(ParamFloat<px4::params::CA_MC_R6_AY>) _param_ca_mc_r6_ay,
(ParamFloat<px4::params::CA_MC_R6_AZ>) _param_ca_mc_r6_az,
(ParamFloat<px4::params::CA_MC_R6_CT>) _param_ca_mc_r6_ct,
(ParamFloat<px4::params::CA_MC_R6_KM>) _param_ca_mc_r6_km,
(ParamFloat<px4::params::CA_MC_R7_PX>) _param_ca_mc_r7_px,
(ParamFloat<px4::params::CA_MC_R7_PY>) _param_ca_mc_r7_py,
(ParamFloat<px4::params::CA_MC_R7_PZ>) _param_ca_mc_r7_pz,
(ParamFloat<px4::params::CA_MC_R7_AX>) _param_ca_mc_r7_ax,
(ParamFloat<px4::params::CA_MC_R7_AY>) _param_ca_mc_r7_ay,
(ParamFloat<px4::params::CA_MC_R7_AZ>) _param_ca_mc_r7_az,
(ParamFloat<px4::params::CA_MC_R7_CT>) _param_ca_mc_r7_ct,
(ParamFloat<px4::params::CA_MC_R7_KM>) _param_ca_mc_r7_km
)
};
@@ -0,0 +1,560 @@
/****************************************************************************
*
* Copyright (c) 2020 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file ActuatorEffectivenessMultirotorParams.c
*
* Parameters for the actuator effectiveness of multirotors.
*
* @author Julien Lecoeur <julien.lecoeur@gmail.com>
*/
/**
* Position of rotor 0 along X body axis
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R0_PX, 0.0);
/**
* Position of rotor 0 along Y body axis
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R0_PY, 0.0);
/**
* Position of rotor 0 along Z body axis
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R0_PZ, 0.0);
/**
* Axis of rotor 0 thrust vector, X body axis component
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R0_AX, 0.0);
/**
* Axis of rotor 0 thrust vector, Y body axis component
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R0_AY, 0.0);
/**
* Axis of rotor 0 thrust vector, Z body axis component
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R0_AZ, -1.0);
/**
* Thrust coefficient of rotor 0
*
* The thrust coefficient if defined as Thrust = CT * u^2,
* where u (with value between CA_ACT0_MIN and CA_ACT0_MAX)
* is the output signal sent to the motor controller.
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R0_CT, 0.0);
/**
* Moment coefficient of rotor 0
*
* The moment coefficient if defined as Torque = KM * Thrust
*
* Use a positive value for a rotor with CCW rotation.
* Use a negative value for a rotor with CW rotation.
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R0_KM, 0.05);
/**
* Position of rotor 1 along X body axis
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R1_PX, 0.0);
/**
* Position of rotor 1 along Y body axis
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R1_PY, 0.0);
/**
* Position of rotor 1 along Z body axis
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R1_PZ, 0.0);
/**
* Axis of rotor 1 thrust vector, X body axis component
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R1_AX, 0.0);
/**
* Axis of rotor 1 thrust vector, Y body axis component
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R1_AY, 0.0);
/**
* Axis of rotor 1 thrust vector, Z body axis component
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R1_AZ, -1.0);
/**
* Thrust coefficient of rotor 1
*
* The thrust coefficient if defined as Thrust = CT * u^2,
* where u (with value between CA_ACT1_MIN and CA_ACT1_MAX)
* is the output signal sent to the motor controller.
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R1_CT, 0.0);
/**
* Moment coefficient of rotor 1
*
* The moment coefficient if defined as Torque = KM * Thrust,
*
* Use a positive value for a rotor with CCW rotation.
* Use a negative value for a rotor with CW rotation.
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R1_KM, 0.05);
/**
* Position of rotor 2 along X body axis
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R2_PX, 0.0);
/**
* Position of rotor 2 along Y body axis
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R2_PY, 0.0);
/**
* Position of rotor 2 along Z body axis
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R2_PZ, 0.0);
/**
* Axis of rotor 2 thrust vector, X body axis component
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R2_AX, 0.0);
/**
* Axis of rotor 2 thrust vector, Y body axis component
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R2_AY, 0.0);
/**
* Axis of rotor 2 thrust vector, Z body axis component
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R2_AZ, -1.0);
/**
* Thrust coefficient of rotor 2
*
* The thrust coefficient if defined as Thrust = CT * u^2,
* where u (with value between CA_ACT2_MIN and CA_ACT2_MAX)
* is the output signal sent to the motor controller.
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R2_CT, 0.0);
/**
* Moment coefficient of rotor 2
*
* The moment coefficient if defined as Torque = KM * Thrust
*
* Use a positive value for a rotor with CCW rotation.
* Use a negative value for a rotor with CW rotation.
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R2_KM, 0.05);
/**
* Position of rotor 3 along X body axis
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R3_PX, 0.0);
/**
* Position of rotor 3 along Y body axis
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R3_PY, 0.0);
/**
* Position of rotor 3 along Z body axis
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R3_PZ, 0.0);
/**
* Axis of rotor 3 thrust vector, X body axis component
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R3_AX, 0.0);
/**
* Axis of rotor 3 thrust vector, Y body axis component
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R3_AY, 0.0);
/**
* Axis of rotor 3 thrust vector, Z body axis component
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R3_AZ, -1.0);
/**
* Thrust coefficient of rotor 3
*
* The thrust coefficient if defined as Thrust = CT * u^2,
* where u (with value between CA_ACT3_MIN and CA_ACT3_MAX)
* is the output signal sent to the motor controller.
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R3_CT, 0.0);
/**
* Moment coefficient of rotor 3
*
* The moment coefficient if defined as Torque = KM * Thrust
*
* Use a positive value for a rotor with CCW rotation.
* Use a negative value for a rotor with CW rotation.
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R3_KM, 0.05);
/**
* Position of rotor 4 along X body axis
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R4_PX, 0.0);
/**
* Position of rotor 4 along Y body axis
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R4_PY, 0.0);
/**
* Position of rotor 4 along Z body axis
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R4_PZ, 0.0);
/**
* Axis of rotor 4 thrust vector, X body axis component
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R4_AX, 0.0);
/**
* Axis of rotor 4 thrust vector, Y body axis component
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R4_AY, 0.0);
/**
* Axis of rotor 4 thrust vector, Z body axis component
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R4_AZ, -1.0);
/**
* Thrust coefficient of rotor 4
*
* The thrust coefficient if defined as Thrust = CT * u^2,
* where u (with value between CA_ACT4_MIN and CA_ACT4_MAX)
* is the output signal sent to the motor controller.
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R4_CT, 0.0);
/**
* Moment coefficient of rotor 4
*
* The moment coefficient if defined as Torque = KM * Thrust
*
* Use a positive value for a rotor with CCW rotation.
* Use a negative value for a rotor with CW rotation.
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R4_KM, 0.05);
/**
* Position of rotor 5 along X body axis
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R5_PX, 0.0);
/**
* Position of rotor 5 along Y body axis
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R5_PY, 0.0);
/**
* Position of rotor 5 along Z body axis
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R5_PZ, 0.0);
/**
* Axis of rotor 5 thrust vector, X body axis component
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R5_AX, 0.0);
/**
* Axis of rotor 5 thrust vector, Y body axis component
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R5_AY, 0.0);
/**
* Axis of rotor 5 thrust vector, Z body axis component
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R5_AZ, -1.0);
/**
* Thrust coefficient of rotor 5
*
* The thrust coefficient if defined as Thrust = CT * u^2,
* where u (with value between CA_ACT5_MIN and CA_ACT5_MAX)
* is the output signal sent to the motor controller.
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R5_CT, 0.0);
/**
* Moment coefficient of rotor 5
*
* The moment coefficient if defined as Torque = KM * Thrust
*
* Use a positive value for a rotor with CCW rotation.
* Use a negative value for a rotor with CW rotation.
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R5_KM, 0.05);
/**
* Position of rotor 6 along X body axis
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R6_PX, 0.0);
/**
* Position of rotor 6 along Y body axis
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R6_PY, 0.0);
/**
* Position of rotor 6 along Z body axis
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R6_PZ, 0.0);
/**
* Axis of rotor 6 thrust vector, X body axis component
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R6_AX, 0.0);
/**
* Axis of rotor 6 thrust vector, Y body axis component
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R6_AY, 0.0);
/**
* Axis of rotor 6 thrust vector, Z body axis component
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R6_AZ, -1.0);
/**
* Thrust coefficient of rotor 6
*
* The thrust coefficient if defined as Thrust = CT * u^2,
* where u (with value between CA_ACT6_MIN and CA_ACT6_MAX)
* is the output signal sent to the motor controller.
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R6_CT, 0.0);
/**
* Moment coefficient of rotor 6
*
* The moment coefficient if defined as Torque = KM * Thrust
*
* Use a positive value for a rotor with CCW rotation.
* Use a negative value for a rotor with CW rotation.
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R6_KM, 0.05);
/**
* Position of rotor 7 along X body axis
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R7_PX, 0.0);
/**
* Position of rotor 7 along Y body axis
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R7_PY, 0.0);
/**
* Position of rotor 7 along Z body axis
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R7_PZ, 0.0);
/**
* Axis of rotor 7 thrust vector, X body axis component
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R7_AX, 0.0);
/**
* Axis of rotor 7 thrust vector, Y body axis component
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R7_AY, 0.0);
/**
* Axis of rotor 7 thrust vector, Z body axis component
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R7_AZ, -1.0);
/**
* Thrust coefficient of rotor 7
*
* The thrust coefficient if defined as Thrust = CT * u^2,
* where u (with value between CA_ACT7_MIN and CA_ACT7_MAX)
* is the output signal sent to the motor controller.
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R7_CT, 0.0);
/**
* Moment coefficient of rotor 7
*
* The moment coefficient if defined as Torque = KM * Thrust
*
* Use a positive value for a rotor with CCW rotation.
* Use a negative value for a rotor with CW rotation.
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_MC_R7_KM, 0.05);
@@ -0,0 +1,102 @@
/****************************************************************************
*
* Copyright (C) 2020 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file ActuatorEffectivenessMultirotorTest.cpp
*
* Tests for Control Allocation Algorithms
*
* @author Julien Lecoeur <julien.lecoeur@gmail.com>
*/
#include <gtest/gtest.h>
#include <ActuatorEffectivenessMultirotor.hpp>
using namespace matrix;
TEST(ActuatorEffectivenessMultirotorTest, AllZeroCase)
{
// Quad wide geometry
ActuatorEffectivenessMultirotor::MultirotorGeometry geometry = {};
geometry.rotors[0].position_x = 1.0f;
geometry.rotors[0].position_y = 1.0f;
geometry.rotors[0].position_z = 0.0f;
geometry.rotors[0].axis_x = 0.0f;
geometry.rotors[0].axis_y = 0.0f;
geometry.rotors[0].axis_z = -1.0f;
geometry.rotors[0].thrust_coef = 1.0f;
geometry.rotors[0].moment_ratio = 0.05f;
geometry.rotors[1].position_x = -1.0f;
geometry.rotors[1].position_y = -1.0f;
geometry.rotors[1].position_z = 0.0f;
geometry.rotors[1].axis_x = 0.0f;
geometry.rotors[1].axis_y = 0.0f;
geometry.rotors[1].axis_z = -1.0f;
geometry.rotors[1].thrust_coef = 1.0f;
geometry.rotors[1].moment_ratio = 0.05f;
geometry.rotors[2].position_x = 1.0f;
geometry.rotors[2].position_y = -1.0f;
geometry.rotors[2].position_z = 0.0f;
geometry.rotors[2].axis_x = 0.0f;
geometry.rotors[2].axis_y = 0.0f;
geometry.rotors[2].axis_z = -1.0f;
geometry.rotors[2].thrust_coef = 1.0f;
geometry.rotors[2].moment_ratio = -0.05f;
geometry.rotors[3].position_x = -1.0f;
geometry.rotors[3].position_y = 1.0f;
geometry.rotors[3].position_z = 0.0f;
geometry.rotors[3].axis_x = 0.0f;
geometry.rotors[3].axis_y = 0.0f;
geometry.rotors[3].axis_z = -1.0f;
geometry.rotors[3].thrust_coef = 1.0f;
geometry.rotors[3].moment_ratio = -0.05f;
matrix::Matrix<float, ActuatorEffectiveness::NUM_AXES, ActuatorEffectiveness::NUM_ACTUATORS> effectiveness =
ActuatorEffectivenessMultirotor::computeEffectivenessMatrix(geometry);
const float expected[ActuatorEffectiveness::NUM_AXES][ActuatorEffectiveness::NUM_ACTUATORS] = {
{-1.0f, 1.0f, 1.0f, -1.0f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
{ 1.0f, -1.0f, 1.0f, -1.0f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
{ 0.05f, 0.05f, -0.05f, -0.05f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
{ 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
{ 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
{-1.0f, -1.0f, -1.0f, -1.0f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}
};
matrix::Matrix<float, ActuatorEffectiveness::NUM_AXES, ActuatorEffectiveness::NUM_ACTUATORS> effectiveness_expected(
expected);
EXPECT_EQ(effectiveness, effectiveness_expected);
}
@@ -0,0 +1,108 @@
/****************************************************************************
*
* Copyright (c) 2020 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file ActuatorEffectivenessStandardVTOL.hpp
*
* Actuator effectiveness for standard VTOL
*
* @author Julien Lecoeur <julien.lecoeur@gmail.com>
*/
#include "ActuatorEffectivenessStandardVTOL.hpp"
ActuatorEffectivenessStandardVTOL::ActuatorEffectivenessStandardVTOL()
{
setFlightPhase(FlightPhase::HOVER_FLIGHT);
}
bool
ActuatorEffectivenessStandardVTOL::update()
{
if (_updated) {
_updated = false;
return true;
}
return false;
}
void
ActuatorEffectivenessStandardVTOL::setFlightPhase(const FlightPhase &flight_phase)
{
ActuatorEffectiveness::setFlightPhase(flight_phase);
_updated = true;
switch (_flight_phase) {
case FlightPhase::HOVER_FLIGHT: {
const float standard_vtol[NUM_AXES][NUM_ACTUATORS] = {
{-0.5f, 0.5f, 0.5f, -0.5f, 0.f, 0.0f, 0.0f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
{ 0.5f, -0.5f, 0.5f, -0.5f, 0.f, 0.f, 0.f, 0.0f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
{ 0.25f, 0.25f, -0.25f, -0.25f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
{ 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
{ 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
{-0.25f, -0.25f, -0.25f, -0.25f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}
};
_effectiveness = matrix::Matrix<float, NUM_AXES, NUM_ACTUATORS>(standard_vtol);
break;
}
case FlightPhase::FORWARD_FLIGHT: {
const float standard_vtol[NUM_AXES][NUM_ACTUATORS] = {
{ 0.f, 0.f, 0.f, 0.f, 0.f, -0.5f, 0.5f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
{ 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.5f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
{ 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
{ 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
{ 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
{ 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}
};
_effectiveness = matrix::Matrix<float, NUM_AXES, NUM_ACTUATORS>(standard_vtol);
break;
}
case FlightPhase::TRANSITION_HF_TO_FF:
case FlightPhase::TRANSITION_FF_TO_HF: {
const float standard_vtol[NUM_AXES][NUM_ACTUATORS] = {
{ -0.5f, 0.5f, 0.5f, -0.5f, 0.f, -0.5f, 0.5f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
{ 0.5f, -0.5f, 0.5f, -0.5f, 0.f, 0.f, 0.f, 0.5f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
{ 0.25f, 0.25f, -0.25f, -0.25f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
{ 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
{ 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
{-0.25f, -0.25f, -0.25f, -0.25f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}
};
_effectiveness = matrix::Matrix<float, NUM_AXES, NUM_ACTUATORS>(standard_vtol);
break;
}
}
}
@@ -0,0 +1,68 @@
/****************************************************************************
*
* Copyright (c) 2020 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file ActuatorEffectivenessStandardVTOL.hpp
*
* Actuator effectiveness for standard VTOL
*
* @author Julien Lecoeur <julien.lecoeur@gmail.com>
*/
#pragma once
#include "ActuatorEffectiveness.hpp"
class ActuatorEffectivenessStandardVTOL: public ActuatorEffectiveness
{
public:
ActuatorEffectivenessStandardVTOL();
virtual ~ActuatorEffectivenessStandardVTOL() = default;
/**
* Update effectiveness matrix
*
* @return True if the effectiveness matrix has changed
*/
virtual bool update() override;
/**
* Set the current flight phase
*
* @param Flight phase
*/
void setFlightPhase(const FlightPhase &flight_phase) override;
protected:
bool _updated{false};
};
@@ -0,0 +1,116 @@
/****************************************************************************
*
* Copyright (c) 2020 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file ActuatorEffectivenessTiltrotorVTOL.hpp
*
* Actuator effectiveness for tiltrotor VTOL
*
* @author Julien Lecoeur <julien.lecoeur@gmail.com>
*/
#include "ActuatorEffectivenessTiltrotorVTOL.hpp"
ActuatorEffectivenessTiltrotorVTOL::ActuatorEffectivenessTiltrotorVTOL()
{
setFlightPhase(FlightPhase::HOVER_FLIGHT);
}
bool
ActuatorEffectivenessTiltrotorVTOL::update()
{
if (_updated) {
_updated = false;
return true;
}
return false;
}
void
ActuatorEffectivenessTiltrotorVTOL::setFlightPhase(const FlightPhase &flight_phase)
{
ActuatorEffectiveness::setFlightPhase(flight_phase);
_updated = true;
// Trim
float tilt = 0.0f;
switch (_flight_phase) {
case FlightPhase::HOVER_FLIGHT: {
tilt = 0.0f;
break;
}
case FlightPhase::FORWARD_FLIGHT: {
tilt = 1.5f;
break;
}
case FlightPhase::TRANSITION_FF_TO_HF:
case FlightPhase::TRANSITION_HF_TO_FF: {
tilt = 1.0f;
break;
}
}
// Trim: half throttle, tilted motors
_trim(0) = 0.5f;
_trim(1) = 0.5f;
_trim(2) = 0.5f;
_trim(3) = 0.5f;
_trim(4) = tilt;
_trim(5) = tilt;
_trim(6) = tilt;
_trim(7) = tilt;
// Effectiveness
const float tiltrotor_vtol[NUM_AXES][NUM_ACTUATORS] = {
{-0.5f * cosf(_trim(4)), 0.5f * cosf(_trim(5)), 0.5f * cosf(_trim(6)), -0.5f * cosf(_trim(7)), 0.5f * _trim(0) *sinf(_trim(4)), -0.5f * _trim(1) *sinf(_trim(5)), -0.5f * _trim(2) *sinf(_trim(6)), 0.5f * _trim(3) *sinf(_trim(7)), -0.5f, 0.5f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
{ 0.5f * cosf(_trim(4)), -0.5f * cosf(_trim(5)), 0.5f * cosf(_trim(6)), -0.5f * cosf(_trim(7)), -0.5f * _trim(0) *sinf(_trim(4)), 0.5f * _trim(1) *sinf(_trim(5)), -0.5f * _trim(2) *sinf(_trim(6)), 0.5f * _trim(3) *sinf(_trim(7)), 0.f, 0.f, 0.5f, 0.f, 0.f, 0.f, 0.f, 0.f},
{-0.5f * sinf(_trim(4)), 0.5f * sinf(_trim(5)), 0.5f * sinf(_trim(6)), -0.5f * sinf(_trim(7)), -0.5f * _trim(0) *cosf(_trim(4)), 0.5f * _trim(1) *cosf(_trim(5)), 0.5f * _trim(2) *cosf(_trim(6)), -0.5f * _trim(3) *cosf(_trim(7)), 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
{ 0.25f * sinf(_trim(4)), 0.25f * sinf(_trim(5)), 0.25f * sinf(_trim(6)), 0.25f * sinf(_trim(7)), 0.25f * _trim(0) *cosf(_trim(4)), 0.25f * _trim(1) *cosf(_trim(5)), 0.25f * _trim(2) *cosf(_trim(6)), 0.25f * _trim(3) *cosf(_trim(7)), 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
{ 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f},
{-0.25f * cosf(_trim(4)), -0.25f * cosf(_trim(5)), -0.25f * cosf(_trim(6)), -0.25f * cosf(_trim(7)), 0.25f * _trim(0) *sinf(_trim(4)), 0.25f * _trim(1) *sinf(_trim(5)), 0.25f * _trim(2) *sinf(_trim(6)), 0.25f * _trim(3) *sinf(_trim(7)), 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}
};
_effectiveness = matrix::Matrix<float, NUM_AXES, NUM_ACTUATORS>(tiltrotor_vtol);
// Temporarily disable a few controls (WIP)
for (size_t j = 4; j < 8; j++) {
_effectiveness(3, j) = 0.0f;
_effectiveness(4, j) = 0.0f;
_effectiveness(5, j) = 0.0f;
}
}
@@ -0,0 +1,68 @@
/****************************************************************************
*
* Copyright (c) 2020 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file ActuatorEffectivenessTiltrotorVTOL.hpp
*
* Actuator effectiveness for tiltrotor VTOL
*
* @author Julien Lecoeur <julien.lecoeur@gmail.com>
*/
#pragma once
#include "ActuatorEffectiveness.hpp"
class ActuatorEffectivenessTiltrotorVTOL: public ActuatorEffectiveness
{
public:
ActuatorEffectivenessTiltrotorVTOL();
virtual ~ActuatorEffectivenessTiltrotorVTOL() = default;
/**
* Update effectiveness matrix
*
* @return True if the effectiveness matrix has changed
*/
virtual bool update() override;
/**
* Set the current flight phase
*
* @param Flight phase
*/
void setFlightPhase(const FlightPhase &flight_phase) override;
protected:
bool _updated{false};
};
@@ -0,0 +1,52 @@
############################################################################
#
# Copyright (c) 2019 PX4 Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name PX4 nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
px4_add_library(ActuatorEffectiveness
ActuatorEffectiveness.hpp
ActuatorEffectivenessMultirotor.cpp
ActuatorEffectivenessMultirotor.hpp
ActuatorEffectivenessStandardVTOL.cpp
ActuatorEffectivenessStandardVTOL.hpp
ActuatorEffectivenessTiltrotorVTOL.cpp
ActuatorEffectivenessTiltrotorVTOL.hpp
)
target_compile_options(ActuatorEffectiveness PRIVATE ${MAX_CUSTOM_OPT_LEVEL})
target_include_directories(ActuatorEffectiveness PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(ActuatorEffectiveness
PRIVATE
mathlib
ControlAllocation
)
# px4_add_unit_gtest(SRC ActuatorEffectivenessMultirotorTest.cpp LINKLIBS ActuatorEffectiveness)
@@ -0,0 +1,52 @@
############################################################################
#
# Copyright (c) 2019 PX4 Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name PX4 nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
add_subdirectory(ActuatorEffectiveness)
add_subdirectory(ControlAllocation)
px4_add_module(
MODULE modules__control_allocator
MAIN control_allocator
COMPILE_FLAGS
${MAX_CUSTOM_OPT_LEVEL}
SRCS
ControlAllocator.cpp
ControlAllocator.hpp
DEPENDS
mathlib
ActuatorEffectiveness
ControlAllocation
mixer
px4_work_queue
)
@@ -0,0 +1,46 @@
############################################################################
#
# Copyright (c) 2019 PX4 Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name PX4 nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
px4_add_library(ControlAllocation
ControlAllocation.cpp
ControlAllocation.hpp
ControlAllocationPseudoInverse.cpp
ControlAllocationPseudoInverse.hpp
ControlAllocationSequentialDesaturation.cpp
ControlAllocationSequentialDesaturation.hpp
)
target_compile_options(ControlAllocation PRIVATE ${MAX_CUSTOM_OPT_LEVEL})
target_include_directories(ControlAllocation PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(ControlAllocation PRIVATE mathlib)
px4_add_unit_gtest(SRC ControlAllocationPseudoInverseTest.cpp LINKLIBS ControlAllocation)
@@ -0,0 +1,164 @@
/****************************************************************************
*
* Copyright (c) 2019 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file ControlAllocation.cpp
*
* Interface for Control Allocation Algorithms
*
* @author Julien Lecoeur <julien.lecoeur@gmail.com>
*/
#include "ControlAllocation.hpp"
const matrix::Vector<float, ControlAllocation::NUM_ACTUATORS> &
ControlAllocation::getActuatorSetpoint() const
{
return _actuator_sp;
}
void
ControlAllocation::setControlSetpoint(const matrix::Vector<float, ControlAllocation::NUM_AXES> &control)
{
_control_sp = control;
}
const matrix::Vector<float, ControlAllocation::NUM_AXES> &
ControlAllocation::getControlSetpoint() const
{
return _control_sp;
}
const matrix::Vector<float, ControlAllocation::NUM_AXES> &
ControlAllocation::getAllocatedControl() const
{
return _control_allocated;
}
void
ControlAllocation::setEffectivenessMatrix(
const matrix::Matrix<float, ControlAllocation::NUM_AXES, ControlAllocation::NUM_ACTUATORS> &effectiveness,
const matrix::Vector<float, ControlAllocation::NUM_ACTUATORS> &actuator_trim)
{
_effectiveness = effectiveness;
_actuator_trim = clipActuatorSetpoint(actuator_trim);
_control_trim = _effectiveness * _actuator_trim;
}
const matrix::Matrix<float, ControlAllocation::NUM_AXES, ControlAllocation::NUM_ACTUATORS> &
ControlAllocation::getEffectivenessMatrix() const
{
return _effectiveness;
}
void
ControlAllocation::setActuatorMin(const matrix::Vector<float, ControlAllocation::NUM_ACTUATORS>
&actuator_min)
{
_actuator_min = actuator_min;
}
const matrix::Vector<float, ControlAllocation::NUM_ACTUATORS> &
ControlAllocation::getActuatorMin() const
{
return _actuator_min;
}
void
ControlAllocation::setActuatorMax(const matrix::Vector<float, ControlAllocation::NUM_ACTUATORS>
&actuator_max)
{
_actuator_max = actuator_max;
}
const matrix::Vector<float, ControlAllocation::NUM_ACTUATORS> &
ControlAllocation::getActuatorMax() const
{
return _actuator_max;
}
void
ControlAllocation::setActuatorSetpoint(
const matrix::Vector<float, ControlAllocation::NUM_ACTUATORS> &actuator_sp)
{
// Set actuator setpoint
_actuator_sp = actuator_sp;
// Clip
_actuator_sp = clipActuatorSetpoint(_actuator_sp);
// Compute achieved control
_control_allocated = _effectiveness * _actuator_sp;
}
matrix::Vector<float, ControlAllocation::NUM_ACTUATORS>
ControlAllocation::clipActuatorSetpoint(const matrix::Vector<float, ControlAllocation::NUM_ACTUATORS> &actuator) const
{
matrix::Vector<float, ControlAllocation::NUM_ACTUATORS> actuator_clipped;
for (size_t i = 0; i < ControlAllocation::NUM_ACTUATORS; i++) {
if (_actuator_max(i) < _actuator_min(i)) {
actuator_clipped(i) = _actuator_trim(i);
} else if (actuator_clipped(i) < _actuator_min(i)) {
actuator_clipped(i) = _actuator_min(i);
} else if (actuator_clipped(i) > _actuator_max(i)) {
actuator_clipped(i) = _actuator_max(i);
} else {
actuator_clipped(i) = actuator(i);
}
}
return actuator_clipped;
}
matrix::Vector<float, ControlAllocation::NUM_ACTUATORS>
ControlAllocation::normalizeActuatorSetpoint(const matrix::Vector<float, ControlAllocation::NUM_ACTUATORS> &actuator)
const
{
matrix::Vector<float, ControlAllocation::NUM_ACTUATORS> actuator_normalized;
for (size_t i = 0; i < ControlAllocation::NUM_ACTUATORS; i++) {
if (_actuator_min(i) < _actuator_max(i)) {
actuator_normalized(i) = -1.0f + 2.0f * (actuator(i) - _actuator_min(i)) / (_actuator_max(i) - _actuator_min(i));
} else {
actuator_normalized(i) = -1.0f + 2.0f * (_actuator_trim(i) - _actuator_min(i)) / (_actuator_max(i) - _actuator_min(i));
}
}
return actuator_normalized;
}
@@ -0,0 +1,216 @@
/****************************************************************************
*
* Copyright (c) 2019 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file ControlAllocation.hpp
*
* Interface for Control Allocation Algorithms
*
* Implementers of this interface are expected to update the members
* of this base class in the `allocate` method.
*
* Example usage:
* ```
* [...]
* // Initialization
* ControlAllocationMethodImpl alloc();
* alloc.setEffectivenessMatrix(effectiveness, actuator_trim);
* alloc.setActuatorMin(actuator_min);
* alloc.setActuatorMin(actuator_max);
*
* while (1) {
* [...]
*
* // Set control setpoint, allocate actuator setpoint, retrieve actuator setpoint
* alloc.setControlSetpoint(control_sp);
* alloc.allocate();
* actuator_sp = alloc.getActuatorSetpoint();
*
* // Check if the control setpoint was fully allocated
* unallocated_control = control_sp - alloc.getAllocatedControl()
*
* [...]
* }
* ```
*
*
* @author Julien Lecoeur <julien.lecoeur@gmail.com>
*/
#pragma once
#include <matrix/matrix/math.hpp>
#include <uORB/topics/vehicle_actuator_setpoint.h>
class ControlAllocation
{
public:
ControlAllocation() = default;
virtual ~ControlAllocation() = default;
static constexpr uint8_t NUM_ACTUATORS = 16;
static constexpr uint8_t NUM_AXES = 6;
typedef matrix::Vector<float, NUM_ACTUATORS> ActuatorVector;
enum ControlAxis {
ROLL = 0,
PITCH,
YAW,
THRUST_X,
THRUST_Y,
THRUST_Z
};
/**
* Allocate control setpoint to actuators
*
* @param control_setpoint Desired control setpoint vector (input)
*/
virtual void allocate() = 0;
/**
* Set the control effectiveness matrix
*
* @param B Effectiveness matrix
*/
virtual void setEffectivenessMatrix(const matrix::Matrix<float, NUM_AXES, NUM_ACTUATORS> &effectiveness,
const matrix::Vector<float, NUM_ACTUATORS> &actuator_trim);
/**
* Get the allocated actuator vector
*
* @return Actuator vector
*/
const matrix::Vector<float, NUM_ACTUATORS> &getActuatorSetpoint() const;
/**
* Set the desired control vector
*
* @param Control vector
*/
void setControlSetpoint(const matrix::Vector<float, NUM_AXES> &control);
/**
* Set the desired control vector
*
* @param Control vector
*/
const matrix::Vector<float, NUM_AXES> &getControlSetpoint() const;
/**
* Get the allocated control vector
*
* @return Control vector
*/
const matrix::Vector<float, NUM_AXES> &getAllocatedControl() const;
/**
* Get the control effectiveness matrix
*
* @return Effectiveness matrix
*/
const matrix::Matrix<float, NUM_AXES, NUM_ACTUATORS> &getEffectivenessMatrix() const;
/**
* Set the minimum actuator values
*
* @param actuator_min Minimum actuator values
*/
void setActuatorMin(const matrix::Vector<float, NUM_ACTUATORS> &actuator_min);
/**
* Get the minimum actuator values
*
* @return Minimum actuator values
*/
const matrix::Vector<float, NUM_ACTUATORS> &getActuatorMin() const;
/**
* Set the maximum actuator values
*
* @param actuator_max Maximum actuator values
*/
void setActuatorMax(const matrix::Vector<float, NUM_ACTUATORS> &actuator_max);
/**
* Get the maximum actuator values
*
* @return Maximum actuator values
*/
const matrix::Vector<float, NUM_ACTUATORS> &getActuatorMax() const;
/**
* Set the current actuator setpoint.
*
* Use this when a new allocation method is started to initialize it properly.
* In most cases, it is not needed to call this method before `allocate()`.
* Indeed the previous actuator setpoint is expected to be stored during calls to `allocate()`.
*
* @param actuator_sp Actuator setpoint
*/
void setActuatorSetpoint(const matrix::Vector<float, NUM_ACTUATORS> &actuator_sp);
/**
* Clip the actuator setpoint between minimum and maximum values.
*
* The output is in the range [min; max]
*
* @param actuator Actuator vector to clip
*
* @return Clipped actuator setpoint
*/
matrix::Vector<float, NUM_ACTUATORS> clipActuatorSetpoint(const matrix::Vector<float, NUM_ACTUATORS> &actuator) const;
/**
* Normalize the actuator setpoint between minimum and maximum values.
*
* The output is in the range [-1; +1]
*
* @param actuator Actuator vector to normalize
*
* @return Clipped actuator setpoint
*/
matrix::Vector<float, NUM_ACTUATORS> normalizeActuatorSetpoint(const matrix::Vector<float, NUM_ACTUATORS> &actuator)
const;
protected:
matrix::Matrix<float, NUM_AXES, NUM_ACTUATORS> _effectiveness; //< Effectiveness matrix
matrix::Vector<float, NUM_ACTUATORS> _actuator_trim; //< Neutral actuator values
matrix::Vector<float, NUM_ACTUATORS> _actuator_min; //< Minimum actuator values
matrix::Vector<float, NUM_ACTUATORS> _actuator_max; //< Maximum actuator values
matrix::Vector<float, NUM_ACTUATORS> _actuator_sp; //< Actuator setpoint
matrix::Vector<float, NUM_AXES> _control_sp; //< Control setpoint
matrix::Vector<float, NUM_AXES> _control_allocated; //< Allocated control
matrix::Vector<float, NUM_AXES> _control_trim; //< Control at trim actuator values
};
@@ -0,0 +1,76 @@
/****************************************************************************
*
* Copyright (c) 2019 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file ControlAllocationPseudoInverse.hpp
*
* Simple Control Allocation Algorithm
*
* @author Julien Lecoeur <julien.lecoeur@gmail.com>
*/
#include "ControlAllocationPseudoInverse.hpp"
void
ControlAllocationPseudoInverse::setEffectivenessMatrix(
const matrix::Matrix<float, ControlAllocation::NUM_AXES, ControlAllocation::NUM_ACTUATORS> &effectiveness,
const matrix::Vector<float, ControlAllocation::NUM_ACTUATORS> &actuator_trim)
{
ControlAllocation::setEffectivenessMatrix(effectiveness, actuator_trim);
_mix_update_needed = true;
}
void
ControlAllocationPseudoInverse::updatePseudoInverse()
{
if (_mix_update_needed) {
_mix = matrix::geninv(_effectiveness);
_mix_update_needed = false;
}
}
void
ControlAllocationPseudoInverse::allocate()
{
//Compute new gains if needed
updatePseudoInverse();
// Allocate
_actuator_sp = _actuator_trim + _mix * (_control_sp - _control_trim);
// Clip
_actuator_sp = clipActuatorSetpoint(_actuator_sp);
// Compute achieved control
_control_allocated = _effectiveness * _actuator_sp;
}
@@ -0,0 +1,70 @@
/****************************************************************************
*
* Copyright (c) 2019 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file ControlAllocationPseudoInverse.hpp
*
* Simple Control Allocation Algorithm
*
* It computes the pseudo-inverse of the effectiveness matrix
* Actuator saturation is handled by simple clipping, do not
* expect good performance in case of actuator saturation.
*
* @author Julien Lecoeur <julien.lecoeur@gmail.com>
*/
#pragma once
#include "ControlAllocation.hpp"
class ControlAllocationPseudoInverse: public ControlAllocation
{
public:
ControlAllocationPseudoInverse() = default;
virtual ~ControlAllocationPseudoInverse() = default;
virtual void allocate() override;
virtual void setEffectivenessMatrix(const matrix::Matrix<float, NUM_AXES, NUM_ACTUATORS> &effectiveness,
const matrix::Vector<float, NUM_ACTUATORS> &actuator_trim) override;
protected:
matrix::Matrix<float, NUM_ACTUATORS, NUM_AXES> _mix;
bool _mix_update_needed{false};
/**
* Recalculate pseudo inverse if required.
*
*/
void updatePseudoInverse();
};
@@ -0,0 +1,67 @@
/****************************************************************************
*
* Copyright (C) 2019 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file ControlAllocationTest.cpp
*
* Tests for Control Allocation Algorithms
*
* @author Julien Lecoeur <julien.lecoeur@gmail.com>
*/
#include <gtest/gtest.h>
#include <ControlAllocationPseudoInverse.hpp>
using namespace matrix;
TEST(ControlAllocationTest, AllZeroCase)
{
ControlAllocationPseudoInverse method;
matrix::Vector<float, 6> control_sp;
matrix::Vector<float, 6> control_allocated;
matrix::Vector<float, 6> control_allocated_expected;
matrix::Matrix<float, 6, 16> effectiveness;
matrix::Vector<float, 16> actuator_sp;
matrix::Vector<float, 16> actuator_trim;
matrix::Vector<float, 16> actuator_sp_expected;
method.setEffectivenessMatrix(effectiveness, actuator_trim, 16);
method.setControlSetpoint(control_sp);
method.allocate();
actuator_sp = method.getActuatorSetpoint();
control_allocated_expected = method.getAllocatedControl();
EXPECT_EQ(actuator_sp, actuator_sp_expected);
EXPECT_EQ(control_allocated, control_allocated_expected);
}
@@ -0,0 +1,124 @@
/****************************************************************************
*
* Copyright (c) 2019 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file ControlAllocationSequentialDesaturation.cpp
*
* @author Roman Bapst <bapstroman@gmail.com>
*/
#include "ControlAllocationSequentialDesaturation.hpp"
void
ControlAllocationSequentialDesaturation::allocate()
{
//Compute new gains if needed
updatePseudoInverse();
// Allocate
_actuator_sp = _actuator_trim + _mix * (_control_sp - _control_trim);
// go through control axes from lowest to highest priority and unsaturate the actuators
for (unsigned i = 0; i < NUM_AXES; i++) {
desaturateActuators(_actuator_sp, _axis_prio_increasing[i]);
}
// Clip
_actuator_sp = clipActuatorSetpoint(_actuator_sp);
// Compute achieved control
_control_allocated = _effectiveness * _actuator_sp;
}
void ControlAllocationSequentialDesaturation::desaturateActuators(
ActuatorVector &actuator_sp,
const ControlAxis &axis)
{
ActuatorVector desaturation_vector = getDesaturationVector(axis);
float gain = computeDesaturationGain(desaturation_vector, actuator_sp);
actuator_sp = actuator_sp + gain * desaturation_vector;
gain = computeDesaturationGain(desaturation_vector, actuator_sp);
actuator_sp = actuator_sp + 0.5f * gain * desaturation_vector;
}
ControlAllocation::ActuatorVector ControlAllocationSequentialDesaturation::getDesaturationVector(
const ControlAxis &axis)
{
ActuatorVector ret;
for (unsigned i = 0; i < NUM_ACTUATORS; i++) {
ret(i) = _mix(i, axis);
}
return ret;
}
float ControlAllocationSequentialDesaturation::computeDesaturationGain(const ActuatorVector &desaturation_vector,
const ActuatorVector &actuator_sp)
{
float k_min = 0.f;
float k_max = 0.f;
for (unsigned i = 0; i < NUM_ACTUATORS; i++) {
// Avoid division by zero. If desaturation_vector(i) is zero, there's nothing we can do to unsaturate anyway
if (fabsf(desaturation_vector(i)) < FLT_EPSILON) {
continue;
}
if (actuator_sp(i) < _actuator_min(i)) {
float k = (_actuator_min(i) - actuator_sp(i)) / desaturation_vector(i);
if (k < k_min) { k_min = k; }
if (k > k_max) { k_max = k; }
}
if (actuator_sp(i) > _actuator_max(i)) {
float k = (_actuator_max(i) - actuator_sp(i)) / desaturation_vector(i);
if (k < k_min) { k_min = k; }
if (k > k_max) { k_max = k; }
}
}
// Reduce the saturation as much as possible
return k_min + k_max;
}
@@ -0,0 +1,89 @@
/****************************************************************************
*
* Copyright (c) 2019 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file ControlAllocationSequentialDesaturation.hpp
*
* Control Allocation Algorithm which sequentially modifies control demands in order to
* eliminate the saturation of the actuator setpoint vector.
*
*
* @author Roman Bapst <bapstroman@gmail.com>
*/
#pragma once
#include "ControlAllocationPseudoInverse.hpp"
class ControlAllocationSequentialDesaturation: public ControlAllocationPseudoInverse
{
public:
ControlAllocationSequentialDesaturation() = default;
virtual ~ControlAllocationSequentialDesaturation() = default;
void allocate() override;
private:
/**
* List of control axis used for desaturating the actuator vector. The desaturation logic will sequentially
* go through this list and if needed apply corrections to the demand of the corresponding axis in order to desaturate
* the actuator vector.
*/
ControlAxis _axis_prio_increasing [NUM_AXES] = {ControlAxis::YAW, ControlAxis::THRUST_Y, ControlAxis::THRUST_X, ControlAxis::THRUST_Z, ControlAxis::PITCH, ControlAxis::ROLL};
/**
* Desaturate actuator setpoint vector.
*
* @return Desaturated actuator setpoint vector.
*/
void desaturateActuators(ActuatorVector &actuator_sp, const ControlAxis &axis);
/**
* Get desaturation vector.
*
* @param axis Control axis
* @return ActuatorVector Column of the pseudo-inverse matrix corresponding to the given control axis.
*/
ActuatorVector getDesaturationVector(const ControlAxis &axis);
/**
* Compute desaturation gain.
*
* @param desaturation_vector Column of the pseudo-inverse matrix corresponding to a given control axis.
* @param Actuator setpoint vector.
* @return Gain which eliminates the saturation of the highest saturated actuator.
*/
float computeDesaturationGain(const ActuatorVector &desaturation_vector, const ActuatorVector &actuator_sp);
};
@@ -0,0 +1,604 @@
/****************************************************************************
*
* Copyright (c) 2013-2019 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file ControlAllocator.cpp
*
* Control allocator.
*
* @author Julien Lecoeur <julien.lecoeur@gmail.com>
*/
#include "ControlAllocator.hpp"
#include <drivers/drv_hrt.h>
#include <circuit_breaker/circuit_breaker.h>
#include <mathlib/math/Limits.hpp>
#include <mathlib/math/Functions.hpp>
using namespace matrix;
using namespace time_literals;
ControlAllocator::ControlAllocator() :
ModuleParams(nullptr),
WorkItem(MODULE_NAME, px4::wq_configurations::ctrl_alloc),
_loop_perf(perf_alloc(PC_ELAPSED, MODULE_NAME": cycle"))
{
parameters_updated();
}
ControlAllocator::~ControlAllocator()
{
if (_control_allocation != nullptr) {
free(_control_allocation);
}
if (_actuator_effectiveness != nullptr) {
free(_actuator_effectiveness);
}
perf_free(_loop_perf);
}
bool
ControlAllocator::init()
{
if (!_vehicle_torque_setpoint_sub.registerCallback()) {
PX4_ERR("vehicle_torque_setpoint callback registration failed!");
return false;
}
if (!_vehicle_thrust_setpoint_sub.registerCallback()) {
PX4_ERR("vehicle_thrust_setpoint callback registration failed!");
return false;
}
return true;
}
void
ControlAllocator::parameters_updated()
{
// Allocation method & effectiveness source
// Do this first: in case a new method is loaded, it will be configured below
update_effectiveness_source();
update_allocation_method();
// Minimum actuator values
matrix::Vector<float, NUM_ACTUATORS> actuator_min;
actuator_min(0) = _param_ca_act0_min.get();
actuator_min(1) = _param_ca_act1_min.get();
actuator_min(2) = _param_ca_act2_min.get();
actuator_min(3) = _param_ca_act3_min.get();
actuator_min(4) = _param_ca_act4_min.get();
actuator_min(5) = _param_ca_act5_min.get();
actuator_min(6) = _param_ca_act6_min.get();
actuator_min(7) = _param_ca_act7_min.get();
actuator_min(8) = _param_ca_act8_min.get();
actuator_min(9) = _param_ca_act9_min.get();
actuator_min(10) = _param_ca_act10_min.get();
actuator_min(11) = _param_ca_act11_min.get();
actuator_min(12) = _param_ca_act12_min.get();
actuator_min(13) = _param_ca_act13_min.get();
actuator_min(14) = _param_ca_act14_min.get();
actuator_min(15) = _param_ca_act15_min.get();
_control_allocation->setActuatorMin(actuator_min);
// Maximum actuator values
matrix::Vector<float, NUM_ACTUATORS> actuator_max;
actuator_max(0) = _param_ca_act0_max.get();
actuator_max(1) = _param_ca_act1_max.get();
actuator_max(2) = _param_ca_act2_max.get();
actuator_max(3) = _param_ca_act3_max.get();
actuator_max(4) = _param_ca_act4_max.get();
actuator_max(5) = _param_ca_act5_max.get();
actuator_max(6) = _param_ca_act6_max.get();
actuator_max(7) = _param_ca_act7_max.get();
actuator_max(8) = _param_ca_act8_max.get();
actuator_max(9) = _param_ca_act9_max.get();
actuator_max(10) = _param_ca_act10_max.get();
actuator_max(11) = _param_ca_act11_max.get();
actuator_max(12) = _param_ca_act12_max.get();
actuator_max(13) = _param_ca_act13_max.get();
actuator_max(14) = _param_ca_act14_max.get();
actuator_max(15) = _param_ca_act15_max.get();
_control_allocation->setActuatorMax(actuator_max);
// Get actuator effectiveness and trim
matrix::Matrix<float, NUM_AXES, NUM_ACTUATORS> effectiveness = _actuator_effectiveness->getEffectivenessMatrix();
matrix::Vector<float, NUM_ACTUATORS> trim = _actuator_effectiveness->getActuatorTrim();
// Assign control effectiveness matrix
_control_allocation->setEffectivenessMatrix(effectiveness, trim);
}
void
ControlAllocator::update_allocation_method()
{
AllocationMethod method = (AllocationMethod)_param_ca_method.get();
if (_allocation_method_id != method) {
// Save current state
matrix::Vector<float, NUM_ACTUATORS> actuator_sp;
if (_control_allocation != nullptr) {
actuator_sp = _control_allocation->getActuatorSetpoint();
}
// try to instanciate new allocation method
ControlAllocation *tmp = nullptr;
switch (method) {
case AllocationMethod::PSEUDO_INVERSE:
tmp = new ControlAllocationPseudoInverse();
break;
case AllocationMethod::SEQUENTIAL_DESATURATION:
tmp = new ControlAllocationSequentialDesaturation();
break;
default:
PX4_ERR("Unknown allocation method");
tmp = nullptr;
break;
}
// Replace previous method with new one
if (tmp == nullptr) {
// It did not work, forget about it
PX4_ERR("Control allocation init failed");
_param_ca_method.set((int)_allocation_method_id);
} else if (_control_allocation == tmp) {
// Nothing has changed, this should not happen
PX4_ERR("Control allocation init error");
_allocation_method_id = method;
} else {
// Successful update
PX4_INFO("Control allocation init success");
// Swap allocation methods
if (_control_allocation != nullptr) {
free(_control_allocation);
}
_control_allocation = tmp;
// Save method id
_allocation_method_id = method;
// Configure new allocation method
_control_allocation->setActuatorSetpoint(actuator_sp);
}
}
// Guard against bad initialization
if (_control_allocation == nullptr) {
PX4_ERR("Falling back to ControlAllocationPseudoInverse");
_control_allocation = new ControlAllocationPseudoInverse();
_allocation_method_id = AllocationMethod::PSEUDO_INVERSE;
}
}
void
ControlAllocator::update_effectiveness_source()
{
EffectivenessSource source = (EffectivenessSource)_param_ca_airframe.get();
if (_effectiveness_source_id != source) {
// try to instanciate new effectiveness source
ActuatorEffectiveness *tmp = nullptr;
switch (source) {
case EffectivenessSource::NONE:
case EffectivenessSource::MULTIROTOR:
tmp = new ActuatorEffectivenessMultirotor();
break;
case EffectivenessSource::STANDARD_VTOL:
tmp = new ActuatorEffectivenessStandardVTOL();
break;
case EffectivenessSource::TILTROTOR_VTOL:
tmp = new ActuatorEffectivenessTiltrotorVTOL();
break;
default:
PX4_ERR("Unknown airframe");
tmp = nullptr;
break;
}
// Replace previous source with new one
if (tmp == nullptr) {
// It did not work, forget about it
PX4_ERR("Actuator effectiveness init failed");
_param_ca_airframe.set((int)_effectiveness_source_id);
} else if (_actuator_effectiveness == tmp) {
// Nothing has changed, this should not happen
PX4_ERR("Actuator effectiveness init error");
_effectiveness_source_id = source;
} else {
// Successful update
PX4_INFO("Actuator effectiveness init success");
// Swap effectiveness sources
if (_actuator_effectiveness != nullptr) {
free(_actuator_effectiveness);
}
_actuator_effectiveness = tmp;
// Save source id
_effectiveness_source_id = source;
}
}
// Guard against bad initialization
if (_actuator_effectiveness == nullptr) {
PX4_ERR("Falling back to ActuatorEffectivenessMultirotor");
_actuator_effectiveness = new ActuatorEffectivenessMultirotor();
_effectiveness_source_id = EffectivenessSource::MULTIROTOR;
}
}
void
ControlAllocator::Run()
{
if (should_exit()) {
_vehicle_torque_setpoint_sub.unregisterCallback();
_vehicle_thrust_setpoint_sub.unregisterCallback();
exit_and_cleanup();
return;
}
perf_begin(_loop_perf);
// Check if parameters have changed
if (_parameter_update_sub.updated()) {
// clear update
parameter_update_s param_update;
_parameter_update_sub.copy(&param_update);
updateParams();
parameters_updated();
}
if (_vehicle_status_sub.updated()) {
vehicle_status_s vehicle_status = {};
_vehicle_status_sub.update(&vehicle_status);
ActuatorEffectiveness::FlightPhase flight_phase{ActuatorEffectiveness::FlightPhase::HOVER_FLIGHT};
// Check if the current flight phase is HOVER or FIXED_WING
if (vehicle_status.vehicle_type == vehicle_status_s::VEHICLE_TYPE_ROTARY_WING) {
flight_phase = ActuatorEffectiveness::FlightPhase::HOVER_FLIGHT;
} else {
flight_phase = ActuatorEffectiveness::FlightPhase::FORWARD_FLIGHT;
}
// Special cases for VTOL in transition
if (vehicle_status.is_vtol && vehicle_status.in_transition_mode) {
if (vehicle_status.in_transition_to_fw) {
flight_phase = ActuatorEffectiveness::FlightPhase::TRANSITION_HF_TO_FF;
} else {
flight_phase = ActuatorEffectiveness::FlightPhase::TRANSITION_FF_TO_HF;
}
}
// Forward to effectiveness source
_actuator_effectiveness->setFlightPhase(flight_phase);
}
// Guard against too small (< 0.2ms) and too large (> 20ms) dt's.
const hrt_abstime now = hrt_absolute_time();
const float dt = math::constrain(((now - _last_run) / 1e6f), 0.0002f, 0.02f);
_last_run = now;
bool do_update = false;
vehicle_torque_setpoint_s vehicle_torque_setpoint;
vehicle_thrust_setpoint_s vehicle_thrust_setpoint;
// Run allocator on torque changes
if (_vehicle_torque_setpoint_sub.update(&vehicle_torque_setpoint)) {
_torque_sp = matrix::Vector3f(vehicle_torque_setpoint.xyz);
do_update = true;
_timestamp_sample = vehicle_torque_setpoint.timestamp_sample;
}
// Also run allocator on thrust setpoint changes if the torque setpoint
// has not been updated for more than 5ms
if (_vehicle_thrust_setpoint_sub.update(&vehicle_thrust_setpoint)) {
_thrust_sp = matrix::Vector3f(vehicle_thrust_setpoint.xyz);
if (dt > 5_ms) {
do_update = true;
_timestamp_sample = vehicle_thrust_setpoint.timestamp_sample;
}
}
if (do_update) {
// Update effectiveness matrix if needed
if (_actuator_effectiveness->update()) {
matrix::Matrix<float, NUM_AXES, NUM_ACTUATORS> effectiveness = _actuator_effectiveness->getEffectivenessMatrix();
matrix::Vector<float, NUM_ACTUATORS> trim = _actuator_effectiveness->getActuatorTrim();
// Set 0 effectiveness for actuators that are disabled (act_min >= act_max)
matrix::Vector<float, NUM_ACTUATORS> actuator_max = _control_allocation->getActuatorMax();
matrix::Vector<float, NUM_ACTUATORS> actuator_min = _control_allocation->getActuatorMin();
for (size_t j = 0; j < NUM_ACTUATORS; j++) {
if (actuator_min(j) >= actuator_max(j)) {
for (size_t i = 0; i < NUM_AXES; i++) {
effectiveness(i, j) = 0.0f;
}
}
}
// Assign control effectiveness matrix
if ((effectiveness - _control_allocation->getEffectivenessMatrix()).abs().max() > 1e-5f) {
_control_allocation->setEffectivenessMatrix(effectiveness, trim);
}
}
// Set control setpoint vector
matrix::Vector<float, NUM_AXES> c;
c(0) = _torque_sp(0);
c(1) = _torque_sp(1);
c(2) = _torque_sp(2);
c(3) = _thrust_sp(0);
c(4) = _thrust_sp(1);
c(5) = _thrust_sp(2);
_control_allocation->setControlSetpoint(c);
// Do allocation
_control_allocation->allocate();
// Publish actuator setpoint and allocator status
publish_actuator_setpoint();
publish_control_allocator_status();
// Publish on legacy topics for compatibility with
// the current mixer system and multicopter controller
// TODO: remove
publish_legacy_actuator_controls();
}
perf_end(_loop_perf);
}
void
ControlAllocator::publish_actuator_setpoint()
{
matrix::Vector<float, NUM_ACTUATORS> actuator_sp = _control_allocation->getActuatorSetpoint();
vehicle_actuator_setpoint_s vehicle_actuator_setpoint{};
vehicle_actuator_setpoint.timestamp = hrt_absolute_time();
vehicle_actuator_setpoint.timestamp_sample = _timestamp_sample;
actuator_sp.copyTo(vehicle_actuator_setpoint.actuator);
_vehicle_actuator_setpoint_pub.publish(vehicle_actuator_setpoint);
}
void
ControlAllocator::publish_control_allocator_status()
{
control_allocator_status_s control_allocator_status{};
control_allocator_status.timestamp = hrt_absolute_time();
// Allocated control
matrix::Vector<float, NUM_AXES> allocated_control = _control_allocation->getAllocatedControl();
control_allocator_status.allocated_torque[0] = allocated_control(0);
control_allocator_status.allocated_torque[1] = allocated_control(1);
control_allocator_status.allocated_torque[2] = allocated_control(2);
control_allocator_status.allocated_thrust[0] = allocated_control(3);
control_allocator_status.allocated_thrust[1] = allocated_control(4);
control_allocator_status.allocated_thrust[2] = allocated_control(5);
// Unallocated control
matrix::Vector<float, NUM_AXES> unallocated_control = _control_allocation->getControlSetpoint() - allocated_control;
control_allocator_status.unallocated_torque[0] = unallocated_control(0);
control_allocator_status.unallocated_torque[1] = unallocated_control(1);
control_allocator_status.unallocated_torque[2] = unallocated_control(2);
control_allocator_status.unallocated_thrust[0] = unallocated_control(3);
control_allocator_status.unallocated_thrust[1] = unallocated_control(4);
control_allocator_status.unallocated_thrust[2] = unallocated_control(5);
// Allocation success flags
control_allocator_status.torque_setpoint_achieved = (Vector3f(unallocated_control(0), unallocated_control(1),
unallocated_control(2)).norm() < FLT_EPSILON);
control_allocator_status.thrust_setpoint_achieved = (Vector3f(unallocated_control(3), unallocated_control(4),
unallocated_control(5)).norm() < FLT_EPSILON);
// Actuator saturation
matrix::Vector<float, NUM_ACTUATORS> actuator_sp = _control_allocation->getActuatorSetpoint();
matrix::Vector<float, NUM_ACTUATORS> actuator_min = _control_allocation->getActuatorMin();
matrix::Vector<float, NUM_ACTUATORS> actuator_max = _control_allocation->getActuatorMax();
for (size_t i = 0; i < NUM_ACTUATORS; i++) {
if (actuator_sp(i) > (actuator_max(i) - FLT_EPSILON)) {
control_allocator_status.actuator_saturation[i] = control_allocator_status_s::ACTUATOR_SATURATION_UPPER;
} else if (actuator_sp(i) < (actuator_min(i) + FLT_EPSILON)) {
control_allocator_status.actuator_saturation[i] = control_allocator_status_s::ACTUATOR_SATURATION_LOWER;
}
}
_control_allocator_status_pub.publish(control_allocator_status);
}
void
ControlAllocator::publish_legacy_actuator_controls()
{
// For compatibility with the current mixer system,
// publish normalized version on actuator_controls_4/5
actuator_controls_s actuator_controls_4{};
actuator_controls_s actuator_controls_5{};
actuator_controls_4.timestamp = hrt_absolute_time();
actuator_controls_5.timestamp = hrt_absolute_time();
actuator_controls_4.timestamp_sample = _timestamp_sample;
actuator_controls_5.timestamp_sample = _timestamp_sample;
matrix::Vector<float, NUM_ACTUATORS> actuator_sp = _control_allocation->getActuatorSetpoint();
matrix::Vector<float, NUM_ACTUATORS> actuator_sp_normalized = _control_allocation->normalizeActuatorSetpoint(
actuator_sp);
for (size_t i = 0; i < 8; i++) {
actuator_controls_4.control[i] = (PX4_ISFINITE(actuator_sp_normalized(i))) ? actuator_sp_normalized(i) : 0.0f;
actuator_controls_5.control[i] = (PX4_ISFINITE(actuator_sp_normalized(i + 8))) ? actuator_sp_normalized(i + 8) : 0.0f;
}
_actuator_controls_4_pub.publish(actuator_controls_4);
_actuator_controls_5_pub.publish(actuator_controls_5);
}
int ControlAllocator::task_spawn(int argc, char *argv[])
{
ControlAllocator *instance = new ControlAllocator();
if (instance) {
_object.store(instance);
_task_id = task_id_is_work_queue;
if (instance->init()) {
return PX4_OK;
}
} else {
PX4_ERR("alloc failed");
}
delete instance;
_object.store(nullptr);
_task_id = -1;
return PX4_ERROR;
}
int ControlAllocator::print_status()
{
PX4_INFO("Running");
// Print current allocation method
switch (_allocation_method_id) {
case AllocationMethod::NONE:
PX4_INFO("Method: None");
break;
case AllocationMethod::PSEUDO_INVERSE:
PX4_INFO("Method: Pseudo-inverse");
break;
case AllocationMethod::SEQUENTIAL_DESATURATION:
PX4_INFO("Method: Sequential desaturation");
break;
}
// Print current airframe
switch ((EffectivenessSource)_param_ca_airframe.get()) {
case EffectivenessSource::NONE:
PX4_INFO("EffectivenessSource: None");
break;
case EffectivenessSource::MULTIROTOR:
PX4_INFO("EffectivenessSource: MC parameters");
break;
case EffectivenessSource::STANDARD_VTOL:
PX4_INFO("EffectivenessSource: Standard VTOL");
break;
case EffectivenessSource::TILTROTOR_VTOL:
PX4_INFO("EffectivenessSource: Tiltrotor VTOL");
break;
}
// Print current effectiveness matrix
if (_control_allocation != nullptr) {
const matrix::Matrix<float, NUM_AXES, NUM_ACTUATORS> &effectiveness = _control_allocation->getEffectivenessMatrix();
PX4_INFO("Effectiveness.T =");
effectiveness.T().print();
}
// Print perf
perf_print_counter(_loop_perf);
return 0;
}
int ControlAllocator::custom_command(int argc, char *argv[])
{
return print_usage("unknown command");
}
int ControlAllocator::print_usage(const char *reason)
{
if (reason) {
PX4_WARN("%s\n", reason);
}
PRINT_MODULE_DESCRIPTION(
R"DESCR_STR(
### Description
This implements control allocation. It takes torque and thrust setpoints
as inputs and outputs actuator setpoint messages.
)DESCR_STR");
PRINT_MODULE_USAGE_NAME(MODULE_NAME, "controller");
PRINT_MODULE_USAGE_COMMAND("start");
PRINT_MODULE_USAGE_DEFAULT_COMMANDS();
return 0;
}
/**
* Control Allocator app start / stop handling function
*/
extern "C" __EXPORT int control_allocator_main(int argc, char *argv[]);
int control_allocator_main(int argc, char *argv[])
{
return ControlAllocator::main(argc, argv);
}
@@ -0,0 +1,201 @@
/****************************************************************************
*
* Copyright (c) 2013-2019 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file ControlAllocator.hpp
*
* Control allocator.
*
* @author Julien Lecoeur <julien.lecoeur@gmail.com>
*/
#pragma once
#include <ActuatorEffectiveness.hpp>
#include <ActuatorEffectivenessMultirotor.hpp>
#include <ActuatorEffectivenessStandardVTOL.hpp>
#include <ActuatorEffectivenessTiltrotorVTOL.hpp>
#include <ControlAllocation.hpp>
#include <ControlAllocationPseudoInverse.hpp>
#include <ControlAllocationSequentialDesaturation.hpp>
#include <lib/matrix/matrix/math.hpp>
#include <lib/perf/perf_counter.h>
#include <px4_platform_common/px4_config.h>
#include <px4_platform_common/module.h>
#include <px4_platform_common/module_params.h>
#include <px4_platform_common/px4_work_queue/ScheduledWorkItem.hpp>
#include <uORB/Publication.hpp>
#include <uORB/Subscription.hpp>
#include <uORB/SubscriptionCallback.hpp>
#include <uORB/topics/actuator_controls.h>
#include <uORB/topics/airspeed.h>
#include <uORB/topics/battery_status.h>
#include <uORB/topics/control_allocator_status.h>
#include <uORB/topics/parameter_update.h>
#include <uORB/topics/vehicle_torque_setpoint.h>
#include <uORB/topics/vehicle_thrust_setpoint.h>
#include <uORB/topics/vehicle_actuator_setpoint.h>
#include <uORB/topics/vehicle_status.h>
class ControlAllocator : public ModuleBase<ControlAllocator>, public ModuleParams, public px4::WorkItem
{
public:
ControlAllocator();
virtual ~ControlAllocator();
/** @see ModuleBase */
static int task_spawn(int argc, char *argv[]);
/** @see ModuleBase */
static int custom_command(int argc, char *argv[]);
/** @see ModuleBase */
static int print_usage(const char *reason = nullptr);
/** @see ModuleBase::print_status() */
int print_status() override;
void Run() override;
bool init();
static constexpr uint8_t NUM_ACTUATORS = ControlAllocation::NUM_ACTUATORS;
static constexpr uint8_t NUM_AXES = ControlAllocation::NUM_AXES;
private:
/**
* initialize some vectors/matrices from parameters
*/
void parameters_updated();
void update_allocation_method();
void update_effectiveness_source();
void publish_actuator_setpoint();
void publish_control_allocator_status();
void publish_legacy_actuator_controls();
void publish_legacy_multirotor_motor_limits();
enum class AllocationMethod {
NONE = -1,
PSEUDO_INVERSE = 0,
SEQUENTIAL_DESATURATION = 1,
};
AllocationMethod _allocation_method_id{AllocationMethod::NONE};
ControlAllocation *_control_allocation{nullptr}; ///< class for control allocation calculations
enum class EffectivenessSource {
NONE = -1,
MULTIROTOR = 0,
STANDARD_VTOL = 1,
TILTROTOR_VTOL = 2,
};
EffectivenessSource _effectiveness_source_id{EffectivenessSource::NONE};
ActuatorEffectiveness *_actuator_effectiveness{nullptr}; ///< class providing actuator effectiveness
// Inputs
uORB::SubscriptionCallbackWorkItem _vehicle_torque_setpoint_sub{this, ORB_ID(vehicle_torque_setpoint)}; /**< vehicle torque setpoint subscription */
uORB::SubscriptionCallbackWorkItem _vehicle_thrust_setpoint_sub{this, ORB_ID(vehicle_thrust_setpoint)}; /**< vehicle thrust setpoint subscription */
// Outputs
uORB::Publication<vehicle_actuator_setpoint_s> _vehicle_actuator_setpoint_pub{ORB_ID(vehicle_actuator_setpoint)}; /**< actuator setpoint publication */
uORB::Publication<control_allocator_status_s> _control_allocator_status_pub{ORB_ID(control_allocator_status)}; /**< actuator setpoint publication */
// actuator_controls publication handles (temporary hack to plug actuator_setpoint into the mixer system)
uORB::Publication<actuator_controls_s> _actuator_controls_4_pub{ORB_ID(actuator_controls_4)}; /**< actuator controls 4 publication */
uORB::Publication<actuator_controls_s> _actuator_controls_5_pub{ORB_ID(actuator_controls_5)}; /**< actuator controls 5 publication */
uORB::Subscription _parameter_update_sub{ORB_ID(parameter_update)}; /**< parameter updates subscription */
uORB::Subscription _battery_status_sub{ORB_ID(battery_status)}; /**< battery status subscription */
uORB::Subscription _airspeed_sub{ORB_ID(airspeed)}; /**< airspeed subscription */
uORB::Subscription _vehicle_status_sub{ORB_ID(vehicle_status)};
matrix::Vector3f _torque_sp;
matrix::Vector3f _thrust_sp;
// float _battery_scale_factor{1.0f};
// float _airspeed_scale_factor{1.0f};
perf_counter_t _loop_perf; /**< loop duration performance counter */
hrt_abstime _task_start{hrt_absolute_time()};
hrt_abstime _last_run{0};
hrt_abstime _timestamp_sample{0};
DEFINE_PARAMETERS(
(ParamInt<px4::params::CA_AIRFRAME>) _param_ca_airframe,
(ParamInt<px4::params::CA_METHOD>) _param_ca_method,
(ParamBool<px4::params::CA_BAT_SCALE_EN>) _param_ca_bat_scale_en,
(ParamBool<px4::params::CA_AIR_SCALE_EN>) _param_ca_air_scale_en,
(ParamFloat<px4::params::CA_ACT0_MIN>) _param_ca_act0_min,
(ParamFloat<px4::params::CA_ACT1_MIN>) _param_ca_act1_min,
(ParamFloat<px4::params::CA_ACT2_MIN>) _param_ca_act2_min,
(ParamFloat<px4::params::CA_ACT3_MIN>) _param_ca_act3_min,
(ParamFloat<px4::params::CA_ACT4_MIN>) _param_ca_act4_min,
(ParamFloat<px4::params::CA_ACT5_MIN>) _param_ca_act5_min,
(ParamFloat<px4::params::CA_ACT6_MIN>) _param_ca_act6_min,
(ParamFloat<px4::params::CA_ACT7_MIN>) _param_ca_act7_min,
(ParamFloat<px4::params::CA_ACT8_MIN>) _param_ca_act8_min,
(ParamFloat<px4::params::CA_ACT9_MIN>) _param_ca_act9_min,
(ParamFloat<px4::params::CA_ACT10_MIN>) _param_ca_act10_min,
(ParamFloat<px4::params::CA_ACT11_MIN>) _param_ca_act11_min,
(ParamFloat<px4::params::CA_ACT12_MIN>) _param_ca_act12_min,
(ParamFloat<px4::params::CA_ACT13_MIN>) _param_ca_act13_min,
(ParamFloat<px4::params::CA_ACT14_MIN>) _param_ca_act14_min,
(ParamFloat<px4::params::CA_ACT15_MIN>) _param_ca_act15_min,
(ParamFloat<px4::params::CA_ACT0_MAX>) _param_ca_act0_max,
(ParamFloat<px4::params::CA_ACT1_MAX>) _param_ca_act1_max,
(ParamFloat<px4::params::CA_ACT2_MAX>) _param_ca_act2_max,
(ParamFloat<px4::params::CA_ACT3_MAX>) _param_ca_act3_max,
(ParamFloat<px4::params::CA_ACT4_MAX>) _param_ca_act4_max,
(ParamFloat<px4::params::CA_ACT5_MAX>) _param_ca_act5_max,
(ParamFloat<px4::params::CA_ACT6_MAX>) _param_ca_act6_max,
(ParamFloat<px4::params::CA_ACT7_MAX>) _param_ca_act7_max,
(ParamFloat<px4::params::CA_ACT8_MAX>) _param_ca_act8_max,
(ParamFloat<px4::params::CA_ACT9_MAX>) _param_ca_act9_max,
(ParamFloat<px4::params::CA_ACT10_MAX>) _param_ca_act10_max,
(ParamFloat<px4::params::CA_ACT11_MAX>) _param_ca_act11_max,
(ParamFloat<px4::params::CA_ACT12_MAX>) _param_ca_act12_max,
(ParamFloat<px4::params::CA_ACT13_MAX>) _param_ca_act13_max,
(ParamFloat<px4::params::CA_ACT14_MAX>) _param_ca_act14_max,
(ParamFloat<px4::params::CA_ACT15_MAX>) _param_ca_act15_max
)
};
@@ -0,0 +1,314 @@
/****************************************************************************
*
* Copyright (c) 2013-2019 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file control_allocator_params.c
*
* Parameters for the control allocator.
*
* @author Julien Lecoeur <julien.lecoeur@gmail.com>
*/
/**
* Airframe ID
*
* This is used to retrieve pre-computed control effectiveness matrix
*
* @min 0
* @max 2
* @value 0 Multirotor
* @value 1 Standard VTOL (WIP)
* @value 2 Tiltrotor VTOL (WIP)
* @group Control Allocation
*/
PARAM_DEFINE_INT32(CA_AIRFRAME, 0);
/**
* Control allocation method
*
* @value 0 Pseudo-inverse with output clipping (default)
* @value 1 Pseudo-inverse with sequential desaturation technique
* @min 0
* @max 1
* @group Control Allocation
*/
PARAM_DEFINE_INT32(CA_METHOD, 0);
/**
* Battery power level scaler
*
* This compensates for voltage drop of the battery over time by attempting to
* normalize performance across the operating range of the battery. The copter
* should constantly behave as if it was fully charged with reduced max acceleration
* at lower battery percentages. i.e. if hover is at 0.5 throttle at 100% battery,
* it will still be 0.5 at 60% battery.
*
* @boolean
* @group Control Allocation
*/
PARAM_DEFINE_INT32(CA_BAT_SCALE_EN, 0);
/**
* Airspeed scaler
*
* This compensates for the variation of flap effectiveness with airspeed.
*
* @boolean
* @group Control Allocation
*/
PARAM_DEFINE_INT32(CA_AIR_SCALE_EN, 0);
/**
* Minimum value for actuator 0
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_ACT0_MIN, 0.0);
/**
* Minimum value for actuator 1
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_ACT1_MIN, 0.0);
/**
* Minimum value for actuator 2
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_ACT2_MIN, 0.0);
/**
* Minimum value for actuator 3
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_ACT3_MIN, 0.0);
/**
* Minimum value for actuator 4
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_ACT4_MIN, 0.0);
/**
* Minimum value for actuator 5
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_ACT5_MIN, 0.0);
/**
* Minimum value for actuator 6
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_ACT6_MIN, 0.0);
/**
* Minimum value for actuator 7
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_ACT7_MIN, 0.0);
/**
* Minimum value for actuator 8
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_ACT8_MIN, 0.0);
/**
* Minimum value for actuator 9
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_ACT9_MIN, 0.0);
/**
* Minimum value for actuator 10
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_ACT10_MIN, 0.0);
/**
* Minimum value for actuator 11
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_ACT11_MIN, 0.0);
/**
* Minimum value for actuator 12
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_ACT12_MIN, 0.0);
/**
* Minimum value for actuator 13
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_ACT13_MIN, 0.0);
/**
* Minimum value for actuator 14
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_ACT14_MIN, 0.0);
/**
* Minimum value for actuator 15
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_ACT15_MIN, 0.0);
/**
* Maximum value for actuator 0
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_ACT0_MAX, 0.0);
/**
* Maximum value for actuator 1
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_ACT1_MAX, 0.0);
/**
* Maximum value for actuator 2
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_ACT2_MAX, 0.0);
/**
* Maximum value for actuator 3
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_ACT3_MAX, 0.0);
/**
* Maximum value for actuator 4
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_ACT4_MAX, 0.0);
/**
* Maximum value for actuator 5
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_ACT5_MAX, 0.0);
/**
* Maximum value for actuator 6
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_ACT6_MAX, 0.0);
/**
* Maximum value for actuator 7
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_ACT7_MAX, 0.0);
/**
* Maximum value for actuator 8
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_ACT8_MAX, 0.0);
/**
* Maximum value for actuator 9
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_ACT9_MAX, 0.0);
/**
* Maximum value for actuator 10
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_ACT10_MAX, 0.0);
/**
* Maximum value for actuator 11
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_ACT11_MAX, 0.0);
/**
* Maximum value for actuator 12
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_ACT12_MAX, 0.0);
/**
* Maximum value for actuator 13
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_ACT13_MAX, 0.0);
/**
* Maximum value for actuator 14
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_ACT14_MAX, 0.0);
/**
* Maximum value for actuator 15
*
* @group Control Allocation
*/
PARAM_DEFINE_FLOAT(CA_ACT15_MAX, 0.0);