Skip to content

Commit b2469cc

Browse files
committed
actuator: Implement Smith predictor for actuator delay compensation.
1 parent e779a10 commit b2469cc

File tree

2 files changed

+113
-5
lines changed

2 files changed

+113
-5
lines changed

flight/Modules/Actuator/actuator.c

+104-5
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
#include "manualcontrolcommand.h"
5252
#include "pios_thread.h"
5353
#include "pios_queue.h"
54+
#include "pios_sensors.h"
5455
#include "misc_math.h"
5556

5657
// Private constants
@@ -97,6 +98,29 @@ static MixerSettingsMixer1TypeOptions types_mixer[MAX_MIX_ACTUATORS];
9798

9899
static float motor_mixer[MAX_MIX_ACTUATORS * MIXERSETTINGS_MIXER1VECTOR_NUMELEM];
99100
static float motor_mixer_inv[MAX_MIX_ACTUATORS * MIXERSETTINGS_MIXER1VECTOR_NUMELEM];
101+
static bool inverse_mixer_computed = false;
102+
103+
#define SMITHP_MAX_DELAY 64
104+
105+
struct smith_predictor {
106+
107+
uint32_t samples;
108+
uint32_t idx;
109+
110+
/* This is gonna be a ring buffer. */
111+
float *data;
112+
113+
float iir_alpha;
114+
float iir[MAX_MIX_ACTUATORS];
115+
116+
float mix;
117+
};
118+
119+
static struct smith_predictor* smithp_init(float delay, float iir, float mix);
120+
static void smithp_push_vect(struct smith_predictor *m, float *motor_vect);
121+
static void smithp_compensate(struct smith_predictor *m, float *motor_vect);
122+
123+
struct smith_predictor *smithp;
100124

101125
/* These are various settings objects used throughout the actuator code */
102126
static ActuatorSettingsData actuatorSettings;
@@ -699,6 +723,14 @@ static void actuator_settings_update()
699723
desired_3d_mask |= (1 << i);
700724
}
701725
}
726+
727+
if (!smithp && actuatorSettings.SmithPredictorDelay > 0.1f) {
728+
float dT = 1.0f / (float)PIOS_SENSORS_GetSampleRate(PIOS_SENSOR_GYRO) * 1000.0f;
729+
int delay = (int)(actuatorSettings.SmithPredictorDelay / dT + 0.5f);
730+
if (delay > 0) {
731+
smithp = smithp_init(delay, actuatorSettings.SmithPredictorIIR, actuatorSettings.SmithPredictorMix);
732+
}
733+
}
702734
}
703735

704736
/**
@@ -754,17 +786,13 @@ static void actuator_task(void* parameters)
754786
SystemSettingsAirframeTypeGet(&airframe_type);
755787

756788
compute_mixer();
757-
<<<<<<< HEAD
758-
=======
759789

760790
/* If we can't calculate a proper inverse mixer,
761791
* set failsafe.
762792
*/
763793
if (compute_inverse_mixer()) {
764-
set_failsafe();
765-
continue;
794+
inverse_mixer_computed = true;
766795
}
767-
>>>>>>> mlyle/mpl-actmodel
768796

769797
MixerSettingsThrottleCurve2Get(curve2);
770798
MixerSettingsCurve2SourceGet(&curve2_src);
@@ -838,6 +866,8 @@ static void actuator_task(void* parameters)
838866
normalize_input_data(this_systime, &desired_vect, &armed,
839867
&spin_while_armed, &stabilize_now);
840868

869+
smithp_compensate(smithp, desired_vect);
870+
841871
/* Multiply the actuators x desired matrix by the
842872
* desired x 1 column vector. */
843873
matrix_mul_check(motor_mixer, desired_vect, motor_vect,
@@ -870,6 +900,8 @@ static void actuator_task(void* parameters)
870900
dT, armed, spin_while_armed, stabilize_now,
871901
&maxpoweradd_bucket);
872902

903+
smithp_push_vect(smithp, motor_vect);
904+
873905
/* If we got this far, everything is OK. */
874906
AlarmsClear(SYSTEMALARMS_ALARM_ACTUATOR);
875907
}
@@ -1076,6 +1108,73 @@ static void set_failsafe()
10761108
ActuatorCommandChannelSet(Channel);
10771109
}
10781110

1111+
static struct smith_predictor* smithp_init(float delay, float iir, float mix)
1112+
{
1113+
struct smith_predictor *m = PIOS_malloc_no_dma(sizeof(*m));
1114+
if (!m)
1115+
return NULL;
1116+
memset(m, 0, sizeof(*m));
1117+
1118+
if (delay > SMITHP_MAX_DELAY) delay = SMITHP_MAX_DELAY;
1119+
1120+
m->samples = delay;
1121+
m->iir_alpha = iir;
1122+
m->mix = mix;
1123+
1124+
m->data = PIOS_malloc_no_dma(delay * MAX_MIX_ACTUATORS * sizeof(*m->data));
1125+
if (!m->data)
1126+
return NULL;
1127+
memset(m->data, 0, sizeof(*m->data) * delay * MAX_MIX_ACTUATORS);
1128+
1129+
return m;
1130+
}
1131+
1132+
/*
1133+
Call order for it to work should be:
1134+
- Compensate
1135+
- Push vect
1136+
*/
1137+
1138+
static void smithp_push_vect(struct smith_predictor *m, float *motor_vect)
1139+
{
1140+
if (!m) return;
1141+
1142+
uint32_t p = (m->idx % m->samples) * MAX_MIX_ACTUATORS;
1143+
1144+
/* Write motor vector to position. */
1145+
for (int i = 0; i < MAX_MIX_ACTUATORS; i++) {
1146+
float v = motor_vect[i];
1147+
m->data[p++] = v != v ? 0 : v;
1148+
}
1149+
1150+
/* Moves pointer to oldest data point (via modulo) for _compensate. */
1151+
m->idx++;
1152+
}
1153+
1154+
static void smithp_compensate(struct smith_predictor *m, float *desired_vect)
1155+
{
1156+
if (!m || !inverse_mixer_computed) return;
1157+
1158+
uint32_t p = (m->idx % m->samples) * MAX_MIX_ACTUATORS;
1159+
1160+
float inv[MIXERSETTINGS_MIXER1VECTOR_NUMELEM];
1161+
1162+
for (int i = 0; i < MAX_MIX_ACTUATORS; i++) {
1163+
/* Do IIR on delayed data*/
1164+
m->iir[i] = m->iir[i] * m->iir_alpha + (1 - m->iir_alpha) * m->data[p++];
1165+
}
1166+
1167+
/* Do inverse stuff. */
1168+
matrix_mul_check(motor_mixer_inv, m->iir, inv,
1169+
MIXERSETTINGS_MIXER1VECTOR_NUMELEM,
1170+
MAX_MIX_ACTUATORS,
1171+
1);
1172+
1173+
for (int i = 0; i < MIXERSETTINGS_MIXER1VECTOR_NUMELEM; i++) {
1174+
desired_vect[i] += m->mix * (desired_vect[i] - inv[i]);
1175+
}
1176+
}
1177+
10791178
/**
10801179
* @}
10811180
* @}

shared/uavobjectdefinition/actuatorsettings.xml

+9
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,14 @@
3333
<field defaultvalue="0.9" elements="1" name="MotorInputOutputCurveFit" type="float" units="">
3434
<description>Actuator mapping of input in [-1,1] to output on [-1,1], using power equation of type x^value. This is intended to correct for the non-linear relationship between input command and output power inherent in brushless ESC/motor combinations. A setting below 1.0 will improve high-throttle control stability.</description>
3535
</field>
36+
<field name="SmithPredictorDelay" elements="1" defaultvalue="3.2" type="float" units="ms">
37+
<description>By how much milliseconds to delay the actuator commands fed into the predictor.</description>
38+
</field>
39+
<field name="SmithPredictorIIR" elements="1" defaultvalue="0.5" type="float" units="">
40+
<description>IIR coefficient for smoothing.</description>
41+
</field>
42+
<field name="SmithPredictorMix" elements="1" defaultvalue="0.5" type="float" units="">
43+
<description>Amount of contribution by the smith predictor to the control signal.</description>
44+
</field>
3645
</object>
3746
</xml>

0 commit comments

Comments
 (0)