@@ -108,12 +108,28 @@ int StepperMotor::initFOC() {
108
108
// alignment necessary for encoders!
109
109
// sensor and motor alignment - can be skipped
110
110
// by setting motor.sensor_direction and motor.zero_electric_angle
111
- _delay (500 );
112
111
if (sensor){
113
112
exit_flag *= alignSensor ();
114
113
// added the shaft_angle update
115
114
sensor->update ();
116
- shaft_angle = sensor->getAngle ();
115
+ shaft_angle = shaftAngle ();
116
+
117
+ // aligning the current sensor - can be skipped
118
+ // checks if driver phases are the same as current sense phases
119
+ // and checks the direction of measuremnt.
120
+ if (exit_flag){
121
+ if (current_sense){
122
+ if (!current_sense->initialized ) {
123
+ motor_status = FOCMotorStatus::motor_calib_failed;
124
+ SIMPLEFOC_DEBUG (" MOT: Init FOC error, current sense not initialized" );
125
+ exit_flag = 0 ;
126
+ }else {
127
+ exit_flag *= alignCurrentSense ();
128
+ }
129
+ }
130
+ else { SIMPLEFOC_DEBUG (" MOT: No current sense." ); }
131
+ }
132
+
117
133
} else {
118
134
SIMPLEFOC_DEBUG (" MOT: No sensor." );
119
135
if ((controller == MotionControlType::angle_openloop || controller == MotionControlType::velocity_openloop)){
@@ -136,6 +152,26 @@ int StepperMotor::initFOC() {
136
152
return exit_flag;
137
153
}
138
154
155
+ // Calibrate the motor and current sense phases
156
+ int StepperMotor::alignCurrentSense () {
157
+ int exit_flag = 1 ; // success
158
+
159
+ SIMPLEFOC_DEBUG (" MOT: Align current sense." );
160
+
161
+ // align current sense and the driver
162
+ exit_flag = current_sense->driverAlign (voltage_sensor_align);
163
+ if (!exit_flag){
164
+ // error in current sense - phase either not measured or bad connection
165
+ SIMPLEFOC_DEBUG (" MOT: Align error!" );
166
+ exit_flag = 0 ;
167
+ }else {
168
+ // output the alignment status flag
169
+ SIMPLEFOC_DEBUG (" MOT: Success: " , exit_flag);
170
+ }
171
+
172
+ return exit_flag > 0 ;
173
+ }
174
+
139
175
// Encoder alignment to electrical 0 angle
140
176
int StepperMotor::alignSensor () {
141
177
int exit_flag = 1 ; // success
@@ -261,8 +297,6 @@ void StepperMotor::loopFOC() {
261
297
262
298
// if open-loop do nothing
263
299
if ( controller==MotionControlType::angle_openloop || controller==MotionControlType::velocity_openloop ) return ;
264
- // shaft angle
265
- shaft_angle = shaftAngle ();
266
300
267
301
// if disabled do nothing
268
302
if (!enabled) return ;
@@ -272,6 +306,44 @@ void StepperMotor::loopFOC() {
272
306
// which is in range 0-2PI
273
307
electrical_angle = electricalAngle ();
274
308
309
+ // Needs the update() to be called first
310
+ // This function will not have numerical issues because it uses Sensor::getMechanicalAngle()
311
+ // which is in range 0-2PI
312
+ electrical_angle = electricalAngle ();
313
+ switch (torque_controller) {
314
+ case TorqueControlType::voltage:
315
+ // no need to do anything really
316
+ break ;
317
+ case TorqueControlType::dc_current:
318
+ if (!current_sense) return ;
319
+ // read overall current magnitude
320
+ current.q = current_sense->getDCCurrent (electrical_angle);
321
+ // filter the value values
322
+ current.q = LPF_current_q (current.q );
323
+ // calculate the phase voltage
324
+ voltage.q = PID_current_q (current_sp - current.q );
325
+ // d voltage - lag compensation
326
+ if (_isset (phase_inductance)) voltage.d = _constrain ( -current_sp*shaft_velocity*pole_pairs*phase_inductance, -voltage_limit, voltage_limit);
327
+ else voltage.d = 0 ;
328
+ break ;
329
+ case TorqueControlType::foc_current:
330
+ if (!current_sense) return ;
331
+ // read dq currents
332
+ current = current_sense->getFOCCurrents (electrical_angle);
333
+ // filter values
334
+ current.q = LPF_current_q (current.q );
335
+ current.d = LPF_current_d (current.d );
336
+ // calculate the phase voltages
337
+ voltage.q = PID_current_q (current_sp - current.q );
338
+ voltage.d = PID_current_d (-current.d );
339
+ // d voltage - lag compensation - TODO verify
340
+ // if(_isset(phase_inductance)) voltage.d = _constrain( voltage.d - current_sp*shaft_velocity*pole_pairs*phase_inductance, -voltage_limit, voltage_limit);
341
+ break ;
342
+ default :
343
+ // no torque control selected
344
+ SIMPLEFOC_DEBUG (" MOT: no torque control selected!" );
345
+ break ;
346
+ }
275
347
// set the phase voltage - FOC heart function :)
276
348
setPhaseVoltage (voltage.q , voltage.d , electrical_angle);
277
349
}
@@ -309,56 +381,70 @@ void StepperMotor::move(float new_target) {
309
381
// estimate the motor current if phase reistance available and current_sense not available
310
382
if (!current_sense && _isset (phase_resistance)) current.q = (voltage.q - voltage_bemf)/phase_resistance;
311
383
312
- // choose control loop
384
+ // upgrade the current based voltage limit
313
385
switch (controller) {
314
386
case MotionControlType::torque:
315
- if (!_isset (phase_resistance)) voltage.q = target; // if voltage torque control
316
- else voltage.q = target*phase_resistance + voltage_bemf;
317
- voltage.q = _constrain (voltage.q , -voltage_limit, voltage_limit);
318
- // set d-component (lag compensation if known inductance)
319
- if (!_isset (phase_inductance)) voltage.d = 0 ;
320
- else voltage.d = _constrain ( -target*shaft_velocity*pole_pairs*phase_inductance, -voltage_limit, voltage_limit);
387
+ if (torque_controller == TorqueControlType::voltage){ // if voltage torque control
388
+ if (!_isset (phase_resistance)) voltage.q = target;
389
+ else voltage.q = target*phase_resistance + voltage_bemf;
390
+ voltage.q = _constrain (voltage.q , -voltage_limit, voltage_limit);
391
+ // set d-component (lag compensation if known inductance)
392
+ if (!_isset (phase_inductance)) voltage.d = 0 ;
393
+ else voltage.d = _constrain ( -target*shaft_velocity*pole_pairs*phase_inductance, -voltage_limit, voltage_limit);
394
+ }else {
395
+ current_sp = target; // if current/foc_current torque control
396
+ }
321
397
break ;
322
398
case MotionControlType::angle:
399
+ // TODO sensor precision: this calculation is not numerically precise. The target value cannot express precise positions when
400
+ // the angles are large. This results in not being able to command small changes at high position values.
401
+ // to solve this, the delta-angle has to be calculated in a numerically precise way.
323
402
// angle set point
324
403
shaft_angle_sp = target;
325
404
// calculate velocity set point
326
405
shaft_velocity_sp = feed_forward_velocity + P_angle ( shaft_angle_sp - shaft_angle );
327
- shaft_velocity_sp = _constrain (shaft_velocity_sp, -velocity_limit, velocity_limit);
328
- // calculate the torque command
406
+ shaft_velocity_sp = _constrain (shaft_velocity_sp,-velocity_limit, velocity_limit);
407
+ // calculate the torque command - sensor precision: this calculation is ok, but based on bad value from previous calculation
329
408
current_sp = PID_velocity (shaft_velocity_sp - shaft_velocity); // if voltage torque control
330
409
// if torque controlled through voltage
331
- // use voltage if phase-resistance not provided
332
- if (!_isset (phase_resistance)) voltage.q = current_sp;
333
- else voltage.q = _constrain ( current_sp*phase_resistance + voltage_bemf , -voltage_limit, voltage_limit);
334
- // set d-component (lag compensation if known inductance)
335
- if (!_isset (phase_inductance)) voltage.d = 0 ;
336
- else voltage.d = _constrain ( -current_sp*shaft_velocity*pole_pairs*phase_inductance, -voltage_limit, voltage_limit);
410
+ if (torque_controller == TorqueControlType::voltage){
411
+ // use voltage if phase-resistance not provided
412
+ if (!_isset (phase_resistance)) voltage.q = current_sp;
413
+ else voltage.q = _constrain ( current_sp*phase_resistance + voltage_bemf , -voltage_limit, voltage_limit);
414
+ // set d-component (lag compensation if known inductance)
415
+ if (!_isset (phase_inductance)) voltage.d = 0 ;
416
+ else voltage.d = _constrain ( -current_sp*shaft_velocity*pole_pairs*phase_inductance, -voltage_limit, voltage_limit);
417
+ }
337
418
break ;
338
419
case MotionControlType::velocity:
339
- // velocity set point
420
+ // velocity set point - sensor precision: this calculation is numerically precise.
340
421
shaft_velocity_sp = target;
341
422
// calculate the torque command
342
423
current_sp = PID_velocity (shaft_velocity_sp - shaft_velocity); // if current/foc_current torque control
343
424
// if torque controlled through voltage control
344
- // use voltage if phase-resistance not provided
345
- if (!_isset (phase_resistance)) voltage.q = current_sp;
346
- else voltage.q = _constrain ( current_sp*phase_resistance + voltage_bemf , -voltage_limit, voltage_limit);
347
- // set d-component (lag compensation if known inductance)
348
- if (!_isset (phase_inductance)) voltage.d = 0 ;
349
- else voltage.d = _constrain ( -current_sp*shaft_velocity*pole_pairs*phase_inductance, -voltage_limit, voltage_limit);
425
+ if (torque_controller == TorqueControlType::voltage){
426
+ // use voltage if phase-resistance not provided
427
+ if (!_isset (phase_resistance)) voltage.q = current_sp;
428
+ else voltage.q = _constrain ( current_sp*phase_resistance + voltage_bemf , -voltage_limit, voltage_limit);
429
+ // set d-component (lag compensation if known inductance)
430
+ if (!_isset (phase_inductance)) voltage.d = 0 ;
431
+ else voltage.d = _constrain ( -current_sp*shaft_velocity*pole_pairs*phase_inductance, -voltage_limit, voltage_limit);
432
+ }
350
433
break ;
351
434
case MotionControlType::velocity_openloop:
352
- // velocity control in open loop
435
+ // velocity control in open loop - sensor precision: this calculation is numerically precise.
353
436
shaft_velocity_sp = target;
354
437
voltage.q = velocityOpenloop (shaft_velocity_sp); // returns the voltage that is set to the motor
355
- voltage.d = 0 ; // TODO d-component lag-compensation
438
+ voltage.d = 0 ;
356
439
break ;
357
440
case MotionControlType::angle_openloop:
358
- // angle control in open loop
441
+ // angle control in open loop -
442
+ // TODO sensor precision: this calculation NOT numerically precise, and subject
443
+ // to the same problems in small set-point changes at high angles
444
+ // as the closed loop version.
359
445
shaft_angle_sp = target;
360
446
voltage.q = angleOpenloop (shaft_angle_sp); // returns the voltage that is set to the motor
361
- voltage.d = 0 ; // TODO d-component lag-compensation
447
+ voltage.d = 0 ;
362
448
break ;
363
449
}
364
450
}
0 commit comments