Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: HIDScope MODSERIAL QEI TextLCD mbed
Fork of TotalControlEmg2 by
main.cpp
- Committer:
- RemcoDas
- Date:
- 2015-10-28
- Revision:
- 52:85ddaee35185
- Parent:
- 51:dcbfdf3b9468
- Child:
- 53:4a0857fbbb34
File content as of revision 52:85ddaee35185:
//--------------------Include files and libraries-------
#include "mbed.h"
#include "QEI.h"
#include "MODSERIAL.h"
#include "TextLCD.h"
#include "HIDScope.h"
#include "Filterdesigns.h"
#include "Kalibratie.h"
#include "Mode.h"
//--------------------Classes------------------------
InterruptIn btnSet(PTC6); // Kalibration button
InterruptIn emgSet(PTA4); // EMG on/off button
MODSERIAL pc(USBTX, USBRX); // Modserial voor Putty
TextLCD lcd(PTC5, PTC7, PTC0, PTC9, PTC8, PTC1); // LCD screen on inner row of K64F, rs, e, d4-d7
PwmOut servo(D3); // PwmOut servo
AnalogIn emgL(A0), emgR(A1); // Analog input of EMG, left and right
AnalogIn potL(A2), potR(A3); // Potential meter left and right
AnalogIn ksLeft(A5), ksRight(A4); // Killswitch left and right
HIDScope scope(2); // Hidscope, amount of scopes
Ticker EMGticker, tickerControl, tickerLcd; // Ticker for EMG, regulator and break
// QEI Encoder(port 1, port 2, ,counts/rev
QEI enc1 (D13, D12, NC, 64), enc2 (D11, D10, NC, 64);
// Motor1 met PWM power control and direction
PwmOut pwmM1(D6);
DigitalOut dirM1(D7);
// Motor2 met PWM power control and direction
PwmOut pwmM2(D5);
DigitalOut dirM2(D4);
enum spelfase {CALIBRATE_EMG, CALIBRATE_AIM, CALIBRATE_BEAM, AIM, BREAK, FIRE}; // Program states, ACKNOWLEDGEMENT switch: BMT groep 4 2014
uint8_t state = CALIBRATE_EMG; // first state program
enum aimFase {OFF, CW, CCW}; // Aim motor possible states
uint8_t aimState = OFF; // first state aim motor
//-------------------------------Variables---------------------------------------------------------------------
int maxCounts = 13000; // max richt motor counts Aim motor
int breakPerc = 0;
volatile int modeL = 1, modeR = 1;
const double servoBreak = 0.0016, servoFree = 0.002; // Range servo,between servoL en servoR (= pulsewidth pwm servo)
const double tControl = 0.05, tLcd = 2; // ticker time (sec)
const double Fs = 200; //Sample frequency Hz
double t = 1/ Fs; // time EMGticker
double thresholdlowL= 0, thresholdmidL = 0, thresholdhighL= 0;
double thresholdlowR= 0, thresholdmidR = 0, thresholdhighR= 0;
double yL = 0, yR = 0; // y values EMG left and right
volatile bool L = false, R = false; // Booleans for checking if mode. has been 1?
volatile bool btn = false; // Button is pressed?
volatile bool controlFlag = false, btnFlag = false, emgFlag = false, lcdFlag = false, runEmg = true; // Go flags
bool boolBrake = false;
//----------------------------Functions-----------------------------------------------------------------------
void PRINT(const char* text){
lcd.cls(); // clear LCD scherm
lcd.printf(text); // print text op lcd
}
void EMGkalibratieL(){ // Determine thresholds left
PRINT("EMG LEFT relax muscle");
double ymin = KalibratieMin(emgL, true); // Minimum value left EMG, boolean indicates left
wait(1);
PRINT("EMG LEFT flex muscle"); // LCD
double ymax = KalibratieMax(emgL, true); // Maxium value left EMG, boolean indicates left
PRINT("EMG LEFT well done!"); // LCD
if((ymax-ymin) < 0.05 || !runEmg){ // No EMG connected or button pushed
ymin = 10;
ymax = 10;
}
thresholdlowL = 4 * ymin; // Lowest threshold
thresholdmidL = 0.5 * ymax; // Midi threshold
thresholdhighL = 0.8 * ymax; // Highest threshold
pc.printf("ymaxL = %f en yminL = %f \r\n",ymax, ymin);
wait(1);
}
void EMGkalibratieR(){ // Determine thresholds right EMG, same as left
PRINT("EMG RIGHT relax muscle");
double ymin = KalibratieMin(emgR, false);
wait(1);
PRINT("EMG RIGHT flex muscle");
double ymax = KalibratieMax(emgR, false);
PRINT("EMG LEFT well done!");
if((ymax-ymin) < 0.05|| !runEmg){
ymin = 10;
ymax = 10;
}
thresholdlowR = 4 * ymin;
thresholdmidR = 0.5 * ymax;
thresholdhighR = 0.8 * ymax;
pc.printf("ymaxR = %f en yminR = %f \r\n",ymax, ymin); // terminal
wait(1);
}
int EMGfilter(AnalogIn& emg, bool side){
double u = emg.read(); // read emg signal (left or right EMG)
int mode = 1;
if(side){
double y = FilterdesignsLeft(u); // filter signal left EMG
mode = Mode(modeL, y, thresholdlowL, thresholdmidL, thresholdhighL); // Determine mode with thresholds (1, 2, 3)
}
else {
double y = FilterdesignsRight(u);
mode = Mode(modeR, y, thresholdlowR, thresholdmidR, thresholdhighR); // right EMG
}
return mode;
}
int PotReader(AnalogIn& pot){ // read potentialmeter and determine its mode (1 = default, 2, 3)
double volt = pot.read();
int mode = 1;
if(volt > 0.95){
mode = 3;
}
else if(volt>0.35 && volt<0.65){
mode = 2;
}
return mode;
}
int defMode(AnalogIn& emg, AnalogIn& pot, bool side){ // Determine mode both from EMG and Potentialmeter, ONE of them must be ONE!
int emgMode = EMGfilter(emg, side);
int potMode = PotReader(pot);
int mode = 1;
if(!(emgMode==1) != !(potMode==1)){ // emgMode = 1 XOR potMode = 1
if(emgMode > potMode){ // maximum of emg and pot
mode = emgMode;
}
else{
mode = potMode;
}
}
return mode;
}
void setEmgFlag(){ // Goflag EMG
emgFlag = true;
}
void setLcdFlag(){ // Goflag EMG
lcdFlag = true;
}
void btnSetAction(){ // Set knop K64F
btn = true; // GoFlag setknop
}
void emgOnOff(){ // Set knop K64F, push
runEmg = !runEmg; // switch enable emg
pc.printf("EMG is enabled: %i\r\n", runEmg);
}
void setControlFlag(){ // Go flag setButton
controlFlag = true;
}
void checkSide(AnalogIn& ks, int dir){
if((dirM2.read() == dir) && (pwmM2.read()>0)){ // direction motor clashes with killswitch and motor is on
if(ks.read()>0.8){
pwmM2.write(0); // Aim motor freeze
pc.printf("BOEM! CRASH! KASTUK!\r\n"); // Terminal
PRINT("BOEM! CRASH!"); // LCD
}
}
}
void checkAim(){ // check if killswitch clashes with direction motor
checkSide(ksLeft, 1);
checkSide(ksRight, 0);
}
void motorAim(int dir){ // Rotate Aim motor with given direction
dirM2.write(dir);
pwmM2.write(0.2);
}
bool controlAim(){ // Function to control aim motor with modes
bool both = false; // boolean if both modes are 3
modeL = defMode(emgL, potL, true); // determine mode left
modeR = defMode(emgR, potR, false); // determine mode right
scope.set(0, modeL);
scope.set(1, modeR);
scope.send(); //send values to HIDScope
if(modeR < 2 && !R){ // control if mode has been 1
R = true;
}
if(modeL < 2 && !L){
L = true;
}
if((modeL>2 && L) && (modeR >2 && R)) { // mode L and mode R both 3, and both has been 1
both = true; // Return true
pwmM2.write(0); // Aim motor freeze
aimState = OFF; // next state
}
else if((modeR == 2)) { // modeR ==2
if(aimState != CCW){
aimState = CCW; // Rotate CCW
pc.printf("Rotate -, CCW\r\n");
PRINT("Rotate CCW");
motorAim(0);
}
}
else if((modeL == 2)) { // modeL == 2
if(aimState != CW){
aimState = CW; // Rotate CW
pc.printf("Rotate +, CW\r\n");
PRINT("Rotate CW");
motorAim(1);
}
}
// modeR AND CCW OR modeL and CW
else if((modeR == 1 && aimState == CCW) || (modeL == 1 && aimState == CW)) { // R=1 en CW
pwmM2.write(0); // Aim motor freeze
aimState = OFF;
pc.printf("Freeze\r\n");
PRINT("Freeze");
}
return both;
}
int main(){
btnSet.mode(PullUp); // Button mode
btnSet.rise(&btnSetAction); // Connect button to function
emgSet.mode(PullUp); // Button mode
emgSet.rise(&emgOnOff); // Connect button to function
tickerControl.attach(&setControlFlag,tControl); // ticker control motor
EMGticker.attach(&setEmgFlag, t); // ticker EMG, 500H
tickerLcd.attach(&setLcdFlag,tLcd); // ticker lcd
pc.printf("\n\n\n\n\n"); // Terminal
pc.printf("---NEW GAME---\r\n");
PRINT("--- NEW GAME ---"); // LCD
while(1){ // Run program
switch(state){
case CALIBRATE_EMG: {
EMGkalibratieL(); // calibrate left EMG, determine thresholds
EMGkalibratieR(); // calibrate right EMG, determine thresholds
state = CALIBRATE_AIM; // Next state
break;
}
case CALIBRATE_AIM: {
pwmM2.period(1/100000); // period motor 2
pc.printf("Position is kalibrating\r\n"); // terminal
PRINT("Wait a moment, please"); // LCD
dirM2.write(0); // direction aim motor
pwmM2.write(0.2); // percentage motor power
bool calibrated = false;
while(state==CALIBRATE_AIM){
if(controlFlag){
controlFlag = false;
if(!calibrated){ // Not calibrated
if((ksRight.read()>0.8)){ // Killswitch?
pwmM2.write(0); // Aim motor freeze
enc2.reset(); // Reset encoder
PRINT("Aim calibrated"); // LCD
pc.printf("Aim calibrated\r\n");// Terminal
calibrated = true;
pc.printf("Go to midi position\r\n");
dirM2.write(1); // direction aim motor
pwmM2.write(0.2); // percentage motor power, turn it on
}
}
if(calibrated) { // Calibrated
//checkAim(); // Check killswitches
if(abs(enc2.getPulses()) > 700){ // rotate aim motor to midi position
pwmM2.write(0); // Aim motor freeze
state = CALIBRATE_BEAM; // next state
}
}
}
}
lcd.cls();
break;
}
case CALIBRATE_BEAM: {
pc.printf("Calibrate beam motor with setknop\r\n"); // Terminal
dirM1.write(0); // direction beam motor
pwmM1.period(1/100000); // period beam motor
servo.period(0.02); // 20ms period servo
btn = false; // Button is unpressed
PRINT("Calibrate beam to 10 o'clock");
while(state==CALIBRATE_BEAM){
if(controlFlag){
pc.printf(""); // lege regel printen, anders doet setknop het niet
controlFlag = false;
if(btn){ // If setbutton is on or one mode is 3, and has been 1
enc1.reset(); // encoder 1 reset
PRINT("Beam calibrated");
pc.printf("Beam calibrated\r\n");
btn = false; // button op false
state = AIM; // next state
}
}
}
lcd.cls();
break;
}
case AIM: {
pc.printf("Aim with EMG\r\n"); // terminal
int i = 0; // counter for lcd
R = false;
L = false;
while(state == AIM){
if(controlFlag){ // motor control on GoFlag
controlFlag = false;
checkAim(); // Check position
}
if(emgFlag){ // Go flag EMG sampel
emgFlag = false;
if(controlAim()){
pc.printf("Position chosen\r\n"); // terminal
state = BREAK; // Next state (BREAK)
}
}
if(lcdFlag){ // LCD loop to project 3 texts on lcd
lcdFlag = false;
if(i%3 == 0){
PRINT("Flex L or R half to aim");
}
else if(i%3 == 1){
PRINT("Flex both half to freeze");
}
else {
PRINT("Flex both full to continue");
}
i++;
}
}
lcd.cls();
break;
}
case BREAK: {
pc.printf("Set break percentage, current is: %i\r\n", breakPerc);
L = false;
R = false;
PRINT("L := -1, R := +1 L+R = continue");
wait(1);
while(state == BREAK){
if(emgFlag){ // Go flag EMG sampelen
emgFlag = false;
modeL = defMode(emgL, potL, true);
modeR = defMode(emgR, potR, false);
if((modeL > 1) && (modeR > 1) && L && R) { // both modes > 1
state = FIRE;
}
else if((modeL > 2 && L)|| (modeR > 2 && R)) { // left of right mode 3 = fire
state = FIRE;
}
else {
if(modeR < 2) { // modeR is 1
R = true;
}
if(modeL < 2) { // modeL is 1
L = true;
}
if(L && R){ // L and R has been 1
if((modeL == 2) && L) { // modeL = BREAK lower with one
if(breakPerc > 0){
breakPerc--;
}
L = false;
}
else if((modeR == 2) && R) { // modeR = Break +1
if(breakPerc < 3){
breakPerc ++;
}
R = false;
}
if(modeL > 1 || modeR > 1){ // Print BREAK scale if one of both modes > 1
pc.printf("Current breaking scale: %i \r\n", breakPerc);
}
}
}
if(lcdFlag){ // every 2 seconds update lcd
lcdFlag = false;
lcd.cls();
lcd.printf("Break scale 0 - 4: %i", breakPerc);
}
}
}
lcd.cls();
lcd.printf("Break fixed on: %i", breakPerc); // lcd
pc.printf("Break fixed\r\n"); // terminal
L = false; // modeL must be one for another action can take place
R = false; // modeR ""
break;
}
case FIRE: {
pc.printf("Shooting\r\n"); // terminal
PRINT("FIRING"); // lcd
pwmM1.write(0.3); // beam motor on
bool breaking = false;
int countBreak = 0;
if(breakPerc > 0){
servo.pulsewidth(servoBreak); // Servo to break position
breaking = true; // boolean breaking?
countBreak = 2100*breakPerc/4; // Amount of counts where must be breaked
}
while(state == FIRE){ // while in FIRE state
if(controlFlag){ // BREAK goFlag half rotation beam = breaking
controlFlag = false; // GoFlag
int counts = abs(enc1.getPulses())+250; // counts encoder beam, +250 is to correct 10 to 12 o'clock // encoder is 0 on 100 counts before 12 o'clock
if(breaking){
if((counts+countBreak)%4200 < 100){ // calculate with remainder, half revolution
servo.pulsewidth(servoFree); // Servo to free position
breaking = false;
}
}
if(!breaking){
if((counts-100)%4200 < 100){ // rotated 1 rev?
pwmM1.write(0); // motor beam off
pc.printf("Beam on startposition\r\n"); // terminal
state = AIM; // Next stage
}
}
}
}
lcd.cls();
break;
}
}
}
}
