Skip to content

Conversation

@askuric
Copy link
Member

@askuric askuric commented Dec 5, 2025

This PR fixes the bug #73 + It fixes the bug of the hard-coded number of samples per motor (5 * motor.pole_pairs) - see more info in the community.

Automatic number of samples given a LUT size

Now the code will automatically choose the number of samples to run in one motor rotation based on the LUT size.

It will always do the closest posible number of samples to the LUT size that is multiple of the motor's pole_pairs number.
That way we guarantee that the sampling is equal for each electrical angle.

Then at the final stage the the samples will be remapped to the user's requested LUT size.

For example if we have a BLDC motor with 7 pole pairs and he wants a LUT size of 200
The calibration will be done with
ceil(200/7) * 7 = 203 positins
And then at the end of the calibration process the 203 values will be mapped to the 200.

This mapping at the moment does not implement any interpolation, it only extrapolates. It should work for most use cases.

uint16 LUT rather than float

The main reason is the memory footprint. The LUT now requires half the memory.

The float to uint16 scaling is done with the encodeOffsetU16 and decodeOffsetU16 functions that basically just scale float angle of [-pi, pi] to [0, 65535].

For the moment the resolution is ~0.000096 rad (~0.0055 deg) , which is probably fine for most of applications.

For example if we take a stepper motor with 50pp, in one electrical rotation is discretized in 360/50/0.0055=1309 elements which amounts the resolution of the electrical angle of around ~0.275 deg.

The resolution can be greatly improved if we consider that the LUT will have a smaller range than [-pi,pi] (which is probably always the case). In that case we can increase the scaling factor LUT_SCALE in the CalibratedSensor.h and increase the overall resolution of the LUT.

@askuric askuric changed the base branch from master to dev December 5, 2025 10:24
@github-actions
Copy link

github-actions bot commented Dec 5, 2025

Memory usage change @ b449248

Board flash % RAM for global variables %
adafruit:samd:adafruit_metro_m4 🔺 0 - +528 0.0 - +0.1 N/A N/A
rp2040:rp2040:rpipico 🔺 0 - +512 0.0 - +0.02 🔺 0 - +112 0.0 - +0.04
arduino:sam:arduino_due_x 🔺 0 - +144 0.0 - +0.03 N/A N/A
arduino:samd:nano_33_iot 🔺 0 - +552 0.0 - +0.21 🔺 0 - +116 0.0 - +0.35
esp32:esp32:esp32 🔺 +2548 - +3148 +0.19 - +0.24 🔺 0 - +112 0.0 - +0.03
esp32:esp32:esp32s2 🔺 +2544 - +3160 +0.19 - +0.24 🔺 0 - +120 0.0 - +0.04
STMicroelectronics:stm32:GenF1:pnum=BLUEPILL_F103C8 🔺 0 - +520 0.0 - +0.79 🔺 0 - +116 0.0 - +0.57
STMicroelectronics:stm32:Nucleo_64:pnum=NUCLEO_F411RE 🔺 0 - +556 0.0 - +0.11 🔺 0 - +116 0.0 - +0.09
Click for full report table
Board examples/drivers/drv8316/drv8316_3pwm
flash
% examples/drivers/drv8316/drv8316_3pwm
RAM for global variables
% examples/drivers/drv8316/drv8316_6pwm
flash
% examples/drivers/drv8316/drv8316_6pwm
RAM for global variables
% examples/encoders/calibrated_sensor/calibration_save
flash
% examples/encoders/calibrated_sensor/calibration_save
RAM for global variables
% examples/encoders/linearhall
flash
% examples/encoders/linearhall
RAM for global variables
% examples/encoders/mt6816/mt6816_spi
flash
% examples/encoders/mt6816/mt6816_spi
RAM for global variables
% examples/encoders/calibrated_sensor/calibrated
flash
% examples/encoders/calibrated_sensor/calibrated
RAM for global variables
%
adafruit:samd:adafruit_metro_m4 0 0.0 N/A N/A 0 0.0 N/A N/A 528 0.1 N/A N/A 0 0.0 N/A N/A 0 0.0 N/A N/A
rp2040:rp2040:rpipico 0 0.0 0 0.0 0 0.0 0 0.0 512 0.02 112 0.04 0 0.0 0 0.0 0 0.0 0 0.0
arduino:sam:arduino_due_x 0 0.0 N/A N/A 0 0.0 N/A N/A 144 0.03 N/A N/A 0 0.0 N/A N/A 0 0.0 N/A N/A
arduino:samd:nano_33_iot 0 0.0 0 0.0 0 0.0 0 0.0 552 0.21 116 0.35 0 0.0 0 0.0 0 0.0 0 0.0
esp32:esp32:esp32 2548 0.19 0 0.0 2548 0.19 0 0.0 3148 0.24 112 0.03 2548 0.19 0 0.0
esp32:esp32:esp32s2 2544 0.19 0 0.0 2544 0.19 0 0.0 3160 0.24 120 0.04 2544 0.19 0 0.0 2544 0.19 0 0.0
STMicroelectronics:stm32:GenF1:pnum=BLUEPILL_F103C8 0 0.0 0 0.0 0 0.0 0 0.0 520 0.79 116 0.57 0 0.0 0 0.0
STMicroelectronics:stm32:Nucleo_64:pnum=NUCLEO_F411RE 0 0.0 0 0.0 0 0.0 0 0.0 556 0.11 116 0.09 0 0.0 0 0.0 0 0.0 0 0.0 436 0.08 8 0.01
Click for full report CSV
Board,examples/drivers/drv8316/drv8316_3pwm<br>flash,%,examples/drivers/drv8316/drv8316_3pwm<br>RAM for global variables,%,examples/drivers/drv8316/drv8316_6pwm<br>flash,%,examples/drivers/drv8316/drv8316_6pwm<br>RAM for global variables,%,examples/encoders/calibrated_sensor/calibration_save<br>flash,%,examples/encoders/calibrated_sensor/calibration_save<br>RAM for global variables,%,examples/encoders/linearhall<br>flash,%,examples/encoders/linearhall<br>RAM for global variables,%,examples/encoders/mt6816/mt6816_spi<br>flash,%,examples/encoders/mt6816/mt6816_spi<br>RAM for global variables,%,examples/encoders/calibrated_sensor/calibrated<br>flash,%,examples/encoders/calibrated_sensor/calibrated<br>RAM for global variables,%
adafruit:samd:adafruit_metro_m4,0,0.0,N/A,N/A,0,0.0,N/A,N/A,528,0.1,N/A,N/A,0,0.0,N/A,N/A,0,0.0,N/A,N/A
rp2040:rp2040:rpipico,0,0.0,0,0.0,0,0.0,0,0.0,512,0.02,112,0.04,0,0.0,0,0.0,0,0.0,0,0.0
arduino:sam:arduino_due_x,0,0.0,N/A,N/A,0,0.0,N/A,N/A,144,0.03,N/A,N/A,0,0.0,N/A,N/A,0,0.0,N/A,N/A
arduino:samd:nano_33_iot,0,0.0,0,0.0,0,0.0,0,0.0,552,0.21,116,0.35,0,0.0,0,0.0,0,0.0,0,0.0
esp32:esp32:esp32,2548,0.19,0,0.0,2548,0.19,0,0.0,3148,0.24,112,0.03,,,,,2548,0.19,0,0.0
esp32:esp32:esp32s2,2544,0.19,0,0.0,2544,0.19,0,0.0,3160,0.24,120,0.04,2544,0.19,0,0.0,2544,0.19,0,0.0
STMicroelectronics:stm32:GenF1:pnum=BLUEPILL_F103C8,0,0.0,0,0.0,0,0.0,0,0.0,520,0.79,116,0.57,0,0.0,0,0.0,,,,
STMicroelectronics:stm32:Nucleo_64:pnum=NUCLEO_F411RE,0,0.0,0,0.0,0,0.0,0,0.0,556,0.11,116,0.09,0,0.0,0,0.0,0,0.0,0,0.0,436,0.08,8,0.01

@HB-Stratos
Copy link

I don't think downsampling the LUT is a good idea. I don't think it should be up to the user to set LUT size in this way. User configurable LUT per electrical angle would make more sense I think, that way you never run into the issue of up/downsampling.
Alternatively, the user could specify a max lut size (to prevent memory overflows) and the code determines a lut that can fit into that max size without having to interpolate. In this case a user would request a max N_LUT 200 and get back a LUT of size 196. This would have to then also change the output print for the LUT after calibration, as well as possibly include the N_LUT variable in the output print.
It just feels backwards to me to create a calibration function and sacrifice accuracy of said calibration to fit some arbitrary number constraint that is entirely self-imposed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants