int16_t CalculatePID(MotorHandleTypeDef *motor)
    float error = motor->TargetSpeed-motor->Speed;
    /// calculate total error
    /// Check if the calculated total error value is in boundries
    else if(motor->PID.TotalError<-motor->PID.MaxTotalError)
    /// Calculate the result of PID
    float duty=(motor->PID.P*error) + (motor->PID.I*motor->PID.TotalError)+(motor->PID.D*(error-motor->PID.PreviousError));
    else if(duty<-1)

    /// Check if the Calculated Duty values are in boundries
    else if(duty<-motor->MaxDuty)
    /// Return calculated value
    return (int16_t)duty;

Hi everyone.

I am trying to make an efficient dc motor speed controller and this is my PID update function. I am running my update loop in 1 kHz. The DC Motor I am using is 24 VDC 100 Watt with 6000 CPR quadrature encoder. I am using Single Dimensional Kalman Filter to calculate motor speed that is running in 2 kHz. With this method there is almost no delay and ripple in speed calculation yet I am keeping my pid frequency lower than encoder update frequency to avoid errors that can be caused by the lag. I have tuned the PID parameters using Genetic Algorithm by using 400 individuals so I am thinking that the parameters are almost at their best. I am also applying speed feed forward control that's coefficient is 0.95.

Open loop step response of the motor has a rise time of 150 ms and the best rise time that I get with PID is 55 ms. I have posted one the output samples for lower 10 and 20 RPMs. (Dont worry about the overshoot. There is a motion planner on higher control level so it will be tolarated) Pid Sample

I would like to know if there is a way to lower this rise time to around 30ms or is this the best I can get from a brushed DC motor?

  • $\begingroup$ Don't saturate the PID input (the error). Rather, you ought to apply saturation to the PID output (feedback duty) and let the integral know what's going on by implementing the anti-windup. Also, the way the derivative is coded is kind of naive. $\endgroup$ – Ugo Pattacini Jan 16 at 11:57
  • 1
    $\begingroup$ I don't think I am saturating the input and there is an anti wind up control in the code too. there is also saturation control at the output of pid. What is the correct way to code derivative term? Kp is Zero by the way $\endgroup$ – Yahya Sevikoğlu Jan 16 at 12:16
  • $\begingroup$ You're right! Sorry, I got confused between error and total_error. Concerning your question, do you have a model of your physical system? Having used a global optimization tool (GA), your intuition on the best estimates of gains is likely true. Nonetheless, you might exploit the physical properties of the system and run some sort of traditional control techniques around the model. $\endgroup$ – Ugo Pattacini Jan 16 at 12:27

Besides the control code, I wonder whether the physics is worth a look:

  1. Is there enough instantaneous torque to accelerate the rotor's moment of inertia as fast as you want?
  2. The torque is proportional to the current. Slow current risetime will give you slow acceleration.
  3. dI/dt = V/L. The motor inductance (L) limits how fast the current can increase (dI/dt). Your 24 VDC motor might briefly tolerate a voltage (V) higher than 24 V -- if you trust your control code not to keep it high for long!
  • $\begingroup$ I think your approach is right because when I monitor motor voltage and speed, motor speed don't change for at least 5 ms despite the motor voltage keeps rising. I also did run the motor at 28.4V and got no markable change with rise time. Maybe it is time for me immigrate to brushless dc motor. Thanks for your answer. $\endgroup$ – Yahya Sevikoğlu Jan 18 at 8:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.