Pages: [1] 2   Go Down
Author Topic: PID Library motor control example?  (Read 7782 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Sr. Member
****
Karma: 0
Posts: 295
Got Karma?
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi - I'm having some trouble setting up the PID library to use for motor control. Does anyone have a sketch/code they would be willing to share?

I am running a DC motor with encoder, etc. and want to see if I can do accurate positioning with the PID library.

Thanks!

--Roy
Logged

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 331
Posts: 16459
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Position control or speed control? Speed control using PID is a pretty straight forward thing, but position control is very difficult using a DC motor, low or no holding torque at setpoint.

Stepper motors are the most effective motor to use for precise position control.

Lefty

Logged

0
Offline Offline
Sr. Member
****
Karma: 0
Posts: 295
Got Karma?
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

 
Quote
position control is very difficult using a DC motor, low or no holding torque at setpoint.

Actually that is not true. I have used the Gamoto boards and they have full torque at holding setpoint with DC motors.  PID w/ a velocity profile = accurate position + speed control.

Anyone done this? I have seen example videos on the web but no example code.

--Roy
Logged

Norway/Hurum/Oslo
Offline Offline
Newbie
*
Karma: 0
Posts: 22
Building a 4-revolute-joint Robotic arm
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm looking for the same thing roypardi. Have you found something yet? I'm builidng a robotic arm and need PID controll for both speed and accuracy for position with encoder.

I had a look at the PID library with front end on the playground but not sure how to use it with an DC motor and encoder.
Logged

0
Offline Offline
Sr. Member
****
Karma: 0
Posts: 295
Got Karma?
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi -

I first wrote my own PID controller and got close but tuning was very tricky. I also tried the PID library but didn't have any success with it (probably operator error - my patience was wearing thin).

I finally went with the Gamoto motor controllers - $100 and very feature complete. Learned (only partially, alas) a valuable lesson @ build vs buy. The pleasure and challenge of building sometimes (often...) results in much wasted time and a stalled project. Trying to pick my build challenges more carefully now....

Anyway I can't help with the PID lib but here are 3 sources for cheap PID motor controllers:

http://www.gamatronix.com/product_info.php/products_id/28
http://www.geckodrive.com/products.aspx?n=711937
http://www.uhu-servo.de/servo_en/index.htm

Also, if your encoder is high resolution, the Arduino will not be able to handle the frequency of interrupt events.

Cheers,
---Roy
Logged

CATALUNYA
Offline Offline
Full Member
***
Karma: 1
Posts: 112
I started my electronics career with MICROCHIP PIC16 microcontrollers and assembler. After 10 years without touching electronics, I restarted it as a hobby (and sometimes work) with ATMEL and Arduinos.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi!

Regarding to position control with DC motors, you must consider the next issues:

1) Most industrial position PID loops consist only on P control. The regulator speed control does the rest of the work.

2) The control must include a feedforward control. Feedforward means that your control is continuously generating a position profile and must calculate what would be the theorical speed to get this profile. This must be done for each time stamp (i.e. 1, 5 or 10 ms), so target speed will be the difference between the next target position and the current position divided by the time stamp.

If there is no interference, this feedforward control makes most of the work.

I hope this helps!


/me
Logged

Toronto, Canada
Offline Offline
Full Member
***
Karma: 0
Posts: 144
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Yes, the Gamoto Motor controller.... Ohh, I wish I could implement these features on my motor controller in Arduino:
- Serial port, at 9600, 19200 or 115200 baud;
- I2C protocol as a slave device;
- Trapezoidal Trajectory Profile processing (constant accel ramp, constant velocity cruise, then constant decel rampdown);
- simple commands like Forward(Speed, Distance). If such a command is issued, the motor controller should accelerate to the Speed value and decelerate and stop at the specified traveled Distance. Now THAT is a motor controller! Any suggestions how to do it?
Logged


Norway/Hurum/Oslo
Offline Offline
Newbie
*
Karma: 0
Posts: 22
Building a 4-revolute-joint Robotic arm
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I know I probably only need a P - regulator.
Suby, would you recommend that I create my own method and not use the PID-libary and set the I and D variables to 0? I didn't quite understand the feedforward explanation.
Looked it up on wikipedia but what do feedforward means in my situation?
Why do I need to have time stamps when I can do it in the void loop().
Shouldn't that be enough?
Logged

CATALUNYA
Offline Offline
Full Member
***
Karma: 1
Posts: 112
I started my electronics career with MICROCHIP PIC16 microcontrollers and assembler. After 10 years without touching electronics, I restarted it as a hobby (and sometimes work) with ATMEL and Arduinos.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Pilkaster,

I recommend you to read thoroughly Microchip's AN696:

http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1824&appnote=en011782

Despite it is Microchip hw based, it describes most of your project needs.

Quote
Suby, would you recommend that I create my own method and not use the PID-libary and set the I and D variables to 0? I didn't quite understand the feedforward explanation.
Yes, of course.
I haven't read Arduino's PID library but I assume that it's good for many things like temperature control or speed regulation but not this issue.

Quote
I know I probably only need a P - regulator.
The simplest position control with DC motor just consists on a position loop that regulates the power drive. I mean:

sp_to_drive = Kp*( target_position - current_position )

This is very simple but may cause you some problems caused by Kp value and maybe your system stops before reaching to the target position.

Next step could be a profile control as shown in AN696. Then you need to generate a position versus time profile: acceleration, cruise speed and deceleration. The simplest way to write this must be to fix an scan time (this time stamp) and have three different position increments for acceleration (usually half the cruise position steps), cruise speed and deceleration (also half the cruise).

This is trapezoidal control, as said Ro-Bot-X:
Quote
- Trapezoidal Trajectory Profile processing (constant accel ramp, constant velocity cruise, then constant decel rampdown);
Now this P regulator will behave a bit different:

Kp*( position_set_point - current_position)

where the position set-point is the sum of all the position steps from start. This must be added to your speed reference.

Your encoder will read an instantaneous position. If you get the counts difference between now and the last time stamp (let's say 10 ms before!), you will get the actual speed.

You can perform this same calculation for the desired speed just taking the current theorical position increment. This is the profile feed-forward.

So now we have

Kp_position*position_error + Kp_speed*speed_error

It's quite common to have also an integral action in speed control.

The final number you get must be scaled between 0 and 255 and sent to an analogWrite().

Industrial systems work like this!!  8-)

Good Luck!

/me
Logged

Norway/Hurum/Oslo
Offline Offline
Newbie
*
Karma: 0
Posts: 22
Building a 4-revolute-joint Robotic arm
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Okey! Thanks!

Suby, I looked up the link you posted on AN696. It's a pretty big solution and it was a bit difficult for me to understand all of the logic and functions in the solution. Would the complete solution be too much in Arduino? It seems difficult to make something based on the entire solutions. I'm trying to do a lot of things in arduino. Two arduino's will control two motors each. So how to create this function as simple and correct as possible? Where comes position_error and speed_error from? I know how a pid/p controller works basically of course, but have problems thinking out how to solve it in arduino. So I'm not sure I understand all of your examples here.
Logged

Athens, Greece
Offline Offline
Newbie
*
Karma: 0
Posts: 19
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello everybody!

Here is some pseudocode for a full PID controller. (I tend to use standard c with the AVR-GCC compiler and have the C files. If somebody is interested I could post them). It is as general as it can be because PID can be used to control many things besides motors.

Some assumptions:
-Lets say we have a routine named setActuator() that takes care of giving a voltage command to the motor (it could be an analogWrite)
-Also a routine called getSensor() that returns the value from the sensor we have attached to the actuator (potentiometer, encoder etc). This could be an analogRead() in case of a potentiometer ie.
- We will need some variables named: sensorValue, actuatorValue, error, previousError, integralPart.
- We will need some constants named pGain, dGain, iGain, antiWindUpLimit

If all variables and constants are not clear yet don't worry I will explain them one by one

Here is the pseudocode (it looks like C) that implements the PID.
(It runs inside a routine called in the main loop)

sensorValue = getSensor();
previousError = error;                          //store the previous error
error = sensorValue - actuatorValue;    //this is how far we are from our goal
integralPart = integralPart + error;       //this is the integral part which eliminates the steady state error
if(integralPart > antiWindUpLimit) then  //here we limit the integral part
integralPart = AntiWindUpLimit;
if(integralPart < antiWindUpLimit) then
integralPart = -AntiWindUpLimit;
//this is the PID calculation
actuatorValue = pGain*(error + dGain*(error - previousError) + iGain*integralPart);
//this can also be written like this
actuatorValue = pGain*error + dGain*(error - previousError) + iGain*integralPart;
//just expanding the multiplication to understand how the change of each gain affects our system better.
setActuator(actuatorValue);

Thats it!!!
Some comments:
- pGain*error is the proportional term and it acts like this: the further we are from our goal the bigger the voltage to the motor (or the command to the actuator) - but when we get close to our goal (setPoint) there is a very small voltage - maybe not enough to move the motor and certainly not enough to keep the motor in place if we try to move it by hand.
- This is where the integral term = iGain * integralPart comes in. If we are close to our goal but have not reached it, at every loop cycle the integral part will become bigger and bigger until it moves the motor in place. Also if we try to take the motor out of its position this term also becomes bigger and bigger until the motor moves back in place. So why the antiWindUp (= limit of the integral part)? and what is it?... Imagine this: we are stronger than the motor and we keep it with our hand out of place even if the integralPart does its thing and commands the motor back in place by the full supply voltage available to the motor. The PID loop goes on increasing the integral term to infinity as time passes... This is not good and also it is pointless... The motor after all can be activated only to 100% of the voltage we have available. So usually we limit the integral term to 100% of the values the setActuator() function can handle (or less). If we dont and a situation like the above happens we will surely overshoot our goal when we release the motor.
- Finally the derivative term. Up to now we have the proportional term which behaves like this: Bigger command the further we are away from our goal - not much when we are close. The integral term which gets bigger the longer we are away from our goal. These two guys don't care how fast we are going towards our goal and if we will overshoot the target - the derivative term does. Look at the calculation - it is exactly this: how fast are we approaching? ( error - prevError ). So the faster we are approaching the derivative term tries to limit the actuatorValue so that we do not overshoot.

The above are a bit simplistic but say what each term does when it is working as it should. Note that THE key factor to PID control is how frequently we execute the calculations. A PID loop at 1KHz is usually enough. A PID loop at 2KHz is better and so on.

I hope this helped smiley . I have been implementing control systems for some time now and it is how I understand the PID inside my head. Once you understand it it is really simple - and ingenious at the same time smiley
Logged

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 331
Posts: 16459
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Nice example and explanation. The part I usually get confused with on implementing PID is the scaling of the input reading and output value and direction of error + or -. I worked with standalone PID controllers in a refinery and all scaling was done on a 0-100% basis for PV, setpoint and output values, so it was kind of dimensionless, where as in Arduino were are frequently dealing with a 10 bit analog input value and a 8 bit PWM output value. It just kind of give me a headache trying to relate the inside code with the outside values.  smiley-wink

Lefty
Logged

Australia
Offline Offline
Jr. Member
**
Karma: 0
Posts: 99
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I think this clamping code:

Quote
Code:
if(integralPart < antiWindUpLimit) then
integralPart = -antiWindUpLimit;

should read:

Code:
if(integralPart < -antiWindUpLimit) then
integralPart = -antiWindUpLimit;
Logged

Athens, Greece
Offline Offline
Newbie
*
Karma: 0
Posts: 19
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@crimony. I stand corrected smiley
Logged

Athens, Greece
Offline Offline
Newbie
*
Karma: 0
Posts: 19
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@roypardi:  Besides the gamoto boards I stumbled onto these guys today: http://www.01mech.com/supermodified who have more or less the same thing + motor + encoder all at about the same price. They also are giving open source schematics ( couldn't find the code anywhere though ).
Logged

Pages: [1] 2   Go Up
Jump to: