## PID motor control

20 posts / 0 new
Author
Message

Hi guys
codes below control the motor speed with PID but I have a problem.If I change the speed like rpm=1000 and then rpm= 100.PID calculation produce very big negative value and this is why I cant set motor speed.How can I do it.

```rpm = bldcObj->func.Get_RPM(bldcObj);
//rpm = kalman1Dobj->func.Calculate(kalman1Dobj,rpm);
err = setRpm - rpm;
pwm = (int16_t)pidObj->func.Calculate(pidObj,err);

if(pwm>3000) pwm=3000;
else if(pwm<0) pwm=0;

bldcObj->func.Set_Duty_Cycle(bldcObj,pwm);```
This topic has a solution.
Last Edited: Fri. Nov 8, 2019 - 04:28 PM

Emrah Duatepe wrote:
.If I change the speed like rpm=1000 and then rpm= 100.PID calculation produce very big negative value

You mean something like -900rpm ???

What where you expecting it to be?   Perhaps you could tell us more about your plant, and what PID parameters your using and your experience using PID controls.

Jim

Ki=0.2 Kp=0,Kd=0;

Plant equation related between rpm and pwm  -> pwm=(2.083*rpm + 176.9)

System works good.But when I want to change speed and this diffference is big like first 1000 and then like 100 rpm in this case

```err = setRpm - rpm;
pwm = (int16_t)pidObj->func.Calculate(pidObj,err);```

This algorithm produce big negative value and I can't use negative value with pwm.Maybe I need a algorithm use set rpm down step by step like 1000.. 999...100 in this case probably I wont get negative value. How solution I need ,How proffesionals do it?

Emrah Duatepe wrote:
with PID
What "PID" class is this? We see you call:

`      pwm = (int16_t)pidObj->func.Calculate(pidObj,err);`

but where is the definition of the class of which pidObj is an instance? Specifically what does Calculate() look like?

Presumably the idea is to make a smooth transition from what PWM is now to what it needs to be? Is the current PWM setting held as a member within the pidObj class?

Emrah Duatepe wrote:
Ki=0.2 Kp=0,Kd=0;

So if I understand this correctly, you are only using integral control for this?  Very odd, what is the application?

Normally one uses proportional control with some minor integral added in to reduce errors over time, dampening may or may not be needed depending on plant reaction time to controls.

Kp=1, Ki=0.01, Kd=0 to begin and limit the range of Ki output to a set limit.

Jim

Emrah Duatepe wrote:
If I change the speed like rpm=1000 and then rpm= 100

So you're demanding an instantaneous, large reduction in the RPM ?

PID calculation produce very big negative value

So it's doing like in the old Westerns where they try to stop a runaway train by putting the locomotive into reverse ... ?

Top Tips:

1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...

Hi guys ,  this is inside pid function

```static float Calculate(pid_t *obj, float err)
{
float out;
/* y[n] = y[n-1] + A0 * x[n] + A1 * x[n-1] + A2 * x[n-2]  */
out = (obj->var.A0 * err) + (obj->var.A1 * obj->var.state) + (obj->var.A2 * obj->var.state) + (obj->var.state);

/* Update state */
obj->var.state = obj->var.state;
obj->var.state = err;
obj->var.state = out;

return out;

}
```

and this is struct belong pid algorithm

```struct
{
float A0;          /**< The derived gain, A0 = Kp + Ki + Kd . */
float A1;          /**< The derived gain, A1 = -Kp - 2Kd. */
float A2;          /**< The derived gain, A2 = Kd . */
float state;    /**< The state array of length 3. */
float Kp;               /**< The proportional gain. */
float Ki;               /**< The integral gain. */
float Kd;               /**< The derivative gain. */
}var;```

awneil wrote:

So you're demanding an instantaneous, large reduction in the RPM ?

Yes I am demanding large reduction in the RPM and Motor should get new RPM slowly and with suitable speed.

Last Edited: Wed. Nov 6, 2019 - 05:31 PM

If I change the rpm from 1000 to 100

`err = setRpm - rpm; `

err = 100 - 1000 = -900 and this change caused a big err .

`   pwm = (int16_t)pidObj->func.Calculate(pidObj,err);`

and algorithm will create a big negative value to set motor speed for 100 and I cant use this negative value in appropriate way.Maybe you have better solutions for it.

Emrah Duatepe wrote:

awneil wrote:

So you're demanding an instantaneous, large reduction in the RPM ?

Yes I am demanding large reduction in the RPM and Motor should get new RPM slowly and with suitable speed.

You should slowly lower your desired RPM from 1000 to 100 over the time you wish your RPM to slowly change.

If you don't know my whole story, keep your mouth shut.

If you know my whole story, you're an accomplice. Keep your mouth shut. If you get a negative value, then set it to zero.

Don't confuse the physical limits with math calculations.

If I'm sitting at the red light & calculate I need to accelerate to 200 mph in 4 seconds, it calculates my engine must produce 800HP

Since I only have 100HP engine, it hits its limit and takes its time getting to 200 mph.

This can cause integrator windup....so take a look at that term.

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Emrah Duatepe wrote:
Ki=0.2 Kp=0,Kd=0;

Emrah Duatepe wrote:
Yes I am demanding large reduction in the RPM and Motor should get new RPM slowly and with suitable speed.

Your PID values are all wrong for the action you desire, you have no P, large I and no D in your params, it sounds like you want P=1, i=0 and a large D to be a foot on the brake pedal so changes happen sloooowwwlllyyyyy.

Jim

Last Edited: Wed. Nov 6, 2019 - 08:00 PM

Placing a clamp around the PWM is the right thing but you probably also want to clamp the value of the absolute integral term so you don't get "reset windup".

EDIT: and if I was doing this I would linearize about something so if that is 100 rpm, figure out what the associated steady-state PWM is then clamp symmetrically about that.   Another thing you can do is add a prefilter so that when you change from 100 rpm to 1000 rpm the set-point to the loop looks like 900*[1 - exp(-t/tau)].

Last Edited: Thu. Nov 7, 2019 - 01:32 AM

Maybe I need to change rpm slowly like Torby said or MattRW told

MattRW wrote:
EDIT: and if I was doing this I would linearize about something so if that is 100 rpm, figure out what the associated steady-state PWM is then clamp symmetrically about that.   Another thing you can do is add a prefilter so that when you change from 100 rpm to 1000 rpm the set-point to the loop looks like 900*[1 - exp(-t/tau)].
I didn't understand excatly this sentence maybe you can explain for me with more detail.How prefilter? Probably I don't have information sufficiently.

Also I got the Kp,Ki,Kd in Matlab PID Tuner.Also I tried different numbers but better is just Ki equals any number 0.08 and 0.5.  0.08 is too slow 0.02 is better.

Probably because of time difference in countries I couldn't respond quick.

pid with prefilter follows.   Think about making pfl = 1.0, 0,1., 0.01, ...

```float pfx = 0.0;
float pfl = 0.01;

float filtered_set_point(float set_point) {
pfx = (1.0 - pfl)*pfx + pfl*set_point;
return pfx;
}

float kp = 0.0;
float ki = 1.0;
float kd = 0.0;

float pid(float error) {
float command;
/* ... */
return command;
}

void main() {
float measurment;
float set_point;
float command;

while (1) {
measurement = get_measurement();
set_point = get_set_point();
set_point = filtered_set_point(set_point);
error = set_point - measurement;
command = pid(error);
output_command(command);
}
}
```

MattRW  it didn't work actually I can't set the setPoint for any number that smaller then current rpm.I can set it higher value but if I try like 990 - 1000 = -10 in this case pwm getting negative.