0

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) I don't see the make, model and link to datasheet of your sensor in your question. (2) I don't see a schematic. (There's a button on the editor toolbar.) (3) You haven't posted any voltage readings on the analog input to confirm that the accelerometer is working properly. – Transistor May 27 '16 at 22:02
  • You appear to be slamming to the alternate output limits. To investigate this type of problem, generally try reducing the gain, look at how the default sample interval means the calculation may only be performed on some loop iterations, and make sure you don't have any "all or nothing" integer vs. floating point conversions. You may want to move the PID code into your sketch and add debug output to it. – Chris Stratton May 27 '16 at 22:49
2

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.

  1. Start at kp = 0,ki = 0, kd = 0
  2. 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.
  3. Very slowly increase kiuntil you are happy.
  4. 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 May 28 '16 at 0:14
  • Thanks for the catch, I am not familiar with the Arduino-flavor PID loop. I'll edit the answer. – slightlynybbled Jun 1 '16 at 19:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.