Goed werkende PID, vanaf nu dit script gebruiken.

Dependencies:   Encoder HIDScope MODSERIAL mbed

main.cpp

Committer:
roosalyn
Date:
2015-10-23
Revision:
5:cd1c63ffdc1a
Parent:
4:6d88a281192f

File content as of revision 5:cd1c63ffdc1a:

#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);

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;

double m2_Kp = 0.0005, m2_Ki = 0.0, m2_Kd = 0.0;
const double m2_Ts = 0.01;
double m2_err_int = 0, m2_prev_err = 0;
double m2_u_prev = 0;

/*
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

const double m2_f_a1 = -1.94042975320, m2_f_a2 = 0.94215346226, m2_f_b0 = 1.0*0.000431, m2_f_b1 = 2.0*0.000431, m2_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 m2_f_v1 = 0, m2_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 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 
} 

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); 
}

void motor2_PID_Controller()
{
    //reference2 = potmeter2.read()*4200;                     //draaiknop uitlezen, tussen 0 en 1
    float hoek2 = bereken_hoek2(countsX,countsY);
    reference2=hoek2;
    if (reference2 <500) {
        reference2=500;
    }
    if (reference2 > 2100) {
        reference2 = 2100;
    }
    double position =(encoder2.getPosition());              // waarde tussen 0 en 4200
    
    scope.set(2,reference2);
    scope.set(3,position);
    
    difference2 = reference2 - position;
    constanteBepalen();
    double u = PID( reference2 - position, m2_Kp, m2_Ki, m2_Kd, m2_Ts, m2_err_int,m2_prev_err, m2_f_v1, m2_f_v2, m2_f_a1, m2_f_a2, m2_f_b0, m2_f_b1, m2_f_b2 );
    if (u < 0) {
        motor2direction = 1;                            //directie bepalen. Waardes zijn tegenovergesteld vergeleken met motor 2
    } else if (u>=0) {
        motor2direction = 0;
    }
    motor2speed = 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 motor2_PID_Controller_activate(){ 
    motor2_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( &motor2_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(motor2_PID_Controller_go) { 
            motor2_PID_Controller_go = false;
            motor2_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();
        }
    }
}