
AVR servodriver för DC motorer
Nu har jag till slut återupptagit detta projektet!
Har jag "översatt" formeln korrekt till kod?
Formeln är Typ C härifrån!
Har jag "översatt" formeln korrekt till kod?
Kod: Markera allt
Formel:
CO(k) = CO(k-1) - Kp * [PV(k) - PV(k-1)] + Ki * T * e(k) - kd / T * [PV(k) - 2PV(k-1) + PV(k-2)]
Pseudo kod:
PV_2 = PV_1;
PV_1 = PV;
e = SP - PV;
P_term = Kp * (PV - PV_1);
I_term = Ki * T * e;
D_term = (kd / T) * (PV - (2 * PV_1) + PV_2);
CO = CO - P_term + I_term - D_term;
Jag hittade en implementering av formeln här:
http://home.hccnet.nl/e.vd.logt/htm/reg ... k.htm#PID2
Den är lite omvänd då den räknar ut P och D negativt och adderar allt i slutet istället!
Jag tror jag ska slänga ihop ett litet test också!
http://home.hccnet.nl/e.vd.logt/htm/reg ... k.htm#PID2
Den är lite omvänd då den räknar ut P och D negativt och adderar allt i slutet istället!
Jag tror jag ska slänga ihop ett litet test också!

Nu har jag gjort ett enkelt test:
Controller output påverkar Process variabeln med 25% "verkningsgrad"
Detta blir resultated av koden:
Som mest var felet 3 så jag orkar inte trimma in P, I och D något
Men det verkar ju fungera utmärkt vid en så linjär "last" och stegning som jag programerade för iaf!
Edit: när jag får orken ska jag hacka ihop ett grafiskt test. Tänkte man kör SP 0 i 50 steg, sen SP 50 i 100 steg sen SP 0 i 100 steg till...
Sen plottar man ut SP Versus PV.
Tänkte slänga in sliders för P, I och D så man lätt kan justera parametrarna också!
Kod: Markera allt
int main()
{
//Globala variabler
int T, E;
int SP, PV, PV_1, PV_2;
int CO;
float Kp, Ki, Kd;
//Inställning
Kp = 1.0;
Ki = 1.0;
Kd = 1.0;
T = 1;
//Nollställ variabler
SP = PV = PV_1 = PV_2 = 0;
CO = 0;
while(1==1)
{
E = SP - PV;
float Pt = Kp * (PV - PV_1);
float It = Ki * T * E;
float Dt = (Kd / T) * (PV - (2 * PV_1) + PV_2);
CO = CO - Pt + It - Dt;
PV_2 = PV_1;
PV_1 = PV;
cout << "SP: " << SP << " PV: " << PV << " Error: " << E << " CO: " << CO << endl;
PV += CO * 0.25;
system("pause");
SP++;
}
}
Detta blir resultated av koden:
Kod: Markera allt
SP - PV - E - CO
-----------------
0 0 0 0
1 0 1 1
2 0 2 3
3 0 3 6
4 1 3 7
5 2 3 9
6 4 2 8
7 6 1 7
8 7 1 8
9 9 0 5
10 10 0 5
11 11 0 4
12 12 0 3
13 12 1 5
14 13 1 4
15 14 1 4
Sedan verkar den stabilisera sig på CO 4 pga upplösningen.

Edit: när jag får orken ska jag hacka ihop ett grafiskt test. Tänkte man kör SP 0 i 50 steg, sen SP 50 i 100 steg sen SP 0 i 100 steg till...
Sen plottar man ut SP Versus PV.
Tänkte slänga in sliders för P, I och D så man lätt kan justera parametrarna också!
Världen är liten! 
Sitter och funderar på hur man primitivt skulle kunna simulera en servo med enkoder...
Om vi tänker oss en motor på max 3000 RPM @ 100V, 400 pulser per varv och en dc spänning på h-bryggan av 100V samt PID på 1kHz:
100/256 = 0,390625 V upplösning
3000/100 = 30 RPM / V
0,390625 * 30 = 11,71875 varv per 1/256 PWM Dutycycle och minut
11,71875 / 60 = 0,1953125 varv per per 1/256 PWM Dutycycle och sekund
0,1953125 / 1000 = 0,0001953125 varv per 1/256 PWM Dutycycle och PID loop.
Detta tal multipliceras först med PWM från PIDen och adderas/subtraheras från en räknare varje PID loop beroende på riktning.
1/400 = 0,0025 varv per puls. Varje gång räknaren ser en summerad ändring större än en puls så ändras Process variabeln.
Har jag tänkt rätt? (om man bortser från att den är helt opåverkad från fysikens lagar)

Sitter och funderar på hur man primitivt skulle kunna simulera en servo med enkoder...
Om vi tänker oss en motor på max 3000 RPM @ 100V, 400 pulser per varv och en dc spänning på h-bryggan av 100V samt PID på 1kHz:
100/256 = 0,390625 V upplösning
3000/100 = 30 RPM / V
0,390625 * 30 = 11,71875 varv per 1/256 PWM Dutycycle och minut
11,71875 / 60 = 0,1953125 varv per per 1/256 PWM Dutycycle och sekund
0,1953125 / 1000 = 0,0001953125 varv per 1/256 PWM Dutycycle och PID loop.
Detta tal multipliceras först med PWM från PIDen och adderas/subtraheras från en räknare varje PID loop beroende på riktning.
1/400 = 0,0025 varv per puls. Varje gång räknaren ser en summerad ändring större än en puls så ändras Process variabeln.
Har jag tänkt rätt? (om man bortser från att den är helt opåverkad från fysikens lagar)

Um, jag tycker det där ser minst sagt konstigt ut...
Om jag tolkat variablerna rätt:
SP = set point, dvs börvärde.
PV = Present value, dvs nuvärdet.
PV_1 = föregående värde
PV_2 = förr-föregående värde.
E = error, felet.
CO = controller output, dvs det du matar ut till vad det nu är.
Då tycker jag att:
P-termen i ditt första värde ser mycket mer ut som derivata-termen. Det borde vara felet som multipliceras, inte skillnaden mellan nuvarande och föregående värde som ju ungefär är derivatan.
I-termen är din proportionella förstärkning eftersom du bara multiplicerar felet med något här.
D-termen är skum.
Du borde göra såhär istället:
PV_1 = PV;
PV = läs in pv;
E = SP-PV;
E-integral = E-integral + E;
P-term = Kp * E;
I-term = Ki * E-integral;
D-term = Kd * (PV-PV_1);
CO = P-term + I-term + D-term;
I Kp, Ki och Kd förkortar du bort alla andra konstantberäkningar(vilket iofs kompilatorn sannolikt gör åt dig i alla fall).
Det här borde ge dig en enkel och smidig pid-regulator, sätt någon av Kp,Ki,Kd till noll för att ta bort någon regulatordel.
Om jag tolkat variablerna rätt:
SP = set point, dvs börvärde.
PV = Present value, dvs nuvärdet.
PV_1 = föregående värde
PV_2 = förr-föregående värde.
E = error, felet.
CO = controller output, dvs det du matar ut till vad det nu är.
Då tycker jag att:
P-termen i ditt första värde ser mycket mer ut som derivata-termen. Det borde vara felet som multipliceras, inte skillnaden mellan nuvarande och föregående värde som ju ungefär är derivatan.
I-termen är din proportionella förstärkning eftersom du bara multiplicerar felet med något här.
D-termen är skum.
Du borde göra såhär istället:
PV_1 = PV;
PV = läs in pv;
E = SP-PV;
E-integral = E-integral + E;
P-term = Kp * E;
I-term = Ki * E-integral;
D-term = Kd * (PV-PV_1);
CO = P-term + I-term + D-term;
I Kp, Ki och Kd förkortar du bort alla andra konstantberäkningar(vilket iofs kompilatorn sannolikt gör åt dig i alla fall).
Det här borde ge dig en enkel och smidig pid-regulator, sätt någon av Kp,Ki,Kd till noll för att ta bort någon regulatordel.
Detta är ju en "Allen Bradley Logix5550 Independent PID equation" eller "textbook PID":
CO = CO + Kp * [E - E_1] + Ki * T * E + (Kd/T) * [E - (2 * E_1) + E_2]
Såvtt jag förstått allt är skälet till att man tar bort Setpoint från P och D är att stora förändringar i setpoint inte ska påverka controller output. Istället ska bara felet samt förändringstakten av process variabeln påverka.
Jag ska pröva den ovan istället senare ikväll!
CO = CO + Kp * [E - E_1] + Ki * T * E + (Kd/T) * [E - (2 * E_1) + E_2]
Såvtt jag förstått allt är skälet till att man tar bort Setpoint från P och D är att stora förändringar i setpoint inte ska påverka controller output. Istället ska bara felet samt förändringstakten av process variabeln påverka.
Jag ska pröva den ovan istället senare ikväll!