@@ -101,6 +101,7 @@ int BLDCMotor::initFOC( float zero_electric_offset, Direction _sensor_direction
101
101
if (sensor){
102
102
exit_flag *= alignSensor ();
103
103
// added the shaft_angle update
104
+ sensor->updateSensor ();
104
105
shaft_angle = sensor->getAngle ();
105
106
}else if (monitor_port) monitor_port->println (F (" MOT: No sensor." ));
106
107
@@ -164,13 +165,15 @@ int BLDCMotor::alignSensor() {
164
165
_delay (2 );
165
166
}
166
167
// take and angle in the middle
168
+ sensor->updateSensor ();
167
169
float mid_angle = sensor->getAngle ();
168
170
// move one electrical revolution backwards
169
171
for (int i = 500 ; i >=0 ; i-- ) {
170
172
float angle = _3PI_2 + _2PI * i / 500 .0f ;
171
173
setPhaseVoltage (voltage_sensor_align, 0 , angle);
172
174
_delay (2 );
173
175
}
176
+ sensor->updateSensor ();
174
177
float end_angle = sensor->getAngle ();
175
178
setPhaseVoltage (0 , 0 , 0 );
176
179
_delay (200 );
@@ -201,6 +204,7 @@ int BLDCMotor::alignSensor() {
201
204
// set angle -90(270 = 3PI/2) degrees
202
205
setPhaseVoltage (voltage_sensor_align, 0 , _3PI_2);
203
206
_delay (700 );
207
+ sensor->updateSensor ();
204
208
zero_electric_angle = _normalizeAngle (_electricalAngle (sensor_direction*sensor->getAngle (), pole_pairs));
205
209
_delay (20 );
206
210
if (monitor_port){
@@ -217,7 +221,8 @@ int BLDCMotor::alignSensor() {
217
221
// Encoder alignment the absolute zero angle
218
222
// - to the index
219
223
int BLDCMotor::absoluteZeroSearch () {
220
-
224
+ // sensor precision: this is all ok, as the search happens near the 0-angle, where the precision
225
+ // of float is sufficient.
221
226
if (monitor_port) monitor_port->println (F (" MOT: Index search..." ));
222
227
// search the absolute zero with small velocity
223
228
float limit_vel = velocity_limit;
@@ -229,7 +234,7 @@ int BLDCMotor::absoluteZeroSearch() {
229
234
angleOpenloop (1 .5f *_2PI);
230
235
// call important for some sensors not to loose count
231
236
// not needed for the search
232
- sensor->getAngle ();
237
+ sensor->updateSensor ();
233
238
}
234
239
// disable motor
235
240
setPhaseVoltage (0 , 0 , 0 );
@@ -247,15 +252,25 @@ int BLDCMotor::absoluteZeroSearch() {
247
252
// Iterative function looping FOC algorithm, setting Uq on the Motor
248
253
// The faster it can be run the better
249
254
void BLDCMotor::loopFOC () {
255
+ // update sensor - do this even in open-loop mode, as user may be switching between modes and we could lose track
256
+ // of full rotations otherwise.
257
+ if (sensor) sensor->updateSensor ();
258
+
250
259
// if open-loop do nothing
251
260
if ( controller==MotionControlType::angle_openloop || controller==MotionControlType::velocity_openloop ) return ;
261
+
252
262
// shaft angle
263
+ // TODO sensor precision: the shaft_angle actually stores the complete position, including full rotations, as a float
264
+ // For this reason it is NOT precise when the angles become large.
265
+ // Additionally, the way LPF works on angle is a precision issue, and the angle-LPF is a problem
266
+ // when switching to a 2-component representation.
253
267
shaft_angle = shaftAngle (); // read value even if motor is disabled to keep the monitoring updated
254
268
255
269
// if disabled do nothing
256
270
if (!enabled) return ;
257
271
258
272
// electrical angle - need shaftAngle to be called first
273
+ // TODO sensor precision: this will have precision issues because the shaft_angle does...
259
274
electrical_angle = electricalAngle ();
260
275
261
276
switch (torque_controller) {
@@ -300,14 +315,14 @@ void BLDCMotor::loopFOC() {
300
315
// - if target is not set it uses motor.target value
301
316
void BLDCMotor::move (float new_target) {
302
317
303
- // get angular velocity
318
+ // downsampling (optional)
319
+ if (motion_cnt++ < motion_downsample) return ;
320
+ motion_cnt = 0 ;
321
+ // get angular velocity - sensor precision: this value is numerically precise. It is filtered by Velocity LPF, and downsamling (depending on sensor)
304
322
shaft_velocity = shaftVelocity (); // read value even if motor is disabled to keep the monitoring updated
305
323
306
324
// if disabled do nothing
307
325
if (!enabled) return ;
308
- // downsampling (optional)
309
- if (motion_cnt++ < motion_downsample) return ;
310
- motion_cnt = 0 ;
311
326
// set internal target variable
312
327
if (_isset (new_target)) target = new_target;
313
328
@@ -322,11 +337,14 @@ void BLDCMotor::move(float new_target) {
322
337
}
323
338
break ;
324
339
case MotionControlType::angle:
340
+ // TODO sensor precision: this calculation is not numerically precise. The target value cannot express precise positions when
341
+ // the angles are large. This results in not being able to command small changes at high position values.
342
+ // to solve this, the delta-angle has to be calculated in a numerically precise way.
325
343
// angle set point
326
344
shaft_angle_sp = target;
327
345
// calculate velocity set point
328
346
shaft_velocity_sp = P_angle ( shaft_angle_sp - shaft_angle );
329
- // calculate the torque command
347
+ // calculate the torque command - sensor precision: this calculation is ok, but based on bad value from previous calculation
330
348
current_sp = PID_velocity (shaft_velocity_sp - shaft_velocity); // if voltage torque control
331
349
// if torque controlled through voltage
332
350
if (torque_controller == TorqueControlType::voltage){
@@ -337,7 +355,7 @@ void BLDCMotor::move(float new_target) {
337
355
}
338
356
break ;
339
357
case MotionControlType::velocity:
340
- // velocity set point
358
+ // velocity set point - sensor precision: this calculation is numerically precise.
341
359
shaft_velocity_sp = target;
342
360
// calculate the torque command
343
361
current_sp = PID_velocity (shaft_velocity_sp - shaft_velocity); // if current/foc_current torque control
@@ -350,13 +368,16 @@ void BLDCMotor::move(float new_target) {
350
368
}
351
369
break ;
352
370
case MotionControlType::velocity_openloop:
353
- // velocity control in open loop
371
+ // velocity control in open loop - sensor precision: this calculation is numerically precise.
354
372
shaft_velocity_sp = target;
355
373
voltage.q = velocityOpenloop (shaft_velocity_sp); // returns the voltage that is set to the motor
356
374
voltage.d = 0 ;
357
375
break ;
358
376
case MotionControlType::angle_openloop:
359
- // angle control in open loop
377
+ // angle control in open loop -
378
+ // TODO sensor precision: this calculation NOT numerically precise, and subject
379
+ // to the same problems in small set-point changes at high angles
380
+ // as the closed loop version.
360
381
shaft_angle_sp = target;
361
382
voltage.q = angleOpenloop (shaft_angle_sp); // returns the voltage that is set to the motor
362
383
voltage.d = 0 ;
@@ -574,6 +595,8 @@ float BLDCMotor::velocityOpenloop(float target_velocity){
574
595
// quick fix for strange cases (micros overflow + timestamp not defined)
575
596
if (Ts <= 0 || Ts > 0 .5f ) Ts = 1e-3f ;
576
597
598
+ // sensor precision: this calculation is numerically precise since we re-normalize
599
+ // the shaft-angle to the range 0-2PI
577
600
// calculate the necessary angle to achieve target velocity
578
601
shaft_angle = _normalizeAngle (shaft_angle + target_velocity*Ts);
579
602
// for display purposes
@@ -583,6 +606,8 @@ float BLDCMotor::velocityOpenloop(float target_velocity){
583
606
float Uq = voltage_limit;
584
607
if (_isset (phase_resistance)) Uq = current_limit*phase_resistance;
585
608
609
+ // sensor precision: this calculation is numerically precise, since shaft_angle is
610
+ // in the range 0-2PI
586
611
// set the maximal allowed voltage (voltage_limit) with the necessary angle
587
612
setPhaseVoltage (Uq, 0 , _electricalAngle (shaft_angle, pole_pairs));
588
613
@@ -605,6 +630,9 @@ float BLDCMotor::angleOpenloop(float target_angle){
605
630
606
631
// calculate the necessary angle to move from current position towards target angle
607
632
// with maximal velocity (velocity_limit)
633
+ // TODO sensor precision: this calculation is not numerically precise. The angle can grow to the point
634
+ // where small position changes are no longer captured by the precision of floats
635
+ // when the total position is large.
608
636
if (abs ( target_angle - shaft_angle ) > abs (velocity_limit*Ts)){
609
637
shaft_angle += _sign (target_angle - shaft_angle) * abs ( velocity_limit )*Ts;
610
638
shaft_velocity = velocity_limit;
@@ -618,6 +646,10 @@ float BLDCMotor::angleOpenloop(float target_angle){
618
646
float Uq = voltage_limit;
619
647
if (_isset (phase_resistance)) Uq = current_limit*phase_resistance;
620
648
// set the maximal allowed voltage (voltage_limit) with the necessary angle
649
+ // TODO sensor precision: this calculation is not numerically precise. The angle is not constrained,
650
+ // and can grow large. It first gets multiplied by the number of pole-pairs (in _electrocalAngle()),
651
+ // and then gets normalized to 0-2PI (before it gets used in setPhaseVoltage()). At large angles,
652
+ // the precision can mean the range 0-2PI is not well represented at the end of that calculation.
621
653
setPhaseVoltage (Uq, 0 , _electricalAngle (shaft_angle, pole_pairs));
622
654
623
655
// save timestamp for next call
0 commit comments