Moin,
ich bin Neuling und ungelehrter aber höchst interessiert an
mikrocontrollern.
Habe mir für den anfang ein arduino duemillanove mit motorshield rev
zugelegt bereu aber auch schon den kauf des motorshields, aber egal zum
Thema. ich habe hier als set up Duelmillanove sainsmart motorshiel einen
getriebe dc motor 1 zu 17 übersetzung 12v travo mehrere linera potis
gewindestange mit einenr mutter an der ein Teleskopierbare Hebel
angebaut ist. Dieser führt zum poti und betätigt diesen. Die
gewindestange wird vom dc motor gedreht und schwenk den hebel von links
nach rechts. Das ist mein Versuchsaufbau, das spätere ziel das der motor
mit hilfe eines moosgummirades am lenkrad und das an der vorderachse ein
ein poti den lenkwinkel bestimmt.
ich hab schon geübt und gespielt mit motor und poti aber bei der pid
positions regelung finde ich momentan meine Grenzen.
Ich hab mir mehrere codes und librarys durchgelesen muss aber sagen aus
den librarys werde ich nicht klug! darum meine bitte an euch könnt ihr
mir bitte weiterhelfen
Brett beguards pid example aus dem tutorial wurde meist als sehr rubust
gelobt aber irgendwie fehlt da doch die würze für meon vorhaben ich
dachte daran die aggressiv KP,KI,KD und konstant KD,KI,KP von der
adaptive tuning pid library einzubauen um schnell und sicher zur
gewünschten position zu kommen.
so ich hab mich mal probiert die beiden zusammen zu bringen weis aber
nicht mehr weiter wie ich die parameter KP,KI,KD tausche und verdammte
axt wie krieg da die drehrichtung raus das kann doch nicht so einfach
wie zum beispiel mit einer if funktion. :D
1
/*working variables*/
2
unsignedlonglastTime;
3
doubleInput,Output,Setpoint;
4
doubleITerm,lastInput;
5
doublekp,ki,kd;
6
intSampleTime=1000;//1 sec
7
doubleoutMin,outMax;
8
boolinAuto=false;
9
doubleaggKp=4,aggKi=0.2,aggKd=1;
10
doubleconsKp=1,consKi=0.05,consKd=0.25;
11
12
#define MANUAL 0
13
#define AUTOMATIC 1
14
15
#define DIRECT 0
16
#define REVERSE 1
17
18
#include<MSMotorShield.h>
19
20
MS_DCMotormotor(4);
21
22
23
24
intcontrollerDirection=DIRECT;
25
26
voidsetup(){
27
Serial.begin(9600);
28
motor.run(RELEASE);
29
Input=analogRead(5);
30
Setpoint=500;
31
32
33
34
}
35
36
voidloop()
37
{
38
Input=analogRead(5);
39
40
doublegap=abs(setoint-input);
41
if(grap<15);
42
SetTunings(consKp,consKi,consKd);
43
else
44
SetTunings(aggKp,aggKi,aggKd);
45
}
46
voidCompute()
47
{
48
if(!inAuto)return;
49
unsignedlongnow=millis();
50
inttimeChange=(now-lastTime);
51
if(timeChange>=SampleTime)
52
Input=analogRead(5);
53
{
54
/*Compute all the working error variables*/
55
doubleerror=Setpoint-Input;
56
ITerm+=(ki*error);
57
if(ITerm>outMax)ITerm=outMax;
58
elseif(ITerm<outMin)ITerm=outMin;
59
doubledInput=(Input-lastInput);
60
61
/*Compute PID Output*/
62
Output=kp*error+ITerm-kd*dInput;
63
if(Output>outMax)Output=outMax;
64
elseif(Output<outMin)Output=outMin;
65
66
/*Remember some variables for next time*/
67
lastInput=Input;
68
lastTime=now;
69
}
70
}
71
72
voidSetTunings(doubleKp,doubleKi,doubleKd)
73
{
74
if(Kp<0||Ki<0||Kd<0)return;
75
76
doubleSampleTimeInSec=((double)SampleTime)/1000;
77
kp=Kp;
78
ki=Ki*SampleTimeInSec;
79
kd=Kd/SampleTimeInSec;
80
81
if(controllerDirection==REVERSE)
82
{
83
kp=(0-kp);
84
ki=(0-ki);
85
kd=(0-kd);
86
}
87
}
88
89
voidSetSampleTime(intNewSampleTime)
90
{
91
if(NewSampleTime>0)
92
{
93
doubleratio=(double)NewSampleTime
94
/(double)SampleTime;
95
ki*=ratio;
96
kd/=ratio;
97
SampleTime=(unsignedlong)NewSampleTime;
98
}
99
}
100
101
voidSetOutputLimits(doubleMin,doubleMax)
102
{
103
if(Min>Max)return;
104
outMin=Min;
105
outMax=Max;
106
107
if(Output>outMax)Output=outMax;
108
elseif(Output<outMin)Output=outMin;
109
110
if(ITerm>outMax)ITerm=outMax;
111
elseif(ITerm<outMin)ITerm=outMin;
112
}
113
114
voidSetMode(intMode)
115
{
116
boolnewAuto=(Mode==AUTOMATIC);
117
if(newAuto==!inAuto)
118
{/*we just went from manual to auto*/
119
Initialize();
120
}
121
inAuto=newAuto;
122
}
123
124
voidInitialize()
125
{
126
lastInput=Input;
127
ITerm=Output;
128
if(ITerm>outMax)ITerm=outMax;
129
elseif(ITerm<outMin)ITerm=outMin;
130
}
131
132
voidSetControllerDirection(intDirection)
133
{
134
controllerDirection=Direction;
135
}
oder sollte man ein autotune regler nehmen auf jeden fall darf er nie
aufhören zu regeln da es fremdeinflüsse auf die lenkung gibt die den
schonmal ne bewegung am lenkrad ausmachen, aber das dauerhafte regeln
dürfte ja ein positiver nebeneffekt sein.
ich hoffe ihr könnt mir helfen
Vielen dank im vorraus
dreyer
Philipp Dreyer schrieb:> if(grap<15);
wo haste denn grap deklariert?
ausserdem: nach if (irgendeine Bedingung) hätte ich jetzt
kein Semikolon (;) erwartet.
tommy schrieb:> ausserdem: nach if (irgendeine Bedingung) hätte ich jetzt> kein Semikolon (;) erwartet.
Nur mit Semikolon dahinter kann der Compiler die Zeile wegoptimieren und
über das nicht deklarierte grap hinwegsehen. ;-)
Muss man zum drehrichtungswechsel die pid paramter mit einem - versehen
?
if (grap<0) (contollerDirection=REVERSE);
if (Output<0) motor.run(BACKWARD);
if (Output>0) motor.run(FORWARD);
double Min=110, Max=250;
set.MotorSpeed(Output);
was meint ihr dazu?
danke im vorraus
dreyer
Mir scheint, du stocherst da etwas im Dunklen. Lass dir doch mal per
seriell einige Parameter, wie z.B. outMin und outMax, sowie den Output
des PID Reglers ausgeben und schau erstmal, wo die Werte überhaupt sind,
wenn du manuell das Rückmeldepoti drehst (Motor abgeklemmt). Je näher du
dann dem Setpoint kommst, umso kleiner sollte Output werden. Übrigens
ist double hier wirklich übertrieben und kostet sehr viel Zeit. Wenn du
schon mit Gleitkommazahlen agierst, reicht float hier dicke aus. Eine
flinke PID Berechnung wäre besser mit int realisiert.
Gut, wenn Output das Vorzeichen wechselt, müsstest du, wenn alles o.k.
ist, den Setpoint überschritten haben und das Servo will in die andere
Richtung drehen.
Dein Ziel ist es nun, Output in ein passendes Format zu bringen und
damit die PWM anzusteuern.
Dein nächstes Ziel müsste sein, die Parameter P,I und D per Konsole
ändern zu können, um dein Servogebilde stabil und reaktionsschnell zu
bekommen, wenn du den Setpoint per Sollwert-Poti änderst.
Als kleiner Tipp: Wenn du den einen Parameter auf null drehst, ist er
ausser Gefecht. Also D auf null und es bleibt ein PI Regler übrig.
Fang mit P alleine an und dann füge die I und D Komponente zu.
Philipp Dreyer schrieb:> Sagen wir mal so wie kriegt man in arduino rein??
Dieser Satz kein Verb :-P
Evtl. fehlt bei deinem Programm die Hauptschleife? Du hast nichts über
das gesagt, was am seriellen Port rauskommt?
Geh doch mal bitte schrittweise vor und fang nicht gleich mit dem
Komplettprogramm an. Prüfe jedes Unterprogramm für sich. Und am besten
liest du dir auch mal die Application Note 221 von Atmel durch, da wird
ein prima PID Regler beschrieben, den du leicht auf deine Bedürfnisse
ändern kannst. Ausserdem steht da eine ganze Menge zur Theorie eines
PID.
Matthias Sch. schrieb:> Philipp Dreyer schrieb:>> Sagen wir mal so wie kriegt man in arduino rein??>> Dieser Satz kein Verb :-P>> Evtl. fehlt bei deinem Programm die Hauptschleife? Du hast nichts über> das gesagt, was am seriellen Port rauskommt?> Geh doch mal bitte schrittweise vor und fang nicht gleich mit dem> Komplettprogramm an. Prüfe jedes Unterprogramm für sich. Und am besten> liest du dir auch mal die Application Note 221 von Atmel durch, da wird> ein prima PID Regler beschrieben, den du leicht auf deine Bedürfnisse> ändern kannst. Ausserdem steht da eine ganze Menge zur Theorie eines> PID.
moin,
ich war frustriert :D
hab mich aber zusammengerissen und ein bisschen gebastellt und bin bis
jetzte bei folgendem code angekommen. Meon problem ist momentan, dass
ich die Pid outputs begränzen will für eine pwm funktion. Also im
positiven bereich von 110bis250 und im negativen bereich von
-110bis-250. Dann hab ich hoffentlich die möglichkeit über eine if
abfrage ob output < als 0 ist die möglichkeit die drehrrichtung des
motors zu bestimmen und kann den output direkt als pwm zahl einsetzen.
Das ist mein nächstes ziel! ich hab die Output begrenzung mit den beiden
Kommentar Strichen "//" aus den code raus genommen. So wie der code ist
lauft er und regelt auch, aber wenn ich die begrenzung einsetzen will
setzt er sich auf -10 beim ITerm fest
und beim Output auf -110.
Noch mal geschirr habe ein poti auf A5 und lasse mir die Zahlen Serial
ausgeben
unsigned long lastTime;
float Input, Output, Setpoint;
float fehler, ITerm, lastInput;
float kp, ki, kd;
int SampleTime = 1000; //1 sec
float NewSampleTime=0;
float outMin, outMax;
bool inAuto = true;
float aggKp=4, aggKi=0.2, aggKd=1;
float consKp=1, consKi=0.05, consKd=0.25;
int Min=(110), Max=(250);
int minusMin(-110), minusMax=(-250);
float Kp=2,Ki=0.5,Kd=2;
float ratio;
float outmax = (255);
int outmin = (10);
int minusoutmax = (-255);
int minusoutmin = (-10);
int minusoutMax;
int minusoutMin;
void setup() {
Serial.begin(9600);
Input=analogRead(5);
Setpoint=(500);
// put your setup code here, to run once:
}
void loop() {
Input=analogRead(5);
if(!inAuto) return;
unsigned long now = millis();
int timeChange = (now - lastTime);
if(timeChange>=SampleTime)
Input=analogRead(5);
/*Compute all the working error variables*/
float fehler = Setpoint - Input;
ITerm = (ki * fehler);
// { if (ITerm > outmax) ITerm = (255);
// if (ITerm < outmin) ITerm = (10);}
// { if (ITerm > minusoutmax) ITerm = (-255);
// if (ITerm < minusoutmin) ITerm = (-10) ;
// }
float dInput = (Input - lastInput);
/*Compute PID Output*/
Output = kp * fehler + ITerm- kd * dInput;
/*Remember some variables for next time*/
lastInput = Input;
lastTime = now;
//if (Kp<0 || Ki<0|| Kd<0) return;
SampleTime=1000;
float SampleTimeInSec = ((int) SampleTime/1000);
kp = Kp;
ki = Ki * SampleTimeInSec;
kd = Kd / SampleTimeInSec;
if (NewSampleTime > 0)
{ float ratio = (NewSampleTime / SampleTime);
ki *= ratio;
kd /= ratio;
SampleTime = (unsigned long)NewSampleTime; }
if(Min > Max) return;
outMin = Min;
outMax = Max;
minusoutMin = minusMin;
minusoutMax = minusMax;
//if(Output > outMax) Output = outMax;
//else if(Output < outMin) Output = outMin;
//if(Output > minusoutMax) Output = outMax;
//else if(Output < minusoutMin) Output = outMin;
//if(ITerm > outMax) ITerm= outMax;
//else if(ITerm < outMin) ITerm= outMin;
//Serial.print("setpoint: ");Serial.print(Setpoint); Serial.print(" ");
Serial.print("input: ");Serial.print(Input); Serial.print(" ");
Serial.print("output: ");Serial.print(Output); Serial.print(" ");
//Serial.print("fehler");Serial.print(fehler);Serial.print(" ");
Serial.print("iterm");Serial.print(ITerm);Serial.print(" ");
Serial.print("ki");Serial.print(ki);Serial.print(" ");
Serial.print("dinput");Serial.print(dInput);Serial.print(" ");
Serial.print("ratio");Serial.print(ratio);Serial.print(" ");
Serial.print("sampletimeinsec");Serial.print(SampleTimeInSec);Serial.pri
nt(" ");
Serial.print("timechange");Serial.print(timeChange);Serial.print(" ");
Serial.flush();
delay(500);
// put your main code here, to run repeatedly:
für irgendwelche verbesserungen in meiner code grammatik und Aufbau?
Immer her damit habe ein offenes ohr für alles.
vielen dank im vorraus Dreyer
Philipp Dreyer schrieb:> outMin = Min;> outMax = Max;> minusoutMin = minusMin;> minusoutMax = minusMax;
Das ist mir nicht klar. Warum setzt du den deine eigentlich festen
Grenzwerte hier auf neue Werte? Lass das mal weg und schau dir dann
nochmal die Werte an.
Ausserdem solltest du dir wirklich mal die AVR221 ansehen, dein ganzes
float-zu-int-und-wieder-zurück hin und her ist nämlich noch eine
Fehlerquelle.
Noch ein Tipp: Bewege dich nur im positiven Zahlenbereich und definiere
einfach z.B. 128 als Grenze. Ist der Output darunter, dreht sich der
Motor in eine Richtung, dadrüber in die andere.