@@ -21,12 +21,14 @@ BLDCMotor::BLDCMotor(int phA, int phB, int phC, int pp, int en)
21
21
22
22
// Velocity loop config
23
23
// PI controller constant
24
- PI_velocity.P = DEF_PI_VEL_P;
25
- PI_velocity.I = DEF_PI_VEL_I;
26
- PI_velocity.timestamp = _micros ();
27
- PI_velocity.voltage_ramp = DEF_PI_VEL_U_RAMP;
28
- PI_velocity.voltage_prev = 0 ;
29
- PI_velocity.tracking_error_prev = 0 ;
24
+ PID_velocity.P = DEF_PID_VEL_P;
25
+ PID_velocity.I = DEF_PID_VEL_I;
26
+ PID_velocity.D = DEF_PID_VEL_D;
27
+ PID_velocity.output_ramp = DEF_PID_VEL_U_RAMP;
28
+ PID_velocity.timestamp = _micros ();
29
+ PID_velocity.integral_prev = 0 ;
30
+ PID_velocity.output_prev = 0 ;
31
+ PID_velocity.tracking_error_prev = 0 ;
30
32
31
33
// velocity low pass filter
32
34
LPF_velocity.Tf = DEF_VEL_FILTER_Tf;
@@ -38,7 +40,7 @@ BLDCMotor::BLDCMotor(int phA, int phB, int phC, int pp, int en)
38
40
P_angle.P = DEF_P_ANGLE_P;
39
41
40
42
// maximum angular velocity to be used for positioning
41
- velocity_limit = DEF_P_ANGLE_VEL_LIM ;
43
+ velocity_limit = DEF_VEL_LIM ;
42
44
// maximum voltage to be set to the motor
43
45
voltage_limit = voltage_power_supply;
44
46
@@ -78,6 +80,8 @@ void BLDCMotor::init() {
78
80
79
81
// sanity check for the voltage limit configuration
80
82
if (voltage_limit > voltage_power_supply) voltage_limit = voltage_power_supply;
83
+ // constrain voltage for sensor alignment
84
+ if (voltage_sensor_align > voltage_limit) voltage_sensor_align = voltage_limit;
81
85
82
86
_delay (500 );
83
87
// enable motor
@@ -169,7 +173,7 @@ int BLDCMotor::absoluteZeroAlign() {
169
173
// search the absolute zero with small velocity
170
174
while (sensor->needsAbsoluteZeroSearch () && shaft_angle < _2PI){
171
175
loopFOC ();
172
- voltage_q = velocityPI (velocity_index_search - shaftVelocity ());
176
+ voltage_q = velocityPID (velocity_index_search - shaftVelocity ());
173
177
}
174
178
voltage_q = 0 ;
175
179
// disable motor
@@ -192,23 +196,14 @@ int BLDCMotor::absoluteZeroAlign() {
192
196
// shaft angle calculation
193
197
float BLDCMotor::shaftAngle () {
194
198
// if no sensor linked return 0
195
- // if(!sensor) return 0;
199
+ if (!sensor) return 0 ;
196
200
return sensor->getAngle ();
197
201
}
198
202
// shaft velocity calculation
199
203
float BLDCMotor::shaftVelocity () {
200
204
// if no sensor linked return 0
201
- // if(!sensor) return 0;
202
- float Ts = (_micros () - LPF_velocity.timestamp ) * 1e-6 ;
203
- // quick fix for strange cases (micros overflow)
204
- if (Ts <= 0 || Ts > 0.5 ) Ts = 1e-3 ;
205
- // calculate the filtering
206
- float alpha = LPF_velocity.Tf /(LPF_velocity.Tf + Ts);
207
- float vel = alpha*LPF_velocity.prev + (1 -alpha)*sensor->getVelocity ();
208
- // save the variables
209
- LPF_velocity.prev = vel;
210
- LPF_velocity.timestamp = _micros ();
211
- return vel;
205
+ if (!sensor) return 0 ;
206
+ return lowPassFilter (sensor->getVelocity (), LPF_velocity);
212
207
}
213
208
// Electrical angle calculation
214
209
float BLDCMotor::electricAngle (float shaftAngle) {
@@ -220,7 +215,7 @@ float BLDCMotor::electricAngle(float shaftAngle) {
220
215
FOC functions
221
216
*/
222
217
// FOC initialization function
223
- int BLDCMotor::initFOC ( float zero_electric_offset, Direction sensor_direction) {
218
+ int BLDCMotor::initFOC ( float zero_electric_offset, Direction sensor_direction ) {
224
219
int exit_flag = 1 ;
225
220
// align motor if necessary
226
221
// alignment necessary for encoders!
@@ -269,13 +264,13 @@ void BLDCMotor::move(float new_target) {
269
264
// include angle loop
270
265
shaft_angle_sp = target;
271
266
shaft_velocity_sp = positionP ( shaft_angle_sp - shaft_angle );
272
- voltage_q = velocityPI (shaft_velocity_sp - shaft_velocity);
267
+ voltage_q = velocityPID (shaft_velocity_sp - shaft_velocity);
273
268
break ;
274
269
case ControlType::velocity:
275
270
// velocity set point
276
271
// include velocity loop
277
272
shaft_velocity_sp = target;
278
- voltage_q = velocityPI (shaft_velocity_sp - shaft_velocity);
273
+ voltage_q = velocityPID (shaft_velocity_sp - shaft_velocity);
279
274
break ;
280
275
case ControlType::velocity_openloop:
281
276
// velocity control in open loop
@@ -420,38 +415,70 @@ int BLDCMotor::hasEnable(){
420
415
return enable_pin != NOT_SET;
421
416
}
422
417
418
+ // low pass filter function
419
+ // - input -singal to be filtered
420
+ // - lpf -LPF_s structure with filter parameters
421
+ float BLDCMotor::lowPassFilter (float input, LPF_s& lpf){
422
+ unsigned long now_us = _micros ();
423
+ float Ts = (now_us - lpf.timestamp ) * 1e-6 ;
424
+ // quick fix for strange cases (micros overflow)
425
+ if (Ts <= 0 || Ts > 0.5 ) Ts = 1e-3 ;
426
+
427
+ // calculate the filtering
428
+ float alpha = lpf.Tf /(lpf.Tf + Ts);
429
+ float out = alpha*lpf.prev + (1 -alpha)*input;
430
+
431
+ // save the variables
432
+ lpf.prev = out;
433
+ lpf.timestamp = now_us;
434
+ return out;
435
+ }
436
+
423
437
424
438
/* *
425
439
Motor control functions
426
440
*/
427
- // PI controller function
428
- float BLDCMotor::controllerPI (float tracking_error, PI_s& cont){
429
- float Ts = (_micros () - cont.timestamp ) * 1e-6 ;
430
-
441
+ // PID controller function
442
+ float BLDCMotor::controllerPID (float tracking_error, PID_s& cont){
443
+ // calculate the time from the last call
444
+ unsigned long now_us = _micros ();
445
+ float Ts = (now_us - cont.timestamp ) * 1e-6 ;
431
446
// quick fix for strange cases (micros overflow)
432
447
if (Ts <= 0 || Ts > 0.5 ) Ts = 1e-3 ;
433
448
434
- // u(s) = (P + I/s)e(s)
435
- // Tustin transform of the PI controller ( a bit optimized )
436
- // uk = uk_1 + (I*Ts/2 + P)*ek + (I*Ts/2 - P)*ek_1
437
- float tmp = cont.I *Ts*0.5 ;
438
- float voltage = cont.voltage_prev + (tmp + cont.P ) * tracking_error + (tmp - cont.P ) * cont.tracking_error_prev ;
449
+ // u(s) = (P + I/s + Ds)e(s)
450
+ // Discrete implementations
451
+ // proportional part
452
+ // u_p = P *e(k)
453
+ float proportional = cont.P * tracking_error;
454
+ // Tustin transform of the integral part
455
+ // u_ik = u_ik_1 + I*Ts/2*(ek + ek_1)
456
+ float integral = cont.integral_prev + cont.I *Ts*0.5 *(tracking_error + cont.tracking_error_prev );
457
+ // antiwindup - limit the output voltage_q
458
+ integral = constrain (integral, -voltage_limit, voltage_limit);
459
+ // Discrete derivation
460
+ // u_dk = D(ek - ek_1)/Ts
461
+ float derivative = cont.D *(tracking_error - cont.tracking_error_prev )/Ts;
462
+ // sum all the components
463
+ float voltage = proportional + integral + derivative;
439
464
440
465
// antiwindup - limit the output voltage_q
441
466
voltage = constrain (voltage, -voltage_limit, voltage_limit);
442
- // limit the acceleration by ramping the the voltage
443
- float d_voltage = voltage - cont.voltage_prev ;
444
- if (abs (d_voltage)/Ts > cont.voltage_ramp ) voltage = d_voltage > 0 ? cont.voltage_prev + cont.voltage_ramp *Ts : cont.voltage_prev - cont.voltage_ramp *Ts;
445
467
468
+ // limit the acceleration by ramping the the voltage
469
+ float d_voltage = voltage - cont.output_prev ;
470
+ if (abs (d_voltage)/Ts > cont.output_ramp ) voltage = d_voltage > 0 ? cont.output_prev + cont.output_ramp *Ts : cont.output_prev - cont.output_ramp *Ts;
446
471
447
- cont.voltage_prev = voltage;
472
+ // saving for the next pass
473
+ cont.integral_prev = integral;
474
+ cont.output_prev = voltage;
448
475
cont.tracking_error_prev = tracking_error;
449
- cont.timestamp = _micros () ;
476
+ cont.timestamp = now_us ;
450
477
return voltage;
451
478
}
452
479
// velocity control loop PI controller
453
- float BLDCMotor::velocityPI (float tracking_error) {
454
- return controllerPI (tracking_error, PI_velocity );
480
+ float BLDCMotor::velocityPID (float tracking_error) {
481
+ return controllerPID (tracking_error, PID_velocity );
455
482
}
456
483
457
484
// P controller for position control loop
@@ -468,12 +495,13 @@ float BLDCMotor::positionP(float ek) {
468
495
// it uses voltage_limit variable
469
496
void BLDCMotor::velocityOpenloop (float target_velocity){
470
497
// get current timestamp
471
- long now_us = _micros ();
498
+ unsigned long now_us = _micros ();
472
499
// calculate the sample time from last call
473
500
float Ts = (now_us - open_loop_timestamp) * 1e-6 ;
474
501
475
502
// calculate the necessary angle to achieve target velocity
476
503
shaft_angle += target_velocity*Ts;
504
+
477
505
// set the maximal allowed voltage (voltage_limit) with the necessary angle
478
506
setPhaseVoltage (voltage_limit, electricAngle (shaft_angle));
479
507
@@ -486,7 +514,7 @@ void BLDCMotor::velocityOpenloop(float target_velocity){
486
514
// it uses voltage_limit and velocity_limit variables
487
515
void BLDCMotor::angleOpenloop (float target_angle){
488
516
// get current timestamp
489
- long now_us = _micros ();
517
+ unsigned long now_us = _micros ();
490
518
// calculate the sample time from last call
491
519
float Ts = (now_us - open_loop_timestamp) * 1e-6 ;
492
520
@@ -517,13 +545,15 @@ void BLDCMotor::useMonitoring(Print &print){
517
545
void BLDCMotor::monitor () {
518
546
if (!monitor_port) return ;
519
547
switch (controller) {
548
+ case ControlType::velocity_openloop:
520
549
case ControlType::velocity:
521
550
monitor_port->print (voltage_q);
522
551
monitor_port->print (" \t " );
523
552
monitor_port->print (shaft_velocity_sp);
524
553
monitor_port->print (" \t " );
525
554
monitor_port->println (shaft_velocity);
526
555
break ;
556
+ case ControlType::angle_openloop:
527
557
case ControlType::angle:
528
558
monitor_port->print (voltage_q);
529
559
monitor_port->print (" \t " );
@@ -558,8 +588,9 @@ int BLDCMotor::command(String user_command) {
558
588
switch (cmd){
559
589
case ' P' : // velocity P gain change
560
590
case ' I' : // velocity I gain change
591
+ case ' D' : // velocity D gain change
561
592
case ' R' : // velocity voltage ramp change
562
- if (monitor_port) monitor_port->print (" PI velocity| " );
593
+ if (monitor_port) monitor_port->print (" PID velocity| " );
563
594
break ;
564
595
case ' F' : // velocity Tf low pass filter change
565
596
if (monitor_port) monitor_port->print (" LPF velocity| " );
@@ -578,24 +609,29 @@ int BLDCMotor::command(String user_command) {
578
609
switch (cmd){
579
610
case ' P' : // velocity P gain change
580
611
if (monitor_port) monitor_port->print (" P: " );
581
- if (!GET) PI_velocity .P = value;
582
- if (monitor_port) monitor_port->println (PI_velocity .P );
612
+ if (!GET) PID_velocity .P = value;
613
+ if (monitor_port) monitor_port->println (PID_velocity .P );
583
614
break ;
584
615
case ' I' : // velocity I gain change
585
616
if (monitor_port) monitor_port->print (" I: " );
586
- if (!GET) PI_velocity.I = value;
587
- if (monitor_port) monitor_port->println (PI_velocity.I );
617
+ if (!GET) PID_velocity.I = value;
618
+ if (monitor_port) monitor_port->println (PID_velocity.I );
619
+ break ;
620
+ case ' D' : // velocity D gain change
621
+ if (monitor_port) monitor_port->print (" D: " );
622
+ if (!GET) PID_velocity.D = value;
623
+ if (monitor_port) monitor_port->println (PID_velocity.D );
624
+ break ;
625
+ case ' R' : // velocity voltage ramp change
626
+ if (monitor_port) monitor_port->print (" volt_ramp: " );
627
+ if (!GET) PID_velocity.output_ramp = value;
628
+ if (monitor_port) monitor_port->println (PID_velocity.output_ramp );
588
629
break ;
589
630
case ' L' : // velocity voltage limit change
590
631
if (monitor_port) monitor_port->print (" volt_limit: " );
591
632
if (!GET)voltage_limit = value;
592
633
if (monitor_port) monitor_port->println (voltage_limit);
593
634
break ;
594
- case ' R' : // velocity voltage ramp change
595
- if (monitor_port) monitor_port->print (" volt_ramp: " );
596
- if (!GET) PI_velocity.voltage_ramp = value;
597
- if (monitor_port) monitor_port->println (PI_velocity.voltage_ramp );
598
- break ;
599
635
case ' F' : // velocity Tf low pass filter change
600
636
if (monitor_port) monitor_port->print (" Tf: " );
601
637
if (!GET) LPF_velocity.Tf = value;
@@ -615,7 +651,7 @@ int BLDCMotor::command(String user_command) {
615
651
// change control type
616
652
if (monitor_port) monitor_port->print (" Control: " );
617
653
618
- if (GET){ // if get commang
654
+ if (GET){ // if get command
619
655
switch (controller){
620
656
case ControlType::voltage:
621
657
if (monitor_port) monitor_port->println (" voltage" );
@@ -626,6 +662,8 @@ int BLDCMotor::command(String user_command) {
626
662
case ControlType::angle:
627
663
if (monitor_port) monitor_port->println (" angle" );
628
664
break ;
665
+ default :
666
+ if (monitor_port) monitor_port->println (" open loop" );
629
667
}
630
668
}else { // if set command
631
669
switch ((int )value){
0 commit comments