AVR servodriver för DC motorer

Berätta om dina pågående projekt.
Användarvisningsbild
Chribbe76
EF Sponsor
Inlägg: 1167
Blev medlem: 17 januari 2004, 22:43:17
Ort: Stockholm

Inlägg av Chribbe76 »

Millox, det du skrivit fungerar dåligt på rörliga mål.
D_term = Kd * (PV-PV_1);
CO = P_term + I_term + D_term;

Om man istället gör så här så strävar D_term mot rätt riktning i förhållande till målet.
E_1 är förra felet.

D_term = Kd * (E-E_1);
CO = P_term + I_term + D_term;
Millox
Inlägg: 559
Blev medlem: 10 december 2005, 22:10:43
Ort: Östhammar

Inlägg av Millox »

Ja, såklart. Miss av mig..

JBV: Det kanske är läge att först få en vanlig pid-kontroller fungerandes innan du laborerar med andra typer. Det är trots allt ganska enkelt att få en tajt reglerloop ändå, och det kanske räcker som prestanda. Om det inte är så att du har väldigt precisa parametrar på motor och h-brygga kommer du ändå att få lite meckel när det hamnar i verkligheten.
JBV
Inlägg: 411
Blev medlem: 4 maj 2006, 11:44:28
Ort: Älvsbyn

Inlägg av JBV »

Jadå jag tänkte börja med en textbook PID:
CO = CO + Kp * [E - E_1] + Ki * T * E + (Kd/T) * [E - (2 * E_1) + E_2]

Sen är det ju bara några få rader att byta ut för att pröva andra algoritmer :)

Justeringen blir "on the fly" med ett program liknande mitt testprogram nedan, man drar i en slider för varje parameter och för varje uppdatering så skickas datan till µCn och ett testprogram körs och returnerar PV och SP så man ser felet i en graf.
JBV
Inlägg: 411
Blev medlem: 4 maj 2006, 11:44:28
Ort: Älvsbyn

Inlägg av JBV »

Nu har jag programerat in en test som mer liknar en motor.
Jag tänkte mig att motorn roterar 0,2 varv per sekund och PWM enhet.
det ger 0,0003 varv per millisekund och PWM enhet.
Vilket, med en 1000 cpr enkoder, ger 0,2 pulser per varv och millisekund (simulerad loophastighet)

Encoder = Encoder + CO * 0.2
PV = Round(Encoder, 0)

Blev genast mycket intressantare att leka med parametrarna! :)

Edit: Gjorde en bild för att jämföra kurvorna mellan 3 olika algoritmer under samma förhållanden!
Bild
Chribbe76's kommer härifrån:
http://www.elektronikforumet.com/forum/ ... hp?t=11034
Användarvisningsbild
Chribbe76
EF Sponsor
Inlägg: 1167
Blev medlem: 17 januari 2004, 22:43:17
Ort: Stockholm

Inlägg av Chribbe76 »

Jag har egentligen inte tid att leka med det här men det är ju så spännande.

Jag har en liten teori, min PID är den enklaste man kan göra och den fungerar hyffsat bra om man låter CO styra motor-strömmen (alltså vridmomentet eller "accelerationen").
Andra lite "flashigare" PIDar kanske är mer anpassade för att hantera PWM-styrning.

Det du gör nu, Encoder = Encoder + CO * 0.2 är väl mer likt PWM-styrning än ström-styrning men en simulering med den enkelheten säger egentligen ingenting om vad som kommer hända i verkligheten.

I mina simuleringar med ström-styrning gör jag istället:
Encoder = Encoder + Fart
Fart = Fart + CO
JBV
Inlägg: 411
Blev medlem: 4 maj 2006, 11:44:28
Ort: Älvsbyn

Inlägg av JBV »

Nej jag vet att det är en mycket dålig motorsimulering :) Många faktorer som saknas! Men jag orkar inte klura ut en vettigare modell då jag snart får några servon så jag kan leka irl ;)

Jag räknar ut hur många enkoderpulser PV ser per PID-loop beroende på CO (och därmed varvtal). Det du beskriver låter ju mer som att man skulle köra tachometer!?

Jag såg jag hade gjort ett fel i Typ A PIDen i mitt testprogram. Jag hade gjort så D-termen adderades istället för att subtraheras, märkte det när jag jämförde dom enskilda parametrarna att den drog åt fel håll! När jag hade ändrat det ser typ A EXAKT likadan ut som din (testade lägga dom över varandra)!

En intressant skillnad är att din PID har:
CO = Pt + It - Dt
Och Typ A:
CO = CO + Pt + It - Dt
Vilket gör din variant till en Position PID och den andra till en Velocity PID!
Velocity är tydligen den typ som används mest i digitala kontroller!
JBV
Inlägg: 411
Blev medlem: 4 maj 2006, 11:44:28
Ort: Älvsbyn

Inlägg av JBV »

Nu har jag börjat knåpa på detta igen, Har just fixat avläsningen på enkodern!

Eftersom mina encoders är på 3600 PPR (max 200kHz) så blir det tungt att få några större hastigheter i quadrature. Jag gjorde en inställning så att man kan läsa av enkodern i:
1 * PPR = 3600 CPR
2 * PPR = 7200 CPR
4 * PPR = 14400 CPR

Fungerar finfint när jag skickar PV till terminalen, riktigt känsligt i quadrature ;)
JBV
Inlägg: 411
Blev medlem: 4 maj 2006, 11:44:28
Ort: Älvsbyn

Inlägg av JBV »

Nu har jag kodat lite mer. Alla inställningar går att hämtas och sättas (samt sparas på EEPROM) via RS232:
KP, KI, KD = heltal (ska köra fixed point decimaltal tänkte jag)
EncoderMode = 1, 2 eller 4 x cpr
StepMultiplier = 1-10
ErrorLimit = 0-9999
CurrentLimit = 0-255
CurrentPeakLimit = 0-255
MinPWM = 0-255 = offset (den spänning där motorn börjar röra på sig)
MaxPWM = 0-255

Dock tar min kommando funktion upp över 60% av det tillgängliga minnet så det måste bantas ned lite eventuellt. Har bara själva PID algoritmen kvar att skriva in. Bör inte var speciellt svårt att banta ner dock då mina kommandon är onödigt långa (för att kunna testa enkelt) t.ex. "set kp 1234".

Har även fixat så att Fault loopen fungerar som den ska. Den stoppar vidare PID beräkningar och därmed PWM utgångarna om:
Enable ingången är låg.
Felet blir större än ErrorLimit.
Strömmen blir större än CurrentPeakLimit.
Strömmen blir större än CurrentLimit i minst en sekund.

Jag funderar på om jag ska sätta en liten strömbrytare på kretskortet som nollställer fault och disablar ErrorLimit så länge den när nedtryckt så att servodrivern kan återställas utan förlust av position!

PID loopen körs i 2441,4 Hz och fault loopen kör jag i 101,7 Hz. Är det vettigt? Är det vettigt att ha en sekund på CurrentLimit? Eller bör jag rentav göra det inställningsbart?
JBV
Inlägg: 411
Blev medlem: 4 maj 2006, 11:44:28
Ort: Älvsbyn

Inlägg av JBV »

Det slog mig att det nog var bättre att reglera strömen med PWM än att bara bryta så jag gjorde såhär istället:

Kod: Markera allt

...
if(Current > Settings.CurrentLimit)
{
  PWMLimit--;
  if(PWMLimit < 0) PWMLimit = 0;
} else {
  PWMLimit++;
  if(PWMLimit > Settings.MaxPWM) PWMLimit = Settings.MaxPWM;
}
PWMLimit är altså det värde som sätter den övre gränsen på PWM output från PID loopen! Hur snabb bör jag ha loopen när jag reglerar så här?
JBV
Inlägg: 411
Blev medlem: 4 maj 2006, 11:44:28
Ort: Älvsbyn

Inlägg av JBV »

Nu har jag börjat skriva in PID loopen:

Kod: Markera allt

.
Error_2 = Error_1;
Error_1 = Error;
Error = SetPoint - ProcessVariable;

int PT = Settings.KP * (Error - Error_1);
int IT = Settings.KI * T * Error;
int DT = (Settings.KD / T) * (Error - (2 * Error_1) + Error_2);

CO = CO + (PT + IT + DT);
Jag tänker mig att om KP ska vara 1,85 så lagrar jag 185 i Settings.KP för att slippa flyttals beräkningar.

Frågan är hur jag ska skala om (PT + IT + DT) så jag får rätt storlek och korrekt avrundning utan att använda flyttalsberäkningar/funktioner? Finns det något vettigt färdigt sätt eller blir det att skriva en egen funktion?

Sedan undrar jag om jag kan skippa T när jag har en fast loop frekvens? Annars, vad ska man sätta för värde där? :?

Edit:
Knåpade ihop en liten skala/avrunda funktion:

Kod: Markera allt

.
static inline int scale(int data)
{
  if(data > 0)
  {
    if((data - ((data / 100) * 100)) >= 50) return ((data + 100) / 100);
  } else {
    if((data - ((data / 100) * 100)) <= -50) return ((data - 100) / 100);
  }
  return (data / 100);
}
JBV
Inlägg: 411
Blev medlem: 4 maj 2006, 11:44:28
Ort: Älvsbyn

Inlägg av JBV »

Nu har jag äntligen lyckats styra ett servo lite! :D I brist på gate drivers så kopplade jag ihop 2 av mina små servon axel mot axel och körde low side drivning på varsin motor.

Sedan skrev jag ett program i VB som skickar setpoint över rs232. Värdet ändras när man drar i en slider: -3600 till +3600. Jag kör enkodern i 1X läget, så jag kan styra servot 2 varv. :P

Har inte orkat koda om kommandofunktionen, tog bort den gamla pga utrymmes brist. Så istället för att tvingas kompilera om varje gång jag skulle testa nya PID parametrar så körde jag: CO = Error; Det oscillerar förståss en del, men ändå kul att få se resultat ;)
Skriv svar