Improving embedded PI controller for DC motor speed control - Page 1
Forum section: electronics / general

author: XaviPacheco
author_rank: Regular Contributor
timestamp: November 22, 2018, 01:44:41 pm
content: I'm posting my C code so you can give me a hand directly on it.Some caveats:1- Kp and Ki are not optimal yet, they are just trial and error values. I haven't implemented any formal tuning method yet like step response.2- The speed feedback is the one described in one of my previous posts about the 6 pulses per rev sensor.3- The PI loop is running every 20 ms by using timer interrupt.4- 0 means 0% duty cycle, 800 means 100% duty cycle.5- 400 RPM is the initial setpoint, so it yields a big error causing a no desired sudden change at the beginning.6- It's apparently working well in a range of 400-4000 RPM as intended, but...I need a way to improve the code so my startup and stop response are not so abrupt. In other words, I need a soft start/stop. Let's imagine we are on 2000 RPM and suddenly the user gives the command to stop the motor, that is, a setpoint of 0 RPM. I can't allow the motor to stop so fast. The same for the startup, from 0 to 400 RPM. Between 400 and 4000 RPM, the control is smooth because every time I want to increase the speed, the setpoint will change in step of 50. That is, 400, 450, 500, 550, 600 and so on.What I think is that this is not directly involved with the PI controller. I know that lowering the Kp gain allows me to have soft start, because the system response will be slow. But the issue is the whole controller then becomes slow and I want the system to fastly compensate any change of the load.Code:float error=0;int32_t target_RPM=0;int32_t current_RPM = 0;int32_t duty_cycle=0;float Kp = 0.2;float Ki = 0.010;float integral = 0;//20 ms loopvoid HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {// This callback is automatically called by the HAL on the UEV eventif(htim->Instance == TIM6) {//Get current RPMcurrent_RPM = read_RPM();//Get the errorerror = target_RPM - current_RPM;//Calculate the integralintegral = integral + (Ki*error);if (integral > 800.0f) // check for integral windup and correct for upper limitintegral = 800;if (integral < 0)//check for integral windup and correct for lower limitintegral = 0;//Calculate the Control Variableduty_cycle = (Kp*error) + integral;//Limit the Control Variable to within 0-800if(duty_cycle>800){duty_cycle = 800;}else if (duty_cycle<0){duty_cycle = 0;}htim1.Instance->CCR1 = duty_cycle;}}

author: Siwastaja
author_rank: Super Contributor
timestamp: November 22, 2018, 02:42:34 pm
content: It's very typical to step the setpoint, like this:int desired_setpoint;int actual setpoint;control_isr(){if(desired_setpoint > actual_setpoint) actual_setpoint += RAMP_SPEED;else if(desired_setpoint < actual_setpoint) actual_setpoint -= RAMP_SPEED;}(works as is with RAMP_SPEED=1. For bigger values, needs a bit more logic to work properly - left as a homework.)Though, you may want to confirm that your PID is at least somehow stable - notcatastrophic- even when you bypass the ramping (or use a much higher ramping rate than you finally end up using).For the initial jerk, set actual_setpoint to 0 and let the same ramp handle it. If you want to support the "power up the already rotating motor" corner case, use an init function that measures the actual speed before enabling power, and sets actual_setpoint to this measured speed. Then the ramp takes care of changing it to whatever initial value you want.

author: XaviPacheco
author_rank: Regular Contributor
timestamp: November 22, 2018, 03:03:58 pm
content: I was thinking of enabling a piece of code that does the ramping only for the start and stop conditions. That is, to remove the PI controller in these conditions and enabling it in the range of 400-4000 RPM because in this range the PI controller works well. This way I can also get rid of the bad behavior of the PI under low speed. I mean, with 6 pulses/rev, the PI is not good with speeds below 300 RPM

author: Kjelt
author_rank: Super Contributor
timestamp: November 22, 2018, 03:11:17 pm
content: Ah this is something I like to tackle myself in the near future but for now I am missing the time.But I have looked shortly in this topic last year out of interest and talked to some guys with knowledge in this field and they told me that you need multiple PID's to do it correctly.So you can look at this presentation for instance where they have three PIDs , one for Position, One for Speed and One for Torque.They ensure that the motor does not get to much "jerk" as you now experience.It is quite tricky and still looking if some pro code shows up somewhere.Good luck.http://www.techtrends.ru/docs/delta/servoprivody_asda_ecma_dmcnet/ASD-M/Tuning_ASDA_Series_Servo_Systems.pdf

author: rstofer
author_rank: Super Contributor
timestamp: November 22, 2018, 04:06:35 pm
content: Quote from: XaviPacheco on November 22, 2018, 01:44:41 pmSearch for Brian Douglas videos and have fun!https://www.youtube.com/user/ControlLectures/playlistsTurn down the P gain and add a D term to handle perturbations.There is a whole series of videos on discrete time controllers and various strategies with a lot of MATLAB demonstrations. The point being that the error term is not tracking the instantaneous error, it is stuck at the error from the last measurement (zero order hold) and this has profound implications for optimal control (and the math gets ugly!). Think about the integral term: It is winding up based on an obsolete measurement. Whatever change might have occurred in an analog control hasn't happened in a discrete control. Obviously, there are ways to work around the problem because, these days, discrete time is the most likely approach.

author: mikerj
author_rank: Super Contributor
timestamp: November 22, 2018, 05:01:30 pm
content: You could dynamically change the loop gains, e.g. a change in setpoint could trigger the loop gains to be lowered to some value that gives a more sluggish response, then the gains can be increased back to their final values over some time period.

author: Siwastaja
author_rank: Super Contributor
timestamp: November 22, 2018, 05:50:28 pm
content: Quote from: mikerj on November 22, 2018, 05:01:30 pmWouldn't do that without some very specific reasons - more complex, and, most importantly, is a typical case of "control something indirectly" approach, while the direct approach is in plain sight (actually, exists for just this purpose).What the OP wants to do is to smoothly ramp up the motor for smooth start/stop. This desire is directly communicated to the PID controller using the setpoint. That's what the setpoint is for, to command it to the exact speed you want! (Which, in this case, would be a ramp function of your choice instead of a constant.) You don't need totunea different set of rules or model/test how they affect the actual ramping; instead, once your PID is tuned to work against normal physical variations, just implement the exact ramp or curve you wantdirectly.Then, you can focus on tuning the loop to do what's it's there for - to feedback the physical system, to give the output you specify it to do, not to give something else.Usually, feeding "impossible" data to the controller is not wise; the mechanical system cannot change its speed in zero time either due to inertia - so it makes sense to have at leastsomeramp, even very quick, every time you change the setpoint significantly. But, testing the stability with excessively quick setpoint changes may be a good idea, since it's easier to do that, than to emulate very large physical changes without special equipment such as strong brakes.RE three loops:usually, excluding very high-end systems, the torque loop is done by very fast motor phase current control, which never has a D term AFAIK, and sometimes isn't a PI controller either, but can be a hysteretic or peak current mode control of some sort, for example, in which case it doesn't need any tuning. This is similar and exactly analoguous to current mode switch mode power supplies which control their inductor current.In a high-end system, yet another loop can be used with a torque sensor, but it would probably be slower than the motor-current based torque loop, which is needed in any case.Position loop is naturally needed only if you need to accurately and quickly control position, such as in a CNC machine. In an electric vehicle, for example, it wouldn't be of much use. It doesn't need to be a PID loop, either, but can be something simpler if exact and quick "keep position regardless of external forces moving the system" feature is not needed.A PID controller is a very basic "building block", and often you even create something similar without even realizing it. A large number of control loops in a system doesn't mean it's necessarily complex. But, the literature around PID control may seem like black magic and maths-heavy first, just like AC motor control theory, which can be even more difficult to grasp.Don't worry, it actually isn't too hard, this is just a conspiracy to keep it black art mastered by the few. Now this is a joke, but I'm serious in that I never got forward by reading PID control theory, and wasted tens and tens of hours on it. After actually implementing something out of my head and then refining it, then suddenly realizing: I have implemented a PID controller - some of the theory started to make sense, and some of the theory started looking like something written by someone who has absolutely no idea what they are talking about, but "mentally copypasting" what they have read from literature as well.

author: rstofer
author_rank: Super Contributor
timestamp: November 22, 2018, 06:24:03 pm
content: Quote from: Siwastaja on November 22, 2018, 05:50:28 pmThat's why I posted the link to the Brian Douglas videos above. There are dozens of videos looking at control systems from a lot of perspectives. Yes, it will take time to go through them. The path to convert from f(t)->f(s)->f(z) is some pretty deep math but it all begins to make sense in the videos. Among other things, the author shows how to get the transfer function for the plant and this function limits how responsive the control system can get. It there are tons of inertia, you can't overcome that in short time without a lot of control action. The physics just gets in the way. He also shows experiments using MATLAB and a small robotic car and with a pre-manufactured heating gadget:https://www.pololu.com/product/3125/resourceshttps://tclab.readthedocs.io/en/latest/notebooks/01_TCLab_Overview.htmlAvailable at Amazon for $35.As the author points out, nobody does the math by hand today. We use MATLAB or Python and we can experiment with settings until we get what we want. MATLAB is especially useful. In fact, it's elegant!One set of experiments on the Pololu robot car demonstrates how to get the impulse transfer function of the vehicle using the rate gyro in the controller. His experiment at tracking to a target despite significant perturbations is really interesting.Mostly people who code PID loops aren't all that interested in optimal control and certainly don't want to learn/use the math required to do so. And that's why there are heuristic methods like Ziegler-Nichols among many others.I haven't played with this stuff since I was in college (prior to '73) and it was darn difficult because we simply didn't have the tools. We had slide rules, the Spirule and a textbook. We didn't have modeling software and we didn't even have approachable test systems. The courses were underwhelming. With MATLAB I have found renewed interest. The videos are a great resource!https://www.youtube.com/user/ControlLectures/videosAnother great resource:

author: Jeroen3
author_rank: Super Contributor
timestamp: November 22, 2018, 07:31:49 pm
content: Quote from: XaviPacheco on November 22, 2018, 01:44:41 pmSo, you need is some setpoint ramping?You can use a averaging filter on the setpoint. You can do a ramp.But the cascaded/summated system is best if you need to keep multiple quantities in control. (speed, jerk, position, torque (limit), end stop)And although this seems complicated, it actually is not (if you use properly modulated code).

author: rstofer
author_rank: Super Contributor
timestamp: November 22, 2018, 09:07:23 pm
content: There are some S curve projects around. The idea is that the motor starts out slowly, ramps quickly and slows as it reaches the setpoint.Google for 's curve motor control'This can be used to provide the setpoint and let the PID deal with the actual motion.