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
main.cpp
- Committer:
- RichardRoos
- Date:
- 2015-10-20
- Revision:
- 34:60391fb72629
- Parent:
- 33:b4757132437e
- Child:
- 35:012b2e045579
File content as of revision 34:60391fb72629:
//--------------------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
DigitalOut ledR(LED_RED), LedB(LED3); // Leds on K64F
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 KS(A4); // Killswitch
HIDScope scope(6); // Hidscope, amount of scopes
Ticker EMGticker, tickerControl, tickerBreak, 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_PEND, AIM, BREAK, FIRE}; // Proframstates, 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---------------------------------------------------------------------
const int on = 0, off = 1; // on off
int maxCounts = 13000; // max richt motor counts Aim motor
int breakPerc = 0;
const double servoL = 0.001, servoR = 0.0011; // Range servo,between servoL en servoR (= pulsewidth pwm servo)
const double tControl = 0.005, tBreak = 0.1, tLcd = 1; // tickers
const double Fs = 50; //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, breakFlag = false, emgFlag = false, lcdFlag = false; // Go flags
//----------------------------Functions-----------------------------------------------------------------------
void flipLed(DigitalOut& led){ //function to flip one LED
led.write(on);
wait(0.2);
led.write(off);
}
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){ // No EMG connected
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);
}
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){
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
}
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(y, thresholdlowL, thresholdmidL, thresholdhighL); // Determine mode with thresholds (1, 2, 3)
}
else {
double y = FilterdesignsRight(u);
mode = Mode(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.8){
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 setControlFlag(){ // Go flag setButton
controlFlag = true;
}
void setBreakFlag(){ // Go flag Break
breakFlag = true;
}
void checkAim(){ // check if Killswitch is on or max counts is reached
double volt = KS.read();
if(volt> 0.5 || abs(enc2.getPulses()) > (maxCounts -50) || enc2.getPulses() < 0){
pwmM2.write(0); // Aim motor freeze
pc.printf("BOEM! CRASH! KASTUK! \r\n"); // Terminal
PRINT("BOEM! CRASH!"); // LCD
}
}
void motorAim(int dir){ // Rotate Aim motor with given direction
dirM2.write(dir);
pwmM2.write(0.25);
}
bool controlAim(){ // Function to control aim motor with modes
bool both = false; // boolean if both modes are 3
int modeL = defMode(emgL, potL, true);
int modeR = defMode(emgR, potR, false);
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) && (modeR >2 && R && L)) { // mode L and mode R both 3, and both has been 1 herefore
both = true; // Return true
pwmM2.write(0); // Aim motor freeze
aimState = OFF; // next state
}
else if((modeR == 2) && (modeL == 2)) { // modes are both 2
if(aimState!=OFF){ // only if aim motor is rotating
pwmM2.write(0); // Aim motor freeze
aimState = OFF; // motor state is off
pc.printf("Motor freeze\r\n"); // LCD
L = false; // Modes must be first 1 for another action
R = false; // ""
}
}
else if((modeL == 2) && (aimState != CCW && (modeR == 1))) { // modeL ==2 AND rotation is not CCW AND modeR has been 1
if(L){
aimState = CCW; // Rotate CCW
pc.printf("Rotate -, CCW\r\n");
motorAim(0);
}
}
else if((modeR == 2) && (aimState != CW && (modeL == 1))) { // modeR == 2 AND rotation is not CW AND modeL has been 1
if(R){
aimState = CW; // Rotate CW
pc.printf("Rotate +, CW\r\n");
motorAim(1);
}
}
return both;
}
int main(){
flipLed(ledR); // test if code begins
btnSet.mode(PullUp); // Button mode
btnSet.rise(&btnSetAction); // Connect button to function
tickerControl.attach(&setControlFlag,tControl); // ticker control motor
tickerBreak.attach(&setBreakFlag,tBreak); // ticker break
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
printf("Position is kalibrating\r\n"); // terminal
PRINT("Wait a moment, please"); // LCD
dirM2.write(0); // direction aim motor
pwmM2.write(0.25); // percentage motor power
bool calibrated = false; //
while(state==CALIBRATE_AIM){
pc.printf("Killswitch: %f\r\n", KS.read()); // terminal
if(KS.read() > 0.5 && !calibrated){ // Killswitch?
pwmM2.write(0); // Aim motor freeze
enc2.reset(); // Reset encoder
PRINT("Aim calibrated"); // LCD
calibrated = true; //
dirM2.write(0); // direction aim motor
pwmM2.write(0.25); // percentage motor power, turn it on
}
if(controlFlag && calibrated){ // motor regelen op GoFlag
controlFlag = false;
if(enc1.getPulses() > maxCounts/2){ // rotate aim motor to midi position
pwmM2.write(0); // Aim motor freeze
state = CALIBRATE_PEND; // next state
}
}
}
break;
}
case CALIBRATE_PEND: {
pc.printf("Calibrate beam motor with setknop\r\n"); // Terminal
pwmM1.period(1/100000); // period beam motor
servo.period(0.02); // 20ms period servo
//pwmM1.write(0.25); // Turn motor on, low power
btn = false; // Button is unpressed
R = false; // modeR must become 1
L = false; // modeL must become 1
PRINT("Calibrate beam");
wait(1);
PRINT("Flex right half to swing beam");
while(state==CALIBRATE_PEND){
if(emgFlag){
pc.printf(""); // lege regel printen, anders doet setknop het niet
emgFlag = false;
int modeL = defMode(emgL, potL, true); // determine modeL
int modeR = defMode(emgR, potR, false); // determine modeR
if(modeR < 2) { // modeR == 1
R = true;
}
if(modeL < 2) { // modeL == 1
L = true;
}
if (btn || (modeL == 3 && L) || (modeR == 3 && R)){ // If setbutton is on or one mode is 3, and has been 1
pwmM1.write(0); // Motor 1 freeze
enc1.reset(); // encoder 1 reset
PRINT("Beam calibrated");
btn = false; // button op false
state = AIM; // next state
}
else if(modeL == 2){
pwmM1.write(0); // beam freeze
PRINT("Flex both full to continue"); // LCD
}
else if(modeR == 2){
pwmM1.write(0.025); // beam rotate
PRINT("Flex left half to stop beam"); // LCD
}
}
}
break;
}
case AIM: {
pc.printf("Aim with EMG\r\n"); // terminal
int i = 0; // counter for lcd
while(state == AIM){
if(lcdFlag){
if(i%3 == 0){
PRINT("Flex left or right half to aim");
}
else if(i%3 == 1){
PRINT("Flex both half to freeze");
}
else {
PRINT("Flex both full to continue");
}
i++;
}
if(controlFlag){ // motor control on GoFlag
controlFlag = false;
checkAim(); // Check position
}
if(emgFlag){ // Go flag EMG sampel
emgFlag = false;
if(controlAim()){
pc.printf("Position choosen, adjust shoot velocity\r\n");
state = BREAK; // Next state (BREAK)
}
}
}
break;
}
case BREAK: {
pc.printf("Set break percentage, current is: %.0f\r\n", breakPerc);
L = false;
R = false;
while(state == BREAK){
if(emgFlag){ // Go flag EMG sampelen
emgFlag = false;
int modeL = defMode(emgL, potL, true);
int modeR = defMode(emgR, potR, false);
if(modeR < 2) { // modeR is 1
R = true;
}
if(modeL < 2) { // modeL is 1
L = true;
}
if(L && R){
if((modeL > 1) && modeR > 1) { // both modes
state = FIRE;
R = false;
L = false;
}
else if(modeL > 2 || modeR > 2) { // left of right mode 3 = fire
state = FIRE;
R = false;
L = false;
}
else if((modeL == 2) && L) { // modeL = BREAK lower with one
if(breakPerc>1){
breakPerc--;
}
L = false;
}
else if((modeR == 2) && R) { // modeR = Break +1
if(breakPerc<10){
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);
lcd.cls();
lcd.printf("Break scale is: %i", breakPerc);
}
}
}
}
L = false; // modeL must be one for another action can take place
R = false; // modeR ""
break;
}
case FIRE: {
pc.printf("Shooting\r\n");
servo.pulsewidth(servoL); // BREAK release
pwmM1.write(0.25); // beam motor on
bool servoPos = true;
while(state == FIRE){ // while in FIRE state
if(breakFlag && (abs(enc1.getPulses())-100)%4200 < (2100*abs(breakPerc)/10)){ // BREAK goFlag half rotation beam = breaking
breakFlag = false;
if(servoPos){
servoPos = false;
servo.pulsewidth(servoL); // left
}
else{
servoPos = true;
servo.pulsewidth(servoR); // right
}
}
if(controlFlag){
controlFlag = false;
if((abs(enc1.getPulses())+50)%4200 < 150){ // rotate beam one revolution
pwmM1.write(0); // motor beam off
pc.printf("beam on startposition\r\n");
state = AIM; // Next stage
}
}
}
break;
}
}
}
}