Goed werkende PID, vanaf nu dit script gebruiken.

Dependencies:   Encoder HIDScope MODSERIAL mbed

Revision:
0:50d492ea0fd0
Child:
1:d9cfdc904b10
Child:
3:eb5b57162e38
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Thu Oct 15 07:57:23 2015 +0000
@@ -0,0 +1,370 @@
+#include "mbed.h"
+#include "encoder.h"
+#include "MODSERIAL.h"
+#include "math.h"
+#include "HIDScope.h"
+#define M_PI           3.14159265358979323846
+
+DigitalOut motor2direction(D4); //D4 en D5 zijn motor 2 (op het motorshield)
+PwmOut motor2speed(D5);
+DigitalOut motor1direction(D7); //D6 en D7 voor motor 1 (op het motorshield)
+PwmOut motor1speed(D6);
+AnalogIn potmeter1(A3);         //blauw draaiknopje, nr1
+AnalogIn potmeter2(A2);         //nr 2
+Encoder encoder2(D13,D12,true);
+Encoder encoder1(D11,D10,true);
+MODSERIAL pc(USBTX,USBRX);
+
+Ticker myControllerTicker1, myControllerTicker2, countStepTickerX, countStepTickerY, buttonStateCheckX, buttonStateCheckY;
+bool motor1_PID_Controller_go = false;
+bool countStepX_go = false;
+bool countStepY_go = false;
+bool checkButtonStateX_go = false;
+bool checkButtonStateY_go = false;
+
+DigitalIn telknopX(SW2);
+DigitalIn telknopY(SW3);
+DigitalOut ledX(D2);
+DigitalOut ledY(D3);
+HIDScope scope(2);
+
+const double motor1_Kp = 1;                   //4200=1 rondje
+double m1_Kp = 0.0005, m1_Ki = 0.0, m1_Kd = 0.0;
+const double m1_Ts = 0.01;
+double m1_err_int = 0, m1_prev_err = 0;
+double m1_u_prev = 0;
+
+const int grens = 50;
+
+/*
+Gain = 0.002356
+B = [ 1.00000000000,  2.00000000000,  1.00000000000]
+A = [ 1.00000000000, -1.85808607200,  0.86750940236]
+*/
+
+const double m1_f_a1 = -1.94042975320, m1_f_a2 = 0.94215346226, m1_f_b0 = 1.0*0.000431, m1_f_b1 = 2.0*0.000431, m1_f_b2 = 1.0*0.000431; 
+                                    //dit zijn de constanten die bij de filter horen (de a0 t/m b2) a0 is altijd 1
+double m1_f_v1 = 0, m1_f_v2 = 0;    //de variabelen van de filter 
+
+int reference1;
+int reference2;
+int difference1;
+int difference2;
+int buttonStateX = 1;
+int buttonStateY = 1;
+int motorDirectionX = 1;
+int motorDirectionY = 1;
+int n;
+int countsX=0;
+int countsY=0;
+int countStateX = 1;
+int countStateY = 1;
+
+float x = 4.0;      // voorbeeld, moet eigenlijk bepaald worden door EMG signaal
+float y = 4.0;      // is het 4de vakje van rechtsonderin de hoek geteld
+float xdist_from_board = 4.0;   //er moet 2 van afgetrokken worden. Als de as 6cm van het bord staat moet er 4 worden ingevuld. Telt namelijk
+float ydist_from_board = 4.0;   //vanaf het midden van een vakje.
+double constante1;
+double constante2;
+double constante3;
+
+bool buttonReleasedX(DigitalIn& button)
+{
+    if (button.read() == 1 && buttonStateX == 0) {
+        buttonStateX = 1;
+        return true;
+    }
+    buttonStateX = button.read();
+    return false;
+}
+
+bool buttonReleasedY(DigitalIn& button)
+{
+    if (button.read() == 1 && buttonStateY == 0) {
+        buttonStateY = 1;
+        return true;
+    }
+    buttonStateY = button.read();
+    return false;
+}
+
+bool buttonHold(DigitalIn& button)
+{
+    return (button.read() == 0);
+}
+
+float bereken_hoek1(float x, float y)
+{
+    float langste_zijde = sqrt(pow(x*4,2) + pow(y*4,2));    //pythagoras
+    float alpha = acos((langste_zijde/2)/30);
+    return (atan((4*y)/(4*x)) + alpha)*4200/(2*M_PI);       // omrekenen van radialen naar counts = *4200/(2*M_PI), dit moet nog omgerekend worden met de gear ratio van de extra tandwielen.
+}
+
+float bereken_hoek2(float x, float y)
+{
+    float langste_zijde = sqrt(pow(x*4,2) + pow(y*4,2));    //pythagoras
+    float alpha = acos((langste_zijde/2)/30);
+    float beta = 0.5*M_PI - alpha;
+    return (2*beta)*4200/(2*M_PI);                          // x wordt hoek voor eerste arm t.o.v. x-as (CW), y hoek voor tweede arm t.o.v. eerste arm (CW)
+}
+
+//-------------------------- MOTORCONTROLLERS --------------------------//
+
+void constanteBepalen()
+{
+    constante1 = potmeter1.read();
+    constante2 = potmeter2.read();
+    m1_Kd = constante2*0.001;                     //loopt nu van 0 tot 1
+    m1_Ki = constante1*0.001;
+}
+
+double P(double error, const double Kp)       //P regelaar
+{
+    return Kp*error;                            //ingangssignaal voor de motor\plant) = dus voltage
+}
+
+double PI(double e, double Kp, const double Ki, double Ts, double &e_int)
+{
+    e_int = e_int + Ts * e;                     // e_int is changed globally because it’s ’by reference’ (&)
+    return Kp * e + Ki * e_int;
+}
+
+double biquad(double u, double &v1, double &v2, const double a1, const double a2,
+    const double b0, const double b1, const double b2){
+        double v = u-a1*v1-a2*v2;       //formule uit slides van biquad filter
+        double y = b0*v+b1*v1+b2*v2;    //zie ook slides
+        v2 = v1; v1 =v;
+        return y;
+}
+
+double PID(double e, const double Kp, const double Ki, const double Kd, double Ts, 
+    double &e_int, double &e_prev, double &f_v1, double &f_v2, const double f_a1,
+    const double f_a2, const double f_b0, const double f_b1, const double f_b2){    //In de slides staat f_b3, maar volgens mij moet het f_b2 zijn
+    //Bereken eerst afgeleide van de error
+    double e_der = (e-e_prev)/Ts;                                       
+    double e_der2 = biquad(e_der, f_v1, f_v2, f_a1, f_a2, f_b0, f_b1, f_b2);    //de y die de biquad returnt is de gefilterde e_der
+    e_prev = e;
+    //Bereken nu de geintegreerde versie van de error
+    e_int = e_int + Ts*e;
+    //PID
+    
+    return Kp*e+Ki*e_int+Kd*e_der2;  //formule uit slides 
+} 
+
+// P controllers
+void motor2_P_Controller()
+{
+    reference2 = potmeter2.read()*4200;                     //draaiknop uitlezen, tussen 0 en 1
+    //reference2 = y;
+    double position =(encoder2.getPosition());              //waarde tussen 0 en 4200
+    double u = P(reference2 - position, motor1_Kp);      //P controller aanroepen
+    
+    if (u > 0) {                                  //directie bepalen
+        motor2direction=1;
+    } else if (u <= 0) {
+        motor2direction =0;
+    }
+    if (u <grens && u>-grens) {               //bepalen of de motor aan of uit moet
+        motor2speed = 0.0f;
+    } else {
+        motor2speed = 0.1f;
+    }
+}
+
+void motor1_P_Controller()
+{
+    reference1 = potmeter1.read()*4200;                     //draaiknop uitlezen, tussen 0 en 1
+    //reference1=x;
+    double position =(encoder1.getPosition());              // waarde tussen 0 en 4200
+    difference1 = reference1-position;
+    double u = P(reference1 - position, motor1_Kp);      //P controller aanroepen
+    if (u > 0) {                                  //directie bepalen. Waardes zijn tegenovergesteld vergeleken met motor 2
+        motor1direction=0;
+    } else if (u <= 0) {
+        motor1direction =1;
+    }
+    if (u <grens && u >-grens) {              //bepalen of de motor aan of uit moet
+        motor1speed = 0.0f;
+    } else {
+        motor1speed = 0.1f;
+    }
+}
+
+//PI controllers
+void motor1_PI_Controller()
+{
+    //reference1 = potmeter1.read()*4200;                     //draaiknop uitlezen, tussen 0 en 1
+    float hoek1 = bereken_hoek1(countsX,countsY);
+    reference1=hoek1;
+    double position =(encoder1.getPosition());              // waarde tussen 0 en 4200
+    
+    difference1 = reference1 - position;
+    constanteBepalen();
+    double u = PI(reference1 - position, m1_Kp, m1_Ki, m1_Ts, m1_err_int);
+    if (u > 0) {                                  //directie bepalen. Waardes zijn tegenovergesteld vergeleken met motor 2
+        motor1direction=0;
+    } else if (u <= 0) {
+        motor1direction =1;
+    }
+    if (u <grens && u >-grens) {              //bepalen of de motor aan of uit moet
+        motor1speed = 0.0f;
+    } else {
+        motor1speed = 0.1f;
+    }
+}
+
+void motor2_PI_Controller()
+{
+    //reference2 = potmeter2.read()*4200;                     //draaiknop uitlezen, tussen 0 en 1
+    float hoek2 = bereken_hoek2(countsX,countsY);
+    reference2 = hoek2;
+    double position =(encoder2.getPosition());              //waarde tussen 0 en 4200
+
+    difference2 = reference2 - position;
+    constanteBepalen();
+    double u = PI(reference2 - position, m1_Kp, m1_Ki, m1_Ts, m1_err_int);
+    if (u > 0) {                                  //directie bepalen. Waardes zijn tegenovergesteld vergeleken met motor 2
+        motor2direction=1;
+    } else if (u <= 0) {
+        motor2direction =0;
+    }
+    if (u <grens && u >-grens) {              //bepalen of de motor aan of uit moet
+        motor2speed = 0.0f;
+    } else {
+        motor2speed = 0.1f;
+    }
+}
+
+void motor1_PID_Controller()
+{
+    //reference1 = potmeter1.read()*4200;                     //draaiknop uitlezen, tussen 0 en 1
+    float hoek1 = bereken_hoek1(countsX,countsY);
+    reference1=hoek1;
+    double position =(encoder1.getPosition());              // waarde tussen 0 en 4200
+    
+    scope.set(0,reference1);
+    scope.set(1,position);
+    scope.send();
+    
+    difference1 = reference1 - position;
+    constanteBepalen();
+    double u = PID( reference1 - position, m1_Kp, m1_Ki, m1_Kd, m1_Ts, m1_err_int,m1_prev_err, m1_f_v1, m1_f_v2, m1_f_a1, m1_f_a2, m1_f_b0, m1_f_b1, m1_f_b2 );
+    if (u < 0) {
+        motor1direction = 1;                            //directie bepalen. Waardes zijn tegenovergesteld vergeleken met motor 2
+    } else if (u>=0) {
+        motor1direction = 0;
+    }
+    motor1speed = fabs(u);
+    pc.printf("u = %.2f \r\n", u); 
+    
+}
+
+//-------------------------- POSITIEBEPALING --------------------------//
+
+void checkButtonStateX()
+{
+    if (buttonReleasedX(telknopX)) {
+        countStateX = -countStateX;
+    }
+}
+
+void checkButtonStateY()
+{
+    if (buttonReleasedY(telknopY)) {
+        countStateY = -countStateY;
+    }
+}
+
+void countStepX()
+{
+    if (buttonHold(telknopX)) {
+        countsX+= countStateX;             //hier moet de richting dus veranderen
+        if(countsX >= 10) {
+            countsX = 10;
+        } else if(countsX<=0) {
+            countsX = 0;
+        }
+    }
+}
+
+void countStepY()
+{
+    if (buttonHold(telknopY)) {          //X en Y kunnen niet tegelijk optellen, alleen als de ander niet ingedrukt is
+        countsY+= countStateY;
+        if(countsY >= 10) {
+            countsY = 10;
+        } else if(countsY<=0) {
+            countsY = 0;
+        }
+    }
+}
+
+void motor1_PID_Controller_activate(){ 
+    motor1_PID_Controller_go = true; 
+}
+
+void countStepX_activate(){
+    countStepX_go = true; 
+}
+
+void checkButtonStateX_activate(){
+    checkButtonStateX_go = true; 
+}
+
+void countStepY_activate(){
+    countStepY_go = true; 
+}
+
+void checkButtonStateY_activate(){
+    checkButtonStateY_go = true;
+}
+
+int main()
+{
+    pc.baud(9600);
+    encoder1.setPosition(0);
+    encoder2.setPosition(0);
+    /*myControllerTicker1.attach( &motor1_PID_Controller, 0.005f ); //Ticker roept elke 0.01 s de motor2 controller aan. = 100Hz
+    myControllerTicker2.attach( &motor2_PI_Controller, 0.01f);
+    countStepTickerX.attach( &countStepX,1.0f );
+    countStepTickerY.attach( &countStepY,1.0f);
+    buttonStateCheckX.attach( &checkButtonStateX,0.001f);
+    buttonStateCheckY.attach( &checkButtonStateY,0.001f);
+    */
+    myControllerTicker1.attach( &motor1_PID_Controller_activate, 0.01f);   // Function@ hz
+    countStepTickerX.attach( &countStepX_activate, 1.0f);                 // Function@ hz
+    countStepTickerY.attach( &countStepY_activate, 1.04f);                 // Function@ hz
+    buttonStateCheckX.attach( &checkButtonStateX_activate, 0.001f);         // Function@ hz
+    buttonStateCheckY.attach( &checkButtonStateY_activate, 0.001f);            // Function@ hz
+
+
+    while (true) {
+
+        pc.printf(" 1: pos: %d, ref: %d, dif: %d, Ki: %.5f, Kd: %.5f, countsX: %d, countsY: %d \r\n", encoder1.getPosition(), reference1,difference1,m1_Kd,m1_Ki,countsX,countsY);
+        //pc.printf(" 2: pos: %d, ref: %d, dif: %d \r\n", encoder2.getPosition(), reference2,difference2);
+        
+        if(motor1_PID_Controller_go) { 
+            motor1_PID_Controller_go = false;
+            motor1_PID_Controller();
+        }
+        if(countStepX_go) {
+            countStepX_go = false;
+            countStepX();
+        }
+        if(countStepY_go) {
+            countStepY_go = false;
+            countStepY();
+        }
+        if(checkButtonStateX_go) {
+            checkButtonStateX_go = false;
+            checkButtonStateX();
+        }
+        if(checkButtonStateY_go) {
+            checkButtonStateY_go = false;
+            checkButtonStateY();
+        }
+        
+        
+
+    }
+}
\ No newline at end of file