Erste version der Software für der Prototyp

Controller.cpp

Committer:
borlanic
Date:
2018-03-29
Revision:
2:3f836b662104
Parent:
1:d5c5bb30ac90
Child:
3:27100cbaaa6e

File content as of revision 2:3f836b662104:

/*
 * 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::RB = 0.095f;                            // Ball Radius in [m]
const float Controller::RW = 0.024f;                            // 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 = 1024.0f;

/**
 * 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.
 */
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.002f);
    pwm0.write(0.5f);

    pwm1.period(0.002f);
    pwm1.write(0.5f);

    pwm2.period(0.002f);
    pwm2.write(0.5f);

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

    phiX = 0.0f;
    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);

    previousValueCounter1 = 0.0f;
    previousValueCounter2 = 0.0f;
    previousValueCounter3 = 0.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);
//}

/**
 * This <code>run()</code> method contains an infinite loop with the run logic.
 */
void Controller::run()
{

    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[3][15] = {
        {0.1010, 0.0000, 2.4661, 0.0000, 0.0639, 0.0621, 0.0000, 0.3066, 0.0000, 0.0237, 0.0816, 0.0000, 0.0000, 0.0000, 0.0577},
        {-0.0505, 0.0875, -1.2330, 2.1357, 0.0639, -0.0311, 0.0538, -0.1533, 0.2655, 0.0237, -0.0408, 0.0707, 0.0000, 0.0000, 0.0577},
        {-0.0505, -0.0875, -1.2330, -2.1357, 0.0639, -0.0311, -0.0538, -0.1533, -0.2655, 0.0237, -0.0408, -0.0707, 0.0000, 0.0000, 0.0577}
    };


    while (true) {

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

        // wait for the periodic signal

        // thread.signal_wait(signal);

        // Read encoder data
        float w1 = counter1.read()/1024.0f *1/(2*PI); // Angle wheel 1
        float w2 = counter2.read()/1024.0f *1/(2*PI); // Angle wheel 2
        float w3 = counter3.read()/1024.0f *1/(2*PI); // Angle wheel 3

        // Calculate Ball angle in [rad] using the kinematic model
        this->phiX = ((w1 - w2 - w3) - sin(ALPHA)*RB/RW*gammaZ)/(2*cos(ALPHA))+gammaX;
        this->phiY = (w2 - w3)/(SQRT_3*cos(ALPHA))+gammaY;

        // Integration states
        integratedGammaX = integratedGammaX + (gammaX-previousGammaX)*PERIOD;
        integratedGammaY = integratedGammaY + (gammaY-previousGammaY)*PERIOD;
        integratedGammaZ = integratedGammaZ + (gammaZ-previousGammaZ)*PERIOD;
        integratedPhiX = integratedPhiX + (phiX-previousPhiX)*PERIOD;
        integratedPhiY = integratedPhiY + (phiY-previousPhiY)*PERIOD;

        // 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((float)countsInPastPeriod1/COUNTS_PER_TURN/PERIOD/(2*PI)); // actual speed motor1 in [rad/s]
        actualSpeed2 = speedFilter2.filter((float)countsInPastPeriod2/COUNTS_PER_TURN/PERIOD/(2*PI)); // actual speed motor1 in [rad/s]
        actualSpeed3 = speedFilter3.filter((float)countsInPastPeriod3/COUNTS_PER_TURN/PERIOD/(2*PI)); // actual speed motor1 in [rad/s]

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

        // Calculate Torque motors

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

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

        float x[15][1] = {
            {gammaX},{gammaY},{gammaZ},{phiX},{phiY},{d_gammaX},{d_gammaY},{d_gammaZ},{d_phiX},{d_phiY},{integratedGammaX},{integratedGammaY},{integratedGammaZ},{integratedPhiX},{integratedPhiY}
        };

        for(int i=0; i<14; i++) {
            M1 = M1 + K[0][i]*x[i][1];
            M2 = M2 + K[1][i]*x[i][1];
            M3 = M3 + K[2][i]*x[i][1];
        };

        // Calculate duty cycles from desired Torque
        
        
        //pwm1.write(dutyCycle1);
        //pwm2.write(dutyCycle2);
        //pwm3.write(dutyCycle3);
        
        // actual robot pose
        this->x = phiY*RB;
        this->y = phiX*RB;
        
        // set new gamma's, phi's
        previousGammaX = gammaX;
        previousGammaY = gammaY;
        previousGammaZ = gammaZ;
        previousPhiX = phiX;
        previousPhiY = phiY;
    }
};