Version for EMG Threshold finding

Dependencies:   HIDScope MODSERIAL QEI biquadFilter mbed

Fork of prog_BioRobotics_Group9_StampRobot by Gerhard Berman

main.cpp

Committer:
GerhardBerman
Date:
2016-11-03
Revision:
37:1360978f49ba
Parent:
36:72f0913c5460

File content as of revision 37:1360978f49ba:

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

/*
THINGS TO CONSIDER
- Line 234, 239: motor action of motor 1 is inverted because it is mounted
opposite to motor 2 in the tower. Check if the clockwise directions of the 
motors correspond to the positive q1, q2-directions (both counterclockwise)
 in the original IK-sketch.
- Line 244,257: motor values have been scaled down for safety at first test, restore
after testing to get proper action.
- Set angle and length boundaries!!
- Set robot constants (lengths etc.)
- Set EMGgain and thresholds
- Add tower height to ReferencePosition_y and Position_y AND inverse kinematics calculation!
- Add (lower) boundaries to TotalErrors
- MotorGain could change due to arm weight!!
- Arms should be placed manually into reference position.
*/

//set pins
DigitalIn encoder1A (D13); //Channel A van Encoder 1
DigitalIn encoder1B (D12); //Channel B van Encoder 1
DigitalIn encoder2A (D11); //Channel A van Encoder 2, kan niet op D15
DigitalIn encoder2B (D10); //Channel B van Encoder 2, kan niet op D14
//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);

DigitalOut ledgrn(LED_GREEN);
DigitalOut ledred(LED_RED);
DigitalOut ledblue(LED_BLUE);

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

//initial values
float dx;
float dy;
double DerivativeCounts;
//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 lengths (VALUES HAVE TO BE CHANGED)
//float x0 = 1.0;
float L0 = 0.232;
float L1 = 0.45;
float L2 = 0.35;
float TowerHeight = 0.232;    //height of motor axes above table surface!
float StampHeight = 0.06;    // height of end effector
float y_stampup = 0.1;      //height stamp while not stamping: 10cm above table surface
float y_stampdown = 0.0;    //height stamp while stamping: at table surface


//set initial conditions
float biceps_l = 0;
float biceps_r = 0;
float ReferencePosition_x = L2;
float ReferencePosition_y = L1 + TowerHeight - StampHeight;
float ReferencePosition_xnew = 0;
float ReferencePosition_ynew = 0;
float Position_x = 0.0;
float Position_y = 0.0;
float q1 = 0;
float q2 = 0;
float q1_ref = 0;
float q2_ref = 0;
float q1start = 0;
float q2start = PI/2;

float q1_error_prev = 0;
float q2_error_prev = 0;
float DerTotalError1 = 0;
float DerTotalError2 = 0;
float q1IntError = 0;
float q2IntError = 0;
float TotalError1_prev = 0;
float TotalError2_prev = 0;

float motorValue1 = 0.0;
float motorValue2 = 0.0;
int counts1 = 0;
int counts2 = 0;
int counts1Prev = 0;
int counts2Prev = 0;


//set constant or variable values (VALUES HAVE TO BE EDITED)
float EMGgain = 1.0;
float dy_stampdown = 2.0; //0.05; //5 cm movement downward to stamp
float MotorGain = 8.4; // rad/s for PWM, is max motor speed (motor value of 1)
float t_sample = 0.1; //seconds
const float maxStampDistance = 2.0;

float q1_refOutNew = 0;
float q1_refOutMin = 0;         //WRONG values
float q1_refOutMax = 0.4722*PI;      //WRONG values
float q2_refOutNew = 0;
float q2_refOutMin = 0.2611*PI;         //WRONG values
float q2_refOutMax = 0.6667*PI;        //WRONG values
float TotalError1= 0;
float TotalError2= 0;
float TotalErrorMin= 0;
 
//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(D10, D11, NC, 32); // turns on encoder

const int counts_per_revolution = 4200; //counts per motor axis revolution
const int inverse_gear_ratio = 131;
const float resolution = counts_per_revolution/(2*PI/inverse_gear_ratio);  //87567.0496892 counts per radian, encoder axis

void GetReferenceKinematics1(float &q1Out, float &q2Out, float &q1_refOut, float &q2_refOut){
    
    //get joint positions q feedback from encoder
    float Encoder1Position = counts1/resolution;         //angular position in radians, encoder axis
    float Encoder2Position = -1*counts2/resolution;

    q1Out = q1start + Encoder1Position*inverse_gear_ratio;        //angular position in radians, motor axis
    q2Out = q2start + Encoder2Position*inverse_gear_ratio;

    //get end effector position feedback with trigonometry
    Position_x = (L1*sin(q1) + L2*sin(q1+q2));
    Position_y = (L1*cos(q1) + L2*cos(q1+q2)) + TowerHeight - StampHeight;  

    pc.baud(115200);
    pc.printf("Counts1: %  f    ", counts1);
    pc.printf("Counts2: %  f    ", counts2);
    pc.printf("posX: %f ",Position_x);
    pc.printf("posY: %f ",Position_y);
    pc.printf("q1: %f   ", q1Out);
    pc.printf("q2: %f   \r\n", q2Out);
   
    }
    

void FeedbackControl1(float q1_ref, float q2_ref, float q1, float q2, float &motorValue1Out, float &motorValue2Out){
    
    // linear feedback control
    float q1_error = q1_ref - q1; //referencePosition1 - Position1;             // proportional angular error in radians
    float q2_error = q2_ref - q2; //referencePosition1 - Position1;             // proportional angular error in radians
    float Kp = 6; //potMeter2.read();

    float q1IntError = q1IntError + q1_error*t_sample;             // integrated error in radians
    float q2IntError = q2IntError + q2_error*t_sample;             // integrated error in radians
    //float maxKi = 0.2;
    float Ki = 0.04*Kp;  //0.01*Kp; //potMeter2.read();
    
    float q1DerivativeError = (q1_error - q1_error_prev)/t_sample;  // derivative of error in radians
    float q2DerivativeError = (q2_error_prev + q2_error)/t_sample;  // derivative of error in radians
    //float maxKd = 0.2;
    float Kd = 0.0;  //0.04*Kp; //potMeter2.read();
    
    //scope.set(0,referencePosition1);
    //scope.set(1,Position1);
    //scope.set(2,Ki);
    //scope.send();
    
    TotalError1 = q1_error * Kp + q1IntError * Ki + q1DerivativeError * Kd;         //total controller output in radians = motor input
    TotalError2 = q2_error * Kp + q2IntError * Ki + q2DerivativeError * Kd;         //total controller output in radians = motor input
    
    /*
    if (fabs(TotalError1) < TotalErrorMin) {
        TotalError1=0;
        }
    else {
        TotalError1=TotalError1;
        }
    if (fabs(TotalError2) < TotalErrorMin) {
        TotalError2=0;
        }
    else {
        TotalError2=TotalError2;
        }
    */
    /*
    DerTotalError1 = (TotalError1 - TotalError1_prev)/t_sample;
    DerTotalError1 = (TotalError1 - TotalError1_prev)/t_sample;
    motorValue1Out = DerTotalError1/MotorGain;       
    motorValue2Out = DerTotalError2/MotorGain;       
    */
    
    motorValue1Out = TotalError1/MotorGain;       
    motorValue2Out = TotalError2/MotorGain;       
    
    /*
    scope.set(0,q1_ref);
    scope.set(1,q1);
    scope.set(2,q2_ref);
    scope.set(3,q2);
    scope.set(4,motorValue1Out);
    scope.set(5,motorValue2Out);
    scope.send();
    */
    /*
    pc.printf("E1: %f  ", q1_error);
    pc.printf("IE1: %f  ", q1IntError);
    pc.printf("DE1: %f  ", q2DerivativeError);
    pc.printf("E2: %f  ", q2_error);
    pc.printf("IE2: %f  ", q2IntError);
    pc.printf("DE2: %f  ", q2DerivativeError);
    */
    pc.printf("TE1: %f  ", TotalError1);
    pc.printf("TE2: %f  ", TotalError2);
    pc.printf("M1: %f   ", motorValue1Out);
    pc.printf("M2: %f   \r\n", motorValue2Out);
      
    q1_error_prev = q1_error;
    q2_error_prev = q2_error;
    TotalError1_prev = TotalError1;
    TotalError2_prev = TotalError2;
}

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) //clockwise rotation
        {motor1DirectionPin=cw;        //inverted due to opposite (to other motor) build-up in tower
        //led1=1;
        //led2=0;
        }
    else    //counterclockwise rotation 
        {motor1DirectionPin=ccw;         //inverted due to opposite (to other motor) build-up in tower
        //led1=0;
        //led2=1;
        }
    if (fabs(motorValue1)>1){
        motor1MagnitudePin = 1;
        }
    else{
        motor1MagnitudePin = fabs(motorValue1);  //fabs(motorValue1);
        }
    
    //control motor 2
    if (motorValue2 >=0)  //clockwise rotation
        {motor2DirectionPin=ccw; //action is cw, due to faulty motor2DirectionPin (inverted)
        //led1=1;
        //led2=0;
        }
    else    //counterclockwise rotation 
        {motor2DirectionPin=cw;    //action is ccw, due to faulty motor2DirectionPin (inverted)
        //led1=0;
        //led2=1;
        }
    if (fabs(motorValue2)>1){
        motor2MagnitudePin = 1;
        }
    else{
        motor2MagnitudePin = fabs(motorValue2);
        }
        float ReadMagn1 = motor1MagnitudePin.read();
        float ReadMagn2 = motor2MagnitudePin.read();
        //pc.printf("motor1Magnitude: %f \r\n", ReadMagn1);
        //pc.printf("motor2Magnitude: %f \r\n", ReadMagn2);
}

void MeasureAndControl()
{
    // This function measures the EMG of both arms, calculates via IK what
    // the joint positions should be, and controls the motor with 
    // a Feedback controller. This is called from a Ticker.
    GetReferenceKinematics1(q1, q2, q1_ref, q2_ref);
    //FeedbackControl1( q1_ref, q2_ref, q1, q2, 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 IK");
 //           counts1 = Encoder1.getPulses();           // gives position of encoder 
 //           counts2 = Encoder2.getPulses();           // gives position of encoder 
 //wait(10.0);
 MeasureTicker.attach(&MeasureTicker_act, 0.1f); 
 bqc.add(&bq1).add(&bq2);
 
 while(1)
    {
        if (MeasureTicker_go){
            MeasureTicker_go=false;
            ledgrn = 1;
            ledblue = 0;
            MeasureAndControl();
            counts1 = Encoder1.getPulses();           // gives position of encoder 
            counts2 = Encoder2.getPulses();           // gives position of encoder 
            pc.printf("counts1main: %i  ", counts1);
            pc.printf("counts2main: %i  ", counts2);
            ledblue = 1;
            ledgrn = 0;
            }
/*
        if (BiQuadTicker_go){
            BiQuadTicker_go=false;
            BiQuadFilter();
        }
  */  
    }
}