0
Offline
Newbie
Karma: 0
Posts: 1
Arduino rocks
|
 |
« Reply #105 on: November 07, 2010, 02:50:52 am » |
very interesting
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Newbie
Karma: 0
Posts: 6
Arduino rocks
|
 |
« Reply #106 on: November 18, 2010, 08:37:10 pm » |
Hey all, I've finished up the code for a standalone sous vide controller with a small LCD screen and a 3-button interface. I'm using the one-wire DS18B20 temperature sensor for input and a solid state relay receives the output. All the parts are here, and everything works, I just need to put it together now. I figured I'd post the code for others to critique: #include <TimerOne.h> #include <PID_Beta6.h> #include <OneWire.h> #include <DallasTemperature.h> #include <LiquidCrystal.h> #include <Button.h>
#define ONE_WIRE_BUS 9
OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire);
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
int controlPin = 10;
int upButtonPin = 6; int downButtonPin = 7; int selButtonPin = 8;
Button upButton = Button(upButtonPin, PULLDOWN); Button downButton = Button(downButtonPin, PULLDOWN); Button selButton = Button(selButtonPin, PULLDOWN);
double params[4] = {140, 90,300,0}; char param_char[4] = {'S', 'P', 'I', 'D'}; double increment[4] = {1, 5, 5, 5};
double Input, Output; double Setpoint = params[0]; double Bias = 200;
float temperature = 0; int menuPos = 0; int loopDelay = 0;
PID pid(&Input, &Output, &Setpoint, &Bias, params[1], params[2], params[3]);
void setup() { /*Serial.begin(9600);*/ pinMode(controlPin, OUTPUT); sensors.begin();
pid.SetOutputLimits(0,1023); Output = 0; pid.SetMode(AUTO);
Timer1.initialize(); Timer1.pwm(controlPin, Output); lcd.begin(16, 2); lcd.clear(); lcd.print("Arduino PID"); lcd.setCursor(0,1); lcd.print("Controller"); /*Serial.print("Arduino PID Controller\n");*/ delay(5000); lcd.clear(); }
void loop() { sensors.requestTemperatures(); temperature = sensors.getTempFByIndex(0);
Input = (double)temperature; if(Setpoint - Input > 3){ Setpoint -= 5; pid.Compute(); Setpoint += 5; } else{ pid.Compute(); } Timer1.setPwmDuty(controlPin, (int)Output); delay(loopDelay); lcd.setCursor(0,0); lcd.print("T:"); lcd.print(temperature,1); lcd.setCursor(9,1); lcd.print("O:"); lcd.print(Output,0); lcd.setCursor(0, 1); lcd.print("S:"); lcd.print(Setpoint,0);
/*Serial.print("T:"); Serial.print(temperature); Serial.print("\t"); Serial.print("O:"); Serial.print(Output,0); Serial.print("\t"); Serial.print("S:"); Serial.print(Setpoint,0); Serial.print("\n");*/ if(selButton.uniquePress()) { lcd.clear(); for(menuPos = 0; menuPos < 4; ){ lcd.setCursor(0,0); lcd.print(param_char[menuPos]); lcd.print(": "); lcd.print(params[menuPos],0);
/*Serial.print(param_char[menuPos]); Serial.print(": "); Serial.print(params[menuPos],0); Serial.print("\n");*/
if (upButton.uniquePress()) { params[menuPos] += increment[menuPos]; } if (downButton.uniquePress()) { params[menuPos] -= increment[menuPos]; } if(selButton.uniquePress()) { menuPos++; lcd.clear(); } } Setpoint = params[0]; pid.SetTunings(params[1], params[2], params[3]); lcd.clear(); } }
All the commented out serial stuff is from testing before my LCD came. Let me know if you have any questions or advice on something I could do better. PS - I just realized scanning my code here that the menu loop keeps the PID from calculating, so if it was left in that mode the output would never change. I guess I'll work a button timer in there to jump back to the main loop if you don't do anything for 5 seconds or so.
|
|
|
|
|
Logged
|
|
|
|
|
San Diego
Offline
Newbie
Karma: 0
Posts: 7
Arduino rocks
|
 |
« Reply #107 on: November 21, 2010, 03:26:29 am » |
Hi, I just got my Arduino last week and have been playing around with it. Im working on part of a robot that is a turntable. Basically a disc with a friction drive (1 DC motor) that needs to rotate to specific locations. I had previously coded it in basic with my own PID but i wanted it to work with my new arduino. I ran across your library and had some questions. How is it that the direction of the motor is changed? not sure if i missed something but i cant seem to find where to define a pin for direction of the motor. The code i have so far is below, the position of the turntable is read with a potentiometer. Any help is appreciated.  /* Created by Alan Sanchez 2010 */
#include <PID_Beta6.h> double Setpoint, Input, Output; PID pid(&Input, &Output, &Setpoint,5,30,1);
//VARIABLES//
int motorpwm = 3; int direc = 2; int button = 12; int pos; int photo;
void setup() { Serial.begin(9600); pinMode(motorpwm, OUTPUT); //pinMode(direc, OUTPUT); pinMode(button, INPUT); //declare button pin as input Input = analogRead(A0); Output = 0; pid.SetOutputLimits(0,500); pid.SetMode(AUTO); //turn on PID Setpoint = 313; }
void loop() { digitalWrite(direc, HIGH); if (digitalRead(button) == HIGH){ //if button is pressed go to end() Serial.println("button has been pressed"); while(1) { //pos = analogRead(A0); //read pot in analog pin A0 //photo = analogRead(A1); //read photosensor in analog pin A1 Input = analogRead(A0); pid.Compute(); analogWrite(motorpwm, Output/4); Serial.print("Pot Value = "); //print pot value Serial.print(Input, DEC); Serial.print(" "); Serial.print("Output = "); //print photo value Serial.println(Output/4, DEC); } analogWrite(motorpwm, 0); } }
|
|
|
|
|
Logged
|
|
|
|
|
Boston
Offline
Full Member
Karma: 0
Posts: 101
Arduino rocks
|
 |
« Reply #108 on: November 21, 2010, 08:05:53 am » |
How is it that the direction of the motor is changed? I understand your question to mean that the motor seems to be going backwards, forcing you away from setpoint. if this is the case, you need to change the sign of the P term. so instead of: PID pid(&Input, &Output, &Setpoint,5,30,1);
you want: PID pid(&Input, &Output, &Setpoint,-5,30,1);
|
|
|
|
« Last Edit: November 21, 2010, 08:06:20 am by br3ttb »
|
Logged
|
|
|
|
|
San Diego
Offline
Newbie
Karma: 0
Posts: 7
Arduino rocks
|
 |
« Reply #109 on: November 21, 2010, 11:41:17 am » |
no, what i meant to ask is how does the PID switch the direction of the motor to deal with overshoot. The way it is right now it just stops but because of inertia it wont stop at the correct spot, and if it goes past the set point there is no bringing it back.
|
|
|
|
|
Logged
|
|
|
|
|
San Diego
Offline
Newbie
Karma: 0
Posts: 7
Arduino rocks
|
 |
« Reply #110 on: November 21, 2010, 12:03:57 pm » |
actually if it isnt supported, i guess what i could do is switch direction depending on error something like: if (Error<0) { Pterm = -5 else if (Error>0) Pterm = 5 }
|
|
|
|
|
Logged
|
|
|
|
|
Boston
Offline
Full Member
Karma: 0
Posts: 101
Arduino rocks
|
 |
« Reply #111 on: November 21, 2010, 12:44:10 pm » |
no, what i meant to ask is how does the PID switch the direction of the motor to deal with overshoot ah. in that case, take a look at Post 16 on this thread. maybe that will help. Brett
|
|
|
|
|
Logged
|
|
|
|
|
San Diego
Offline
Newbie
Karma: 0
Posts: 7
Arduino rocks
|
 |
« Reply #112 on: November 21, 2010, 03:56:52 pm » |
that works! thank you this is what the code looks like now /* Created by Alan Sanchez 2010 */
#include <PID_Beta6.h> double Setpoint, Input, Output; PID pid(&Input, &Output, &Setpoint,3,30,5);
//VARIABLES//
int motorpwm = 5; int direc = 4; int button = 2; int pos; int photo;
void setup() { Serial.begin(9600); pinMode(motorpwm, OUTPUT); pinMode(direc, OUTPUT); pinMode(button, INPUT); //declare button pin as input Input = analogRead(A0); Output = 0; pid.SetOutputLimits(-400,400); pid.SetMode(AUTO); //turn on PID Setpoint = 313; }
void loop() { //digitalWrite(direc, HIGH); if (digitalRead(button) == HIGH){ //if button is pressed go to end() Serial.println("button has been pressed"); while(1) { //pos = analogRead(A0); //read pot in analog pin A0 //photo = analogRead(A1); //read photosensor in analog pin A1 Input = analogRead(A0); pid.Compute(); if (Output < 0) { digitalWrite(direc, LOW); } else if (Output>0) { digitalWrite(direc, HIGH); } else { Output=0; } int drive = Output/4; analogWrite(motorpwm, drive); Serial.print("Pot Value = "); //print pot value Serial.print(Input, DEC); Serial.print(" "); Serial.print("Output = "); //print photo value Serial.println(drive, DEC); } } }
all thats left to do is fine tune the PID. Again thanks for the library, it saves soooo much time.
|
|
|
|
|
Logged
|
|
|
|
|
San Diego
Offline
Newbie
Karma: 0
Posts: 7
Arduino rocks
|
 |
« Reply #113 on: November 22, 2010, 02:29:29 am » |
actually, ive been noticing that the Output value doesnt change when i set ranges for output from -255 to 255 . it just goes to max or min no matter what the gains are. as soon as comment out the limits it starts working again. any idea what might be causing this? code below: /* Created by Alan Sanchez 2010 */
#include <PID_Beta6.h> double Setpoint, Input, Output; PID pid(&Input, &Output, &Setpoint,4,35,10);
//VARIABLES//
int motorpwm = 5; int direc = 4; int button = 2; int pos; int photo;
void setup() { Serial.begin(9600); pinMode(motorpwm, OUTPUT); pinMode(direc, OUTPUT); pinMode(button, INPUT); //declare button pin as input Input = analogRead(A0); Output = 0; pid.SetInputLimits(0,1023); pid.SetOutputLimits(-255,255); pid.SetMode(AUTO); //turn on PID Setpoint = 313; }
void loop() { //digitalWrite(direc, HIGH); if (digitalRead(button) == HIGH){ //if button is pressed go to end() Serial.println("button has been pressed"); while(1) { //pos = analogRead(A0); //read pot in analog pin A0 //photo = analogRead(A1); //read photosensor in analog pin A1 Input = analogRead(A0); pid.Compute(); if (Output < 0) { digitalWrite(direc, LOW); } else if (Output>0) { digitalWrite(direc, HIGH); } else { Output=0; } int drive = abs(Output)/4; analogWrite(motorpwm, drive); //Serial.print("Pot Value = "); //print pot value Serial.println(Input, DEC); //Serial.print(" "); //Serial.print("Drive = "); //print photo value Serial.println(Output, DEC); //Serial.print(" "); //Serial.print("Direc = "); //print photo value //Serial.println(direc, DEC); } } }
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Newbie
Karma: 0
Posts: 3
Arduino rocks
|
 |
« Reply #114 on: November 24, 2010, 12:41:37 pm » |
Hello Brett, First of all GREAT WORK!! Your library has saved me a lot of time. But i´m having a small problem. For some reason using the Processing Front End, everything works great, but when i try to edit manually the values and click to send it to Arduino, it just comes back to the original values. As i couldn´t figure out what is wrong, since the communication seems to be ok, and i can see Processing IS sending something to arduino, and the arduino portion seems to be alright.. i had the ideia to have the best of both worlds anyway. I addes 3 pots to manually contro e P.I and D values. I would watch the values and the result on the Processing Front End, and manually adjust the values via the potentiometers. The only problem now is that for some reason, pid.SetTunings doesn´t seem to change the values correctly. Remember the Example 2 ? Well i´m doing exactly the same thing exept for the setpoint ramp stuff. Mine´s fixed. Here´s the relevant portion of my code. I´m using it to stabilize de Y axis of a UAV. It´s loaded into a test platform where i have a horizontal arm being held in place by a fixed vertical arm. It has a motor on each side, and they try to keep the arm stable and leveled. Any disturbances should be imediately compensated. double Input, Output, Setpoint; PID pid(&Input, &Output, &Setpoint, 3,9,3); // PID pid(&Input, &Output, &Setpoint,potPin1,potPin2,potPin3); double Outputinv; unsigned long serialTime; //this will help us know when to talk with processing
const int buttonPin = 52; int buttonState = 0;
void setup() { static int i; Serial.begin(57600); pinMode(13, OUTPUT); servoL.attach(2); servoR.attach(3); pinMode(buttonPin, INPUT); pid.SetInputLimits(-80,89); pid.SetOutputLimits(900,1200); //tell the PID to range the output from 1000 to 2000 Output = 900; //start the output at min and let the PID adjust it from there pid.SetMode(AUTO); //turn on the PID pid.SetSampleTime(10); Setpoint = 57;
void loop() { buttonState = digitalRead(buttonPin); if (buttonState == HIGH) { initmotors(); delay(2000); } getEstimatedInclination();
pot1Value = analogRead(potPin1); pot1Value = pot1Value /100; pot2Value = analogRead(potPin2); pot2Value = pot2Value /100; pot3Value = analogRead(potPin3); pot3Value = pot3Value /100;
pid.SetTunings(potPin1,potPin2,potPin3);
Input = (RwEst[1]*100); pid.Compute(); servoR.writeMicroseconds(Output); Outputinv = map(Output, 900, 1200, 1200, 900); servoL.writeMicroseconds(Outputinv); if(millis()>serialTime) { SerialReceive(); SerialSend(); serialTime+=500; } }
Any help would be much appreciated.
|
|
|
|
|
Logged
|
|
|
|
|
San Diego
Offline
Newbie
Karma: 0
Posts: 7
Arduino rocks
|
 |
« Reply #115 on: November 24, 2010, 12:47:16 pm » |
hello everyone, I gave up using the library for my DC motor project. I was just wasting too much time and getting nowhere. However I wrote my own PID. Code is attached below for anyone to use if they run into the same problems. It will allow you to switch motor directions to do precise positioning with a DC motor, all you have to do is adjust the gains to suit your needs. -Alan /* Created by Alan Sanchez 2010 */
//VARIABLES//
int motorpin = 5; int drive; int direc = 4; // int direc; int button = 2; int pos; int photo; int target = 313; //PID Variables//
int kp = 90; int ki = 2; int kd = 100; int error; int last; int P; int I; int D; int integral = 0; int inthresh = 25; int nMet; int nMetReq = 5; int Emax = 2; int Vmax = 2; int V; void setup() { Serial.begin(9600); pinMode(motorpin, OUTPUT); pinMode(direc, OUTPUT); pinMode(button, INPUT); //declare button pin as input }
void loop() { // direc = HIGH; //digitalWrite(direc, HIGH); analogWrite(motorpin,0); int state = digitalRead(button); if (state == HIGH){ //if button is pressed begin PID Serial.println("button has been pressed"); while(1) { pos = analogRead(A0); //read pot in analog pin A0 photo = analogRead(A1); //read photosensor in analog pin A1 drive = PID(); //get drive val from PID analogWrite(motorpin, drive); //send PID drive command to motor Serial.print("nMet = "); Serial.println(nMet,DEC); //Check nMet, if satisfied end program. if(abs(error) < Emax && abs(V) < Vmax) { nMet = nMet+1; if(nMet > nMetReq) { analogWrite(motorpin, 0); Serial.println("Target reached :D"); end(); } } //Serial.print("Pot Value = "); //print pot value //Serial.print(pos, DEC); //Serial.print(" "); Serial.print("Drive = "); //print drive value Serial.print(drive, DEC); Serial.print(" "); Serial.print("Direc = "); //print direc Serial.println(direc, DEC); } } }
//PID: Calculates PID drive value. int PID() { //Serial.println("inside PID"); error = target-pos; //Serial.print("abs(error)="); //Serial.println(abs(error),DEC); if (abs(error) < inthresh) { integral = integral + error; } else { integral = 0; } //Serial.println(integral,DEC); P = error*kp; I = integral*ki; D = V*kd; drive = P+I+D; Serial.print("P+I+D= "); Serial.println(drive, DEC); if (drive<0) { digitalWrite(direc, LOW); } else if (drive>0) { digitalWrite(direc, HIGH); } else { drive=0; } Serial.print("direc_inside= "); Serial.println(direc, DEC); drive = abs(drive)/50; Serial.print("drive1= "); Serial.println(drive, DEC); drive = min(drive, 170); Serial.print("drive2= "); Serial.println(drive, DEC); drive = max(drive, 80); Serial.print("drive 3 "); Serial.println(drive, DEC); last = pos; return(drive); }
//end program int end() { Serial.println("Program will now end"); while(1); }
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Newbie
Karma: 0
Posts: 3
Arduino rocks
|
 |
« Reply #116 on: November 25, 2010, 10:51:11 pm » |
Never mind, i got it to work. Still don´t know what was causing the error though. I just deleted that portion of the code and re-typed it, and when i tried to compile, it did with no errors this time. Go figure. Anyways, i´m still trying to get the tunings right. That is one hard task to acomplish. Here´s my first test with manual tuning: I wonder if i ever am going to see that "axis" stable. Either i am too "intelectually challenged" , or there´s a looot of smart guys out there, because so many people seem to have built this kind of UAV´s seemingly with no big problems at all.. Maybe there´s an easier implementation of PID for a UAV that works better, with a fast response time and an easier way of tuning it. One more thing, during the tests i have noticed that after a few minutes of continuous running of the engines, they start to stress out and they characteristics change a bit (sensitivity to commands and stuff). Isn´t there a way of implementing some kind of "dynamic tuning" system? Thanks !
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Newbie
Karma: 1
Posts: 11
Arduino rocks
|
 |
« Reply #117 on: January 08, 2011, 12:35:42 am » |
Hey all,
I've finished up the code for a standalone sous vide controller with a small LCD screen and a 3-button interface. I'm using the one-wire DS18B20 temperature sensor for input and a solid state relay receives the output. I'm planning on doing the same thing in a few weeks here(with an lm335 though). What did you do to waterproof the sensor?
|
|
|
|
|
Logged
|
|
|
|
|
'round the world...
Offline
Edison Member
Karma: 19
Posts: 2307
|
 |
« Reply #118 on: January 08, 2011, 04:35:06 am » |
Anyways, i´m still trying to get the tunings right. That is one hard task to acomplish.
There are some manuals around the web. Have you got feedback sent to the computer so you can see the response and measure overshoot, settling time, etc, etc?? I find this one to be acceptable. http://www.expertune.com/tutor.htmlWikipedia's article is a good reference for this also. Also, if you go through ATMEL's application notes, they have application note 221 for AVR that is the implementation of a PID in C for AVR. You can get some info from that too.
|
|
|
|
|
Logged
|
Eu não sou o teu criado. Se respondo no fórum é para ajudar todos mediante a minha disponibilidade e disposição. Responder por mensagem pessoal iria contra o propósito do fórum e por isso evito-o. Se realmente pretendes que eu te ajude por mensagem pessoal, então podemos chegar a um acordo e contrato onde me pagas pela ajuda que eu fornecer e poderás então definir os termos de confidencialidade do meu serviço. De forma contrária toda e qualquer ajuda que eu der tem de ser visível a todos os participantes do fórum (será boa ideia, veres o significado da palavra fórum). Nota também que eu não me responsabilizo por parvoíces escritas neste espaço pelo que se vais seguir algo dito por mim, entende que o farás por tua conta e risco.
Dito isto, mensagens pessoais só se forem pessoais, ou seja, se já interagimos de alguma forma no passado ou se me pretendes convidar para uma churrascada com cerveja (paga por ti, obviamente).
|
|
|
|
0
Offline
Newbie
Karma: 0
Posts: 1
Arduino rocks
|
 |
« Reply #119 on: January 08, 2011, 04:47:35 am » |
There are some interger versions available e.g. google for: AVR221: Discrete PID controller on tinyAVR and megaAVR devices
|
|
|
|
|
Logged
|
|
|
|
|
|