Optimised alignSensors function
[betaflight.git] / src / main / sensors / acceleration.c
blob40b6b0ec96736fa5df73d7d0cc050b36bfc0a2fe
1 /*
2 * This file is part of Cleanflight.
4 * Cleanflight is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Cleanflight is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
18 #include <stdbool.h>
19 #include <stdint.h>
20 #include <math.h>
22 #include "platform.h"
24 #include "common/axis.h"
25 #include "common/maths.h"
26 #include "common/filter.h"
28 #include "drivers/sensor.h"
30 #include "sensors/battery.h"
31 #include "sensors/sensors.h"
32 #include "io/beeper.h"
33 #include "sensors/boardalignment.h"
34 #include "fc/runtime_config.h"
36 #include "config/config.h"
38 #include "sensors/acceleration.h"
40 acc_t acc; // acc access functions
41 int32_t accADC[XYZ_AXIS_COUNT];
42 sensor_align_e accAlign = 0;
43 uint32_t accTargetLooptime;
45 static uint16_t calibratingA = 0; // the calibration is done is the main loop. Calibrating decreases at each cycle down to 0, then we enter in a normal mode.
46 static int16_t accADCRaw[XYZ_AXIS_COUNT];
48 static flightDynamicsTrims_t * accZero;
49 static flightDynamicsTrims_t * accGain;
51 static uint8_t accLpfCutHz = 0;
52 static biquadFilter_t accFilter[XYZ_AXIS_COUNT];
54 void accInit(uint32_t targetLooptime)
56 accTargetLooptime = targetLooptime;
57 if (accLpfCutHz) {
58 for (int axis = 0; axis < 3; axis++) {
59 biquadFilterInitLPF(&accFilter[axis], accLpfCutHz, accTargetLooptime);
64 void accSetCalibrationCycles(uint16_t calibrationCyclesRequired)
66 calibratingA = calibrationCyclesRequired;
69 bool isAccelerationCalibrationComplete(void)
71 return calibratingA == 0;
74 bool isOnFinalAccelerationCalibrationCycle(void)
76 return calibratingA == 1;
79 bool isOnFirstAccelerationCalibrationCycle(void)
81 return calibratingA == CALIBRATING_ACC_CYCLES;
84 static sensorCalibrationState_t calState;
85 static bool calibratedAxis[6];
86 static int32_t accSamples[6][3];
87 static int calibratedAxisCount = 0;
89 int getPrimaryAxisIndex(int32_t sample[3])
91 if (ABS(sample[Z]) > ABS(sample[X]) && ABS(sample[Z]) > ABS(sample[Y])) {
92 //Z-axis
93 return (sample[Z] > 0) ? 0 : 1;
95 else if (ABS(sample[X]) > ABS(sample[Y]) && ABS(sample[X]) > ABS(sample[Z])) {
96 //X-axis
97 return (sample[X] > 0) ? 2 : 3;
99 else if (ABS(sample[Y]) > ABS(sample[X]) && ABS(sample[Y]) > ABS(sample[Z])) {
100 //Y-axis
101 return (sample[Y] > 0) ? 4 : 5;
103 else
104 return -1;
107 void performAcclerationCalibration(void)
109 int axisIndex = getPrimaryAxisIndex(accADC);
111 // Check if sample is usable
112 if (axisIndex < 0) {
113 return;
116 // Top-up and first calibration cycle, reset everything
117 if (axisIndex == 0 && isOnFirstAccelerationCalibrationCycle()) {
118 for (int axis = 0; axis < 6; axis++) {
119 calibratedAxis[axis] = false;
120 accSamples[axis][X] = 0;
121 accSamples[axis][Y] = 0;
122 accSamples[axis][Z] = 0;
125 calibratedAxisCount = 0;
126 sensorCalibrationResetState(&calState);
129 if (!calibratedAxis[axisIndex]) {
130 sensorCalibrationPushSampleForOffsetCalculation(&calState, accADC);
131 accSamples[axisIndex][X] += accADC[X];
132 accSamples[axisIndex][Y] += accADC[Y];
133 accSamples[axisIndex][Z] += accADC[Z];
135 if (isOnFinalAccelerationCalibrationCycle()) {
136 calibratedAxis[axisIndex] = true;
137 calibratedAxisCount++;
139 beeperConfirmationBeeps(2);
143 if (calibratedAxisCount == 6) {
144 float accTmp[3];
145 int32_t accSample[3];
147 /* Calculate offset */
148 sensorCalibrationSolveForOffset(&calState, accTmp);
150 for (int axis = 0; axis < 3; axis++) {
151 accZero->raw[axis] = lrintf(accTmp[axis]);
154 /* Not we can offset our accumulated averages samples and calculate scale factors and calculate gains */
155 sensorCalibrationResetState(&calState);
157 for (int axis = 0; axis < 6; axis++) {
158 accSample[X] = accSamples[axis][X] / CALIBRATING_ACC_CYCLES - accZero->raw[X];
159 accSample[Y] = accSamples[axis][Y] / CALIBRATING_ACC_CYCLES - accZero->raw[Y];
160 accSample[Z] = accSamples[axis][Z] / CALIBRATING_ACC_CYCLES - accZero->raw[Z];
162 sensorCalibrationPushSampleForScaleCalculation(&calState, axis / 2, accSample, acc.acc_1G);
165 sensorCalibrationSolveForScale(&calState, accTmp);
167 for (int axis = 0; axis < 3; axis++) {
168 accGain->raw[axis] = lrintf(accTmp[axis] * 4096);
171 saveConfigAndNotify();
174 calibratingA--;
177 static void applyAccelerationZero(const flightDynamicsTrims_t * accZero, const flightDynamicsTrims_t * accGain)
179 accADC[X] = (accADC[X] - accZero->raw[X]) * accGain->raw[X] / 4096;
180 accADC[Y] = (accADC[Y] - accZero->raw[Y]) * accGain->raw[Y] / 4096;
181 accADC[Z] = (accADC[Z] - accZero->raw[Z]) * accGain->raw[Z] / 4096;
184 void updateAccelerationReadings(void)
186 if (!acc.read(accADCRaw)) {
187 return;
190 for (int axis = 0; axis < XYZ_AXIS_COUNT; axis++) {
191 accADC[axis] = accADCRaw[axis];
194 if (accLpfCutHz) {
195 for (int axis = 0; axis < XYZ_AXIS_COUNT; axis++) {
196 accADC[axis] = lrintf(biquadFilterApply(&accFilter[axis], (float) accADC[axis]));
200 if (!isAccelerationCalibrationComplete()) {
201 performAcclerationCalibration();
204 applyAccelerationZero(accZero, accGain);
206 alignSensors(accADC, accAlign);
209 void setAccelerationZero(flightDynamicsTrims_t * accZeroToUse)
211 accZero = accZeroToUse;
214 void setAccelerationGain(flightDynamicsTrims_t * accGainToUse)
216 accGain = accGainToUse;
219 void setAccelerationFilter(uint8_t initialAccLpfCutHz)
221 accLpfCutHz = initialAccLpfCutHz;
222 if (accTargetLooptime) {
223 for (int axis = 0; axis < XYZ_AXIS_COUNT; axis++) {
224 biquadFilterInitLPF(&accFilter[axis], accLpfCutHz, accTargetLooptime);