Hi you all
I would very much appreciate to find help here for my problem. I'm trying to control a metalic ball on a resistive wire. Thing is that somehow the code i'm using does not quite understand what I want to mean (the ball should stay at the middle, as my Setpoint is kinda in the middle of the beam; it moves, but it does not even try to stay there. I suppose the signal noise are the big issue, but even so).
Here's my code for you to help me to find where it is lacking of some more algorithim. Please notice some parts as comments, as I test with/without this parts. Please ignore that.
#include <PID_v1.h>
#include <Servo.h>
// #define NUMREADINGS 10
//int readings[NUMREADINGS];
//int index = 0;
//int total = 0;
//int average = 0;
//Define Variables we'll be connecting to
double Setpoint, Input, Output,ServoOutput;
//int ControllerDirection;
//Define the aggressive and conservative Tuning Parameters
double aggKp=15.05, aggKi=13.63, aggKd=4.156;
double consKp=0.0001502, consKi=0, consKd=0.04291;
//PID::PID (int ControllerDirection);
// PID::SetControllerDirection(ControllerDirection);
//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint, consKp, consKi, consKd, DIRECT);
Servo myservo;
void setup() {
Serial.begin(9600);
// for (int i = 0; i < NUMREADINGS; i++)
// readings[i] = 0;
myservo.attach(9);
//initialize the variables we're linked to
Input = analogRead(0);
Setpoint = 575;
//turn the PID on
myPID.SetMode(AUTOMATIC);
myPID.SetOutputLimits(-60, 60);
}
void loop(){
//
Input = analogRead(0);
Serial.println(Input);
//
// total -= readings[index];
// readings[index] = analogRead(Input);
// total += readings[index];
// index = (index + 1);
// if (index >= NUMREADINGS)
// index = 0;
// average = total / NUMREADINGS;
// Serial.println(average);
//
double gap = abs(Setpoint-Input);
if (/*Input > Setpoint && */ gap>10)
{
myPID.SetTunings(aggKp, aggKi, aggKd);
// myPID.SetControllerDirection(DIRECT);
}
else if (/*Input > Setpoint &&*/ gap < 10)
{
myPID.SetTunings(consKp, consKi, consKd);
// myPID.SetControllerDirection(DIRECT);
}
// else if (Input < Setpoint && gap < 10)
// {
// myPID.SetTunings(consKp, consKi, consKd);
// myPID.SetControllerDirection(REVERSE);
// }
//else if (Input < Setpoint && gap > 15)
// {
// myPID.SetTunings(aggKp, aggKi, aggKd);
// myPID.SetControllerDirection(REVERSE);
// }
myPID.Compute();
delay(100);
ServoOutput=Output;
myservo.write(Output);
delay(100);
}
[code]
You set the output limits to +/-60. That is not the usual input range for a servo. Does the servo hold the beam close to the balance point if you send it 0?
The 200ms of delays will also make it very difficult to balance. Thats like trying to drive a car with your eyes closed for 10 seconds.
Thanks for responding man!
So, actually 0 is the min angle of the beam. For the beam to be close to the balance, it will be around 35-40. That makes 60 as the max angle.
I actually saw that the delay was high, so i turned it to 10 for the PID + 10 for the servo output.
now it is simply doing this:
when bigger then setpoint, stay above setpoint. When lower then setpoint, go under setpoint. So, basically the ball is being leaded to the extremes of the beam, not to the setpoint. What am i doing so wrong that i dont see? OMG i need help
Code until now (consider the coments now as coments, once the situation told above is happening exactly as it is being loaded to arduino as here below:)
#include <PID_v1.h>
#include <Servo.h>
// #define NUMREADINGS 10
//int readings[NUMREADINGS];
//int index = 0;
//int total = 0;
//int average = 0;
//Define Variables we'll be connecting to
double Setpoint, Input, Output,ServoOutput;
//int ControllerDirection;
//Define the aggressive and conservative Tuning Parameters
double aggKp=15.05, aggKi=13.63, aggKd=4.156;
double consKp=0.0001502, consKi=0, consKd=0.04291;
//PID::PID (int ControllerDirection);
// PID::SetControllerDirection(ControllerDirection);
//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint, consKp, consKi, consKd, DIRECT);
Servo myservo;
//int pos = 0;
void setup() {
Serial.begin(9600);
// for (int i = 0; i < NUMREADINGS; i++)
// readings[i] = 0;
myservo.attach(9);
//initialize the variables we're linked to
Input = analogRead(0);
Setpoint = 550;
//turn the PID on
myPID.SetMode(AUTOMATIC);
myPID.SetOutputLimits(-60,60);
}
void loop(){
//
Input = analogRead(0);
Serial.println(Input);
//
// total -= readings[index];
// readings[index] = analogRead(Input);
// total += readings[index];
// index = (index + 1);
// if (index >= NUMREADINGS)
// index = 0;
// average = total / NUMREADINGS;
// Serial.println(average);
//
double gap = abs(Setpoint-Input);
if (Input > Setpoint && gap > 5 /*|| Input < Setpoint && gap > 1*/)
{
myPID.SetTunings(aggKp, aggKi, aggKd);
//myPID.SetControllerDirection(DIRECT);
}
else if (Input > Setpoint && gap < 5 /*|| Input < Setpoint && gap < 1*/)
{
myPID.SetTunings(consKp, consKi, consKd);
// myPID.SetControllerDirection(DIRECT);
}
else if (Input < Setpoint && gap < 5)
{
myPID.SetTunings(consKp, consKi, consKd);
// myPID.SetControllerDirection(REVERSE);
}
else if (Input < Setpoint && gap > 5)
{
myPID.SetTunings(aggKp, aggKi, aggKd);
//myPID.SetControllerDirection(REVERSE);
}
//
myPID.Compute();
// delay(10);
ServoOutput=Output;
myservo.write(Output);
// delay(10);
}
[code]
lophill:
when bigger then setpoint, stay above setpoint. When lower then setpoint, go under setpoint. So, basically the ball is being leaded to the extremes of the beam, not to the setpoint. What am i doing so wrong that i dont see? OMG i need help
I would start by getting rid of the code that switches between two sets of tuning parameters. Get it working with one set first.
I would change the Output range to 0 - 180 (or better yet: 1000 to 2000 and switch to myServo.writeMicroseconds()).
If the PID is going the wrong direction, change from DIRECT to REVERSE.
lophill:
now it is simply doing this:
when bigger then setpoint, stay above setpoint. When lower then setpoint, go under setpoint. So, basically the ball is being leaded to the extremes of the beam, not to the setpoint. What am i doing so wrong that i dont see? OMG i need help
That's easy then. Put this into setup():
myPID.SetControllerDirection(REVERSE);
Don't change directions in loop().