Kod för PID-reglering i C

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Stene
Inlägg: 276
Blev medlem: 13 maj 2008, 19:21:52
Ort: Uppsala

Kod för PID-reglering i C

Inlägg av Stene »

Jag har nu försökt länge med att skriva en egen kod för pid i c till en 16f887 men ej lyckats få den att fungera. Är det någon som har en sådan skriven eller en länk till en som man kan tjuvkika lite på?
Senast redigerad av blueint 6 september 2010, 19:32:20, redigerad totalt 1 gång.
Anledning: Rubrik "kod för pid i c"
Användarvisningsbild
Icecap
Inlägg: 26658
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: kod för pid i c

Inlägg av Icecap »

Jag antar att du menar en PID-reglering, detta finns det tidigare tråd om med kod och allt.
bos
Inlägg: 2314
Blev medlem: 24 februari 2007, 23:29:15
Kontakt:

Re: kod för pid i c

Inlägg av bos »

Hur ser din kod ut, och vad är det som inte fungerar?
Stene
Inlägg: 276
Blev medlem: 13 maj 2008, 19:21:52
Ort: Uppsala

Re: kod för pid i c

Inlägg av Stene »

Jag får ingen ordning på utgångsvärdet. Den bygger bara upp utgångsvärdet. Går alldrig nedåt.
P,I och D värdet justerar jag med vridputtar 0-255. Värdena har jag synliga i en lcd där jag även ser bör o är värdet.

Kod: Markera allt

 /* breäkning PID  */

    
    fel = bor - ar;                                   /* beräkning av felet i varvtals ökning */
    pid_reg = P * fel;                              /* beräkning av p i pidregler           */
    sum_fel = sum_fel + fel ;                         /* beräkning av totala felet            */
    pid_reg += sum_fel * I ;                          /* beräkning av i i pidregler        */ 
    skil_fel = senast_fel - fel ;                     /* beräkning av skillnaden mellan fel värdena */
    pid_reg += skil_fel * D ;                         /* beräkning av d i pidregler  */
    senast_fel = fel ;                                /* lägger värdet fel i senaste fel   */
    
    pid_reg = pid_reg / 255;                          /* gör om så talet kan användas för pwm */
    
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: kod för pid i c

Inlägg av sodjan »

Komplett värdelöst kodexempel utan definitioner av variabler.
Vad vill du att vi ska göra med det ?

(signed/unsigned ?)
Stene
Inlägg: 276
Blev medlem: 13 maj 2008, 19:21:52
Ort: Uppsala

Re: Kod för PID-reglering i C

Inlägg av Stene »

Kod: Markera allt


unsigned long P;                                       /* char P i pidregleringen */
unsigned long I;                                       /* char I i pidregleringen */
unsigned long D;                                       /* char D i pidregleringen */


bank1 long ar;                                           /* värdet varvtal är */
bank1 long bor;                                          /* värdet varvtal bör */
bank1 long fel;                                          /* värdet skillnaden varvtal är - bör  int */
bank1 long sum_fel;                                      /* värdet summa fel   */
bank1 unsigned long pid_reg ;                            /* värdet för regleringen   long */
bank1 long senast_fel;                                   /* värdet senaste mätta felet */
bank1 long skil_fel ;                                    /* värdet mellan felmätningarna */
Användarvisningsbild
Icecap
Inlägg: 26658
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Kod för PID-reglering i C

Inlägg av Icecap »

Och då kommer standardfrågan: vad har du testat?
* Har du kollat att felet blir negativt? (alltså vid fel = bor - ar;)
* Har du kollat med fasta värden (t.ex. fel = -1) vad som händer?

Rent omedelbart skulle jag tro att det beror på att P, I & D-faktorerna är unsigned, det konstiga språket du använder kan mycket väl komma fram till att unsigned * signed = unsigned och då är du rökt.
Agwan
Inlägg: 1617
Blev medlem: 15 september 2009, 09:05:14

Re: Kod för PID-reglering i C

Inlägg av Agwan »

Är du säker på att det är din kod som inte fungerar? Det är inte trivialt att trimma in en PID-regulator. Vad har du för system? Måste du ha en PID, P räcker för väldigt många reglersystem.

Jag skulle börja med att trimma in P och se till att I och D är 0.

Öka P tills att systemet börjar självsvänga. Halvera P och se om du är nöjd med hur den reglerar. Om du får problem med att regulatorn inte når temperaturen/positionen/värdet du var ute efter, typ du vill reglera till 270 grader, men kommer bara till 240, då behöver du ta med integrerande del.

Öka P igen tills systemet självsvänger, notera nu både vad P är och vilken svängningstid du har. Minska P till 0.45 av värdet du hade nyss, och sätt I till 1.2*P(nuvarande)/svänningstiden. Det kan behövas trimmas lite upp och ner på parametrarna härifrån för att få systemet stabilt. Får du för mycket overshoot nu så kan du implementera D-delen i regulatorn.

Kom ihåg samma P och svängningstid som du hade när systemet precis började självsvänga innan. Välj nu nya P till 0.65 av det toppvärdet. Sätt I till 2*P(nuvarande)/svängningstiden och väl D till P(nuvarande)*svängningstiden/8. Känns systemet ryckigt, öka D lite eller minska P.

Kom ihåg att systemet inte kommer att bli perfekt, men gör du små trimmningar utifrån de värden jag gett dig så kommer det att bli ganska så bra.
Gimbal
Inlägg: 8687
Blev medlem: 20 april 2005, 15:43:53

Re: Kod för PID-reglering i C

Inlägg av Gimbal »

Utvärdet läggs i pid_reg som är unsigned, dvs minusvärde blir svårt att få till.
Agwan
Inlägg: 1617
Blev medlem: 15 september 2009, 09:05:14

Re: Kod för PID-reglering i C

Inlägg av Agwan »

Ja fast det är väl utparametern till värmaren eller motorn eller vad det nu är som regleras. Har man tex en PWM så kan 512 vara stilla, 0 fullt åt ena hållet och 1024 fullt åt andra.
Gimbal
Inlägg: 8687
Blev medlem: 20 april 2005, 15:43:53

Re: Kod för PID-reglering i C

Inlägg av Gimbal »

Sant, man bör också ha lite begränsningar inlagda så att inga parametrar (och särskilt det integrerande värdet) växer sig alltför stort vilket är lätt hänt om bör och är värde skiljer sig mycket vid startup och det tar lång tid att korrigera. Är inte så lyckat om utsignalen bygger upp till 11 miljoner om max gas är 1024, det tar ju sin tid att komma ner från 11 miljoner igen.
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Kod för PID-reglering i C

Inlägg av jesse »

Men du måste ha gränser så att du ser till att max och min-värdena inte överskrids. Om P skulle bli -1 så skulle den siffran omvandlas till ett enormt stort positivt tal. Eller om P bilr 2550. Vad händer då?
(Gimbal hann före)

Sen undrar jag hur du får in värden till dina P,I och D. Om du använder potar - kan du ställa in ett negativt värde?

till sist delar du pid med 255... det låter ojämnt. Är det säkert att det inte ska delas med 256?

Det verkar finnas en hel del matematiska problem inbakat i det här. Hade jag varit du så hade jag nog gjort samma program i en PC med flyttal och ritat upp de olika delresultaten i en graf (eller skrivit ut en lista). Då ser jag direkt om något värde blir 11 miljoner ... :roll:
Användarvisningsbild
Icecap
Inlägg: 26658
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Kod för PID-reglering i C

Inlägg av Icecap »

Kod: Markera allt

#define PID_MAX_I -1
static int PID_Do_Once; /* Local to this routine */

void PID_Initiate(void)
  {
  PID_Do_Once = 1; /* Make it disable D-part on first regulation */
  }

unsigned short PID_Regulate(short Current, short Target, unsigned short P_Factor, unsigned short I_Factor, unsigned short D_factor, unsigned short Factor_Divisor)
  {
  static unsigned short Previous, I_Value; /* Holds previous "Current"-value, used by D-part  */
  long  Work_S, Work_P, Work_I, Work_D;
  short Diff; /* Could be positive or negative */
  Diff = Target - Current; /* Positive = the need for speed */
  /* Now calculate the P-part */
  Work_P  = Diff * P_Factor;
  Work_P /= Factor_Divisor;
  if(Work_P > (unsigned)PID_MAX_I) Work_P = (unsigned)PID_MAX_I; /* Top limit */
  if(Work_P < 0)                   Work_P = 0;                   /* Bottom limit */
  /* Now calculate the I-part */
  Work_I  = Diff * I_Factor;
  Work_I /= Factor_Divisor;
  if(Work_I > (unsigned)PID_MAX_I) Work_I = (unsigned)PID_MAX_I; /* Top limit */
  if(Work_I < 0)                   Work_I = 0;                   /* Bottom limit */
  I_Value += Work_I;
  /* And lastly the D-part */
  Diff    = Current - Previous; /* Negative = hold back a little */
  Work_D  = Diff * D_Factor;
  Work_D /= Factor_Divisor;
  Previous = Current; /* remember to next time */
  /* Now put it all together */
  if(PID_Do_Once)
    {
    PID_Do_Once = 0; /* OK, register that it's done */
    Work_D      = 0; /* Set to known state as no Prevoius exists */
    I_Value     = 0; /* Set to known state as it's the starting point */
    }
  Work_S  = Work_P; /* Start putting it together */
  Work_S += I_Value;
  Work_S += Work_D;
  if(Work_S > (unsigned short)PID_MAX_I) Work_S = (unsigned short)PID_MAX_I;
  if(Work_S < 0)                         Work_S = 0;
  return((unsigned short)Work_S);
  }
Detta är en jag skrev ihop för ett tag sedan, jag garanterar inget men den är en "finskrivning" av en väl fungerande rutin i ett projekt. Den ger enbart positivt värden ut då den är designat att köra mellan 0 och full patte, jag använder den att reglera effekt med och värmeenheten har svårt att alstra negativ värme varför negativa värden ut är ointressant.
Skriv svar