BBR 1 Ebene

Controller.cpp

Committer:
borlanic
Date:
2018-05-14
Revision:
0:fbdae7e6d805

File content as of revision 0:fbdae7e6d805:

/*
 * Controller.cpp
 * Copyright (c) 2018, ZHAW
 * All rights reserved.
 *
 *  Created on: 27.03.2018
 *      Author: BaBoRo Development Team
 */

#include <cmath>
#include "Controller.h"

using namespace std;

const float Controller::PERIOD = 0.001f;                        // the period of the timer interrupt, given in [s]
const float Controller::ALPHA = 0.785398163397448f;             // alpha = 45° in [rad]
const float Controller::COS_ALPHA = 0.707106781186548;           // cos(alpha)
const float Controller::SIN_ALPHA = 0.707106781186548;           // cos(alpha)
const float Controller::RB = 0.09f;                            // Ball Radius in [m]
const float Controller::RW = 0.029f;                            // Wheel Radius in [m]
const float Controller::PI = 3.141592653589793f;                // PI
const float Controller::SQRT_3 = 1.732050807568877f;            // Square root of 3
const float Controller::LOWPASS_FILTER_FREQUENCY = 300.0f;      // frequency of lowpass filter for actual speed values, given in [rad/s]
const float Controller::COUNTS_PER_TURN = 4096.0f;
const float Controller::KI = 58.5f;                             // torque constant [mNm/A]
const float Controller::MIN_DUTY_CYCLE = 0.1f;                  // minimum allowed value for duty cycle (10%)
const float Controller::MAX_DUTY_CYCLE = 0.9f;                  // maximum allowed value for duty cycle (90%)
const float Controller::MAX_ACC_M = 3.5f;
const float Controller::MB = 0.6;                                // masse der Ball
/**
 * Create and initialize a robot controller object.
 * @param pwm0 a pwm output object to set the duty cycle for the first motor.
 * @param pwm1 a pwm output object to set the duty cycle for the second motor.
 * @param pwm2 a pwm output object to set the duty cycle for the third motor.
 * @param counter1
 */
Controller::Controller(PwmOut& pwm0, PwmOut& pwm1, PwmOut& pwm2, EncoderCounter& counter1, EncoderCounter& counter2, EncoderCounter& counter3, IMU& imu) : pwm0(pwm0), pwm1(pwm1), pwm2(pwm2), counter1(counter1), counter2(counter2), counter3(counter3), imu(imu), thread(osPriorityHigh, STACK_SIZE)
{

    // initialize local values

    pwm0.period(0.0005f);// 0.5ms 2KHz
    pwm0.write(0.5f);

    pwm1.period(0.0005f);
    //pwm1.write(0.5f);

    pwm2.period(0.0005f);
    //pwm2.write(0.5f);

    gammaX = imu.getGammaX();
    gammaY = imu.getGammaY();
    gammaZ = imu.getGammaZ();

    phiX = 0.0f;
    phiY = 0.0f;

    d_phiX = 0.0f;
    d_phiY = 0.0f;

    x = 0.0f;
    y = 0.0f;

    float previousValueCounter1 = counter1.read();
    float previousValueCounter2 = counter2.read();
    float previousValueCounter3 = -counter3.read();

    speedFilter1.setPeriod(PERIOD);
    speedFilter1.setFrequency(LOWPASS_FILTER_FREQUENCY);

    speedFilter2.setPeriod(PERIOD);
    speedFilter2.setFrequency(LOWPASS_FILTER_FREQUENCY);

    speedFilter3.setPeriod(PERIOD);
    speedFilter3.setFrequency(LOWPASS_FILTER_FREQUENCY);

    d_phiXFilter.setPeriod(PERIOD);
    d_phiXFilter.setFrequency(10.0f);

    d_phiYFilter.setPeriod(PERIOD);
    d_phiYFilter.setFrequency(10.0f);

    gammaXFilter.setPeriod(PERIOD);
    gammaXFilter.setFrequency(100.0f);
    gammaYFilter.setPeriod(PERIOD);
    gammaYFilter.setFrequency(100.0f);
    d_gammaXFilter.setPeriod(PERIOD);
    d_gammaXFilter.setFrequency(100.0f);
    d_gammaYFilter.setPeriod(PERIOD);
    d_gammaYFilter.setFrequency(100.0f);

    M1Filter.setPeriod(PERIOD);
    M1Filter.setFrequency(20.0f);

    M2Filter.setPeriod(PERIOD);
    M2Filter.setFrequency(20.0f);

    M3Filter.setPeriod(PERIOD);
    M3Filter.setFrequency(20.0f);

    previousValueCounter1 = 0.0f;
    previousValueCounter2 = 0.0f;
    previousValueCounter3 = 0.0f;

    actualSpeed1 = 0.0f;
    actualSpeed2 = 0.0f;
    actualSpeed3 = 0.0f;

    gammaXref = 0.0f;
    gammaYref = 0.0f;
    gammaZref = 0.0f;
    phiXref = 0.0f;
    phiYref = 0.0f;

    M1motion.setProfileVelocity(0.4f);
    M1motion.setProfileAcceleration(MAX_ACC_M);
    M1motion.setProfileDeceleration(MAX_ACC_M);

    M2motion.setProfileVelocity(0.4f);
    M2motion.setProfileAcceleration(MAX_ACC_M);
    M2motion.setProfileDeceleration(MAX_ACC_M);

    M3motion.setProfileVelocity(0.4f);
    M3motion.setProfileAcceleration(MAX_ACC_M);
    M3motion.setProfileDeceleration(MAX_ACC_M);

    d_phiXMotion.setProfileVelocity(0.5f);
    d_phiXMotion.setProfileAcceleration(1.0f);
    d_phiXMotion.setProfileDeceleration(2.0f);

    d_phiYMotion.setProfileVelocity(0.5f);
    d_phiYMotion.setProfileAcceleration(1.0f);
    d_phiYMotion.setProfileDeceleration(2.0f);
    
    
    
    gainG = 1.0f;
    gain_dG = 1.0f;
    offsetX = 1.0f;
    offsetY = 1.0f;
    

    // start thread and timer interrupt

    thread.start(callback(this, &Controller::run));
    ticker.attach(callback(this, &Controller::sendSignal), PERIOD);
}

/**
 * Delete the robot controller object and release all allocated resources.
 */
Controller::~Controller()
{

    //ticker.detach();
}

// set --------------------------------
void Controller::setGammaX(float gammaX)
{

    this->gammaX = gammaX;
}


void Controller::setGammaY(float gammaY)
{

    this->gammaY = gammaY;
}


void Controller::setGammaZ(float gammaZ)
{

    this->gammaZ = gammaZ;
}


void Controller::setPhiX(float phiX)
{

    this->phiX = phiX;
}

void Controller::setPhiY(float phiY)
{

    this->phiY = phiY;
}

void Controller::setX(float x)
{

    this->x = x;
}

/**
 * Sets the actual y coordinate of the robots position.
 * @param y the y coordinate of the position, given in [m].
 */
void Controller::setY(float y)
{

    this->y = y;
}

// get --------------------------------

float Controller::getPhiX()
{

    return phiX;
}

float Controller::getPhiY()
{

    return phiY;
}

/**
 * Gets the actual x coordinate of the robots position.
 * @return the x coordinate of the position, given in [m].
 */
float Controller::getX()
{

    return x;
}

/**
 * Gets the actual y coordinate of the robots position.
 * @return the y coordinate of the position, given in [m].
 */
float Controller::getY()
{

    return y;
}

/**
 * This method is called by the ticker timer interrupt service routine.
 * It sends a signal to the thread to make it run again.
 */
//void Controller::sendSignal() {

//    thread.signal_set(signal);
//}

float Controller::sign(float v)
{
    if (v < 0.5) return -1;
    if (v > 0.5) return 1;
    return 0;

}

void Controller::sendSignal()
{

    thread.signal_set(signal);
}

/**
 * This <code>run()</code> method contains an infinite loop with the run logic.
 */
void Controller::run()
{
    Serial pc1(USBTX, USBRX); // tx, rx
    pc1.baud(100000);

    float integratedGammaX = 0.0f;
    float integratedGammaY = 0.0f;
    float integratedGammaZ = 0.0f;
    float integratedPhiX = 0.0f;
    float integratedPhiY = 0.0f;

    float previousGammaX = 0.0;
    float previousGammaY = 0.0;
    float previousGammaZ = 0.0;
    float previousPhiX = 0.0;
    float previousPhiY = 0.0;

    // K matrix
    float K[4] = {0.0036,4.1925,0.0231,1.2184};


    float rad1 = 0.0f;
    float rad2 = 0.0f;
    float rad3 = 0.0f;

    float rad1contr = 0.0f;

    long int t = 0;

    /*
    // messung
    int * T = new int[2000];
    float * Mes1 = new float[2000];
    float * Mes2 = new float[2000];
    float * Mes3 = new float[2000];
    float * Mes4 = new float[2000];
    float * Mes5 = new float[2000];
    float * Mes6 = new float[2000];
    */

    int a = 0;

    // escon I/O
    AnalogIn M1_AOUT1(PC_4); // neu
    AnalogIn M1_AOUT2(PA_5); // neu

    AnalogIn M2_AOUT1(PC_1); // neu
    AnalogIn M2_AOUT2(PC_0); // neu

    AnalogIn M3_AOUT1(PA_7); // neu
    AnalogIn M3_AOUT2(PA_4); // neu


    while (true) {

        // wait for the periodic signal

        thread.signal_wait(signal);


        //pc1.printf("controller\r\n");


        /*
        if(t==21000) {
            pc1.printf("invio dati:\r\n\n");
            for(int j=0; j<2000; j++) {
                //pc1.printf("%d %.7f %.7f %.7f %.7f %.7f %.7f %.7f %.7f %.7f %.7f %.7f %.7f %.7f\r\n",*(T+j),*(PX+j),*(PY+j),*(GX+j),*(GY+j),*(GZ+j),*(dGX+j),*(dGY+j),*(dGZ+j),*(dPX+j),*(dPY+j),*(W1+j),*(W2+j),*(W3+j));
                pc1.printf("%d %.7f %.7f %.7f %.7f %.7f %.7f\r\n",*(T+j),*(Mes1+j),*(Mes2+j),*(Mes3+j),*(Mes4+j),*(Mes5+j),*(Mes6+j));
            }
            pc1.printf("fine dati:\r\n\n");
            delete T;
            delete Mes1;
            delete Mes2;
            delete Mes3;
            delete Mes4;
            delete Mes5;
            delete Mes6;
        }
        */

        // gain correction vie bluetooth
        //if(com.dataRecived){gainG = com.gainG; gain_dG = com.gain_dG; com.dataRecived = false;}

        //pc1.printf("data recived %d gainG = %.7f gain_d = %.7f\r\n",com.dataRecived,com.gainG,com.gain_dG);
        //printf("Controller start\r\n");

        gammaX = imu.getGammaX();
        gammaY = imu.getGammaY();
        gammaZ = imu.getGammaZ();
        d_gammaX = imu.getDGammaX();
        d_gammaY = imu.getDGammaY();
        d_gammaZ = imu.getDGammaZ();

        gammaZ = 0.0f;//0.0175f*cos(18.0f*t);


        // wait for the periodic signal

        // thread.signal_wait(signal);

        //printf("%d %d %d\r\n",counter1.read(),counter2.read(),counter3.read());
        //pwm0.write(0.6f);
        //pwm1.write(0.6f);
        //pwm2.write(0.6f);




        // Calculate Ball Velocities
        short valueCounter1 = counter1.read();
        short valueCounter2 = counter2.read();
        short valueCounter3 = -counter3.read();

        short countsInPastPeriod1 = valueCounter1-previousValueCounter1;
        short countsInPastPeriod2 = valueCounter2-previousValueCounter2;
        short countsInPastPeriod3 = valueCounter3-previousValueCounter3;

        previousValueCounter1 = valueCounter1;
        previousValueCounter2 = valueCounter2;
        previousValueCounter3 = valueCounter3;

        actualSpeed1 = speedFilter1.filter((2*PI)*(float)countsInPastPeriod1/COUNTS_PER_TURN/PERIOD); // actual speed motor1 in [rad/s]
        actualSpeed2 = speedFilter2.filter((2*PI)*(float)countsInPastPeriod2/COUNTS_PER_TURN/PERIOD); // actual speed motor1 in [rad/s]
        actualSpeed3 = speedFilter3.filter((2*PI)*(float)countsInPastPeriod3/COUNTS_PER_TURN/PERIOD); // actual speed motor1 in [rad/s]

        rad1 += actualSpeed1*PERIOD;
        rad2 += actualSpeed2*PERIOD;
        rad3 += actualSpeed3*PERIOD;

        //printf("rad1 = %.7f rad2 = %.7f rad3 = %.7f\r\n",rad1,rad2,rad3);

        //printf("%.7f %.7f %.7f %.7f %.7f %.7f\r\n",(2*PI)*(float)countsInPastPeriod1/COUNTS_PER_TURN/PERIOD,actualSpeed1,(2*PI)*(float)countsInPastPeriod2/COUNTS_PER_TURN/PERIOD,actualSpeed2,(2*PI)*(float)countsInPastPeriod3/COUNTS_PER_TURN/PERIOD,actualSpeed3);


        //printf("%.7f %.7f %.7f\r\n",actualSpeed1/2*PI,actualSpeed2/2*PI,actualSpeed3/2*PI);

        float actualDPhiX = d_phiXFilter.filter(RW/RB*((actualSpeed1 - actualSpeed2 - actualSpeed3) - sin(ALPHA)*RB/RW*0.0f)/(2*cos(ALPHA))+d_gammaX);
        float actualDPhiY = d_phiYFilter.filter((RW/RB*(actualSpeed2 - actualSpeed3))/(SQRT_3*cos(ALPHA))+d_gammaY); //float actualDPhiY = d_phiYFilter.filter((RW/RB*(actualSpeed2 - actualSpeed3 - actualSpeed1)+cos(ALPHA)*(actualDPhiX-gammaX)+sin(ALPHA)*0.0f)/(SQRT_3*cos(ALPHA))+d_gammaY);

        //printf("%.7f %.7f %.7f\r\n",d_gammaX,d_gammaY,d_gammaZ);

        //this->d_phiX = RB/RW*(((actualSpeed1 - actualSpeed2 - actualSpeed3) - sin(ALPHA)*RB/RW*d_gammaZ)/(2*cos(ALPHA))+d_gammaX);
        //this->d_phiY = RB/RW*((actualSpeed2 - actualSpeed3)/(SQRT_3*cos(ALPHA))+d_gammaY);

        this->d_phiX = actualDPhiX;
        this->d_phiY = actualDPhiY;

        this->phiX = phiX + actualDPhiX*PERIOD;
        this->phiY = phiY + actualDPhiY*PERIOD;




        //printf("phiX = %.5f phiY = %.5f\r\n",phiX/PI*180.0f,phiY/PI*180.0f);
        //printf("%.5f %.5f\r\n",phiX,phiY);
        //printf("%.7f %.7f %.7f %.7f %.7f %.7f %.7f %.7f %.7f %.7f %.7f %.7f %.7f\r\n", phiX,phiY,gammaX,gammaY,gammaZ,d_phiX,d_phiY,d_gammaX,d_gammaY,d_gammaZ,actualSpeed1,actualSpeed2,actualSpeed3);
        //printf("%.7f %.7f %.7f %.7f %.7f\r\n", phiX,phiY,gammaX,gammaY,gammaZ);

        // calculate actual error
        float errorGammaX = -gammaXref + gammaX;
        float errorGammaY = -gammaYref + gammaY;
        float errorGammaZ = -gammaZref + gammaZ;
        float errorPhiX = -phiXref + phiX;
        float errorPhiY = -phiYref + phiY;

        // Integration states
        integratedGammaX = integratedGammaX + (errorGammaX-previousGammaX)*PERIOD;
        integratedGammaY = integratedGammaY + (errorGammaY-previousGammaY)*PERIOD;
        integratedGammaZ = integratedGammaZ + (errorGammaZ-previousGammaZ)*PERIOD;
        integratedPhiX = integratedPhiX + (errorPhiX-previousPhiX)*PERIOD;
        integratedPhiY = integratedPhiY + (errorPhiY-previousPhiY)*PERIOD;

        // set new gamma's, phi's
        previousGammaX = errorGammaX;
        previousGammaY = errorGammaY;
        previousGammaZ = errorGammaZ;
        previousPhiX = errorPhiX;
        previousPhiY = errorPhiY;

        // Calculate Torque motors

        //[M1,M2,M3]=K*x

        float M1 = 0.0f;
        float M2 = 0.0f;
        float M3 = 0.0f;

        d_phiXMotion.incrementToVelocity(d_phiX,PERIOD);
        d_phiYMotion.incrementToVelocity(d_phiY,PERIOD);

        //printf("%.7f %.7f\r\n", gammaX-0.0025f,gammaY-0.043f);

        //pc1.printf("gainG = %.7f gain_d = %.7f\r\n",gainG,gain_dG);

        float x[4] = {0.0f,gammaY,0.0f,d_gammaY};

        /*
        if(gammaX<0.02f && gammaX>-0.02f) {
            x[2][0]=0.0f;
        }
        if(gammaY<0.02f && gammaY>-0.02f) {
            x[3][0]=0.0f;
        }
        if(d_gammaX<0.02f && gammaX>-0.02f) {
            x[7][0]=0.0f;
        }
        if(d_gammaY<0.02f && gammaY>-0.02f) {
            x[8][0]=0.0f;
        }
        */
        
        float k0 = 0.037f;
        float k1 = 13.5f*gainG;
        float k2 = 0.02f;
        float k3 = 1.185868f*gain_dG;
        
        float Mx = k1*(gammaX -0.0238f*offsetX) + k3*d_gammaX;
        float My = k1*(gammaY -0.0167f*offsetY) + k3*d_gammaY;
        float Mz = 0.0f;
        
        M1 = (2.0f/(3.0f*COS_ALPHA))*Mx + (1.0f/(3.0f*SIN_ALPHA))*Mz;
        M2 = (-1.0f/(3.0f*COS_ALPHA))*Mx + (SQRT_3/(3.0f*COS_ALPHA))*My + (1.0f/(3.0f*SIN_ALPHA))*Mz;
        M3 = (-1.0f/(3.0f*COS_ALPHA))*Mx + (-SQRT_3/(3.0f*COS_ALPHA))*My + (1.0f/(3.0f*SIN_ALPHA))*Mz;

        M1motion.incrementToVelocity(M1, PERIOD);
        M2motion.incrementToVelocity(M2, PERIOD);
        M3motion.incrementToVelocity(M3, PERIOD);


        //printf("x:\r\n %.7f %.7f %.7f %.7f %.7f %.7f %.7f %.7f %.7f %.7f %.7f %.7f %.7f %.7f %.7f\r\n M:\r\n %.7f %.7f %.7f\r\n", phiX,phiY,gammaX,gammaY,gammaZ,d_phiX,d_phiY,d_gammaX,d_gammaY,d_gammaZ,integratedPhiX,integratedPhiY,integratedGammaX,integratedGammaY,integratedGammaZ,M1,M2,M3);

        // Calculate duty cycles from desired Torque, limit and set duty cycles
        float I1 = -M1motion.velocity*1000.0f/KI;
        float I2 = -M2motion.velocity*1000.0f/KI;
        float I3 = -M3motion.velocity*1000.0f/KI;

        /*
        if(t<20001) {
            if (t % 10 == 0) {
                *(T+a) = t;
                *(Mes1+a) = M1; //M1_AOUT1.read()*3.3f*4000.0f/3.0f - 2000.0f;
                *(Mes2+a) = M1motion.velocity;
                *(Mes3+a) = -I1*KI/1000.0f;
                *(Mes4+a) = M2;
                *(Mes5+a) = M2motion.velocity; //[rad/s]
                *(Mes6+a) = -I2*KI/1000.0f;
                a++;
            }
        }
        */
        
        // security constrain that retard motor start
        if(t<1000.0f){I1 = 0.0f; I2 = 0.0f; I3 = 0.0f;}

        float dutyCycle1 = 0.4f/6.0f*I1 + 0.5f;
        if (dutyCycle1 < MIN_DUTY_CYCLE) {
            dutyCycle1 = MIN_DUTY_CYCLE;
        } else if (dutyCycle1 > MAX_DUTY_CYCLE) {
            dutyCycle1 = MAX_DUTY_CYCLE;
        }
        pwm0.write(dutyCycle1);

        float dutyCycle2 = 0.4f/6.0f*I2 + 0.5f;
        if (dutyCycle2 < MIN_DUTY_CYCLE) dutyCycle2 = MIN_DUTY_CYCLE;
        else if (dutyCycle2 > MAX_DUTY_CYCLE) dutyCycle2 = MAX_DUTY_CYCLE;
        pwm1.write(dutyCycle2);

        float dutyCycle3 = 0.4f/6.0f*I3 + 0.5f;
        if (dutyCycle3 < MIN_DUTY_CYCLE) dutyCycle3 = MIN_DUTY_CYCLE;
        else if (dutyCycle3 > MAX_DUTY_CYCLE) dutyCycle3 = MAX_DUTY_CYCLE;
        pwm2.write(dutyCycle3);



        //pc1.printf("%.7f %.7f %.7f\r\n", dutyCycle1,dutyCycle2,dutyCycle3);

        //printf("pwm1 = %.5f pwm2 = %.5f pwm3 = %.5f\r\n",dutyCycle1,dutyCycle2,dutyCycle3);

        // actual robot pose
        this->x = phiY*RB;
        this->y = phiX*RB;


        t++;


        //printf("Controller end\r\n");

    }
};