Merged in filnet/librepilot/LP-419_avoid_gcs_config_reset (pull request #457)
[librepilot.git] / flight / modules / TxPID / txpid.c
blob8452727c2459a4a1c7422fbdbc2138afeae3db7b
1 /**
2 ******************************************************************************
3 * @addtogroup OpenPilotModules OpenPilot Modules
4 * @{
5 * @addtogroup TxPIDModule TxPID Module
6 * @brief Optional module to tune PID settings using R/C transmitter.
7 * Updates PID settings in RAM in real-time using configured Accessory channels as controllers.
8 * @{
10 * @file txpid.c
11 * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015.
12 * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2011.
13 * @brief Optional module to tune PID settings using R/C transmitter.
15 * @see The GNU Public License (GPL) Version 3
17 *****************************************************************************/
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 3 of the License, or
22 * (at your option) any later version.
24 * This program is distributed in the hope that it will be useful, but
25 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
26 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
27 * for more details.
29 * You should have received a copy of the GNU General Public License along
30 * with this program; if not, write to the Free Software Foundation, Inc.,
31 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 /**
35 * Output object: StabilizationSettings
37 * This module will periodically update values of stabilization PID settings
38 * depending on configured input control channels. New values of stabilization
39 * settings are not saved to flash, but updated in RAM. It is expected that the
40 * module will be enabled only for tuning. When desired values are found, they
41 * can be read via GCS and saved permanently. Then this module should be
42 * disabled again.
44 * UAVObjects are automatically generated by the UAVObjectGenerator from
45 * the object definition XML file.
47 * Modules have no API, all communication to other modules is done through UAVObjects.
48 * However modules may use the API exposed by shared libraries.
49 * See the OpenPilot wiki for more details.
50 * http://wiki.openpilot.org/display/Doc/OpenPilot+Architecture
54 #include "openpilot.h"
55 #include "txpidsettings.h"
56 #include "accessorydesired.h"
57 #include "manualcontrolcommand.h"
58 #include "stabilizationsettings.h"
59 #include "attitudesettings.h"
60 #ifdef REVOLUTION
61 #include "altitudeholdsettings.h"
62 #endif
63 #include "stabilizationbank.h"
64 #include "stabilizationsettingsbank1.h"
65 #include "stabilizationsettingsbank2.h"
66 #include "stabilizationsettingsbank3.h"
67 #include "flightstatus.h"
68 #include "txpidstatus.h"
69 #include "hwsettings.h"
72 // Configuration
74 #define SAMPLE_PERIOD_MS 200
75 #define TELEMETRY_UPDATE_PERIOD_MS 0 // 0 = update on change (default)
77 // Sanity checks
78 #if (TXPIDSETTINGS_PIDS_NUMELEM != TXPIDSETTINGS_INPUTS_NUMELEM) || \
79 (TXPIDSETTINGS_PIDS_NUMELEM != TXPIDSETTINGS_MINPID_NUMELEM) || \
80 (TXPIDSETTINGS_PIDS_NUMELEM != TXPIDSETTINGS_MAXPID_NUMELEM)
81 #error Invalid TxPID UAVObject definition (inconsistent number of field elements)
82 #endif
84 // Private types
86 // Private variables
88 // Private functions
89 static void updatePIDs(UAVObjEvent *ev);
90 static uint8_t update(float *var, float val);
91 static uint8_t updateUint16(uint16_t *var, float val);
92 static uint8_t updateUint8(uint8_t *var, float val);
93 static uint8_t updateInt8(int8_t *var, float val);
94 static float scale(float val, float inMin, float inMax, float outMin, float outMax);
96 /**
97 * Initialise the module, called on startup
98 * \returns 0 on success or -1 if initialisation failed
100 int32_t TxPIDInitialize(void)
102 bool txPIDEnabled;
103 HwSettingsOptionalModulesData optionalModules;
105 #ifdef REVOLUTION
106 AltitudeHoldSettingsInitialize();
107 #endif
109 HwSettingsInitialize();
110 HwSettingsOptionalModulesGet(&optionalModules);
112 if (optionalModules.TxPID == HWSETTINGS_OPTIONALMODULES_ENABLED) {
113 txPIDEnabled = true;
114 } else {
115 txPIDEnabled = false;
118 if (txPIDEnabled) {
119 TxPIDSettingsInitialize();
120 TxPIDStatusInitialize();
121 AccessoryDesiredInitialize();
123 UAVObjEvent ev = {
124 .obj = AccessoryDesiredHandle(),
125 .instId = 0,
126 .event = 0,
127 .lowPriority = false,
129 EventPeriodicCallbackCreate(&ev, updatePIDs, SAMPLE_PERIOD_MS / portTICK_RATE_MS);
131 #if (TELEMETRY_UPDATE_PERIOD_MS != 0)
132 // Change StabilizationSettings update rate from OnChange to periodic
133 // to prevent telemetry link flooding with frequent updates in case of
134 // control channel jitter.
135 // Warning: saving to flash with this code active will change the
136 // StabilizationSettings update rate permanently. Use Metadata via
137 // browser to reset to defaults (telemetryAcked=true, OnChange).
138 UAVObjMetadata metadata;
139 StabilizationSettingsInitialize();
140 StabilizationSettingsGetMetadata(&metadata);
141 metadata.telemetryAcked = 0;
142 metadata.telemetryUpdateMode = UPDATEMODE_PERIODIC;
143 metadata.telemetryUpdatePeriod = TELEMETRY_UPDATE_PERIOD_MS;
144 StabilizationSettingsSetMetadata(&metadata);
146 AttitudeSettingsInitialize();
147 AttitudeSettingsGetMetadata(&metadata);
148 metadata.telemetryAcked = 0;
149 metadata.telemetryUpdateMode = UPDATEMODE_PERIODIC;
150 metadata.telemetryUpdatePeriod = TELEMETRY_UPDATE_PERIOD_MS;
151 AttitudeSettingsSetMetadata(&metadata);
152 #endif /* if (TELEMETRY_UPDATE_PERIOD_MS != 0) */
154 return 0;
157 return -1;
160 /* stub: module has no module thread */
161 int32_t TxPIDStart(void)
163 return 0;
166 MODULE_INITCALL(TxPIDInitialize, TxPIDStart);
169 * Update PIDs callback function
171 static void updatePIDs(UAVObjEvent *ev)
173 if (ev->obj != AccessoryDesiredHandle()) {
174 return;
177 TxPIDSettingsData inst;
178 TxPIDSettingsGet(&inst);
180 if (inst.UpdateMode == TXPIDSETTINGS_UPDATEMODE_NEVER) {
181 return;
184 uint8_t armed;
185 FlightStatusArmedGet(&armed);
186 if ((inst.UpdateMode == TXPIDSETTINGS_UPDATEMODE_WHENARMED) &&
187 (armed == FLIGHTSTATUS_ARMED_DISARMED)) {
188 return;
191 StabilizationBankData bank;
192 switch (inst.BankNumber) {
193 case 0:
194 StabilizationSettingsBank1Get((StabilizationSettingsBank1Data *)&bank);
195 break;
197 case 1:
198 StabilizationSettingsBank2Get((StabilizationSettingsBank2Data *)&bank);
199 break;
201 case 2:
202 StabilizationSettingsBank3Get((StabilizationSettingsBank3Data *)&bank);
203 break;
205 default:
206 return;
208 StabilizationSettingsData stab;
209 StabilizationSettingsGet(&stab);
211 AttitudeSettingsData att;
212 AttitudeSettingsGet(&att);
214 #ifdef REVOLUTION
215 AltitudeHoldSettingsData altitude;
216 AltitudeHoldSettingsGet(&altitude);
217 #endif
218 AccessoryDesiredData accessory;
220 TxPIDStatusData txpid_status;
221 TxPIDStatusGet(&txpid_status);
223 bool easyTuneEnabled = false;
225 uint8_t needsUpdateBank = 0;
226 uint8_t needsUpdateStab = 0;
227 uint8_t needsUpdateAtt = 0;
228 #ifdef REVOLUTION
229 uint8_t needsUpdateAltitude = 0;
230 #endif
232 // Loop through every enabled instance
233 for (uint8_t i = 0; i < TXPIDSETTINGS_PIDS_NUMELEM; i++) {
234 if (TxPIDSettingsPIDsToArray(inst.PIDs)[i] != TXPIDSETTINGS_PIDS_DISABLED) {
235 float value;
236 if (TxPIDSettingsInputsToArray(inst.Inputs)[i] == TXPIDSETTINGS_INPUTS_THROTTLE) {
237 ManualControlCommandThrottleGet(&value);
238 value = scale(value,
239 inst.ThrottleRange.Min,
240 inst.ThrottleRange.Max,
241 TxPIDSettingsMinPIDToArray(inst.MinPID)[i],
242 TxPIDSettingsMaxPIDToArray(inst.MaxPID)[i]);
243 } else if (AccessoryDesiredInstGet(
244 TxPIDSettingsInputsToArray(inst.Inputs)[i] - TXPIDSETTINGS_INPUTS_ACCESSORY0,
245 &accessory) == 0) {
246 value = scale(accessory.AccessoryVal, -1.0f, 1.0f,
247 TxPIDSettingsMinPIDToArray(inst.MinPID)[i],
248 TxPIDSettingsMaxPIDToArray(inst.MaxPID)[i]);
249 } else {
250 continue;
253 TxPIDStatusCurPIDToArray(txpid_status.CurPID)[i] = value;
255 switch (TxPIDSettingsPIDsToArray(inst.PIDs)[i]) {
256 case TXPIDSETTINGS_PIDS_ROLLRATEKP:
257 needsUpdateBank |= update(&bank.RollRatePID.Kp, value);
258 break;
259 case TXPIDSETTINGS_PIDS_EASYTUNERATEROLL:
260 easyTuneEnabled = true;
261 needsUpdateBank |= update(&bank.RollRatePID.Kp, value);
262 needsUpdateBank |= update(&bank.RollRatePID.Ki, value * inst.EasyTunePitchRollRateFactors.I);
263 needsUpdateBank |= update(&bank.RollRatePID.Kd, value * inst.EasyTunePitchRollRateFactors.D);
264 break;
265 case TXPIDSETTINGS_PIDS_EASYTUNERATEPITCH:
266 easyTuneEnabled = true;
267 needsUpdateBank |= update(&bank.PitchRatePID.Kp, value);
268 needsUpdateBank |= update(&bank.PitchRatePID.Ki, value * inst.EasyTunePitchRollRateFactors.I);
269 needsUpdateBank |= update(&bank.PitchRatePID.Kd, value * inst.EasyTunePitchRollRateFactors.D);
270 break;
271 case TXPIDSETTINGS_PIDS_ROLLRATEKI:
272 needsUpdateBank |= update(&bank.RollRatePID.Ki, value);
273 break;
274 case TXPIDSETTINGS_PIDS_ROLLRATEKD:
275 needsUpdateBank |= update(&bank.RollRatePID.Kd, value);
276 break;
277 case TXPIDSETTINGS_PIDS_ROLLRATEILIMIT:
278 needsUpdateBank |= update(&bank.RollRatePID.ILimit, value);
279 break;
280 case TXPIDSETTINGS_PIDS_ROLLRATERESP:
281 needsUpdateBank |= updateUint16(&bank.ManualRate.Roll, value);
282 break;
283 case TXPIDSETTINGS_PIDS_ROLLATTITUDEKP:
284 needsUpdateBank |= update(&bank.RollPI.Kp, value);
285 break;
286 case TXPIDSETTINGS_PIDS_ROLLATTITUDEKI:
287 needsUpdateBank |= update(&bank.RollPI.Ki, value);
288 break;
289 case TXPIDSETTINGS_PIDS_ROLLATTITUDEILIMIT:
290 needsUpdateBank |= update(&bank.RollPI.ILimit, value);
291 break;
292 case TXPIDSETTINGS_PIDS_ROLLATTITUDERESP:
293 needsUpdateBank |= updateUint8(&bank.RollMax, value);
294 break;
295 case TXPIDSETTINGS_PIDS_PITCHRATEKP:
296 needsUpdateBank |= update(&bank.PitchRatePID.Kp, value);
297 break;
298 case TXPIDSETTINGS_PIDS_PITCHRATEKI:
299 needsUpdateBank |= update(&bank.PitchRatePID.Ki, value);
300 break;
301 case TXPIDSETTINGS_PIDS_PITCHRATEKD:
302 needsUpdateBank |= update(&bank.PitchRatePID.Kd, value);
303 break;
304 case TXPIDSETTINGS_PIDS_PITCHRATEILIMIT:
305 needsUpdateBank |= update(&bank.PitchRatePID.ILimit, value);
306 break;
307 case TXPIDSETTINGS_PIDS_PITCHRATERESP:
308 needsUpdateBank |= updateUint16(&bank.ManualRate.Pitch, value);
309 break;
310 case TXPIDSETTINGS_PIDS_PITCHATTITUDEKP:
311 needsUpdateBank |= update(&bank.PitchPI.Kp, value);
312 break;
313 case TXPIDSETTINGS_PIDS_PITCHATTITUDEKI:
314 needsUpdateBank |= update(&bank.PitchPI.Ki, value);
315 break;
316 case TXPIDSETTINGS_PIDS_PITCHATTITUDEILIMIT:
317 needsUpdateBank |= update(&bank.PitchPI.ILimit, value);
318 break;
319 case TXPIDSETTINGS_PIDS_PITCHATTITUDERESP:
320 needsUpdateBank |= updateUint8(&bank.PitchMax, value);
321 break;
322 case TXPIDSETTINGS_PIDS_ROLLPITCHRATEKP:
323 needsUpdateBank |= update(&bank.RollRatePID.Kp, value);
324 needsUpdateBank |= update(&bank.PitchRatePID.Kp, value);
325 break;
326 case TXPIDSETTINGS_PIDS_ROLLPITCHRATEKI:
327 needsUpdateBank |= update(&bank.RollRatePID.Ki, value);
328 needsUpdateBank |= update(&bank.PitchRatePID.Ki, value);
329 break;
330 case TXPIDSETTINGS_PIDS_ROLLPITCHRATEKD:
331 needsUpdateBank |= update(&bank.RollRatePID.Kd, value);
332 needsUpdateBank |= update(&bank.PitchRatePID.Kd, value);
333 break;
334 case TXPIDSETTINGS_PIDS_ROLLPITCHRATEILIMIT:
335 needsUpdateBank |= update(&bank.RollRatePID.ILimit, value);
336 needsUpdateBank |= update(&bank.PitchRatePID.ILimit, value);
337 break;
338 case TXPIDSETTINGS_PIDS_ROLLPITCHRATERESP:
339 needsUpdateBank |= updateUint16(&bank.ManualRate.Roll, value);
340 needsUpdateBank |= updateUint16(&bank.ManualRate.Pitch, value);
341 break;
342 case TXPIDSETTINGS_PIDS_ROLLPITCHATTITUDEKP:
343 needsUpdateBank |= update(&bank.RollPI.Kp, value);
344 needsUpdateBank |= update(&bank.PitchPI.Kp, value);
345 break;
346 case TXPIDSETTINGS_PIDS_ROLLPITCHATTITUDEKI:
347 needsUpdateBank |= update(&bank.RollPI.Ki, value);
348 needsUpdateBank |= update(&bank.PitchPI.Ki, value);
349 break;
350 case TXPIDSETTINGS_PIDS_ROLLPITCHATTITUDEILIMIT:
351 needsUpdateBank |= update(&bank.RollPI.ILimit, value);
352 needsUpdateBank |= update(&bank.PitchPI.ILimit, value);
353 break;
354 case TXPIDSETTINGS_PIDS_ROLLPITCHATTITUDERESP:
355 needsUpdateBank |= updateUint8(&bank.RollMax, value);
356 needsUpdateBank |= updateUint8(&bank.PitchMax, value);
357 break;
358 case TXPIDSETTINGS_PIDS_YAWRATEKP:
359 needsUpdateBank |= update(&bank.YawRatePID.Kp, value);
360 break;
361 case TXPIDSETTINGS_PIDS_YAWRATEKI:
362 needsUpdateBank |= update(&bank.YawRatePID.Ki, value);
363 break;
364 case TXPIDSETTINGS_PIDS_YAWRATEKD:
365 needsUpdateBank |= update(&bank.YawRatePID.Kd, value);
366 break;
367 case TXPIDSETTINGS_PIDS_YAWRATEILIMIT:
368 needsUpdateBank |= update(&bank.YawRatePID.ILimit, value);
369 break;
370 case TXPIDSETTINGS_PIDS_YAWRATERESP:
371 needsUpdateBank |= updateUint16(&bank.ManualRate.Yaw, value);
372 break;
373 case TXPIDSETTINGS_PIDS_YAWATTITUDEKP:
374 needsUpdateBank |= update(&bank.YawPI.Kp, value);
375 break;
376 case TXPIDSETTINGS_PIDS_YAWATTITUDEKI:
377 needsUpdateBank |= update(&bank.YawPI.Ki, value);
378 break;
379 case TXPIDSETTINGS_PIDS_YAWATTITUDEILIMIT:
380 needsUpdateBank |= update(&bank.YawPI.ILimit, value);
381 break;
382 case TXPIDSETTINGS_PIDS_YAWATTITUDERESP:
383 needsUpdateBank |= updateUint8(&bank.YawMax, value);
384 break;
385 case TXPIDSETTINGS_PIDS_ROLLEXPO:
386 needsUpdateBank |= updateInt8(&bank.StickExpo.Roll, value);
387 break;
388 case TXPIDSETTINGS_PIDS_PITCHEXPO:
389 needsUpdateBank |= updateInt8(&bank.StickExpo.Pitch, value);
390 break;
391 case TXPIDSETTINGS_PIDS_ROLLPITCHEXPO:
392 needsUpdateBank |= updateInt8(&bank.StickExpo.Roll, value);
393 needsUpdateBank |= updateInt8(&bank.StickExpo.Pitch, value);
394 break;
395 case TXPIDSETTINGS_PIDS_YAWEXPO:
396 needsUpdateBank |= updateInt8(&bank.StickExpo.Yaw, value);
397 break;
398 case TXPIDSETTINGS_PIDS_GYROTAU:
399 needsUpdateStab |= update(&stab.GyroTau, value);
400 break;
401 case TXPIDSETTINGS_PIDS_ACROROLLFACTOR:
402 needsUpdateBank |= updateUint8(&bank.AcroInsanityFactor.Roll, value);
403 break;
404 case TXPIDSETTINGS_PIDS_ACROPITCHFACTOR:
405 needsUpdateBank |= updateUint8(&bank.AcroInsanityFactor.Pitch, value);
406 break;
407 case TXPIDSETTINGS_PIDS_ACROROLLPITCHFACTOR:
408 needsUpdateBank |= updateUint8(&bank.AcroInsanityFactor.Roll, value);
409 needsUpdateBank |= updateUint8(&bank.AcroInsanityFactor.Pitch, value);
410 break;
411 case TXPIDSETTINGS_PIDS_ACCELTAU:
412 needsUpdateAtt |= update(&att.AccelTau, value);
413 break;
414 case TXPIDSETTINGS_PIDS_ACCELKP:
415 needsUpdateAtt |= update(&att.AccelKp, value);
416 break;
417 case TXPIDSETTINGS_PIDS_ACCELKI:
418 needsUpdateAtt |= update(&att.AccelKi, value);
419 break;
421 #ifdef REVOLUTION
422 case TXPIDSETTINGS_PIDS_ALTITUDEPOSKP:
423 needsUpdateAltitude |= update(&altitude.VerticalPosP, value);
424 break;
425 case TXPIDSETTINGS_PIDS_ALTITUDEVELOCITYKP:
426 needsUpdateAltitude |= update(&altitude.VerticalVelPID.Kp, value);
427 break;
428 case TXPIDSETTINGS_PIDS_ALTITUDEVELOCITYKI:
429 needsUpdateAltitude |= update(&altitude.VerticalVelPID.Ki, value);
430 break;
431 case TXPIDSETTINGS_PIDS_ALTITUDEVELOCITYKD:
432 needsUpdateAltitude |= update(&altitude.VerticalVelPID.Kd, value);
433 break;
434 case TXPIDSETTINGS_PIDS_ALTITUDEVELOCITYBETA:
435 needsUpdateAltitude |= update(&altitude.VerticalVelPID.Beta, value);
436 break;
437 #endif
438 default:
439 PIOS_Assert(0);
443 if (needsUpdateStab) {
444 StabilizationSettingsSet(&stab);
446 if (needsUpdateAtt) {
447 AttitudeSettingsSet(&att);
449 #ifdef REVOLUTION
450 if (needsUpdateAltitude) {
451 AltitudeHoldSettingsSet(&altitude);
453 #endif
454 if (easyTuneEnabled && (inst.EasyTuneRatePIDRecalculateYaw != TXPIDSETTINGS_EASYTUNERATEPIDRECALCULATEYAW_FALSE)) {
455 float newKp = (bank.RollRatePID.Kp + bank.PitchRatePID.Kp) * .5f * inst.EasyTuneYawRateFactors.P;
456 needsUpdateBank |= update(&bank.YawRatePID.Kp, newKp);
457 needsUpdateBank |= update(&bank.YawRatePID.Ki, newKp * inst.EasyTuneYawRateFactors.I);
458 needsUpdateBank |= update(&bank.YawRatePID.Kd, newKp * inst.EasyTuneYawRateFactors.D);
460 if (needsUpdateBank) {
461 switch (inst.BankNumber) {
462 case 0:
463 StabilizationSettingsBank1Set((StabilizationSettingsBank1Data *)&bank);
464 break;
466 case 1:
467 StabilizationSettingsBank2Set((StabilizationSettingsBank2Data *)&bank);
468 break;
470 case 2:
471 StabilizationSettingsBank3Set((StabilizationSettingsBank3Data *)&bank);
472 break;
474 default:
475 return;
479 if (needsUpdateStab ||
480 needsUpdateAtt ||
481 #ifdef REVOLUTION
482 needsUpdateAltitude ||
483 #endif /* REVOLUTION */
484 needsUpdateBank) {
485 TxPIDStatusSet(&txpid_status);;
490 * Scales input val from [inMin..inMax] range to [outMin..outMax].
491 * If val is out of input range (inMin <= inMax), it will be bound.
492 * (outMin > outMax) is ok, in that case output will be decreasing.
494 * \returns scaled value
496 static float scale(float val, float inMin, float inMax, float outMin, float outMax)
498 // bound input value
499 if (val > inMax) {
500 val = inMax;
502 if (val < inMin) {
503 val = inMin;
506 // normalize input value to [0..1]
507 if (inMax <= inMin) {
508 val = 0.0f;
509 } else {
510 val = (val - inMin) / (inMax - inMin);
513 // update output bounds
514 if (outMin > outMax) {
515 float t = outMin;
516 outMin = outMax;
517 outMax = t;
518 val = 1.0f - val;
521 return (outMax - outMin) * val + outMin;
525 * Updates var using val if needed.
526 * \returns 1 if updated, 0 otherwise
528 static uint8_t update(float *var, float val)
530 /* FIXME: this is not an entirely correct way
531 * to check if the two floating point
532 * numbers are 'not equal'.
533 * Epsilon of 1e-9 is probably okay for the range
534 * of numbers we see here*/
535 if (fabsf(*var - val) > 1e-9f) {
536 *var = val;
537 return 1;
539 return 0;
543 * Updates var using val if needed.
544 * \returns 1 if updated, 0 otherwise
546 static uint8_t updateUint16(uint16_t *var, float val)
548 uint16_t roundedVal = (uint16_t)roundf(val);
550 if (*var != roundedVal) {
551 *var = roundedVal;
552 return 1;
554 return 0;
558 * Updates var using val if needed.
559 * \returns 1 if updated, 0 otherwise
561 static uint8_t updateUint8(uint8_t *var, float val)
563 uint8_t roundedVal = (uint8_t)roundf(val);
565 if (*var != roundedVal) {
566 *var = roundedVal;
567 return 1;
569 return 0;
573 * Updates var using val if needed.
574 * \returns 1 if updated, 0 otherwise
576 static uint8_t updateInt8(int8_t *var, float val)
578 int8_t roundedVal = (int8_t)roundf(val);
580 if (*var != roundedVal) {
581 *var = roundedVal;
582 return 1;
584 return 0;
588 * @}
592 * @}