@@ -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
193197float 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
199203float 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
214209float 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
469496void 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
487515void 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){
517545void 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){
0 commit comments