Skip to content

Commit 5dc0563

Browse files
committed
CalibratedSensor: allow saving of lut at runtime
Before this change you needed to recompile the code with the calibration data. This change allows you to write code that saves the data to non volatile storage and load on the next power cycle
1 parent e96c5b8 commit 5dc0563

File tree

3 files changed

+47
-28
lines changed

3 files changed

+47
-28
lines changed

examples/encoders/calibrated_sensor/calibration_save/calibration_save.ino

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
/**
22
* The example demonstrates the calibration of the magnetic sensor with the calibration procedure and saving the calibration data.
33
* So that the calibration procedure does not have to be run every time the motor is powered up.
4+
*
5+
* 1. Run this Sketch as is and wait for the calibration data to be generated and printed over Serial.
6+
* 2. Then copy the output from Serial to calibrationLut, zero_electric_angle and sensor_direction
7+
* 3. Change values_provided to true and run the Sketch again to see the motor skipping the calibration.
48
*/
59

610
#include <SimpleFOC.h>
@@ -10,7 +14,9 @@
1014
// fill this array with the calibration values outputed by the calibration procedure
1115
float calibrationLut[50] = {0};
1216
float zero_electric_angle = 0;
13-
Direction sensor_direction = Direction::CW;
17+
Direction sensor_direction = Direction::UNKNOWN;
18+
19+
const bool values_provided = false;
1420

1521
// magnetic sensor instance - SPI
1622
MagneticSensorSPI sensor = MagneticSensorSPI(AS5147_SPI, 14);
@@ -22,7 +28,8 @@ StepperDriver4PWM driver = StepperDriver4PWM(10, 9, 5, 6,8);
2228
// argument 1 - sensor object
2329
// argument 2 - number of samples in the LUT (default 200)
2430
// argument 3 - pointer to the LUT array (defualt nullptr)
25-
CalibratedSensor sensor_calibrated = CalibratedSensor(sensor, 50);
31+
CalibratedSensor sensor_calibrated = CalibratedSensor(
32+
sensor, sizeof(calibrationLut) / sizeof(calibrationLut[0]));
2633

2734
// voltage set point variable
2835
float target_voltage = 2;
@@ -57,9 +64,13 @@ void setup() {
5764
// initialize motor
5865
motor.init();
5966

60-
// Running calibration
61-
// the function will setup everything for the provided calibration LUT
62-
sensor_calibrated.calibrate(motor, calibrationLut, zero_electric_angle, sensor_direction);
67+
if(values_provided) {
68+
motor.zero_electric_angle = zero_electric_angle;
69+
motor.sensor_direction = sensor_direction;
70+
} else {
71+
// Running calibration
72+
sensor_calibrated.calibrate(motor);
73+
}
6374

6475
// Linking sensor to motor object
6576
motor.linkSensor(&sensor_calibrated);

src/encoders/calibrated/CalibratedSensor.cpp

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@
33
// CalibratedSensor()
44
// sensor - instance of original sensor object
55
// n_lut - number of samples in the LUT
6-
CalibratedSensor::CalibratedSensor(Sensor &wrapped, int n_lut) : _wrapped(wrapped) {
7-
this->n_lut = n_lut;
8-
};
6+
CalibratedSensor::CalibratedSensor(Sensor &wrapped, int n_lut, float *lut)
7+
: _wrapped(wrapped), n_lut(n_lut), allocated(false), calibrationLut(lut) {
8+
};
99

1010
CalibratedSensor::~CalibratedSensor() {
1111
// delete calibrationLut;
12+
if(allocated) {
13+
delete []calibrationLut;
14+
}
1215
};
1316

1417
// call update of calibrated sensor
@@ -28,6 +31,9 @@ void CalibratedSensor::init()
2831
// Retrieve the calibrated sensor angle
2932
float CalibratedSensor::getSensorAngle()
3033
{
34+
if(!calibrationLut) {
35+
return _wrapped.getMechanicalAngle();
36+
}
3137
// raw encoder position e.g. 0-2PI
3238
float raw_angle = fmodf(_wrapped.getMechanicalAngle(), _2PI);
3339
raw_angle += raw_angle < 0 ? _2PI:0;
@@ -86,19 +92,15 @@ void CalibratedSensor::filter_error(float* error, float &error_mean, int n_ticks
8692

8793
}
8894

89-
void CalibratedSensor::calibrate(FOCMotor &motor, float* lut, float zero_electric_angle, Direction senor_direction, int settle_time_ms)
95+
void CalibratedSensor::calibrate(FOCMotor &motor, int settle_time_ms)
9096
{
9197
// if the LUT is already defined, skip the calibration
92-
if(lut != nullptr){
93-
motor.monitor_port->println("Using the provided LUT.");
94-
motor.zero_electric_angle = zero_electric_angle;
95-
motor.sensor_direction = senor_direction;
96-
this->calibrationLut = lut;
97-
return;
98-
}else{
99-
this->calibrationLut = new float[n_lut]();
100-
motor.monitor_port->println("Starting Sensor Calibration.");
98+
99+
if(calibrationLut == NULL) {
100+
allocated = true;
101+
calibrationLut = new float[n_lut];
101102
}
103+
motor.monitor_port->println("Starting Sensor Calibration.");
102104

103105
// Calibration variables
104106

@@ -174,11 +176,11 @@ void CalibratedSensor::calibrate(FOCMotor &motor, float* lut, float zero_electri
174176
_delay(settle_time_ms);
175177
_wrapped.update();
176178
// calculate the error
177-
theta_actual = motor.sensor_direction*(_wrapped.getAngle() - theta_init);
179+
theta_actual = (int)motor.sensor_direction * (_wrapped.getAngle() - theta_init);
178180
error[i] = 0.5 * (theta_actual - elec_angle / _NPP);
179181

180182
// calculate the current electrical zero angle
181-
float zero_angle = (motor.sensor_direction*_wrapped.getMechanicalAngle() * _NPP ) - (elec_angle + _PI_2);
183+
float zero_angle = ((int)motor.sensor_direction * _wrapped.getMechanicalAngle() * _NPP ) - (elec_angle + _PI_2);
182184
zero_angle = _normalizeAngle(zero_angle);
183185
// remove the 2PI jumps
184186
if(zero_angle - zero_angle_prev > _PI){
@@ -214,10 +216,10 @@ void CalibratedSensor::calibrate(FOCMotor &motor, float* lut, float zero_electri
214216
_delay(settle_time_ms);
215217
_wrapped.update();
216218
// calculate the error
217-
theta_actual = motor.sensor_direction*(_wrapped.getAngle() - theta_init);
219+
theta_actual = (int)motor.sensor_direction * (_wrapped.getAngle() - theta_init);
218220
error[i] += 0.5 * (theta_actual - elec_angle / _NPP);
219221
// calculate the current electrical zero angle
220-
float zero_angle = (motor.sensor_direction*_wrapped.getMechanicalAngle() * _NPP ) - (elec_angle + _PI_2);
222+
float zero_angle = ((int)motor.sensor_direction * _wrapped.getMechanicalAngle() * _NPP ) - (elec_angle + _PI_2);
221223
zero_angle = _normalizeAngle(zero_angle);
222224
// remove the 2PI jumps
223225
if(zero_angle - zero_angle_prev > _PI){
@@ -272,7 +274,7 @@ void CalibratedSensor::calibrate(FOCMotor &motor, float* lut, float zero_electri
272274
if (ind < 0) ind += n_lut;
273275
calibrationLut[ind] = (float)(error[(int)(i * dn)] - error_mean);
274276
// negate the error if the sensor is in the opposite direction
275-
calibrationLut[ind] = motor.sensor_direction * calibrationLut[ind];
277+
calibrationLut[ind] = (int)motor.sensor_direction * calibrationLut[ind];
276278
}
277279
motor.monitor_port->println("");
278280
_delay(1000);

src/encoders/calibrated/CalibratedSensor.h

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,13 @@
1010
class CalibratedSensor: public Sensor{
1111

1212
public:
13-
// constructor of class with pointer to base class sensor and driver
14-
CalibratedSensor(Sensor& wrapped, int n_lut = 200);
13+
/**
14+
* @brief Constructor of class with pointer to base class sensor and driver
15+
* @param wrapped the wrapped sensor which needs calibration
16+
* @param n_lut the number of entries in the lut
17+
* @param lut the look up table (if null, the lut will be allocated on the heap)
18+
*/
19+
CalibratedSensor(Sensor& wrapped, int n_lut = 200, float* lut = nullptr);
1520

1621
~CalibratedSensor();
1722

@@ -23,7 +28,7 @@ class CalibratedSensor: public Sensor{
2328
/**
2429
* Calibrate method computes the LUT for the correction
2530
*/
26-
virtual void calibrate(FOCMotor& motor, float* lut = nullptr, float zero_electric_angle = 0.0, Direction senor_direction= Direction::CW, int settle_time_ms = 30);
31+
virtual void calibrate(FOCMotor& motor, int settle_time_ms = 30);
2732

2833
// voltage to run the calibration: user input
2934
float voltage_calibration = 1;
@@ -49,9 +54,10 @@ class CalibratedSensor: public Sensor{
4954

5055
// lut size - settable by the user
5156
int n_lut { 200 } ;
52-
// create pointer for lut memory
57+
// pointer for lut memory
5358
// depending on the size of the lut
54-
// will be allocated in the constructor
59+
// will be allocated in the calibrate function if not given.
60+
bool allocated;
5561
float* calibrationLut;
5662
};
5763

0 commit comments

Comments
 (0)