Hi guys. I'm after a little help and I know very little about writing code (Sorry)
One of the lessons I teach involves a little introduction to basic PID control. Basically the students need to have a basic understanding of what it is and how it works. We do have a pretty good rig we use which applies an input, the system reacts and the students get to see the I/O trace on the smart board. We also get to play with the values for PID to improve accuracy and stability. However some guys still struggle a little. So I did some googling and found a guy who came up with a neat little solution using a ball on a balance, a servo motor and IR sensor. The idea is the sensor measures the distance to the ball and controls the servo to keep the ball in the middle of the balance. http://electronoobs.com/eng_arduino_tut100.php .
I think this would be quite a good visual tool for my lesson (better that a powerpoint presentation) as you can demonstrate how each individual component of the PID affects the system both individually and in combination with each other. (The video in the link above makes more sense than me)
However, what I really don't want to have to do each time I want to change the values of P,I and D is re flash the board, so, I got myself 3 10K pots and wondered if I could use them as inputs to control the PID values?
I know how to attach the pots as analogue inputs, what I don't know is how to tell the board to read the values of the pots and convert them to PID constants.
Or does anyone have any other suggestions that allows me to alter each of the P.I and D values from 0 to max, individually without the need to flash the board for each new set of values.
Would anyone be willing to help out a complete Arduino noob
Thanks in advance.
this is the code supplied with the project:
/* PID balance code with ping pong ball and distance sensor sharp 2y0a21
*/
#include <Wire.h>
#include <Servo.h>
///////////////////////Inputs/outputs///////////////////////
int Analog_in = A0;
Servo myservo; // create servo object to control a servo, later attatched to D9
///////////////////////////////////////////////////////
////////////////////////Variables///////////////////////
int Read = 0;
float distance = 0.0;
float elapsedTime, time, timePrev; //Variables for time control
float distance_previous_error, distance_error;
int period = 50; //Refresh rate period of the loop is 50ms
///////////////////////////////////////////////////////
///////////////////PID constants///////////////////////
float kp=8; //Mine was 8
float ki=0.2; //Mine was 0.2
float kd=3100; //Mine was 3100
float distance_setpoint = 21; //Should be the distance from sensor to the middle of the bar in mm
float PID_p, PID_i, PID_d, PID_total;
///////////////////////////////////////////////////////
void setup() {
//analogReference(EXTERNAL);
Serial.begin(9600);
myservo.attach(9); // attaches the servo on pin 9 to the servo object
myservo.write(125); //Put the servco at angle 125, so the balance is in the middle
pinMode(Analog_in,INPUT);
time = millis();
}
void loop() {
if (millis() > time+period)
{
time = millis();
distance = get_dist(100);
distance_error = distance_setpoint - distance;
PID_p = kp * distance_error;
float dist_diference = distance_error - distance_previous_error;
PID_d = kd*((distance_error - distance_previous_error)/period);
if(-3 < distance_error && distance_error < 3)
{
PID_i = PID_i + (ki * distance_error);
}
else
{
PID_i = 0;
}
PID_total = PID_p + PID_i + PID_d;
PID_total = map(PID_total, -150, 150, 0, 150);
if(PID_total < 20){PID_total = 20;}
if(PID_total > 160) {PID_total = 160; }
myservo.write(PID_total+30);
distance_previous_error = distance_error;
}
}
float get_dist(int n)
{
long sum=0;
for(int i=0;i<n;i++)
{
sum=sum+analogRead(Analog_in);
}
float adc=sum/n;
//float volts = analogRead(adc)*0.0048828125; // value from sensor * (5/1024)
//float volts = sum*0.003222656; // value from sensor * (3.3/1024) EXTERNAL analog refference
float distance_cm = 17569.7 * pow(adc, -1.2062);
//float distance_cm = 13*pow(volts, -1);
return(distance_cm);
}
I remember seeing that video and thinking it was a nice demo of PID. So this is just a quick of the top of my head response. Whilst I don't doubt you could get potentiometers to work I think it would be much easier with encoders where you just count the pulses and interpret them to whatever scale you want. So the KD could be from 0 to 8000 and set to an initial mid point of 4000, and the KI you could have a range of 2.0 to -1.0 etc. You would decide on how many pulses would be used to increment each, so, for example, you could increment the KD to go from 4000 to 8000 with a complete turn to the right and from 4000 to 0 with a complete turn to the left. (or half a turn or 2 turns whatever is best for you.)
As it happens there is a nice DronbotWorkshop video on the use of encoders if you peruse the back catalogue, with example code that you should the be able to incorporate in the code you present above. I would also think of have a cheap LCD display that shows the current values of kp, ki and kd as the nobs get twiddled.
I know how to attach the pots as analogue inputs, what I don't know is how to tell the board to read the values of the pots and convert them to PID constants.
Arduino provides a map function, however you would be working with integers, and the resolution wouldn't be that good, as the analog to digital converter is only 10 bit, giving you a maximum of 0 - 1023 integer values. There is an example with the following reference page if you wish to give it a go:
Or does anyone have any other suggestions that allows me to alter each of the P.I and D values from 0 to max, individually without the need to flash the board for each new set of values.
Although not the ideal solution, you could pass the values you want in dynamically, and directly via the serial interface, as long as your Arduino is connected to your computer. You could for example, pass in a string such as:
kp=8
Then within the main code, parse out the string and apply the value to the appropriate variable identified.
I think this can work, and may be worth a try.
Cheers!
I think a pot would be a better choice here. Less stuff to do in the code. Just a map and constrain pair with the analog value.
Thanks for the advice guys.
I like the idea of an lcd display, probably outside my ability level right now but I like the challenge.
I did see about mapping. I think it could work for my needs. I
Once I have the PID dialled in, my thought was to have each pot some where near the middle range for each. I dont need it to be super accurate. The idea is mainly to be able to turn each or a combination of P,I and D on and off so the students get to visualise the effects. (Teaching differentiation and integration without calculus lol)
The biggest problem I have is that the IT guys won't put IDE on the works computers and im not taking my laptop in to work each time I teach (I ride a bike and its a big laptop) so I'm trying to get a standalone unit that can work without being connected to IT....
I think a pot would be a better choice here. Less stuff to do in the code. Just a map and constrain pair with the analog value.
Sounds like exactly what I need given my skillset.
In my head I have an LCD and maybe a keypad to view and enter the values (although rotary encoders would look almost as good on the final project)
The problem is the ideas are in my head, the ability to execute, not so much. But I'm in no real rush so I have time to learn (famous last words)
The following youtube video just poped into my inbox, doing PID control for a self balancing robot, and like you he did not want to keep changing the PID values and used potentiometers to change the values. So I thought of you and hope this helps
As said I would rather use encoders as its easy to make each encoder 'click' (assuming you get clickable ones 😎 ) increment or decrement by a chosen value. So for kd you could increment in steps of 10 and for ki you could move in precise 0.01 steps etc. And each click would increment the same value. You will not be able to get such precise setting with a potentiometer. Well you can look at the code for the potentiometer as per above and then look at the code in the DroneBot video to see which keeps you on the level 😀. (note that the DroneBot article also covers encoders for motors, but the bit of code for his knob is the bit to look at, oo err missus 😍 )