Arduino Pid Research
Arduino Pid Research
Table of Contents
Balancing Robots
Balancing Robot for dummies
Self Balancing Robot
Arduway: a mini Segway using the Arduino
YBot - Balancing Arduino Robot
Build a (simple) balancing robot
BoRam: Balancing Robot using Arduino and Lego
nBot Balancing Robot
LegoBot
SR04 Robot
Building a Balancing Scooter/Unicycle
Misc. Arduino
Labyrinth Maze Game
Control Examples
Tuning
PID Control Software Examples
AeroQuadPID Control Software
AeroQuad.h
DataStorage.h
FlightControl.pde
PID.h
Bare Bones (PID) Coffee Controller
PIDLibrary - PID_Beta6.cpp
Appendix A: Source Material
Control
PIDS
Designing a PID
Learning
Tuning
Kalman Filter
Wheel Encoder
Parts
Motor
Video
Balancing Robot Forum Threads
Balancing robot for dummies
Self Balancing Robot
PID Library
Balancing Robots
Balancing Robot for dummies
Arduino Forum General Exhibition Balancing robot for dummies
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1284738418
post 9/17/2010
Part I
Arduino Forum General Exhibition DC motor control with PID
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1282384853/0
See Kalman filter section here for latest code.
LegoBot
http://www.geology.smu.edu/~dpa-www/robo/lego/
SR04 Robot
http://www.geology.smu.edu/~dpa-www/robots/sr04/
Trailing wheel
Misc. Arduino
Arduino Forum Software Troubleshooting 5DOF + Inverted Pendulum = Problems
post - 9/16/2010
Arduino Forum General Exhibition Six servo lego hexapod
Arduino Forum General Exhibition Self balancing vehicle lowcost Arduino based
Easy build self balancing skateboard/robot/segway platform This is an Instructable
The three are presented in order of the complexity of the PID controller implementation. The
coffee controller is a single PID, which can be documented in a single Arduino PDE file. The
AeroQuad PID software is a modified version of the BBCC: Bare Bones (PID) Coffee Controller
with the ability to control multiple control loops. The RepRap uses the Arduno PID Library
(PIDLibrary). The PIDLibrary is an industrial standard PID controller. RepRap is the feed
forward example (PIDSample3) in the PID_Beta6 project folder. Here is a quick comparison of
features.
Like the AeroQuad PID, the coffee controller does not normalize the input. Both include non
industrial-standard reset-windup mitigation code. Unlike the AeroQuad PID, the coffee controller
does not calculate the integral term as a function of delta time. The Arduino PID library
(PID_Beta6)
The inclusion of dT in the computation of accError is simply an academic point of interest (and
calculations are accelerated without it). Mathematically, dT can be extracted out of the sum and
simply included in the taur term. taur *= ((double)NewSampleTime)/((double) tSample);
Tuning
Tuning the PID is where most of the magic wand action occurs. For some of the software
control examples, the term Configurator is used for the development environment used for
tuning the PID. It is not clear what IDE was used to develop the Configurator used by
AeroQuad. The Coffee Controller used a Processing as its IDE for developing a simple
configurator. The PIDLibrary also used Processing as illustrated here. It has since been ported
to the mbed platform. Here is a very nice step-by-step Tuning Example using mbed.
PID Control Software Examples
AeroQuadPID Control Software
Useful Links:
1. AeroQuad Home - http://aeroquad.com/content.php
2. The Manual -
http://code.google.com/p/aeroquad/downloads/detail?name=AeroQuad%20Manual%20
V9.pdf&can=2&q=
3. The Software including the Configurator -
http://code.google.com/p/aeroquad/downloads/list
4. Configurator Help - http://aeroquad.com/content.php?116
The following AeroQuad header and pde files are key to understanding the AeroQuad PID
software.
AeroQuad.h
This header file defines AeroQuad mnemonics
DataStorage.h
This header file is used to read and write default settings to the ATmega EEPROM.
FlightControl.pde
This C++ program calls the PID updatePID function and zeroIntegralError subroutine. Here are a few
example calls.
PID.h
The PID data structure and PID algorithm
struct PIDdata {
float P, I, D;
float lastPosition;
float integratedError;
} PID[8];
float windupGuard; // Read in from EEPROM
// Modified from
http://www.arduino.cc/playground/Main/BarebonesPIDForEspresso
float updatePID(float targetPosition, float currentPosition, struct PIDdata
*PIDparameters) {
float error;
float dTerm;
void zeroIntegralError() {
for (axis = ROLL; axis < LASTLEVELAXIS; axis++)
PID[axis].integratedError = 0;
}
Bare Bones (PID) Coffee Controller
As commented on in the code, the AeroQuad PID software is a modified version of the BBCC:
Bare Bones (PID) Coffee Controller The coffee controller is a single PID and so is a little
simpler to understand.
Like the AeroQuad PID, the coffee controller does not normalize the input. Both include non
industrial-standard reset-windup mitigation code. Unlike the AeroQuad PID, the coffee controller
does not calculate the integral term as a function of delta time. The Arduino PID library
(PID_Beta6)
/* Compute() ******************************************************************
* This, as they say, is where the magic happens. this function should
* be called every time "void loop()" executes. the function will decide
* for itself whether a new pid Output needs to be computed
*
* Some notes for people familiar with the nuts and bolts of PID control:
* - I used the Ideal form of the PID equation. mainly because I like IMC
* tunings. lock in the I and D, and then just vary P to get more
* aggressive or conservative
*
* - While this controller presented to the outside world as being a Reset Time
* controller, when the user enters their tunings the I term is converted to
* Reset Rate. I did this merely to avoid the div0 error when the user wants
* to turn Integral action off.
*
* - Derivative on Measurement is being used instead of Derivative on Error. The
* performance is identical, with one notable exception. DonE causes a kick in
* the controller output whenever there's a setpoint change. DonM does not.
*
* If none of the above made sense to you, and you would like it to, go to:
* http://www.controlguru.com . Dr. Cooper was my controls professor, and is
* gifted at concisely and clearly explaining PID control
*******************************************************************************/
void PID::Compute()
{
justCalced=false;
if (!inAuto) return; //if we're in manual just leave;
//pull in the input and setpoint, and scale them into percent span
double scaledInput = (*myInput - inMin) / inSpan;
if (scaledInput>1.0) scaledInput = 1.0;
else if (scaledInput<0.0) scaledInput = 0.0;
//if we're using an external bias (i.e. the user used the
//overloaded constructor,) then pull that in now
if(UsingFeedForward)
{
bias = (*myBias - outMin) / outSpan;
}
//scale the output from percent span back out to a real world number
*myOutput = ((output * outSpan) + outMin);
justCalced=true; //set the flag that will tell the outside world
// that the output was just computed
}
}
Appendix A: Source Material
Control
There is no magic control design technique. Any linear control technique yields a filter (the
compensator) in the end, and there is only so much that the filter can do. Just because the filter
comes from PID, or LQG, or QFT, or H-infinity, or LQR -
http://www.control.com/thread/966880428
The robot acts as an inverted pendulum and works better when the weight is high.
PIDS
http://www.controlguru.com/pages/table.html
Designing a PID
Making your robot get from point A to point B smoothly
http://thecodebender.com/journal/2009/3/30/designing-a-pid-making-your-robot-get-from-point-a-to-
point.html
Learning
If you are unfamiliar with PID control, a good place you start might be:
http://en.wikipedia.org/wiki/PID_controller
http://www.controlguru.com . Dr. Cooper is gifted at concisely and clearly explaining PID control
Tuning
http://mbed.org/cookbook/PID
Kalman Filter
http://en.wikipedia.org/wiki/Kalman_filter
Kalman filter module works pretty well but is still a Black Box for me
I tried hard to understand and finally gave up.
This code is a modified version from the AeroQuad project from Ted Carancho
http://code.google.com/p/aeroquad/
I spent some hours playing with Q_angle, Q_gyro and R_angle, and finally reverted to the
original parameters
Here is a comparison between the raw accelerator angle (red) and the Kalman filtered angle
(blue)
The smoothing effect is impressive (source) http://www.youtube.com/v/H5Drlqv1t3s? This is a
simple custom development in LabView. The Arduino sends 2 integers separated by a comma.
Data can be sent alternatively to IDE serial monitor or to LabView. Angles are scaled in Quids
(360 = 2 PI = 1024 Quids)
This unit is convenient and can be manipulated as integer while retaining a good resolution
Code:
void serialOut_labView() {
Serial.print(Angle + 512); Serial.print(","); // in Quids
Serial.print(ACC_angle + 512); Serial.print("\n");
}
If your robot rolls about the x axis, you only need GYR_X, ACC_Y and ACC_Z
I notice that signal quality is much better when the sensor is upward, apparently, the IMU does
not appreciate to be upside down This was posted here on 9/11/2010
float x_angle = 0;
float x_bias = 0;
float P_00 = 0, P_01 = 0, P_10 = 0, P_11 = 0;
float dt, y, S;
float K_0, K_1;
y = newAngle - x_angle;
S = P_00 + R_angle;
K_0 = P_00 / S;
K_1 = P_10 / S;
x_angle += K_0 * y;
x_bias += K_1 * y;
P_00 -= K_0 * P_00;
P_01 -= K_0 * P_01;
P_10 -= K_1 * P_00;
P_11 -= K_1 * P_01;
return x_angle;
}
a kalman filter must be used with accelerometers and many other sensors..
Wheel Encoder
http://www.mindspring.com/~tom2000/Delphi/Codewheel.html
Parts
Motor
The servos do not have a fast enough response (RPM = 60). Use of DC motors with an RPM
over 200 is needed. - Build a (simple) balancing robot
Video
Balancing Arduino Robot
Balancing Arduino Robot
http://www.youtube.com/watch?v=RaN0itBbVR4
Self balacing robot using Arduino
http://www.youtube.com/watch?v=QskYp5lM1BE&NR=1
Makershed.com
Parallax Memsic 2125 2-axis accelerometer
How-to Tuesday: Arduino 101 Accelerometers (Talks about balancing robots)
http://www.youtube.com/watch?v=HYUYbN2gRuQ&NR=1&feature=fvwp
Sun Tracking Solar Panel w/ Arduino
http://www.youtube.com/watch?v=ATnnMFO60y8&feature=related
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1275324410
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1280253883
The rest is the pid controller (not that complex), something to use the LCD and other glue.
I don't know if you already know it. In few words, it's a well know way to take into account three
different parameters into the calculation of the final speed: the Proportional (that is the error, in
our case, the current angle of the robot), the Derivative (that is, the angular velocity, or how fast
it is falling/raising), and the Integrative, which is a sum of the errors in all previous iterations.
Ah ok, than that's the reason. You cannot just sum up the readings from the gyro to get the
absolute angle, it will drift quite a lot with time like any kind of dead reckoning.
The kalman filter is what helps in this situation: using data from accelerometers (that sense the
gravitational acceleration) you can get an absolute value for the current angle. The problem is
that while on the long time it averages to the right value, it will change badly as the robot swing,
rotate or stop. The kalman filter is what makes an adeguate "combination" of the gyro and
accelerometers to get a value that is correct both in the short time and in the long time.
Here's a serie of article that explain this far better than i did:
http://tom.pycke.be/mav/69/accelerometer-to-attitude
http://tom.pycke.be/mav/70/gyroscope-to-roll-pitch-and-yaw
http://tom.pycke.be/mav/71/kalman-filtering-of-imu-data
The "looseness" you describe is a real problem with balancers. I used motors similar to yours at
first, but was able to achieve much tighter and more responsive balancing by switching to zero-
backlash servos (Dynamixel AX-12).
PID Library
Neurasonic asked for a story on PID control. Here's my take.
PID stands for Proportional, Integral, differential. What do THEY stand for? Start with
comparing what you have with what you want with what you have. The difference is called the
error signal. If you use only this error signal to drive the output, you have a proportional
controller (if the error signal is linear or proportional). This can be OK, but there HAS to be an
error to keep driving the output, so it's never exactly right.
OK, how about toting up the small difference, time after time, when you are as close as you can
get with the proportional circuit, and driving the output with THAT too? That can work and hit the
desired output on the nose.
Now what about if we next want a step change in output?
If we grow restless with a fast start, and a slower slower approach to the desired output, we can
get bold. By monitoring the rate that the error signal changes we reduce the time to reach the
target value, and (hopefully) minimize the over shoot and hunting chances.
Having said all that PID controllers can be a pig to tune. Some people find fuzzy logic controllers
are much easier to understand and to set up.
Brian Whatcott
Altus OK
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1226431507/30
...I find that the blessing and the curse of the PID is it's ease of configurability. you can get a
control loop to "good 'nuf" pretty quickly. the problem is that sometimes that's a ways away
from "good." I'd say, as far as arduino is concerned, simple fuzzy logic is the right place to start.
that can get real complicated real quickly though, and at that point it's time for this library (IMO)
I don't understand why you have problems making your PID faster....maybe because I've never
used it . Sometimes the measurement is not at the same frequency than the Computing
frequency, maybe you can't achieve the maximum speed because you are not using timer
interrupts, and almost every PID ready-to-use software made by big companies uses timer
interrupts. When you use timer interrupts the only limit is the clock speed and the timer's pre-
escalator, ahh one last thing, the common acronyms are:
Set Point, (SP)
input: PV (Present Value)
output: MV(manipulated variable)
error
dt : (delta t) that's what you call calc period
Kp
Ki,Ti (I prefer Ki than Ti, where Ki=Kp/Ti)
Kd,Td (same with Kd, Kd=Kp*Td)
what I was talking about when I said "faster" was the computation itself. the fewer processor
cycles it takes to perform its calculation, the more time the arduino has to do other things. and,
just as a point of pride, I want the pid to be as efficient as possible.
as far as abbreviations, some are certainly more common than others, but they do vary from
manufacturer to manufacturer. off the top of my head:
Process Variable: PV, ME
SetPoint: SP, SV
Controller Output: CO, CV, OUT, OT, OP.
dt is commonly used. I settled on SampleTime (which is also commonly used) because I felt it
was easier to understand.
at any rate, give the library a shot! I'd love to hear any more suggestions you might have.
...I just looked at the source, and it looks very well, I can see that you have done something to
prevent windup, I also prefer the Ideal form of the PID algorithm, everything is done efficiently
(computing time-speaking), maybe millis() is taking too much, I don't see where else the code
could be made more efficient, I will try to do it with interrupts and I will let you know if it works
better, also I'm going to implement a kalman filter, so maybe that will be my first contribution to
the arduino project, for those who don't know what I'm talking about, a kalman filter must be
used with accelerometers and many other sensors..
By the way PV is often referred as "Process Value" in engineering terms
There is no problem to run it in master slave configuration. Just run it twice with different inputs.
We have used this successfully
Last year I have trained a student during 3 month in order to make a complex regulation, for this
purpose we have developed and implemented the Broda method that allows to identity PID
coefficient by measuring the response of the open loop system to square by measuring an
amplitude and two time (at 0.28*deltaA* and 0.40*deltaA) it gives parameters depending of the
kind of PID you want (with or without overshoot). This method seems to work up to the 6th
order.
What do you think about coding this into the arduino platform ?
I think it can works on a lot of cases !
this may be a good place to start:
http://www.arduino.cc/playground/Main/InterfacingWithHardware (scroll down to ADC/DAC)
I am building a simple temperature controller and I'm attempting to use your PID library. The
arduino reads the temperature from an LM35 and then outputs a slow PWM pulse to a solid
state relay which will switch a standard electrical output. I figure I'll plug in either a water bath
heater or an electric smoker to the outlet, it seems like it should work just as well for either
application. Anyhow, I don't have much of the hardware yet (it's all on order), but I put together
the code and I wanted to make sure I was utilizing the PID library correctly. As you can see, I'm
using the Timer1 library to run a 1 second PWM pulse. I wouldn't think a heating element would
need anything faster than that. The PID output adjusts the duty cycle of the pulse:
first off, there's a timer library?! why did I not know this?
your code looks good. be advised that you will need to adjust the tuning parameters (3,4,1)
depending on what you're connected to. it's unlikely that the default values will give you the
response you want, or that the same values will work for both the water bath heater and
smoker.
Yeah, I understand about the tuning parameters, I guess I'll just have to eyeball things until I get
them set up right. Like I said, nothing is built just yet, it's still diagrams and connections floating
around in my head. I've heard it'll probably take a long time (hours? days?) to tune due to the
slow response of my systems (I'm thinking the smoker will probably be faster than the water
bath though).
The Timer1 library is something I stumbled upon while trying to figure out how to slow down the
arduino PWM. I think I understood the software "window" method that you wrote into the
second example on the PID library page, but it seemed like there must be a better way. I don't
claim to understand it completely, but it seems like just the ticket for what I'm trying to do:
http://www.arduino.cc/playground/Code/Timer1
Thanks again!
sorry for the confusion. there's various forms of the pid equation.
(http://en.wikipedia.org/wiki/PID_controller scroll down to "Alternative nomenclature and PID
forms")
they're mathematically equivalent, but the one listed as the "standard form" is the one i chose.
it's a little more work on the backend as you mentioned, but I find it easier to tune. if you know
the time constant of the process, you just make that the I term, then adjust P to get more
aggressive or conservative)
I started a new thread specific to PID Tuning:http://www.arduino.cc/cgi-
bin/yabb2/YaBB.pl?num=1280251311 From Brett (the creator)