First trial for Inverse Kinematics Feedforward implementation. No errors, not yet tested with board

Dependencies:   HIDScope MODSERIAL QEI biquadFilter mbed

Fork of prog_pract3_3_PI_controller by Gerhard Berman

main.cpp

Committer:
GerhardBerman
Date:
2016-10-19
Revision:
11:773b3532d50f
Parent:
10:45473f650198
Child:
12:05e5964b69a4

File content as of revision 11:773b3532d50f:

#include "mbed.h"
#include <math.h>
#include "MODSERIAL.h"
#include "QEI.h"
#include "HIDScope.h"
#include "BiQuad.h"

//set pins
DigitalIn encoder1A (D13); //Channel A van Encoder 1
DigitalIn encoder1B (D12); //Channel B van Encoder 1
DigitalIn encoder2A (D14);
DigitalIn encoder2B (D15);
DigitalOut led1 (D11); 
DigitalOut led2 (D10);
AnalogIn potMeter1(A2);
AnalogIn potMeter2(A1);
DigitalOut motor1DirectionPin(D7);
PwmOut motor1MagnitudePin(D6);
DigitalOut motor2DirectionPin(D4);
PwmOut motor2MagnitudePin(D5);
DigitalIn button1(D3);
DigitalIn button2(D9);

//library settings
Serial pc(USBTX,USBRX);
Ticker MeasureTicker, BiQuadTicker; //, TimeTracker; // sampleT;
HIDScope    scope(4);

//set initial conditions
float error1_prev = 0;
float error2_prev = 0;
float IntError1 = 0;
float IntError2 = 0;
float q1 = 0;
float q2 = 0;
//set initial conditions for function references
 float q1_dot = 0.0;
 float q2_dot = 0.0;
 float motorValue1 = 0.0;
 float motorValue2 = 0.0;
 
//set constant or variable values
int counts1 = 0;
int counts2 = 0;
int counts1Prev = 0;
int counts2Prev = 0;
double DerivativeCounts;
float x0 = 1.0;
float L0 = 1.0;
float L1 = 1.0;
float dx;
float dy;
float dy_stampdown = 0.05; //5 cm movement downward to stamp

float t_sample = 0.01; //seconds
float referenceVelocity = 0;
float bqcDerivativeCounts = 0;
const float PI = 3.141592653589793;
const int cw = 0;       //values for cw and ccw are inverted!! cw=0 and ccw=1
const int ccw = 1;

//set BiQuad
BiQuadChain bqc;
BiQuad bq1(0.0186,    0.0743,    0.1114,    0.0743,    0.0186); //get numbers from butter filter MATLAB
BiQuad bq2(1.0000,   -1.5704,    1.2756,   -0.4844,    0.0762);

//set go-Ticker settings
volatile bool MeasureTicker_go=false, BiQuadTicker_go=false, FeedbackTicker_go=false, TimeTracker_go=false; // sampleT_go=false;
void MeasureTicker_act(){MeasureTicker_go=true;}; // Activates go-flags
void BiQuadTicker_act(){BiQuadTicker_go=true;};
void FeedbackTicker_act(){FeedbackTicker_go=true;};
void TimeTracker_act(){TimeTracker_go=true;};
//void sampleT_act(){sampleT_go=true;};

//define encoder counts and degrees
QEI Encoder1(D12, D13, NC, 32); // turns on encoder
QEI Encoder2(D14, D15, NC, 32); // turns on encoder
const int counts_per_revolution = 4200; //counts per motor axis revolution
const int inverse_gear_ratio = 131;
//const float motor_axial_resolution = counts_per_revolution/(2*PI);
const float resolution = counts_per_revolution/(2*PI/inverse_gear_ratio);  //87567.0496892 counts per radian, encoder axis

void GetReferenceKinematics1(float &q1_dotOut, float &q2_dotOut){
    
    //get joint positions q from encoder
    float Encoder1Position = counts1/resolution;         //position in radians, encoder axis
    float Encoder2Position = counts2/resolution;
    
    float q1 = Encoder1Position*inverse_gear_ratio;        //position in radians, motor axis
    float q2 = Encoder2Position*inverse_gear_ratio;
      
    //get velocity vector v = (Pe*- Pe) = [0; dx; dy] from EMG  
    float biceps1 = !button1.read();
    float biceps2 = !button2.read();
    if (biceps1 > 0 && biceps2 > 0){
        //both arms activated: stamp moves down
        led1 = 1;
        led2 = 1;
        dx = 0;
        dy = dy_stampdown; //into stamping vertical position?? ~the stamp down action
         wait(1);
        dy = -(dy_stampdown);  //reset vertical position
        }
    else if (biceps1 > 0 && biceps2 <= 0){
        //arm 1 activated, move left
        led1 = 1;
        led2 = 0;
        dx = -biceps1;
        dy = 0;
        }
    else if (biceps1 <= 0 && biceps2 > 0){
        //arm 1 activated, move left
        led1 = 0;
        led2 = 1;
        dx = biceps2;
        dy = 0;
        }
    else{
        led1 = 0;
        led2 = 0;
        dx=0;
        dy=0;
        }
            
    //get joint angles change q_dot = Jpseudo * TwistEndEff  (Matlab)
    q1_dotOut = dy*(((x0 + L1*cos(q1))*(L0*L0 + L1*sin(q1)*L0 + x0*x0 + L1*cos(q1)*x0 + 1))/(pow(L1*cos(q1),2) + pow(L1*sin(q1),2) + pow(L1*x0*sin(q1),2) + pow(L0*L1*cos(q1),2) - 2*L0*L1*L1*x0*cos(q1)*sin(q1)) - (x0*(pow(L1*cos(q1),2) + pow(L1*sin(q1),2) + L0*L0 + x0*x0 + 2*L0*L1*sin(q1) + 2*L1*x0*cos(q1) + 1))/(pow(L1*cos(q1),2) + pow(L1*sin(q1),2) + pow(L1*x0*sin(q1),2) + pow(L0*L1*cos(q1),2) - 2*L0*L1*L1*x0*cos(q1)*sin(q1))) - dx*(((L0 + L1*sin(q1))*(L0*L0 + L1*sin(q1)*L0 + x0*x0 + L1*cos(q1)*x0 + 1))/(pow(L1*cos(q1),2) + pow(L1*sin(q1),2) + pow(L1*x0*sin(q1),2) + pow(L0*L1*cos(q1),2) - 2*L0*L1*L1*x0*cos(q1)*sin(q1)) - (L0*(pow(L1*cos(q1),2) + pow(L1*sin(q1),2) + L0*L0 + x0*x0 + 2*L0*L1*sin(q1) + 2*L1*x0*cos(q1) + 1))/(pow(L1*cos(q1),2) + pow(L1*sin(q1),2) + pow(L1*x0*sin(q1),2) + pow(L0*L1*cos(q1),2) - 2*L0*L1*L1*x0*cos(q1)*sin(q1)));
    q2_dotOut = dy*((x0*(L0*L0 + L1*sin(q1)*L0 + x0*x0 + L1*cos(q1)*x0 + 1))/(L1*L1*pow(cos(q1),2) + pow(L1*sin(q1),2) + pow(L1*x0*sin(q1),2) + pow(L0*L1*cos(q1),2) - 2*L0*pow(L1,2)*x0*cos(q1)*sin(q1)) - ((x0 + L1*cos(q1))*(pow(L0,2) + pow(x0,2) + 1))/(pow(L1*cos(q1),2)) + pow(L1*sin(q1),2) + pow(L1*x0*sin(q1),2) + pow(L0*L1*cos(q1),2) - 2*L0*pow(L1,2)*x0*cos(q1)*sin(q1)) - dx*((L0*(L0*L0+L1*sin(q1)*L0+x0*x0+L1*cos(q1)*x0+1))/(pow(L1*cos(q1),2)+pow(L1*sin(q1),2)+pow(L1*x0*sin(q1),2)+pow(L0*L1*cos(q1),2)-2*L0*L1*L1*x0*cos(q1)*sin(q1))-((L0 + L1*sin(q1))*(L0*L0 + x0*x0 + 1))/(pow(L1*cos(q1),2)+pow(L1*sin(q1),2)+pow(L1*x0*sin(q1),2)+pow(L0*L1*cos(q1),2)-2*L0*L1*L1*x0*cos(q1)*sin(q1)));

    //update joint angles
    q1 = q1 + q1_dotOut;
    q2 = q2 + q2_dotOut;
    
    }

void FeedForwardControl1(float q1_dot, float q2_dot, float &motorValue1Out, float &motorValue2Out){
    //float Encoder1Position = counts1/resolution;         //position in radians, encoder axis
    //float Position1 = Encoder1Position*inverse_gear_ratio;        //position in radians, motor axis
    
    // linear feedback control
    float error1 = q1_dot; //referencePosition1 - Position1;             // proportional error in radians
    float error2 = q2_dot; //referencePosition1 - Position1;             // proportional error in radians
    float Kp = 1; //potMeter2.read();

    float IntError1 = IntError1 + error1*t_sample;             // integrated error in radians
    float IntError2 = IntError2 + error2*t_sample;             // integrated error in radians
    //float maxKi = 0.2;
    float Ki = 0.1; //potMeter2.read();
    
    float DerivativeError1 = (error1_prev + error1)/t_sample;  // derivative of error in radians
    float DerivativeError2 = (error2_prev + error2)/t_sample;  // derivative of error in radians
    //float maxKd = 0.2;
    float Kd = 0.0; //potMeter2.read();
    
    //scope.set(0,referencePosition1);
    //scope.set(1,Position1);
    //scope.set(2,Ki);
    //scope.send();
    
    motorValue1Out = error1 * Kp + IntError1 * Ki + DerivativeError1 * Kd;    //total controller output = motor input
    motorValue2Out = error2 * Kp + IntError2 * Ki + DerivativeError2 * Kd;    //total controller output = motor input
    //pc.printf("Motor Axis Position: %f rad \r\n", Position1);
    //pc.printf("Counts encoder1: %i rad \r\n", counts1);
    //pc.printf("Kp: %f \r\n", Kp);
    //pc.printf("MotorValue: %f \r\n", motorValue1);
    
    error1_prev = error1;
    error2_prev = error1;
    float biceps1 = !button1.read();
    float biceps2 = !button2.read();
       
    scope.set(0,q1_dot);
    scope.set(1,q2_dot);
    scope.set(2,biceps1);
    scope.set(3,biceps2);
    scope.send();
}

void SetMotor1(float motorValue1, float motorValue2)
{
    // Given -1<=motorValue<=1, this sets the PWM and direction
    // bits for motor 1. Positive value makes motor rotating
    // clockwise. motorValues outside range are truncated to
    // within range
    //control motor 1
    if (motorValue1 >=0) 
        {motor1DirectionPin=cw;
        //led1=1;
        //led2=0;
        }
    else {motor1DirectionPin=ccw;
        //led1=0;
        //led2=1;
        }
    if (fabs(motorValue1)>1) motor1MagnitudePin = 1;
        else motor1MagnitudePin = fabs(motorValue1);
    //control motor 2
    if (motorValue2 >=0) 
        {motor2DirectionPin=cw;
        //led1=1;
        //led2=0;
        }
    else {motor2DirectionPin=ccw;
        //led1=0;
        //led2=1;
        }
    if (fabs(motorValue2)>1) motor2MagnitudePin = 1;
        else motor2MagnitudePin = fabs(motorValue2);
}

void MeasureAndControl()
{
    // This function measures the EMG of both arms, calculates via IK what
    // the joint speeds should be, and controls the motor with 
    // a Feedforward controller. This is called from a Ticker.
    GetReferenceKinematics1(q1_dot, q2_dot);
    FeedForwardControl1( q1_dot, q2_dot, motorValue1, motorValue2);
    SetMotor1(motorValue1, motorValue2);
}

void TimeTrackerF(){
     //wait(1);   
     //float Potmeter1 = potMeter1.read();
     //float referencePosition1 = GetReferencePosition();
     //pc.printf("TTReference Position: %d rad \r\n", referencePosition1);
     //pc.printf("TTPotmeter1, for refpos: %f \r\n", Potmeter1);
     //pc.printf("TTPotmeter2, Kp: %f \r\n", Potmeter2);
     //pc.printf("TTCounts: %i \r\n", counts1);
}

/*
void BiQuadFilter(){            //this function creates a BiQuad filter for the DerivativeCounts
    //double in=DerivativeCounts();
    bqcDerivativeCounts=bqc.step(DerivativeCounts);
    //return(bqcDerivativeCounts);
    }
*/  

int main()
{
 //Initialize
 int led1val = led1.read();
 int led2val = led2.read();
  
  /*
  pc.baud(115200);
 pc.printf("Test putty ledvals IK");
    while (true) {
        wait(0.2f);
        pc.printf("Led1: %i \r\n", led1val);
        pc.printf("Led2: %i \r\n", led2val);    
    }
    */
 MeasureTicker.attach(&MeasureTicker_act, 1.0f); 
 bqc.add(&bq1).add(&bq2);
 
 while(1)
    {
        if (MeasureTicker_go){
            MeasureTicker_go=false;
            MeasureAndControl();
            counts1 = Encoder1.getPulses();           // gives position of encoder 
            counts2 = Encoder2.getPulses();           // gives position of encoder 
            //pc.printf("Resolution: %f pulses/rad \r\n",resolution);
            }
/*
        if (BiQuadTicker_go){
            BiQuadTicker_go=false;
            BiQuadFilter();
        }
  */  
    }
}