Skip to content

Commit 674d1a4

Browse files
committed
FEAT added D controller component and a bit od restruscturing
1 parent f6430f3 commit 674d1a4

File tree

4 files changed

+115
-67
lines changed

4 files changed

+115
-67
lines changed

keywords.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ _round KEYWORD3
2121
monitor KEYWORD3
2222
command KEYWORD3
2323

24-
PI_velocity KEYWORD2
24+
PID_velocity KEYWORD2
2525
LPF_velocity KEYWORD2
2626
P_angle KEYWORD2
2727

@@ -77,9 +77,9 @@ UNKNOWN KEYWORD2
7777

7878
P KEYWORD2
7979
I KEYWORD2
80+
D KEYWORD2
8081
Tf KEYWORD2
8182
voltage_limit KEYWORD2
82-
voltage_ramp KEYWORD2
8383
velocity_limit KEYWORD2
8484
voltage_power_supply KEYWORD2
8585
voltage_sensor_align KEYWORD2

src/BLDCMotor.cpp

Lines changed: 90 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,14 @@ BLDCMotor::BLDCMotor(int phA, int phB, int phC, int pp, int en)
2121

2222
// Velocity loop config
2323
// 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;
3032

3133
// velocity low pass filter
3234
LPF_velocity.Tf = DEF_VEL_FILTER_Tf;
@@ -38,7 +40,7 @@ BLDCMotor::BLDCMotor(int phA, int phB, int phC, int pp, int en)
3840
P_angle.P = DEF_P_ANGLE_P;
3941

4042
// maximum angular velocity to be used for positioning
41-
velocity_limit = DEF_P_ANGLE_VEL_LIM;
43+
velocity_limit = DEF_VEL_LIM;
4244
// maximum voltage to be set to the motor
4345
voltage_limit = voltage_power_supply;
4446

@@ -78,6 +80,8 @@ void BLDCMotor::init() {
7880

7981
// sanity check for the voltage limit configuration
8082
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;
8185

8286
_delay(500);
8387
// enable motor
@@ -169,7 +173,7 @@ int BLDCMotor::absoluteZeroAlign() {
169173
// search the absolute zero with small velocity
170174
while(sensor->needsAbsoluteZeroSearch() && shaft_angle < _2PI){
171175
loopFOC();
172-
voltage_q = velocityPI(velocity_index_search - shaftVelocity());
176+
voltage_q = velocityPID(velocity_index_search - shaftVelocity());
173177
}
174178
voltage_q = 0;
175179
// disable motor
@@ -192,23 +196,14 @@ int BLDCMotor::absoluteZeroAlign() {
192196
// shaft angle calculation
193197
float BLDCMotor::shaftAngle() {
194198
// if no sensor linked return 0
195-
//if(!sensor) return 0;
199+
if(!sensor) return 0;
196200
return sensor->getAngle();
197201
}
198202
// shaft velocity calculation
199203
float BLDCMotor::shaftVelocity() {
200204
// 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);
212207
}
213208
// Electrical angle calculation
214209
float BLDCMotor::electricAngle(float shaftAngle) {
@@ -220,7 +215,7 @@ float BLDCMotor::electricAngle(float shaftAngle) {
220215
FOC functions
221216
*/
222217
// 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 ) {
224219
int exit_flag = 1;
225220
// align motor if necessary
226221
// alignment necessary for encoders!
@@ -269,13 +264,13 @@ void BLDCMotor::move(float new_target) {
269264
// include angle loop
270265
shaft_angle_sp = target;
271266
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);
273268
break;
274269
case ControlType::velocity:
275270
// velocity set point
276271
// include velocity loop
277272
shaft_velocity_sp = target;
278-
voltage_q = velocityPI(shaft_velocity_sp - shaft_velocity);
273+
voltage_q = velocityPID(shaft_velocity_sp - shaft_velocity);
279274
break;
280275
case ControlType::velocity_openloop:
281276
// velocity control in open loop
@@ -420,38 +415,70 @@ int BLDCMotor::hasEnable(){
420415
return enable_pin != NOT_SET;
421416
}
422417

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+
423437

424438
/**
425439
Motor control functions
426440
*/
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;
431446
// quick fix for strange cases (micros overflow)
432447
if(Ts <= 0 || Ts > 0.5) Ts = 1e-3;
433448

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;
439464

440465
// antiwindup - limit the output voltage_q
441466
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;
445467

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;
446471

447-
cont.voltage_prev = voltage;
472+
// saving for the next pass
473+
cont.integral_prev = integral;
474+
cont.output_prev = voltage;
448475
cont.tracking_error_prev = tracking_error;
449-
cont.timestamp = _micros();
476+
cont.timestamp = now_us;
450477
return voltage;
451478
}
452479
// 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);
455482
}
456483

457484
// P controller for position control loop
@@ -468,12 +495,13 @@ float BLDCMotor::positionP(float ek) {
468495
// it uses voltage_limit variable
469496
void BLDCMotor::velocityOpenloop(float target_velocity){
470497
// get current timestamp
471-
long now_us = _micros();
498+
unsigned long now_us = _micros();
472499
// calculate the sample time from last call
473500
float Ts = (now_us - open_loop_timestamp) * 1e-6;
474501

475502
// calculate the necessary angle to achieve target velocity
476503
shaft_angle += target_velocity*Ts;
504+
477505
// set the maximal allowed voltage (voltage_limit) with the necessary angle
478506
setPhaseVoltage(voltage_limit, electricAngle(shaft_angle));
479507

@@ -486,7 +514,7 @@ void BLDCMotor::velocityOpenloop(float target_velocity){
486514
// it uses voltage_limit and velocity_limit variables
487515
void BLDCMotor::angleOpenloop(float target_angle){
488516
// get current timestamp
489-
long now_us = _micros();
517+
unsigned long now_us = _micros();
490518
// calculate the sample time from last call
491519
float Ts = (now_us - open_loop_timestamp) * 1e-6;
492520

@@ -517,13 +545,15 @@ void BLDCMotor::useMonitoring(Print &print){
517545
void BLDCMotor::monitor() {
518546
if(!monitor_port) return;
519547
switch (controller) {
548+
case ControlType::velocity_openloop:
520549
case ControlType::velocity:
521550
monitor_port->print(voltage_q);
522551
monitor_port->print("\t");
523552
monitor_port->print(shaft_velocity_sp);
524553
monitor_port->print("\t");
525554
monitor_port->println(shaft_velocity);
526555
break;
556+
case ControlType::angle_openloop:
527557
case ControlType::angle:
528558
monitor_port->print(voltage_q);
529559
monitor_port->print("\t");
@@ -558,8 +588,9 @@ int BLDCMotor::command(String user_command) {
558588
switch(cmd){
559589
case 'P': // velocity P gain change
560590
case 'I': // velocity I gain change
591+
case 'D': // velocity D gain change
561592
case 'R': // velocity voltage ramp change
562-
if(monitor_port) monitor_port->print(" PI velocity| ");
593+
if(monitor_port) monitor_port->print(" PID velocity| ");
563594
break;
564595
case 'F': // velocity Tf low pass filter change
565596
if(monitor_port) monitor_port->print(" LPF velocity| ");
@@ -578,24 +609,29 @@ int BLDCMotor::command(String user_command) {
578609
switch(cmd){
579610
case 'P': // velocity P gain change
580611
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);
583614
break;
584615
case 'I': // velocity I gain change
585616
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);
588629
break;
589630
case 'L': // velocity voltage limit change
590631
if(monitor_port) monitor_port->print("volt_limit: ");
591632
if(!GET)voltage_limit = value;
592633
if(monitor_port) monitor_port->println(voltage_limit);
593634
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;
599635
case 'F': // velocity Tf low pass filter change
600636
if(monitor_port) monitor_port->print("Tf: ");
601637
if(!GET) LPF_velocity.Tf = value;
@@ -615,7 +651,7 @@ int BLDCMotor::command(String user_command) {
615651
// change control type
616652
if(monitor_port) monitor_port->print("Control: ");
617653

618-
if(GET){ // if get commang
654+
if(GET){ // if get command
619655
switch(controller){
620656
case ControlType::voltage:
621657
if(monitor_port) monitor_port->println("voltage");
@@ -626,6 +662,8 @@ int BLDCMotor::command(String user_command) {
626662
case ControlType::angle:
627663
if(monitor_port) monitor_port->println("angle");
628664
break;
665+
default:
666+
if(monitor_port) monitor_port->println("open loop");
629667
}
630668
}else{ // if set command
631669
switch((int)value){

src/BLDCMotor.h

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,16 @@ enum FOCModulationType{
3434
};
3535

3636
/**
37-
* PI controller structure
37+
* PID controller structure
3838
*/
39-
struct PI_s{
39+
struct PID_s{
4040
float P; //!< Proportional gain
4141
float I; //!< Integral gain
42-
float voltage_ramp; //!< Maximum speed of change of the output value
42+
float D; //!< Derivative gain
4343
long timestamp; //!< Last execution timestamp
44-
float voltage_prev; //!< last controller output value
44+
float integral_prev; //!< last integral component value
45+
float output_prev; //!< last pid output value
46+
float output_ramp; //!< Maximum speed of change of the output value
4547
float tracking_error_prev; //!< last tracking error value
4648
};
4749

@@ -162,7 +164,7 @@ class BLDCMotor
162164
// configuration structures
163165
ControlType controller; //!< parameter determining the control loop to be used
164166
FOCModulationType foc_modulation;//!< parameter derterniming modulation algorithm
165-
PI_s PI_velocity;//!< parameter determining the velocity PI configuration
167+
PID_s PID_velocity;//!< parameter determining the velocity PI configuration
166168
P_s P_angle; //!< parameter determining the position P configuration
167169
LPF_s LPF_velocity;//!< parameter determining the velocity Lpw pass filter configuration
168170

@@ -270,17 +272,24 @@ class BLDCMotor
270272
/** determining if the enable pin has been provided */
271273
int hasEnable();
272274

275+
/**
276+
* Low pass filter function - iterative
277+
* @param input - singal to be filtered
278+
* @param lpf - LPF_s structure with filter parameters
279+
*/
280+
float lowPassFilter(float input, LPF_s& lpf);
281+
273282
// Motion control functions
274283
/**
275284
* Generic PI controller function executing one step of a controller
276-
* receives tracking error and PI_s structure and outputs the control signal
285+
* receives tracking error and PID_s structure and outputs the control signal
277286
*
278287
* @param tracking_error Current error in between target value and mesasured value
279-
* @param controller PI_s structure containing all the necessary PI controller config and variables
288+
* @param controller PID_s structure containing all the necessary PI controller config and variables
280289
*/
281-
float controllerPI(float tracking_error, PI_s &controller);
290+
float controllerPID(float tracking_error, PID_s &controller);
282291
/** Velocity PI controller implementation */
283-
float velocityPI(float tracking_error);
292+
float velocityPID(float tracking_error);
284293
/** Position P controller implementation */
285294
float positionP(float ek);
286295

src/defaults.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33

44
#define DEF_POWER_SUPPLY 12.0 //!< default power supply voltage
55
// velocity PI controller params
6-
#define DEF_PI_VEL_P 0.5 //!< default PI controller P value
7-
#define DEF_PI_VEL_I 10 //!< default PI controller I value
8-
#define DEF_PI_VEL_U_RAMP 1000 //!< default PI controller voltage ramp value
6+
#define DEF_PID_VEL_P 0.5 //!< default PID controller P value
7+
#define DEF_PID_VEL_I 10 //!< default PID controller I value
8+
#define DEF_PID_VEL_D 0 //!< default PID controller D value
9+
#define DEF_PID_VEL_U_RAMP 1000 //!< default PID controller voltage ramp value
910
// angle P params
1011
#define DEF_P_ANGLE_P 20 //!< default P controller P value
11-
#define DEF_P_ANGLE_VEL_LIM 20 //!< angle velocity limit default
12+
#define DEF_VEL_LIM 20 //!< angle velocity limit default
1213
// index search
1314
#define DEF_INDEX_SEARCH_TARGET_VELOCITY 1 //!< default index search velocity
1415
// align voltage

0 commit comments

Comments
 (0)