Control up to two motors using filtered EMG signals and a PID controller
Dependencies: FastPWM HIDScope MODSERIAL QEI Matrix biquadFilter controller errorFetch mbed motorConfig refGen MatrixMath inverseKinematics
Fork of Minor_test_serial by
main.cpp
- Committer:
- tvlogman
- Date:
- 2017-10-06
- Revision:
- 26:4f84448b4d46
- Parent:
- 25:df780572cfc8
- Child:
- 27:a4228ea8fb8f
File content as of revision 26:4f84448b4d46:
#include "mbed.h" #include "MODSERIAL.h" #include "HIDScope.h" #include "QEI.h" #include "FastPWM.h" enum robotStates {KILLED, ACTIVE}; robotStates currentState = KILLED; QEI Encoder(D12,D13,NC,64, QEI::X4_ENCODING); MODSERIAL pc(USBTX, USBRX); // Defining outputs // Leds can be used to indicate status DigitalOut ledG(LED_GREEN); DigitalOut ledR(LED_RED); DigitalOut ledB(LED_BLUE); DigitalOut motor1_direction(D4); PwmOut motor1_pwm(D5); // Defining inputs InterruptIn sw2(SW2); InterruptIn sw3(SW3); InterruptIn button1(D2); AnalogIn pot1(A0); AnalogIn pot2(A1); // PWM settings float pwmPeriod = 1.0/5000.0; int frequency_pwm = 10000; //10kHz PWM volatile float x; volatile float x_prev =0; volatile float y; // filtered 'output' of ReadAnalogInAndFilter // Initializing encoder Ticker encoderTicker; Ticker controllerTicker; volatile int counts = 0; volatile float revs = 0.00; // MOTOR CONTROL PART bool m1_direction = false; int posRevRange = 5; // describes the ends of the position range in complete motor output shaft revolutions in both directions const float maxAngle = 2*3.14*posRevRange; // max angle in radians const float Ts = 0.1; // Function getReferencePosition returns reference angle within range float getReferencePosition(){ double r; if(m1_direction == false){ // Clockwise rotation yields positive reference r = maxAngle*pot1.read(); } if(m1_direction == true){ // Counterclockwise rotation yields negative reference r = -1*maxAngle*pot1.read(); } return r; } // Initializing position and integral errors float e_pos = 0; float e_int = 0; float e_der = 0; float e_prev = 0; float e = e_pos + e_int + e_der; // readEncoder reads counts and revs and logs results to serial window void getError(float &e_pos, float &e_int, float &e_der){ counts = Encoder.getPulses(); double motor1Position = 2*3.14*(counts/(131*64.0f)); pc.printf("%0.2f revolutions \r\n", motor1Position); e_pos = getReferencePosition() - motor1Position; e_int = e_int + Ts*e_pos; e_der = (e_pos - e_prev)/Ts; e = e_pos + e_int + e_der; // not sure if this is really even all that useful e_prev = e_pos; // Store current error as we'll need it to compute the next derivative error pc.printf("Error is %0.2f \r \n", e); } const float k_p = 0.1; // use potmeter 2 to adjust k_p within range 0 to 1 const float k_i = 0.05; // Still needs a reasonable value const float k_d = 0.01; // Again, still need to pick a reasonable value // motorController sets a motorValue based on the position error. Sign indicates direction and magnitude indicates speed. Right now this is a simple feedforward float motorController(float e_pos, float e_int, float e_der){ // NOTE: do I still need the maxangle bit here? double motorValue = (e_pos*k_p) + 0.35 + k_i*e_int + k_d*e_der; // motorValue is the normalized voltage applied to motor magnitude pin between -1 and 1 added 0.35 as motorvalue of 0.35 does nothing return motorValue; } // setMotor1 sets the direction and magnitude pins of motor1 depending on the given motorValue. Negative motorValue means clockwise rotation void setMotor1(float motorValue){ switch(currentState){ case KILLED: motor1_pwm.write(0.0); ledR = 0; ledG = 1; ledB = 1; break; case ACTIVE: // Set motor direction if (motorValue >=0){ motor1_direction = 0; } else { motor1_direction = 1; } // Set motor speed if (fabs(motorValue)>1){ motor1_pwm = 1; } else { motor1_pwm.write(fabs(motorValue)); } ledR = 1; ledG = 1; ledB = 0; break; } } void measureAndControl(){ getError(e_pos, e_int, e_der); float motorValue = motorController(e_pos, e_int, e_der); pc.printf("Position action is %.2f \r \n", k_p*e_pos); pc.printf("Derivative action is %.2f \r \n", k_d*e_der); pc.printf("Integral action is %.2f", k_i*e_int); pc.printf("Total action is %.2f", k_p*e_pos + k_d*e_der + k_i*e_int); pc.printf("Motorvalue is %.2f \r \n", motorValue); pc.printf("Actual error is %.2f \r \n", e_pos); setMotor1(motorValue); } void killSwitch(){ pc.printf("Motors turned off"); currentState = KILLED; } void turnMotorsOn(){ pc.printf("Motors turned on"); currentState = ACTIVE; } void M1switchDirection(){ m1_direction = !m1_direction; pc.printf("Switched direction!"); } int main() { pc.printf("Main function"); motor1_direction = 0; // False = clockwise rotation motor1_pwm.period(pwmPeriod);//T=1/f sw2.fall(&killSwitch); sw3.fall(&turnMotorsOn); button1.rise(&M1switchDirection); pc.baud(115200); controllerTicker.attach(measureAndControl, Ts); pc.printf("Encoder ticker attached and baudrate set"); }