I am hooking up an accelerometer to an arduino uno and running it through this pid controller. However the output isnt going to my setpoint. When i move the accelerometer back and forth the data goes to 255 or 0. Any ideas?
Datasheet for accelerometer: https://www.sparkfun.com/datasheets/Components/SMD/adxl335.pdf
I get 336 for the x direction, which is the only direction i'm using, when its set flat on the table, which is my setpoint/desired output.
Note: Is the output the value away from the setpoint or the actual acceleration it calculates through the controller?
#include <PID_v1.h>
#define PIN_INPUT A0
//Define Variables we'll be connecting to
double Setpoint, Input, Output;
//Define the aggressive and conservative Tuning Parameters
double aggKp=4, aggKi=0.2, aggKd=1;
double consKp=1, consKi=0.05, consKd=0.25;
//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint, consKp, consKi, consKd, DIRECT);
void setup()
{
//initialize the variables we're linked to
Serial.begin(9600); //Start a serial session
int xdata = analogRead(PIN_INPUT);
Input = map(xdata, 0, 1024, 0, 255); //Change read scale to analog out scale
int setPoint = 336;
Setpoint = map(setPoint, 0, 1024, 0, 255); //Change read scale to analog out
//turn the PID on
myPID.SetMode(AUTOMATIC);
}
void loop()
{
int xdata = analogRead(PIN_INPUT);
Input = map(xdata, 0, 1024, 0, 255); //Change read scale to analog out scale
double gap = abs(Setpoint-Input); //distance away from setpoint
if (gap < 10)
{ //we're close to setpoint, use conservative tuning parameters
myPID.SetTunings(consKp, consKi, consKd);
}
else
{
//we're far from setpoint, use aggressive tuning parameters
myPID.SetTunings(aggKp, aggKi, aggKd);
}
myPID.Compute();
Serial.print("Setpoint = ");
Serial.print(Setpoint);
Serial.print(" Input = ");
Serial.print(Input);
Serial.print(" Output = ");
Serial.print(Output);
Serial.print("\n");
// analogWrite(PIN_OUTPUT, Output);
}
OUTPUT:
Setpoint = 83.00 Input = 87.00 Output = 0.00
Setpoint = 83.00 Input = 81.00 Output = 0.00
Setpoint = 83.00 Input = 64.00 Output = 255.00
Setpoint = 83.00 Input = 64.00 Output = 255.00
Setpoint = 83.00 Input = 68.00 Output = 255.00
Setpoint = 83.00 Input = 79.00 Output = 0.00
Setpoint = 83.00 Input = 91.00 Output = 0.00
Setpoint = 83.00 Input = 96.00 Output = 0.00
Setpoint = 83.00 Input = 99.00 Output = 0.00
Setpoint = 83.00 Input = 88.00 Output = 0.00
Setpoint = 83.00 Input = 68.00 Output = 0.00
Setpoint = 83.00 Input = 58.00 Output = 255.00
Setpoint = 83.00 Input = 64.00 Output = 255.00
Setpoint = 83.00 Input = 78.00 Output = 255.00
Setpoint = 83.00 Input = 95.00 Output = 0.00
Setpoint = 83.00 Input = 97.00 Output = 0.00
Setpoint = 83.00 Input = 95.00 Output = 0.00
1 Answer 1
Ensure that your period for the PID execution routine is reasonable for your system. I generally like to execute my PID loops at 5 to 20 times the system impulse response. For instance, with a motor, I will apply 100% power from a standstill and measure the time it takes to get up to 90% of final value. I will then multiply that time by 0.1 and start there. If it takes 1s, then I will start my PID loop executing every 0.1s. Sometimes I adjust this up or down, depending on system requirements, but this is not a bad starting point.
If your PID loop is executing too fast, then it will respond too quickly to actually have a real-world effect on the system. The output will tend to oscillate. Motors vibrate and make more noise.... different systems respond differently, but you see the point.
- Start at
kp = 0
,ki = 0
,kd = 0
- Increase
kp
until you get a reasonable response. Don't expect your error to go to 0. As long as you aren't oscillating, that should be good. - Very slowly increase
ki
until you are happy. - You should probably keep
kd
to 0. It is for advanced usage and PI loops will meet the vast majority of application requirements.
This is a very crude guide. There are better on google, but this should get you started. PID loops are fun, especially with motors. Enjoy!
-
If you find and study the code of the PID implementation (which should have been in or linked from the question) it already has a sense of sample interval, and simply does nothing if called before the next interval has elapsed. So your first suggestion is basically already implemented, though the period may need consideration, and may be interacting oddly with the serial output.Chris Stratton– Chris Stratton2016年05月28日 00:14:34 +00:00Commented May 28, 2016 at 0:14
-
Thanks for the catch, I am not familiar with the Arduino-flavor PID loop. I'll edit the answer.slightlynybbled– slightlynybbled2016年06月01日 19:01:20 +00:00Commented Jun 1, 2016 at 19:01
map()
rather than use the measurements and setpoints directly? If you want to think in terms of '336' being level, you should use it drectle and scale your pid parameters to translate units of error into units of output.