mirror of
https://bitbucket.org/librepilot/librepilot.git
synced 2025-02-26 15:54:15 +01:00
OP-1835 - Motor Constraints for 15.02.02
OP-1835 - Motor Constraints for 15.02.02
This commit is contained in:
parent
5475b395e8
commit
57d062ff67
@ -40,6 +40,7 @@
|
|||||||
#include "actuatordesired.h"
|
#include "actuatordesired.h"
|
||||||
#include "actuatorcommand.h"
|
#include "actuatorcommand.h"
|
||||||
#include "flightstatus.h"
|
#include "flightstatus.h"
|
||||||
|
#include <flightmodesettings.h>
|
||||||
#include "mixersettings.h"
|
#include "mixersettings.h"
|
||||||
#include "mixerstatus.h"
|
#include "mixerstatus.h"
|
||||||
#include "cameradesired.h"
|
#include "cameradesired.h"
|
||||||
@ -98,9 +99,10 @@ static int mixer_settings_count = 2;
|
|||||||
// Private functions
|
// Private functions
|
||||||
static void actuatorTask(void *parameters);
|
static void actuatorTask(void *parameters);
|
||||||
static int16_t scaleChannel(float value, int16_t max, int16_t min, int16_t neutral);
|
static int16_t scaleChannel(float value, int16_t max, int16_t min, int16_t neutral);
|
||||||
|
static int16_t scaleMotor(float value, int16_t max, int16_t min, int16_t neutral, float maxMotor, float minMotor, bool armed, bool AlwaysStabilizeWhenArmed, float throttleDesired);
|
||||||
static void setFailsafe();
|
static void setFailsafe();
|
||||||
static float MixerCurveFullRangeProportional(const float input, const float *curve, uint8_t elements);
|
static float MixerCurveFullRangeProportional(const float input, const float *curve, uint8_t elements, bool multirotor);
|
||||||
static float MixerCurveFullRangeAbsolute(const float input, const float *curve, uint8_t elements);
|
static float MixerCurveFullRangeAbsolute(const float input, const float *curve, uint8_t elements, bool multirotor);
|
||||||
static bool set_channel(uint8_t mixer_channel, uint16_t value);
|
static bool set_channel(uint8_t mixer_channel, uint16_t value);
|
||||||
static void actuator_update_rate_if_changed(bool force_update);
|
static void actuator_update_rate_if_changed(bool force_update);
|
||||||
static void MixerSettingsUpdatedCb(UAVObjEvent *ev);
|
static void MixerSettingsUpdatedCb(UAVObjEvent *ev);
|
||||||
@ -108,7 +110,7 @@ static void ActuatorSettingsUpdatedCb(UAVObjEvent *ev);
|
|||||||
static void SettingsUpdatedCb(UAVObjEvent *ev);
|
static void SettingsUpdatedCb(UAVObjEvent *ev);
|
||||||
float ProcessMixer(const int index, const float curve1, const float curve2,
|
float ProcessMixer(const int index, const float curve1, const float curve2,
|
||||||
ActuatorDesiredData *desired,
|
ActuatorDesiredData *desired,
|
||||||
const float period);
|
const float period, bool multirotor);
|
||||||
|
|
||||||
// this structure is equivalent to the UAVObjects for one mixer.
|
// this structure is equivalent to the UAVObjects for one mixer.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -199,6 +201,7 @@ static void actuatorTask(__attribute__((unused)) void *parameters)
|
|||||||
ActuatorCommandData command;
|
ActuatorCommandData command;
|
||||||
ActuatorDesiredData desired;
|
ActuatorDesiredData desired;
|
||||||
MixerStatusData mixerStatus;
|
MixerStatusData mixerStatus;
|
||||||
|
FlightModeSettingsData settings;
|
||||||
FlightStatusData flightStatus;
|
FlightStatusData flightStatus;
|
||||||
float throttleDesired;
|
float throttleDesired;
|
||||||
float collectiveDesired;
|
float collectiveDesired;
|
||||||
@ -245,6 +248,7 @@ static void actuatorTask(__attribute__((unused)) void *parameters)
|
|||||||
dTSeconds = dTMilliseconds * 0.001f;
|
dTSeconds = dTMilliseconds * 0.001f;
|
||||||
|
|
||||||
FlightStatusGet(&flightStatus);
|
FlightStatusGet(&flightStatus);
|
||||||
|
FlightModeSettingsGet(&settings);
|
||||||
ActuatorDesiredGet(&desired);
|
ActuatorDesiredGet(&desired);
|
||||||
ActuatorCommandGet(&command);
|
ActuatorCommandGet(&command);
|
||||||
|
|
||||||
@ -266,22 +270,32 @@ static void actuatorTask(__attribute__((unused)) void *parameters)
|
|||||||
bool armed = flightStatus.Armed == FLIGHTSTATUS_ARMED_ARMED;
|
bool armed = flightStatus.Armed == FLIGHTSTATUS_ARMED_ARMED;
|
||||||
bool activeThrottle = (throttleDesired < -0.001f || throttleDesired > 0.001f); // for ground and reversible motors
|
bool activeThrottle = (throttleDesired < -0.001f || throttleDesired > 0.001f); // for ground and reversible motors
|
||||||
bool positiveThrottle = (throttleDesired > 0.00f);
|
bool positiveThrottle = (throttleDesired > 0.00f);
|
||||||
|
bool multirotor = (GetCurrentFrameType() == FRAME_TYPE_MULTIROTOR); // check if frame is a multirotor.
|
||||||
|
bool alwaysArmed = settings.Arming == FLIGHTMODESETTINGS_ARMING_ALWAYSARMED;
|
||||||
|
bool AlwaysStabilizeWhenArmed = settings.AlwaysStabilizeWhenArmed == FLIGHTMODESETTINGS_ALWAYSSTABILIZEWHENARMED_TRUE;
|
||||||
|
|
||||||
|
if (alwaysArmed) {
|
||||||
|
AlwaysStabilizeWhenArmed = false; // Do not allow always stabilize when alwaysArmed is active. This is dangerous.
|
||||||
|
}
|
||||||
// safety settings
|
// safety settings
|
||||||
if (!armed) {
|
if (!armed) {
|
||||||
throttleDesired = 0;
|
throttleDesired = 0.00f; // this also happens in scaleMotors as a per axis check
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((frameType == FRAME_TYPE_GROUND && !activeThrottle) || (frameType != FRAME_TYPE_GROUND && throttleDesired <= 0.00f) || !armed) {
|
if ((frameType == FRAME_TYPE_GROUND && !activeThrottle) || (frameType != FRAME_TYPE_GROUND && throttleDesired <= 0.00f) || !armed) {
|
||||||
|
// throttleDesired should never be 0 or go below 0.
|
||||||
// force set all other controls to zero if throttle is cut (previously set in Stabilization)
|
// force set all other controls to zero if throttle is cut (previously set in Stabilization)
|
||||||
if (actuatorSettings.LowThrottleZeroAxis.Roll == ACTUATORSETTINGS_LOWTHROTTLEZEROAXIS_TRUE) {
|
// todo: can probably remove this
|
||||||
desired.Roll = 0;
|
if (!(multirotor && AlwaysStabilizeWhenArmed && armed)) { // we don't do this if this is a multirotor AND AlwaysStabilizeWhenArmed is true and the model is armed
|
||||||
}
|
if (actuatorSettings.LowThrottleZeroAxis.Roll == ACTUATORSETTINGS_LOWTHROTTLEZEROAXIS_TRUE) {
|
||||||
if (actuatorSettings.LowThrottleZeroAxis.Pitch == ACTUATORSETTINGS_LOWTHROTTLEZEROAXIS_TRUE) {
|
desired.Roll = 0.00f;
|
||||||
desired.Pitch = 0;
|
}
|
||||||
}
|
if (actuatorSettings.LowThrottleZeroAxis.Pitch == ACTUATORSETTINGS_LOWTHROTTLEZEROAXIS_TRUE) {
|
||||||
if (actuatorSettings.LowThrottleZeroAxis.Yaw == ACTUATORSETTINGS_LOWTHROTTLEZEROAXIS_TRUE) {
|
desired.Pitch = 0.00f;
|
||||||
desired.Yaw = 0;
|
}
|
||||||
|
if (actuatorSettings.LowThrottleZeroAxis.Yaw == ACTUATORSETTINGS_LOWTHROTTLEZEROAXIS_TRUE) {
|
||||||
|
desired.Yaw = 0.00f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,13 +310,13 @@ static void actuatorTask(__attribute__((unused)) void *parameters)
|
|||||||
|
|
||||||
AlarmsClear(SYSTEMALARMS_ALARM_ACTUATOR);
|
AlarmsClear(SYSTEMALARMS_ALARM_ACTUATOR);
|
||||||
|
|
||||||
float curve1 = 0.0f;
|
float curve1 = 0.0f; // curve 1 is the throttle curve applied to all motors.
|
||||||
float curve2 = 0.0f;
|
float curve2 = 0.0f;
|
||||||
|
|
||||||
// Interpolate curve 1 from throttleDesired as input.
|
// Interpolate curve 1 from throttleDesired as input.
|
||||||
// assume reversible motor/mixer initially. We can later reverse this. The difference is simply that -ve throttleDesired values
|
// assume reversible motor/mixer initially. We can later reverse this. The difference is simply that -ve throttleDesired values
|
||||||
// map differently
|
// map differently
|
||||||
curve1 = MixerCurveFullRangeProportional(throttleDesired, mixerSettings.ThrottleCurve1, MIXERSETTINGS_THROTTLECURVE1_NUMELEM);
|
curve1 = MixerCurveFullRangeProportional(throttleDesired, mixerSettings.ThrottleCurve1, MIXERSETTINGS_THROTTLECURVE1_NUMELEM, multirotor);
|
||||||
|
|
||||||
// The source for the secondary curve is selectable
|
// The source for the secondary curve is selectable
|
||||||
AccessoryDesiredData accessory;
|
AccessoryDesiredData accessory;
|
||||||
@ -310,25 +324,38 @@ static void actuatorTask(__attribute__((unused)) void *parameters)
|
|||||||
switch (curve2Source) {
|
switch (curve2Source) {
|
||||||
case MIXERSETTINGS_CURVE2SOURCE_THROTTLE:
|
case MIXERSETTINGS_CURVE2SOURCE_THROTTLE:
|
||||||
// assume reversible motor/mixer initially
|
// assume reversible motor/mixer initially
|
||||||
curve2 = MixerCurveFullRangeProportional(throttleDesired, mixerSettings.ThrottleCurve2, MIXERSETTINGS_THROTTLECURVE2_NUMELEM);
|
curve2 = MixerCurveFullRangeProportional(throttleDesired, mixerSettings.ThrottleCurve2, MIXERSETTINGS_THROTTLECURVE2_NUMELEM, multirotor);
|
||||||
break;
|
break;
|
||||||
case MIXERSETTINGS_CURVE2SOURCE_ROLL:
|
case MIXERSETTINGS_CURVE2SOURCE_ROLL:
|
||||||
// Throttle curve contribution the same for +ve vs -ve roll
|
// Throttle curve contribution the same for +ve vs -ve roll
|
||||||
curve2 = MixerCurveFullRangeAbsolute(desired.Roll, mixerSettings.ThrottleCurve2, MIXERSETTINGS_THROTTLECURVE2_NUMELEM);
|
if (multirotor) {
|
||||||
|
curve2 = MixerCurveFullRangeProportional(desired.Roll, mixerSettings.ThrottleCurve2, MIXERSETTINGS_THROTTLECURVE2_NUMELEM, multirotor);
|
||||||
|
} else {
|
||||||
|
curve2 = MixerCurveFullRangeAbsolute(desired.Roll, mixerSettings.ThrottleCurve2, MIXERSETTINGS_THROTTLECURVE2_NUMELEM, multirotor);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case MIXERSETTINGS_CURVE2SOURCE_PITCH:
|
case MIXERSETTINGS_CURVE2SOURCE_PITCH:
|
||||||
// Throttle curve contribution the same for +ve vs -ve pitch
|
// Throttle curve contribution the same for +ve vs -ve pitch
|
||||||
curve2 = MixerCurveFullRangeAbsolute(desired.Pitch, mixerSettings.ThrottleCurve2,
|
if (multirotor) {
|
||||||
MIXERSETTINGS_THROTTLECURVE2_NUMELEM);
|
curve2 = MixerCurveFullRangeProportional(desired.Pitch, mixerSettings.ThrottleCurve2,
|
||||||
|
MIXERSETTINGS_THROTTLECURVE2_NUMELEM, multirotor);
|
||||||
|
} else {
|
||||||
|
curve2 = MixerCurveFullRangeAbsolute(desired.Pitch, mixerSettings.ThrottleCurve2,
|
||||||
|
MIXERSETTINGS_THROTTLECURVE2_NUMELEM, multirotor);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case MIXERSETTINGS_CURVE2SOURCE_YAW:
|
case MIXERSETTINGS_CURVE2SOURCE_YAW:
|
||||||
// Throttle curve contribution the same for +ve vs -ve yaw
|
// Throttle curve contribution the same for +ve vs -ve yaw
|
||||||
curve2 = MixerCurveFullRangeAbsolute(desired.Yaw, mixerSettings.ThrottleCurve2, MIXERSETTINGS_THROTTLECURVE2_NUMELEM);
|
if (multirotor) {
|
||||||
|
curve2 = MixerCurveFullRangeProportional(desired.Yaw, mixerSettings.ThrottleCurve2, MIXERSETTINGS_THROTTLECURVE2_NUMELEM, multirotor);
|
||||||
|
} else {
|
||||||
|
curve2 = MixerCurveFullRangeAbsolute(desired.Yaw, mixerSettings.ThrottleCurve2, MIXERSETTINGS_THROTTLECURVE2_NUMELEM, multirotor);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case MIXERSETTINGS_CURVE2SOURCE_COLLECTIVE:
|
case MIXERSETTINGS_CURVE2SOURCE_COLLECTIVE:
|
||||||
// assume reversible motor/mixer initially
|
// assume reversible motor/mixer initially
|
||||||
curve2 = MixerCurveFullRangeProportional(collectiveDesired, mixerSettings.ThrottleCurve2,
|
curve2 = MixerCurveFullRangeProportional(collectiveDesired, mixerSettings.ThrottleCurve2,
|
||||||
MIXERSETTINGS_THROTTLECURVE2_NUMELEM);
|
MIXERSETTINGS_THROTTLECURVE2_NUMELEM, multirotor);
|
||||||
break;
|
break;
|
||||||
case MIXERSETTINGS_CURVE2SOURCE_ACCESSORY0:
|
case MIXERSETTINGS_CURVE2SOURCE_ACCESSORY0:
|
||||||
case MIXERSETTINGS_CURVE2SOURCE_ACCESSORY1:
|
case MIXERSETTINGS_CURVE2SOURCE_ACCESSORY1:
|
||||||
@ -338,7 +365,7 @@ static void actuatorTask(__attribute__((unused)) void *parameters)
|
|||||||
case MIXERSETTINGS_CURVE2SOURCE_ACCESSORY5:
|
case MIXERSETTINGS_CURVE2SOURCE_ACCESSORY5:
|
||||||
if (AccessoryDesiredInstGet(mixerSettings.Curve2Source - MIXERSETTINGS_CURVE2SOURCE_ACCESSORY0, &accessory) == 0) {
|
if (AccessoryDesiredInstGet(mixerSettings.Curve2Source - MIXERSETTINGS_CURVE2SOURCE_ACCESSORY0, &accessory) == 0) {
|
||||||
// Throttle curve contribution the same for +ve vs -ve accessory....maybe not want we want.
|
// Throttle curve contribution the same for +ve vs -ve accessory....maybe not want we want.
|
||||||
curve2 = MixerCurveFullRangeAbsolute(accessory.AccessoryVal, mixerSettings.ThrottleCurve2, MIXERSETTINGS_THROTTLECURVE2_NUMELEM);
|
curve2 = MixerCurveFullRangeAbsolute(accessory.AccessoryVal, mixerSettings.ThrottleCurve2, MIXERSETTINGS_THROTTLECURVE2_NUMELEM, multirotor);
|
||||||
} else {
|
} else {
|
||||||
curve2 = 0.0f;
|
curve2 = 0.0f;
|
||||||
}
|
}
|
||||||
@ -350,6 +377,8 @@ static void actuatorTask(__attribute__((unused)) void *parameters)
|
|||||||
|
|
||||||
float *status = (float *)&mixerStatus; // access status objects as an array of floats
|
float *status = (float *)&mixerStatus; // access status objects as an array of floats
|
||||||
Mixer_t *mixers = (Mixer_t *)&mixerSettings.Mixer1Type;
|
Mixer_t *mixers = (Mixer_t *)&mixerSettings.Mixer1Type;
|
||||||
|
float maxMotor = -1.0f; // highest motor value. Addition method needs this to be -1.0f, division method needs this to be 1.0f
|
||||||
|
float minMotor = 1.0f; // lowest motor value Addition method needs this to be 1.0f, division method needs this to be -1.0f
|
||||||
|
|
||||||
for (int ct = 0; ct < MAX_MIX_ACTUATORS; ct++) {
|
for (int ct = 0; ct < MAX_MIX_ACTUATORS; ct++) {
|
||||||
// During boot all camera actuators should be completely disabled (PWM pulse = 0).
|
// During boot all camera actuators should be completely disabled (PWM pulse = 0).
|
||||||
@ -367,13 +396,15 @@ static void actuatorTask(__attribute__((unused)) void *parameters)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((mixer_type == MIXERSETTINGS_MIXER1TYPE_MOTOR)) {
|
if ((mixer_type == MIXERSETTINGS_MIXER1TYPE_MOTOR)) {
|
||||||
if (curve1 < 0.0f) {
|
float nonreversible_curve1 = curve1;
|
||||||
curve1 = 0.0f;
|
float nonreversible_curve2 = curve2;
|
||||||
|
if (nonreversible_curve1 < 0.0f) {
|
||||||
|
nonreversible_curve1 = 0.0f;
|
||||||
}
|
}
|
||||||
if (curve2 < 0.0f) {
|
if (nonreversible_curve2 < 0.0f) {
|
||||||
curve2 = 0.0f;
|
nonreversible_curve2 = 0.0f;
|
||||||
}
|
}
|
||||||
status[ct] = ProcessMixer(ct, curve1, curve2, &desired, dTSeconds);
|
status[ct] = ProcessMixer(ct, nonreversible_curve1, nonreversible_curve2, &desired, dTSeconds, multirotor);
|
||||||
// If not armed or motors aren't meant to spin all the time
|
// If not armed or motors aren't meant to spin all the time
|
||||||
if (!armed ||
|
if (!armed ||
|
||||||
(!spinWhileArmed && !positiveThrottle)) {
|
(!spinWhileArmed && !positiveThrottle)) {
|
||||||
@ -384,10 +415,14 @@ static void actuatorTask(__attribute__((unused)) void *parameters)
|
|||||||
// If armed meant to keep spinning,
|
// If armed meant to keep spinning,
|
||||||
else if ((spinWhileArmed && !positiveThrottle) ||
|
else if ((spinWhileArmed && !positiveThrottle) ||
|
||||||
(status[ct] < 0)) {
|
(status[ct] < 0)) {
|
||||||
status[ct] = 0;
|
if (!multirotor) {
|
||||||
|
status[ct] = 0;
|
||||||
|
// allow throttle values lower than 0 if multirotor.
|
||||||
|
// Values will be scaled to 0 if they need to be in the scaleMotor function
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (mixer_type == MIXERSETTINGS_MIXER1TYPE_REVERSABLEMOTOR) {
|
} else if (mixer_type == MIXERSETTINGS_MIXER1TYPE_REVERSABLEMOTOR) {
|
||||||
status[ct] = ProcessMixer(ct, curve1, curve2, &desired, dTSeconds);
|
status[ct] = ProcessMixer(ct, curve1, curve2, &desired, dTSeconds, multirotor);
|
||||||
// Reversable Motors are like Motors but go to neutral instead of minimum
|
// Reversable Motors are like Motors but go to neutral instead of minimum
|
||||||
// If not armed or motor is inactive - no "spinwhilearmed" for this engine type
|
// If not armed or motor is inactive - no "spinwhilearmed" for this engine type
|
||||||
if (!armed || !activeThrottle) {
|
if (!armed || !activeThrottle) {
|
||||||
@ -396,7 +431,7 @@ static void actuatorTask(__attribute__((unused)) void *parameters)
|
|||||||
status[ct] = 0; // force neutral throttle
|
status[ct] = 0; // force neutral throttle
|
||||||
}
|
}
|
||||||
} else if (mixer_type == MIXERSETTINGS_MIXER1TYPE_SERVO) {
|
} else if (mixer_type == MIXERSETTINGS_MIXER1TYPE_SERVO) {
|
||||||
status[ct] = ProcessMixer(ct, curve1, curve2, &desired, dTSeconds);
|
status[ct] = ProcessMixer(ct, curve1, curve2, &desired, dTSeconds, multirotor);
|
||||||
} else {
|
} else {
|
||||||
status[ct] = -1;
|
status[ct] = -1;
|
||||||
|
|
||||||
@ -442,16 +477,39 @@ static void actuatorTask(__attribute__((unused)) void *parameters)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If mixer type is motor we need to find which motor has the highest value and which motor has the lowest value.
|
||||||
|
// For use in function scaleMotor
|
||||||
|
if (mixers[ct].type == MIXERSETTINGS_MIXER1TYPE_MOTOR) {
|
||||||
|
if (maxMotor < status[ct]) {
|
||||||
|
maxMotor = status[ct];
|
||||||
|
}
|
||||||
|
if (minMotor > status[ct]) {
|
||||||
|
minMotor = status[ct];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set real actuator output values scaling them from mixers. All channels
|
// Set real actuator output values scaling them from mixers. All channels
|
||||||
// will be set except explicitly disabled (which will have PWM pulse = 0).
|
// will be set except explicitly disabled (which will have PWM pulse = 0).
|
||||||
for (int i = 0; i < MAX_MIX_ACTUATORS; i++) {
|
for (int i = 0; i < MAX_MIX_ACTUATORS; i++) {
|
||||||
if (command.Channel[i]) {
|
if (command.Channel[i]) {
|
||||||
command.Channel[i] = scaleChannel(status[i],
|
if (mixers[i].type == MIXERSETTINGS_MIXER1TYPE_MOTOR) { // If mixer is for a motor we need to find the highest value of all motors
|
||||||
actuatorSettings.ChannelMax[i],
|
command.Channel[i] = scaleMotor(status[i],
|
||||||
actuatorSettings.ChannelMin[i],
|
actuatorSettings.ChannelMax[i],
|
||||||
actuatorSettings.ChannelNeutral[i]);
|
actuatorSettings.ChannelMin[i],
|
||||||
|
actuatorSettings.ChannelNeutral[i],
|
||||||
|
maxMotor,
|
||||||
|
minMotor,
|
||||||
|
armed,
|
||||||
|
AlwaysStabilizeWhenArmed,
|
||||||
|
throttleDesired);
|
||||||
|
} else { // else we scale the channel
|
||||||
|
command.Channel[i] = scaleChannel(status[i],
|
||||||
|
actuatorSettings.ChannelMax[i],
|
||||||
|
actuatorSettings.ChannelMin[i],
|
||||||
|
actuatorSettings.ChannelNeutral[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -495,7 +553,7 @@ static void actuatorTask(__attribute__((unused)) void *parameters)
|
|||||||
* Process mixing for one actuator
|
* Process mixing for one actuator
|
||||||
*/
|
*/
|
||||||
float ProcessMixer(const int index, const float curve1, const float curve2,
|
float ProcessMixer(const int index, const float curve1, const float curve2,
|
||||||
ActuatorDesiredData *desired, const float period)
|
ActuatorDesiredData *desired, const float period, bool multirotor)
|
||||||
{
|
{
|
||||||
static float lastFilteredResult[MAX_MIX_ACTUATORS];
|
static float lastFilteredResult[MAX_MIX_ACTUATORS];
|
||||||
const Mixer_t *mixers = (Mixer_t *)&mixerSettings.Mixer1Type; // pointer to array of mixers in UAVObjects
|
const Mixer_t *mixers = (Mixer_t *)&mixerSettings.Mixer1Type; // pointer to array of mixers in UAVObjects
|
||||||
@ -509,8 +567,10 @@ float ProcessMixer(const int index, const float curve1, const float curve2,
|
|||||||
|
|
||||||
// note: no feedforward for reversable motors yet for safety reasons
|
// note: no feedforward for reversable motors yet for safety reasons
|
||||||
if (mixer->type == MIXERSETTINGS_MIXER1TYPE_MOTOR) {
|
if (mixer->type == MIXERSETTINGS_MIXER1TYPE_MOTOR) {
|
||||||
if (result < 0.0f) { // idle throttle
|
if (!multirotor) { // we allow negative throttle with a multirotor
|
||||||
result = 0.0f;
|
if (result < 0.0f) { // zero throttle
|
||||||
|
result = 0.0f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// feed forward
|
// feed forward
|
||||||
@ -558,9 +618,9 @@ float ProcessMixer(const int index, const float curve1, const float curve2,
|
|||||||
* Input of 0 -> lookup(0)
|
* Input of 0 -> lookup(0)
|
||||||
* Input of 1 -> lookup(1)
|
* Input of 1 -> lookup(1)
|
||||||
*/
|
*/
|
||||||
static float MixerCurveFullRangeProportional(const float input, const float *curve, uint8_t elements)
|
static float MixerCurveFullRangeProportional(const float input, const float *curve, uint8_t elements, bool multirotor)
|
||||||
{
|
{
|
||||||
float unsigned_value = MixerCurveFullRangeAbsolute(input, curve, elements);
|
float unsigned_value = MixerCurveFullRangeAbsolute(input, curve, elements, multirotor);
|
||||||
|
|
||||||
if (input < 0.0f) {
|
if (input < 0.0f) {
|
||||||
return -unsigned_value;
|
return -unsigned_value;
|
||||||
@ -578,7 +638,7 @@ static float MixerCurveFullRangeProportional(const float input, const float *cur
|
|||||||
* Input of 0 -> lookup(0)
|
* Input of 0 -> lookup(0)
|
||||||
* Input of 1 -> lookup(1)
|
* Input of 1 -> lookup(1)
|
||||||
*/
|
*/
|
||||||
static float MixerCurveFullRangeAbsolute(const float input, const float *curve, uint8_t elements)
|
static float MixerCurveFullRangeAbsolute(const float input, const float *curve, uint8_t elements, bool multirotor)
|
||||||
{
|
{
|
||||||
float abs_input = fabsf(input);
|
float abs_input = fabsf(input);
|
||||||
float scale = abs_input * (float)(elements - 1);
|
float scale = abs_input * (float)(elements - 1);
|
||||||
@ -586,16 +646,22 @@ static float MixerCurveFullRangeAbsolute(const float input, const float *curve,
|
|||||||
|
|
||||||
scale -= (float)idx1; // remainder
|
scale -= (float)idx1; // remainder
|
||||||
if (curve[0] < -1) {
|
if (curve[0] < -1) {
|
||||||
return input;
|
return abs_input;
|
||||||
}
|
|
||||||
if (idx1 < 0) {
|
|
||||||
idx1 = 0; // clamp to lowest entry in table
|
|
||||||
scale = 0;
|
|
||||||
}
|
}
|
||||||
int idx2 = idx1 + 1;
|
int idx2 = idx1 + 1;
|
||||||
if (idx2 >= elements) {
|
if (idx2 >= elements) {
|
||||||
idx2 = elements - 1; // clamp to highest entry in table
|
idx2 = elements - 1; // clamp to highest entry in table
|
||||||
if (idx1 >= elements) {
|
if (idx1 >= elements) {
|
||||||
|
if (multirotor) {
|
||||||
|
// if multirotor frame we can return throttle values higher than 100%.
|
||||||
|
// Since the we don't have elements in the curve higher than 100% we return
|
||||||
|
// the last element multiplied by the throttle float
|
||||||
|
if (input < 2.0f) { // this limits positive throttle to 200% of max value in table (Maybe this is too much allowance)
|
||||||
|
return curve[idx2] * input;
|
||||||
|
} else {
|
||||||
|
return curve[idx2] * 2.0f; // return 200% of max value in table
|
||||||
|
}
|
||||||
|
}
|
||||||
idx1 = elements - 1;
|
idx1 = elements - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -638,6 +704,73 @@ static int16_t scaleChannel(float value, int16_t max, int16_t min, int16_t neutr
|
|||||||
return valueScaled;
|
return valueScaled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constrain motor values to keep any one motor value from going too far out of range of another motor
|
||||||
|
*/
|
||||||
|
static int16_t scaleMotor(float value, int16_t max, int16_t min, int16_t neutral, float maxMotor, float minMotor, bool armed, bool AlwaysStabilizeWhenArmed, float throttleDesired)
|
||||||
|
{
|
||||||
|
int16_t valueScaled;
|
||||||
|
int16_t maxMotorScaled;
|
||||||
|
int16_t minMotorScaled;
|
||||||
|
int16_t diff;
|
||||||
|
|
||||||
|
// Scale
|
||||||
|
valueScaled = (int16_t)(value * ((float)(max - neutral))) + neutral;
|
||||||
|
maxMotorScaled = (int16_t)(maxMotor * ((float)(max - neutral))) + neutral;
|
||||||
|
minMotorScaled = (int16_t)(minMotor * ((float)(max - neutral))) + neutral;
|
||||||
|
|
||||||
|
|
||||||
|
if (max > min) {
|
||||||
|
diff = max - maxMotorScaled; // difference between max allowed and actual max motor
|
||||||
|
if (diff < 0) { // if the difference is smaller than 0 we add it to the scaled value
|
||||||
|
valueScaled += diff;
|
||||||
|
}
|
||||||
|
diff = neutral - minMotorScaled; // difference between min allowed and actual min motor
|
||||||
|
if (diff > 0) { // if the difference is larger than 0 we add it to the scaled value
|
||||||
|
valueScaled += diff;
|
||||||
|
}
|
||||||
|
// todo: make this flow easier to understand
|
||||||
|
if (valueScaled > max) {
|
||||||
|
valueScaled = max; // clamp to max value only after scaling is done.
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((valueScaled < neutral) && (spinWhileArmed) && AlwaysStabilizeWhenArmed) {
|
||||||
|
valueScaled = neutral; // clamp to neutral value only after scaling is done.
|
||||||
|
} else if ((valueScaled < neutral) && (!spinWhileArmed) && AlwaysStabilizeWhenArmed) {
|
||||||
|
valueScaled = neutral; // clamp to neutral value only after scaling is done. //throttle goes to min if throttledesired is equal to or less than 0 below
|
||||||
|
} else if (valueScaled < neutral) {
|
||||||
|
valueScaled = min; // clamp to min value only after scaling is done.
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// not sure what to do about reversed polarity right now. Why would anyone do this?
|
||||||
|
if (valueScaled < max) {
|
||||||
|
valueScaled = max; // clamp to max value only after scaling is done.
|
||||||
|
}
|
||||||
|
if (valueScaled > min) {
|
||||||
|
valueScaled = min; // clamp to min value only after scaling is done.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// I've added the bool AlwaysStabilizeWhenArmed to this function. Right now we command the motors at min or a range between neutral and max.
|
||||||
|
// NEVER should a motor be command at between min and neutral. I don't like the idea of stabilization ever commanding a motor to min, but we give people the option
|
||||||
|
// This prevents motors startup sync issues causing possible ESC failures.
|
||||||
|
|
||||||
|
// safety checks
|
||||||
|
if (!armed) {
|
||||||
|
// if not armed return min EVERYTIME!
|
||||||
|
valueScaled = min;
|
||||||
|
} else if (!AlwaysStabilizeWhenArmed && (throttleDesired <= 0.0f) && spinWhileArmed) {
|
||||||
|
// all motors idle is AlwaysStabilizeWhenArmed is false, throttle is less than or equal to neutral and spin while armed
|
||||||
|
// stabilize when armed?
|
||||||
|
valueScaled = neutral;
|
||||||
|
} else if (!spinWhileArmed && (throttleDesired <= 0.0f)) {
|
||||||
|
// soft disarm
|
||||||
|
valueScaled = min;
|
||||||
|
}
|
||||||
|
|
||||||
|
return valueScaled;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set actuator output to the neutral values (failsafe)
|
* Set actuator output to the neutral values (failsafe)
|
||||||
*/
|
*/
|
||||||
|
@ -49,7 +49,7 @@
|
|||||||
#include <stabilization.h>
|
#include <stabilization.h>
|
||||||
#include <virtualflybar.h>
|
#include <virtualflybar.h>
|
||||||
#include <cruisecontrol.h>
|
#include <cruisecontrol.h>
|
||||||
|
#include <sanitycheck.h>
|
||||||
// Private constants
|
// Private constants
|
||||||
|
|
||||||
#define CALLBACK_PRIORITY CALLBACK_PRIORITY_CRITICAL
|
#define CALLBACK_PRIORITY CALLBACK_PRIORITY_CRITICAL
|
||||||
@ -239,6 +239,7 @@ static void stabilizationInnerloopTask()
|
|||||||
float *actuatorDesiredAxis = &actuator.Roll;
|
float *actuatorDesiredAxis = &actuator.Roll;
|
||||||
int t;
|
int t;
|
||||||
float dT;
|
float dT;
|
||||||
|
bool multirotor = (GetCurrentFrameType() == FRAME_TYPE_MULTIROTOR); // check if frame is a multirotor
|
||||||
dT = PIOS_DELTATIME_GetAverageSeconds(&timeval);
|
dT = PIOS_DELTATIME_GetAverageSeconds(&timeval);
|
||||||
|
|
||||||
for (t = 0; t < AXES; t++) {
|
for (t = 0; t < AXES; t++) {
|
||||||
@ -308,7 +309,12 @@ static void stabilizationInnerloopTask()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
actuatorDesiredAxis[t] = boundf(actuatorDesiredAxis[t], -1.0f, 1.0f);
|
if (!multirotor) {
|
||||||
|
// we only need to clamp the desired axis to a sane range if the frame is not a multirotor type
|
||||||
|
// we don't want to do any clamping until after the motors are calculated and scaled.
|
||||||
|
// need to figure out what to do with a tricopter tail servo.
|
||||||
|
actuatorDesiredAxis[t] = boundf(actuatorDesiredAxis[t], -1.0f, 1.0f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
actuator.UpdateTime = dT * 1000;
|
actuator.UpdateTime = dT * 1000;
|
||||||
|
@ -105,6 +105,7 @@
|
|||||||
%0402NE:PositionHold:CourseLock:PositionRoam:HomeLeash:AbsolutePosition:ReturnToBase:Land:PathPlanner:POI:AutoCruise,\
|
%0402NE:PositionHold:CourseLock:PositionRoam:HomeLeash:AbsolutePosition:ReturnToBase:Land:PathPlanner:POI:AutoCruise,\
|
||||||
%0903NE:POI:PathPlanner:AutoCruise:Land;"/>
|
%0903NE:POI:PathPlanner:AutoCruise:Land;"/>
|
||||||
|
|
||||||
|
<field name="AlwaysStabilizeWhenArmed" units="" type="enum" elements="1" options="FALSE,TRUE" defaultvalue="FALSE" description="For Multirotors. Always stabilize no matter the throttle setting when vehicle is armed. Does not work when vehicle is set to Always Armed."/>
|
||||||
<field name="ArmedTimeout" units="ms" type="uint16" elements="1" defaultvalue="30000"/>
|
<field name="ArmedTimeout" units="ms" type="uint16" elements="1" defaultvalue="30000"/>
|
||||||
<field name="ArmingSequenceTime" units="ms" type="uint16" elements="1" defaultvalue="1000"/>
|
<field name="ArmingSequenceTime" units="ms" type="uint16" elements="1" defaultvalue="1000"/>
|
||||||
<field name="DisarmingSequenceTime" units="ms" type="uint16" elements="1" defaultvalue="1000"/>
|
<field name="DisarmingSequenceTime" units="ms" type="uint16" elements="1" defaultvalue="1000"/>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user