1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2024-11-29 07:24:13 +01:00

Merge remote-tracking branch 'origin/rel-15.02.02' into next

Conflicts:
	flight/modules/Actuator/actuator.c
This commit is contained in:
abeck70 2015-05-06 08:35:21 +10:00
commit 143f09d216
10 changed files with 273 additions and 67 deletions

View File

@ -1,3 +1,27 @@
--- RELEASE-15.02.02-RC3 ---
This release fixes a bug that prevents revo onboard mag to work correctly.
Release Notes - OpenPilot - Version RELEASE-15.02.02
The full list of bugfixes in this release is accessible here:
https://progress.openpilot.org/issues/?filter=12262
** Bug
* [OP-1820] - fix onboard mag orientation
* [OP-1821] - Tricopter tail servo wrong speed on wizard
* [OP-1827] - Version ID wrong in Windows uninstaller
* [OP-1857] - PPM on Flexi does not work on CC/CC3D
* [OP-1872] - Vehicle Wiz Tricopter tail servo settings don't save
** Improvement
* [OP-1835] - Add motor constraints in place of overhead throttle buffer for enhanced stability and power. Add swash constraints for helis.
** Task
* [OP-1831] - due to oneshot higher pid values ki now shows "red" warning in stabilization page
--- RELEASE-15.02.01 --- --- RELEASE-15.02.01 ---
This release fixes an in important bug that may prevent failsafe to work correctly using CC3D/CC with a PWM receiver. This release fixes an in important bug that may prevent failsafe to work correctly using CC3D/CC with a PWM receiver.

View File

@ -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).
@ -373,9 +402,11 @@ static void actuatorTask(__attribute__((unused)) void *parameters)
nonreversible_curve1 = 0.0f; nonreversible_curve1 = 0.0f;
} }
if (nonreversible_curve2 < 0.0f) { if (nonreversible_curve2 < 0.0f) {
nonreversible_curve2 = 0.0f; if (!multirotor) { // allow negative throttle if multirotor. function scaleMotors handles the sanity checks.
nonreversible_curve2 = 0.0f;
}
} }
status[ct] = ProcessMixer(ct, nonreversible_curve1, nonreversible_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)) {
@ -386,10 +417,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) {
@ -398,7 +433,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;
@ -444,16 +479,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]);
}
} }
} }
@ -497,7 +555,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
@ -511,8 +569,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
@ -560,9 +620,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;
@ -580,7 +640,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);
@ -594,6 +654,16 @@ static float MixerCurveFullRangeAbsolute(const float input, const float *curve,
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;
} }
} }
@ -636,6 +706,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)
*/ */

View File

@ -242,6 +242,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);
StabilizationStatusOuterLoopData outerLoop; StabilizationStatusOuterLoopData outerLoop;
@ -324,7 +325,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;

View File

@ -97,7 +97,7 @@
/* PIOS receiver drivers */ /* PIOS receiver drivers */
#define PIOS_INCLUDE_PWM #define PIOS_INCLUDE_PWM
#define PIOS_INCLUDE_PPM #define PIOS_INCLUDE_PPM
/* #define PIOS_INCLUDE_PPM_FLEXI */ #define PIOS_INCLUDE_PPM_FLEXI
#define PIOS_INCLUDE_DSM #define PIOS_INCLUDE_DSM
#define PIOS_INCLUDE_SBUS #define PIOS_INCLUDE_SBUS
/* #define PIOS_INCLUDE_GCSRCVR */ /* #define PIOS_INCLUDE_GCSRCVR */

View File

@ -5621,13 +5621,16 @@ Beware of not locking yourself out!</source>
<source>If enabled, a fast recalibration of gyro zero point will be done <source>If enabled, a fast recalibration of gyro zero point will be done
whenever the frame is armed. Do not move the airframe while whenever the frame is armed. Do not move the airframe while
arming it in that case!</source> arming it in that case!</source>
<translation> <translation>
</translation>
Z轴读取到的重力加速度才是用来维持
</translation>
</message> </message>
<message> <message>
<location/> <location/>
<source>Zero gyros while arming aircraft</source> <source>Zero gyros while arming aircraft</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location/> <location/>
@ -9244,32 +9247,32 @@ Please select the type of multirotor you want to create a configuration for belo
</message> </message>
<message> <message>
<location/> <location/>
<location filename="../../../src/plugins/setupwizard/pages/outputcalibrationpage.cpp" line="+435"/> <location filename="../../../src/plugins/setupwizard/pages/outputcalibrationpage.cpp" line="+561"/>
<location line="+104"/> <location line="+131"/>
<source>Start</source> <source>Start</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../../../src/plugins/setupwizard/pages/outputcalibrationpage.cpp" line="-198"/> <location filename="../../../src/plugins/setupwizard/pages/outputcalibrationpage.cpp" line="-268"/>
<location line="+8"/> <location line="+8"/>
<location line="+178"/> <location line="+243"/>
<location line="+25"/> <location line="+38"/>
<source>Output value : &lt;b&gt;%1&lt;/b&gt; µs</source> <source>Output value : &lt;b&gt;%1&lt;/b&gt; µs</source>
<translation>&lt;b&gt;%1&lt;/b&gt;µs</translation> <translation>&lt;b&gt;%1&lt;/b&gt;µs</translation>
</message> </message>
<message> <message>
<location line="-206"/> <location line="-284"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;To find &lt;/span&gt;&lt;span style=&quot; font-size:10pt; font-weight:600;&quot;&gt;the neutral rate for this reversable motor&lt;/span&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;, press the Start button below and slide the slider to the right or left until you find the value where the motor doesn&apos;t start. &lt;br/&gt;&lt;br/&gt;When done press button again to stop.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source> <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;To find &lt;/span&gt;&lt;span style=&quot; font-size:10pt; font-weight:600;&quot;&gt;the neutral rate for this reversable motor&lt;/span&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;, press the Start button below and slide the slider to the right or left until you find the value where the motor doesn&apos;t start. &lt;br/&gt;&lt;br/&gt;When done press button again to stop.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+89"/> <location line="+132"/>
<location line="+104"/> <location line="+131"/>
<source>Stop</source> <source>Stop</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location line="-43"/> <location line="-59"/>
<source>The actuator module is in an error state. <source>The actuator module is in an error state.
Please make sure the correct firmware version is used then restart the wizard and try again. If the problem persists please consult the openpilot.org support forum.</source> Please make sure the correct firmware version is used then restart the wizard and try again. If the problem persists please consult the openpilot.org support forum.</source>
@ -9277,6 +9280,16 @@ Please make sure the correct firmware version is used then restart the wizard an
openpilot.org官网论坛寻求进一步技术支持</translation> openpilot.org官网论坛寻求进一步技术支持</translation>
</message> </message>
<message>
<location line="+132"/>
<source>Output value : &lt;b&gt;%1&lt;/b&gt; µs (Min)</source>
<translation>&lt;b&gt;%1&lt;/b&gt;µs ()</translation>
</message>
<message>
<location line="+31"/>
<source>Output value : &lt;b&gt;%1&lt;/b&gt; µs (Max)</source>
<translation>&lt;b&gt;%1&lt;/b&gt;µs ()</translation>
</message>
<message> <message>
<location filename="../../../src/plugins/setupwizard/pages/outputcalibrationpage.ui"/> <location filename="../../../src/plugins/setupwizard/pages/outputcalibrationpage.ui"/>
<source>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt; <source>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
@ -9370,6 +9383,11 @@ p, li { white-space: pre-wrap; }
<source>Output value: 1000µs</source> <source>Output value: 1000µs</source>
<translation>1000µs</translation> <translation>1000µs</translation>
</message> </message>
<message>
<location/>
<source>Calibrate all motor outputs at the same time</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>SavePage</name> <name>SavePage</name>
@ -10268,7 +10286,7 @@ Do you still want to proceed?</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location line="+210"/> <location line="+212"/>
<source>Next</source> <source>Next</source>
<translation></translation> <translation></translation>
</message> </message>
@ -10348,6 +10366,16 @@ You can press &apos;back&apos; at any time to return to the previous screen or p
<source>For a Quad: Elevator is Pitch, Ailerons are Roll, and Rudder is Yaw.</source> <source>For a Quad: Elevator is Pitch, Ailerons are Roll, and Rudder is Yaw.</source>
<translation>ELEVAILERUDD</translation> <translation>ELEVAILERUDD</translation>
</message> </message>
<message>
<location line="+1016"/>
<source>Warning</source>
<translation></translation>
</message>
<message>
<location line="+0"/>
<source>&lt;p&gt;There is something wrong with Throttle range. Please redo calibration and move &lt;b&gt;ALL sticks&lt;/b&gt;, Throttle stick included.&lt;/p&gt;</source>
<translation>&lt;p&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;</translation>
</message>
<message> <message>
<source>Please center all controls and trims and press Next when ready. <source>Please center all controls and trims and press Next when ready.
@ -10377,7 +10405,7 @@ IMPORTANT: These new settings have not been saved to the board yet. After pressi
</translation> </translation>
</message> </message>
<message> <message>
<location line="+191"/> <location line="-825"/>
<source>Please enable throttle hold mode. <source>Please enable throttle hold mode.
Move the Collective Pitch stick.</source> Move the Collective Pitch stick.</source>
@ -10419,7 +10447,7 @@ Move the %1 stick.</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location line="+3"/> <location line="+4"/>
<source>&lt;p&gt;Arming Settings are now set to &apos;Always Disarmed&apos; for your safety.&lt;/p&gt;&lt;p&gt;Be sure your receiver is powered with an external source and Transmitter is on.&lt;/p&gt;&lt;p align=&apos;center&apos;&gt;&lt;b&gt;Stop Manual Calibration&lt;/b&gt; when done&lt;/p&gt;</source> <source>&lt;p&gt;Arming Settings are now set to &apos;Always Disarmed&apos; for your safety.&lt;/p&gt;&lt;p&gt;Be sure your receiver is powered with an external source and Transmitter is on.&lt;/p&gt;&lt;p align=&apos;center&apos;&gt;&lt;b&gt;Stop Manual Calibration&lt;/b&gt; when done&lt;/p&gt;</source>
<translation>&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p align=&apos;center&apos;&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;</translation> <translation>&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p align=&apos;center&apos;&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;</translation>
</message> </message>
@ -10429,12 +10457,12 @@ Move the %1 stick.</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location line="+33"/> <location line="+51"/>
<source>Start Manual Calibration</source> <source>Start Manual Calibration</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location line="-764"/> <location line="-783"/>
<source> Alternatively, click Next to skip this channel.</source> <source> Alternatively, click Next to skip this channel.</source>
<translation>/</translation> <translation>/</translation>
</message> </message>
@ -10762,14 +10790,14 @@ Move the %1 stick.</source>
<location line="+24"/> <location line="+24"/>
<location line="+6"/> <location line="+6"/>
<location line="+19"/> <location line="+19"/>
<location line="+16"/> <location line="+19"/>
<location line="+16"/> <location line="+16"/>
<location line="+38"/> <location line="+38"/>
<source>Unknown</source> <source>Unknown</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location line="-182"/> <location line="-185"/>
<source>Vehicle type: </source> <source>Vehicle type: </source>
<translation> </translation> <translation> </translation>
</message> </message>
@ -10927,6 +10955,11 @@ Move the %1 stick.</source>
</message> </message>
<message> <message>
<location line="+9"/> <location line="+9"/>
<source>Synched ESC</source>
<translation>Synched电调</translation>
</message>
<message>
<location line="+3"/>
<source>Oneshot ESC</source> <source>Oneshot ESC</source>
<translation>Oneshot电调</translation> <translation>Oneshot电调</translation>
</message> </message>
@ -11040,7 +11073,7 @@ Move the %1 stick.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+199"/> <location line="+196"/>
<location line="+32"/> <location line="+32"/>
<location line="+37"/> <location line="+37"/>
<source>Writing actuator settings</source> <source>Writing actuator settings</source>
@ -11073,7 +11106,7 @@ Move the %1 stick.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location line="+146"/> <location line="+144"/>
<source>Writing mixer settings</source> <source>Writing mixer settings</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -13400,7 +13433,7 @@ p, li { white-space: pre-wrap; }
</message> </message>
<message> <message>
<location filename="../../../src/plugins/setupwizard/pages/esccalibrationpage.cpp" line="+49"/> <location filename="../../../src/plugins/setupwizard/pages/esccalibrationpage.cpp" line="+49"/>
<location line="+49"/> <location line="+58"/>
<location line="+42"/> <location line="+42"/>
<location line="+7"/> <location line="+7"/>
<location line="+9"/> <location line="+9"/>
@ -14305,7 +14338,7 @@ Please first select the area of the map to rip with &lt;CTRL&gt;+Left mouse clic
<location line="+3"/> <location line="+3"/>
<location line="+261"/> <location line="+261"/>
<source>%1 Hz</source> <source>%1 Hz</source>
<translation type="unfinished"></translation> <translation></translation>
</message> </message>
<message> <message>
<location line="-201"/> <location line="-201"/>
@ -14329,8 +14362,12 @@ Please first select the area of the map to rip with &lt;CTRL&gt;+Left mouse clic
</message> </message>
<message> <message>
<location line="+32"/> <location line="+32"/>
<source>OneShot and PWMSync output only works with Receiver Port settings marked with &apos;+OneShot&apos;&lt;br&gt;When using Receiver Port setting &apos;PPM_PIN8+OneShot&apos; &lt;b&gt;&lt;font color=&apos;%1&apos;&gt;Bank %2&lt;/font&gt;&lt;/b&gt; must be set to PWM</source>
<translation>OneShot以及PWMSync输出+OneShot&lt;br&gt;PPM_PIN8+OneShot&lt;b&gt;&lt;font color=&apos;#C3A8FF&apos;&gt;%2&lt;/font&gt;&lt;/b&gt;PWM</translation>
</message>
<message>
<source>OneShot only works with Receiver Port settings marked with &apos;+OneShot&apos;&lt;br&gt;When using Receiver Port setting &apos;PPM_PIN8+OneShot&apos; &lt;b&gt;&lt;font color=&apos;%1&apos;&gt;Bank %2&lt;/font&gt;&lt;/b&gt; must be set to PWM</source> <source>OneShot only works with Receiver Port settings marked with &apos;+OneShot&apos;&lt;br&gt;When using Receiver Port setting &apos;PPM_PIN8+OneShot&apos; &lt;b&gt;&lt;font color=&apos;%1&apos;&gt;Bank %2&lt;/font&gt;&lt;/b&gt; must be set to PWM</source>
<translation>+OneShot&lt;br&gt;PPM_PIN6+OneShot&lt;b&gt;&lt;font color=&apos;%1&apos;&gt;%2&lt;/font&gt;&lt;/b&gt;PWM</translation> <translation type="vanished">+OneShot&lt;br&gt;PPM_PIN6+OneShot&lt;b&gt;&lt;font color=&apos;%1&apos;&gt;%2&lt;/font&gt;&lt;/b&gt;PWM</translation>
</message> </message>
<message> <message>
<source>OneShot only works with Receiver Port settings marked with &apos;+OneShot&apos;&lt;br&gt;When using Receiver Port setting &apos;PPM_PIN6+OneShot&apos; &lt;b&gt;&lt;font color=&apos;#C3A8FF&apos;&gt;Bank 4 (output 6,9-10)&lt;/font&gt;&lt;/b&gt; must be set to PWM</source> <source>OneShot only works with Receiver Port settings marked with &apos;+OneShot&apos;&lt;br&gt;When using Receiver Port setting &apos;PPM_PIN6+OneShot&apos; &lt;b&gt;&lt;font color=&apos;#C3A8FF&apos;&gt;Bank 4 (output 6,9-10)&lt;/font&gt;&lt;/b&gt; must be set to PWM</source>

View File

@ -420,7 +420,7 @@ void ConfigMultiRotorWidget::refreshWidgetsValues(QString frameType)
m_aircraft->multiThrottleCurve->initCurve(&curveValues); m_aircraft->multiThrottleCurve->initCurve(&curveValues);
} else { } else {
// no, init a straight curve // no, init a straight curve
m_aircraft->multiThrottleCurve->initLinearCurve(curveValues.count(), 0.9); m_aircraft->multiThrottleCurve->initLinearCurve(curveValues.count(), 1.0);
} }
GUIConfigDataUnion config = getConfigData(); GUIConfigDataUnion config = getConfigData();

View File

@ -690,6 +690,8 @@ void OutputCalibrationPage::on_motorNeutralSlider_valueChanged(int value)
void OutputCalibrationPage::on_servoButton_toggled(bool checked) void OutputCalibrationPage::on_servoButton_toggled(bool checked)
{ {
ui->servoButton->setText(checked ? tr("Stop") : tr("Start")); ui->servoButton->setText(checked ? tr("Stop") : tr("Start"));
// Now we set servos, motors are done (Tricopter fix)
ui->calibrateAllMotors->setChecked(false);
QList<quint16> currentChannels; QList<quint16> currentChannels;
getCurrentChannels(currentChannels); getCurrentChannels(currentChannels);

View File

@ -433,7 +433,6 @@ void VehicleConfigurationHelper::applyActuatorConfiguration()
if (m_configSource->getControllerType() == VehicleConfigurationSource::CONTROLLER_CC || if (m_configSource->getControllerType() == VehicleConfigurationSource::CONTROLLER_CC ||
m_configSource->getControllerType() == VehicleConfigurationSource::CONTROLLER_CC3D) { m_configSource->getControllerType() == VehicleConfigurationSource::CONTROLLER_CC3D) {
data.BankUpdateFreq[1] = servoFrequence; data.BankUpdateFreq[1] = servoFrequence;
data.BankMode[1] = bankMode;
} else if (m_configSource->getControllerType() == VehicleConfigurationSource::CONTROLLER_REVO) { } else if (m_configSource->getControllerType() == VehicleConfigurationSource::CONTROLLER_REVO) {
data.BankUpdateFreq[1] = escFrequence; data.BankUpdateFreq[1] = escFrequence;
data.BankMode[1] = bankMode; data.BankMode[1] = bankMode;
@ -711,7 +710,7 @@ void VehicleConfigurationHelper::applyMixerConfiguration(mixerChannelSettings ch
} }
// Default maxThrottle and minThrottle // Default maxThrottle and minThrottle
float maxThrottle = 0.9; float maxThrottle = 1;
float minThrottle = 0; float minThrottle = 0;
@ -1011,7 +1010,7 @@ void VehicleConfigurationHelper::resetVehicleConfig()
Q_ASSERT(field); Q_ASSERT(field);
// Set default curve at 90% max for Multirotors // Set default curve at 90% max for Multirotors
for (quint32 i = 0; i < field->getNumElements(); i++) { for (quint32 i = 0; i < field->getNumElements(); i++) {
field->setValue(i * (0.9f / (field->getNumElements() - 1)), i); field->setValue(i * (1.0f / (field->getNumElements() - 1)), i);
} }
} }

View File

@ -296,7 +296,7 @@ Section ; create uninstall info
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenPilot" "UninstallString" '"$INSTDIR\Uninstall.exe"' WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenPilot" "UninstallString" '"$INSTDIR\Uninstall.exe"'
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenPilot" "DisplayIcon" '"$INSTDIR\bin\openpilotgcs.exe"' WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenPilot" "DisplayIcon" '"$INSTDIR\bin\openpilotgcs.exe"'
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenPilot" "Publisher" "OpenPilot Team" WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenPilot" "Publisher" "OpenPilot Team"
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenPilot" "DisplayVersion" "Ragin Cajun" WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenPilot" "DisplayVersion" "Ragin' Cajun"
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenPilot" "URLInfoAbout" "http://www.openpilot.org" WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenPilot" "URLInfoAbout" "http://www.openpilot.org"
WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenPilot" "HelpLink" "http://wiki.openpilot.org" WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenPilot" "HelpLink" "http://wiki.openpilot.org"
WriteRegDWORD HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenPilot" "EstimatedSize" 100600 WriteRegDWORD HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenPilot" "EstimatedSize" 100600

View File

@ -105,6 +105,7 @@
%0402NE:PositionHold:CourseLock:PositionRoam:HomeLeash:AbsolutePosition:ReturnToBase:Land:PathPlanner:POI:AutoCruise,AutoTakeoff\ %0402NE:PositionHold:CourseLock:PositionRoam:HomeLeash:AbsolutePosition:ReturnToBase:Land:PathPlanner:POI:AutoCruise,AutoTakeoff\
%0903NE:POI:PathPlanner:AutoCruise;"/> %0903NE:POI:PathPlanner:AutoCruise;"/>
<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"/>