@@ -24,7 +24,7 @@ BLDCMotor::BLDCMotor(int phA, int phB, int phC, int pp, int en)
24
24
PI_velocity.P = DEF_PI_VEL_P;
25
25
PI_velocity.I = DEF_PI_VEL_I;
26
26
PI_velocity.timestamp = _micros ();
27
- PI_velocity.voltage_limit = voltage_power_supply/ 2 ;
27
+ PI_velocity.voltage_limit = voltage_power_supply;
28
28
PI_velocity.voltage_ramp = DEF_PI_VEL_U_RAMP;
29
29
PI_velocity.voltage_prev = 0 ;
30
30
PI_velocity.tracking_error_prev = 0 ;
@@ -40,51 +40,46 @@ BLDCMotor::BLDCMotor(int phA, int phB, int phC, int pp, int en)
40
40
// maximum angular velocity to be used for positioning
41
41
P_angle.velocity_limit = DEF_P_ANGLE_VEL_LIM;
42
42
43
- // index search PI controller
44
- PI_velocity_index_search.P = DEF_PI_VEL_INDEX_P;
45
- PI_velocity_index_search.I = DEF_PI_VEL_INDEX_I;
46
- PI_velocity_index_search.voltage_limit = voltage_power_supply/2 ;
47
- PI_velocity_index_search.voltage_ramp = DEF_PI_VEL_INDEX_U_RAMP;
48
- PI_velocity_index_search.timestamp = _micros ();
49
- PI_velocity_index_search.voltage_prev = 0 ;
50
- PI_velocity_index_search.tracking_error_prev = 0 ;
51
-
52
43
// index search velocity
53
- index_search_velocity = DEF_INDEX_SEARCH_TARGET_VELOCITY;
44
+ velocity_index_search = DEF_INDEX_SEARCH_TARGET_VELOCITY;
45
+ // sensor and motor align voltage
46
+ voltage_sensor_align = DEF_VOLTAGE_SENSOR_ALIGN;
54
47
55
48
// electric angle of the zero angle
56
49
zero_electric_angle = 0 ;
57
50
58
51
// default modulation is SinePWM
59
52
foc_modulation = FOCModulationType::SinePWM;
60
53
61
- // debugger
62
- debugger = nullptr ;
54
+ // default target value
55
+ target = 0 ;
56
+
57
+ // monitor_port
58
+ monitor_port = nullptr ;
63
59
}
64
60
65
61
// init hardware pins
66
62
void BLDCMotor::init () {
67
- if (debugger) debugger ->println (" DEBUG : Initialize the motor pins." );
63
+ if (monitor_port) monitor_port ->println (" MONITOR : Initialize the motor pins." );
68
64
// PWM pins
69
65
pinMode (pwmA, OUTPUT);
70
66
pinMode (pwmB, OUTPUT);
71
67
pinMode (pwmC, OUTPUT);
72
68
if (hasEnable ()) pinMode (enable_pin, OUTPUT);
73
69
74
- if (debugger) debugger ->println (" DEBUG : Set high frequency PWM." );
70
+ if (monitor_port) monitor_port ->println (" MONITOR : Set high frequency PWM." );
75
71
// Increase PWM frequency to 32 kHz
76
72
// make silent
77
73
setPwmFrequency (pwmA);
78
74
setPwmFrequency (pwmB);
79
75
setPwmFrequency (pwmC);
80
76
81
77
// sanity check for the voltage limit configuration
82
- if (PI_velocity.voltage_limit > 0.7 *voltage_power_supply) PI_velocity.voltage_limit = 0.7 *voltage_power_supply;
83
- if (PI_velocity_index_search.voltage_limit > 0.7 *voltage_power_supply) PI_velocity_index_search.voltage_limit = 0.7 *voltage_power_supply;
78
+ if (PI_velocity.voltage_limit > voltage_power_supply) PI_velocity.voltage_limit = voltage_power_supply;
84
79
85
80
_delay (500 );
86
81
// enable motor
87
- if (debugger) debugger ->println (" DEBUG : Enabling motor." );
82
+ if (monitor_port) monitor_port ->println (" MONITOR : Enabling motor." );
88
83
enable ();
89
84
_delay (500 );
90
85
@@ -120,11 +115,11 @@ void BLDCMotor::linkSensor(Sensor* _sensor) {
120
115
121
116
// Encoder alignment to electrical 0 angle
122
117
int BLDCMotor::alignSensor () {
123
- if (debugger) debugger ->println (" DEBUG : Align the sensor's and motor electrical 0 angle." );
118
+ if (monitor_port) monitor_port ->println (" MONITOR : Align the sensor's and motor electrical 0 angle." );
124
119
// align the electrical phases of the motor and sensor
125
- setPwm (pwmA, voltage_power_supply/ 2.0 );
126
- setPwm (pwmB, 0 );
127
- setPwm (pwmC, 0 );
120
+ // set angle -90 degrees
121
+ setPhaseVoltage (voltage_sensor_align, _3PI_2 );
122
+ // let the motor stabilize for 3 sec
128
123
_delay (3000 );
129
124
// set sensor to zero
130
125
sensor->initRelativeZero ();
@@ -135,10 +130,10 @@ int BLDCMotor::alignSensor() {
135
130
// find the index if available
136
131
int exit_flag = absoluteZeroAlign ();
137
132
_delay (500 );
138
- if (debugger ){
139
- if (exit_flag< 0 ) debugger ->println (" DEBUG : Error: Absolute zero not found!" );
140
- if (exit_flag> 0 ) debugger ->println (" DEBUG : Success: Absolute zero found!" );
141
- else debugger ->println (" DEBUG : Absolute zero not available!" );
133
+ if (monitor_port ){
134
+ if (exit_flag< 0 ) monitor_port ->println (" MONITOR : Error: Absolute zero not found!" );
135
+ if (exit_flag> 0 ) monitor_port ->println (" MONITOR : Success: Absolute zero found!" );
136
+ else monitor_port ->println (" MONITOR : Absolute zero not available!" );
142
137
}
143
138
return exit_flag;
144
139
}
@@ -150,13 +145,13 @@ int BLDCMotor::absoluteZeroAlign() {
150
145
// if no absolute zero return
151
146
if (!sensor->hasAbsoluteZero ()) return 0 ;
152
147
153
- if (debugger) debugger ->println (" DEBUG : Aligning the absolute zero." );
148
+ if (monitor_port) monitor_port ->println (" MONITOR : Aligning the absolute zero." );
154
149
155
- if (debugger && sensor->needsAbsoluteZeroSearch ()) debugger ->println (" DEBUG : Searching for absolute zero." );
150
+ if (monitor_port && sensor->needsAbsoluteZeroSearch ()) monitor_port ->println (" MONITOR : Searching for absolute zero." );
156
151
// search the absolute zero with small velocity
157
152
while (sensor->needsAbsoluteZeroSearch () && shaft_angle < _2PI){
158
153
loopFOC ();
159
- voltage_q = velocityIndexSearchPI (index_search_velocity - shaftVelocity ());
154
+ voltage_q = velocityPI (velocity_index_search - shaftVelocity ());
160
155
}
161
156
voltage_q = 0 ;
162
157
// disable motor
@@ -169,7 +164,7 @@ int BLDCMotor::absoluteZeroAlign() {
169
164
// remember zero electric angle
170
165
zero_electric_angle = electricAngle (zero_offset);
171
166
}
172
- // return bool is zero found
167
+ // return bool if zero found
173
168
return !sensor->needsAbsoluteZeroSearch () ? 1 : -1 ;
174
169
}
175
170
@@ -208,6 +203,9 @@ int BLDCMotor::initFOC() {
208
203
_delay (500 );
209
204
int exit_flag = alignSensor ();
210
205
_delay (500 );
206
+
207
+ if (monitor_port) monitor_port->println (" MONITOR: FOC init finished - motor ready." );
208
+
211
209
return exit_flag;
212
210
}
213
211
@@ -224,13 +222,16 @@ void BLDCMotor::loopFOC() {
224
222
// Behavior of this function is determined by the motor.controller variable
225
223
// It runs either angle, velocity or voltage loop
226
224
// - needs to be called iteratively it is asynchronous function
227
- void BLDCMotor::move (float target) {
225
+ // - if target is not set it uses motor.target value
226
+ void BLDCMotor::move (float new_target) {
227
+ // set internal target variable
228
+ if ( new_target != NOT_SET ) target = new_target;
228
229
// get angular velocity
229
230
shaft_velocity = shaftVelocity ();
230
231
// choose control loop
231
232
switch (controller) {
232
233
case ControlType::voltage:
233
- voltage_q = target;
234
+ voltage_q = target;
234
235
break ;
235
236
case ControlType::angle:
236
237
// angle set point
@@ -281,7 +282,7 @@ void BLDCMotor::setPhaseVoltage(float Uq, float angle_el) {
281
282
282
283
// if negative voltages change inverse the phase
283
284
// angle + 180degrees
284
- if (Uq < 0 ) angle_el += M_PI ;
285
+ if (Uq < 0 ) angle_el += _PI ;
285
286
Uq = abs (Uq);
286
287
287
288
// angle normalisation in between 0 and 2pi
@@ -296,7 +297,7 @@ void BLDCMotor::setPhaseVoltage(float Uq, float angle_el) {
296
297
// two versions possible
297
298
// centered around voltage_power_supply/2
298
299
float T0 = 1 - T1 - T2;
299
- // centered around 0
300
+ // pulled to 0 - better for low power supply voltage
300
301
// T0 = 0;
301
302
302
303
// calculate the duty cycles(times)
@@ -381,7 +382,7 @@ float BLDCMotor::normalizeAngle(float angle){
381
382
}
382
383
// determining if the enable pin has been provided
383
384
int BLDCMotor::hasEnable (){
384
- return enable_pin != 0 ;
385
+ return enable_pin != NOT_SET ;
385
386
}
386
387
387
388
@@ -391,6 +392,7 @@ int BLDCMotor::hasEnable(){
391
392
// PI controller function
392
393
float BLDCMotor::controllerPI (float tracking_error, PI_s& cont){
393
394
float Ts = (_micros () - cont.timestamp ) * 1e-6 ;
395
+
394
396
// quick fix for strange cases (micros overflow)
395
397
if (Ts <= 0 || Ts > 0.5 ) Ts = 1e-3 ;
396
398
@@ -406,6 +408,7 @@ float BLDCMotor::controllerPI(float tracking_error, PI_s& cont){
406
408
float d_voltage = voltage - cont.voltage_prev ;
407
409
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;
408
410
411
+
409
412
cont.voltage_prev = voltage;
410
413
cont.tracking_error_prev = tracking_error;
411
414
cont.timestamp = _micros ();
@@ -415,10 +418,7 @@ float BLDCMotor::controllerPI(float tracking_error, PI_s& cont){
415
418
float BLDCMotor::velocityPI (float tracking_error) {
416
419
return controllerPI (tracking_error, PI_velocity);
417
420
}
418
- // index search PI contoller
419
- float BLDCMotor::velocityIndexSearchPI (float tracking_error) {
420
- return controllerPI (tracking_error, PI_velocity_index_search);
421
- }
421
+
422
422
// P controller for position control loop
423
423
float BLDCMotor::positionP (float ek) {
424
424
// calculate the target velocity from the position error
@@ -429,38 +429,153 @@ float BLDCMotor::positionP(float ek) {
429
429
}
430
430
431
431
/* *
432
- * Debugger functions
432
+ * Monitoring functions
433
433
*/
434
- // function implementing the debugger setter
435
- void BLDCMotor::useDebugging (Print &print){
436
- debugger = &print; // operate on the address of print
437
- if (debugger )debugger ->println (" DEBUG : Serial debugger enabled!" );
434
+ // function implementing the monitor_port setter
435
+ void BLDCMotor::useMonitoring (Print &print){
436
+ monitor_port = &print; // operate on the address of print
437
+ if (monitor_port ) monitor_port ->println (" MONITOR : Serial monitor enabled!" );
438
438
}
439
439
// utility function intended to be used with serial plotter to monitor motor variables
440
440
// significantly slowing the execution down!!!!
441
441
void BLDCMotor::monitor () {
442
- if (!debugger ) return ;
442
+ if (!monitor_port ) return ;
443
443
switch (controller) {
444
444
case ControlType::velocity:
445
- debugger ->print (voltage_q);
446
- debugger ->print (" \t " );
447
- debugger ->print (shaft_velocity_sp);
448
- debugger ->print (" \t " );
449
- debugger ->println (shaft_velocity);
445
+ monitor_port ->print (voltage_q);
446
+ monitor_port ->print (" \t " );
447
+ monitor_port ->print (shaft_velocity_sp);
448
+ monitor_port ->print (" \t " );
449
+ monitor_port ->println (shaft_velocity);
450
450
break ;
451
451
case ControlType::angle:
452
- debugger ->print (voltage_q);
453
- debugger ->print (" \t " );
454
- debugger ->print (shaft_angle_sp);
455
- debugger ->print (" \t " );
456
- debugger ->println (shaft_angle);
452
+ monitor_port ->print (voltage_q);
453
+ monitor_port ->print (" \t " );
454
+ monitor_port ->print (shaft_angle_sp);
455
+ monitor_port ->print (" \t " );
456
+ monitor_port ->println (shaft_angle);
457
457
break ;
458
458
case ControlType::voltage:
459
- debugger ->print (voltage_q);
460
- debugger ->print (" \t " );
461
- debugger ->print (shaft_angle);
462
- debugger ->print (" \t " );
463
- debugger ->println (shaft_velocity);
459
+ monitor_port ->print (voltage_q);
460
+ monitor_port ->print (" \t " );
461
+ monitor_port ->print (shaft_angle);
462
+ monitor_port ->print (" \t " );
463
+ monitor_port ->println (shaft_velocity);
464
464
break ;
465
465
}
466
- }
466
+ }
467
+
468
+ int BLDCMotor::command (String user_command) {
469
+ // error flag
470
+ int errorFlag = 1 ;
471
+ // parse command letter
472
+ char cmd = user_command.charAt (0 );
473
+ // check if get command
474
+ char GET = user_command.charAt (1 ) == ' \n ' ;
475
+ // parse command values
476
+ float value = user_command.substring (1 ).toFloat ();
477
+
478
+ // apply the the command
479
+ switch (cmd){
480
+ case ' P' : // velocity P gain change
481
+ if (monitor_port) monitor_port->print (" PI velocity P: " );
482
+ if (!GET) PI_velocity.P = value;
483
+ if (monitor_port) monitor_port->println (PI_velocity.P );
484
+ break ;
485
+ case ' I' : // velocity I gain change
486
+ if (monitor_port) monitor_port->print (" PI velocity I: " );
487
+ if (!GET) PI_velocity.I = value;
488
+ if (monitor_port) monitor_port->println (PI_velocity.I );
489
+ break ;
490
+ case ' L' : // velocity voltage limit change
491
+ if (monitor_port) monitor_port->print (" PI velocity voltage limit: " );
492
+ if (!GET)PI_velocity.voltage_limit = value;
493
+ if (monitor_port) monitor_port->println (PI_velocity.voltage_limit );
494
+ break ;
495
+ case ' R' : // velocity voltage ramp change
496
+ if (monitor_port) monitor_port->print (" PI velocity voltage ramp: " );
497
+ if (!GET) PI_velocity.voltage_ramp = value;
498
+ if (monitor_port) monitor_port->println (PI_velocity.voltage_ramp );
499
+ break ;
500
+ case ' F' : // velocity Tf low pass filter change
501
+ if (monitor_port) monitor_port->print (" LPF velocity time constant: " );
502
+ if (!GET) LPF_velocity.Tf = value;
503
+ if (monitor_port) monitor_port->println (LPF_velocity.Tf );
504
+ break ;
505
+ case ' K' : // angle loop gain P change
506
+ if (monitor_port) monitor_port->print (" P angle P value: " );
507
+ if (!GET) P_angle.P = value;
508
+ if (monitor_port) monitor_port->println (P_angle.P );
509
+ break ;
510
+ case ' N' : // angle loop gain velocity_limit change
511
+ if (monitor_port) monitor_port->print (" P angle velocity limit: " );
512
+ if (!GET) P_angle.velocity_limit = value;
513
+ if (monitor_port) monitor_port->println (P_angle.velocity_limit );
514
+ break ;
515
+ case ' C' :
516
+ // change control type
517
+ if (monitor_port) monitor_port->print (" Contoller type: " );
518
+
519
+ if (GET){ // if get commang
520
+ switch (controller){
521
+ case ControlType::voltage:
522
+ if (monitor_port) monitor_port->println (" voltage" );
523
+ break ;
524
+ case ControlType::velocity:
525
+ if (monitor_port) monitor_port->println (" velocity" );
526
+ break ;
527
+ case ControlType::angle:
528
+ if (monitor_port) monitor_port->println (" angle" );
529
+ break ;
530
+ }
531
+ }else { // if set command
532
+ switch ((int )value){
533
+ case 0 :
534
+ if (monitor_port) monitor_port->println (" voltage" );
535
+ controller = ControlType::voltage;
536
+ break ;
537
+ case 1 :
538
+ if (monitor_port) monitor_port->println (" velocity" );
539
+ controller = ControlType::velocity;
540
+ break ;
541
+ case 2 :
542
+ if (monitor_port) monitor_port->println (" angle" );
543
+ controller = ControlType::angle;
544
+ break ;
545
+ default : // not valid command
546
+ errorFlag = 0 ;
547
+ }
548
+ }
549
+ break ;
550
+ case ' V' : // get current values of the state variables
551
+ switch ((int )value){
552
+ case 0 : // get voltage
553
+ if (monitor_port) monitor_port->print (" Uq: " );
554
+ if (monitor_port) monitor_port->println (voltage_q);
555
+ break ;
556
+ case 1 : // get velocity
557
+ if (monitor_port) monitor_port->print (" Velocity: " );
558
+ if (monitor_port) monitor_port->println (shaft_velocity);
559
+ break ;
560
+ case 2 : // get angle
561
+ if (monitor_port) monitor_port->print (" Angle: " );
562
+ if (monitor_port) monitor_port->println (shaft_angle);
563
+ break ;
564
+ case 3 : // get angle
565
+ if (monitor_port) monitor_port->print (" Target: " );
566
+ if (monitor_port) monitor_port->println (target);
567
+ break ;
568
+ default : // not valid command
569
+ errorFlag = 0 ;
570
+ }
571
+ break ;
572
+ default : // target change
573
+ if (monitor_port) monitor_port->print (" Target : " );
574
+ target = user_command.toFloat ();
575
+ if (monitor_port) monitor_port->println (target);
576
+ }
577
+ // return 0 if error and 1 if ok
578
+ return errorFlag;
579
+ }
580
+
581
+
0 commit comments