ECE4180 Final Project Team / Mbed 2 deprecated Sliding_Camera_Rail

Dependencies:   mbed mbed-rtos Linear_Stepper_Motor_Nema17

Fork of Sliding_Camera_Rail by Michael Marzano

main.cpp

Committer:
mikermarza
Date:
2020-04-28
Revision:
1:8134c43fdb08
Parent:
0:59fcbfc00e50
Child:
2:7facfc9e53ff

File content as of revision 1:8134c43fdb08:

/* Written by Michael Marzano
ECE 4180 Final Project
Sliding Camera Rail

Souce code for the camera rail
*/

#include "mbed.h"
#include "rtos.h"
#include "lin_step_mtr.h"

/**********
* Defines *
**********/
#define ABSOLUTE_MIN 0      // minimum rev for software stop
#define ABSOLUTE_MAX 49.5   // maximum rev for software stop
#define MAX_SPEED 400       // maximum speed in RPM
#define MIN_SPEED 200       // minimum speed in RPM

// range over all possible speeds, used in calculating the rotation input to 
// LinStepMtr::rotate() for smooth operation
#define SPEED_RNG MAX_SPEED - MIN_SPEED
                            

/***********
* Hardware *
***********/
LinStepMtr mtr(p19, p20, p17, p18); // for linear motor, coresponds t0 A,A',B,B'
BusOut lights (LED4,LED3,LED2,LED1);
Serial xbee(p28,p27);
//Serial xbee(USBTX,USBRX);

/********
* Enums *
********/
typedef enum {
    OFF = 0b0000,
    ALL = 0b1111,
    L2  = 0b1100,
    R2  = 0b0011,
    AH1 = 0b1010,
    AH2 = 0b0101    
} LightPattern;

typedef enum {
    STOP = 0,
    MV_L,
    MV_R,    
} RailState;

typedef enum {
    NORMAL = 0,
    LOCK_N,     // LOCK for normal mode
    CALIBRATE,
    GO_HOME,
    RESET,
    OVERRIDE
} RailMode;

typedef enum {
    GOOD = 0,
    START,
    HOME,
    AWAY
} CalibrateStatus;

/***********************
* Flag/State Variables *
***********************/
volatile RailState rail_state;      // the state of rail movement
volatile RailMode rail_mode;        // rail mode, described in RailMode enum
volatile CalibrateStatus cal_stat;   // status of calibration
volatile double home;               // rev count for rail's "home", initialized to ABSOLUTE_MIN
volatile double away;               // rev count for rail's farthest movement point initialized to ABSOLUTE_MAX;
volatile char speed;                // current speed setting from inputs
volatile float rot;                 // number of revolutions to rotate based on speed

volatile bool going_home;           // flag for if rail is headed back to "home"
volatile bool home_set;             // flag for if home has been set
volatile bool away_set;             // flag for if away has been set
volatile bool cal_done;             // flag for if calibration is complete
volatile bool toggle;

/***************************
* General Static Functions *
***************************/

static inline void send_ack()
{
    xbee.printf("!A");
}

/*******************
* Thread Functions *
*******************/
// reads the input from the serial com port
void read_input(void const *arg) 
{
    char input;
    
    while(1) {
        if(!xbee.readable()){
            Thread::yield();
        } else {
            input = xbee.getc();
            if (input != '!'){
                Thread::yield();
            }else {
                while(!xbee.readable()) Thread::yield();
                input = xbee.getc();
                
                switch(input){
                    case '0': // no movement
                        rail_state = STOP;
                        while(!xbee.readable()) Thread::yield();
                        input = xbee.getc();
                        break;
                    case '1':
                    case '2':
                    case '3':
                    case '4':
                    case '5':
                        // handle speed
                        if(speed != input) {
                            speed = input;
                            rot = ((float)input - 49) * .0125 + .2;
                            mtr.set_speed(((float) input - 49)*50 + 200);
                        }
                        while(!xbee.readable()) Thread::yield();
                        input = xbee.getc();
                        xbee.printf("DIR: %c\n",input);
                    
                        switch(input){
                            case 'L':   // move left
                                rail_state = MV_L;
                                break;
                            case 'R':   // move right
                                rail_state = MV_R;
                                break;
                            default:
                                break;
                        }
                        break;
                    case 'S':   // stop movement
                        rail_state = STOP;                        
                        break;
                    case 'F':   // Lock or Unlock rail
                        switch(rail_mode) {
                            case NORMAL:
                                rail_mode = LOCK_N;
                                break;
                            case LOCK_N:
                                rail_mode = NORMAL;
                                rail_state = STOP;
                                break;
                            default:
                                break; // do nothing                            
                        }
                        break;
                    case 'C':
                        switch(rail_mode){
                            case NORMAL:
                            case LOCK_N:
                            case CALIBRATE:
                                switch(cal_stat){
                                    case GOOD:
                                        rail_state = STOP;
                                        home_set = false;
                                        away_set = false;
                                        cal_done = false;
                                        cal_stat = START;
                                        rail_mode = CALIBRATE;
                                        Thread::wait(600);
                                        break;
                                    case START:
                                    case HOME:
                                        home = mtr.get_rev();
                                        rail_state = STOP;
                                        home_set = true;
                                        send_ack();
                                        cal_stat = AWAY;
                                        Thread::wait(600);
                                        break;
                                    case AWAY:
                                        away = mtr.get_rev();
                                        rail_state = STOP;
                                        away_set = true;
                                        send_ack();
                                        cal_stat = GOOD;
                                        Thread::wait(600);
                                        break;
                                }
                                break;
                            default:
                                break;
                        }
                        break;
                    case 'H':   // send rail to home
                        switch(rail_mode){
                            case NORMAL:
                            case LOCK_N:
                                rail_state = STOP;
                                going_home = true;
                                rail_mode = GO_HOME;
                                break;
                        }
                        break;
                    default:
                        break; // do nothing because invalid input
                }
                Thread::yield(); // hopefully makes this thread run a little faster
            }
        }
    }

}

// blinks leds a set number of times with a wait time of w
static inline void blink_leds(int t, int w, LightPattern p)
{
    for(int i=0; i < t; ++i){
        lights = OFF;
        Thread::wait(w);
        lights = p;
        Thread::wait(w);
    }
    lights = OFF;
    Thread::wait(w);
}

// reads flag variables to control LED status lights
void status_lights(void const *arg) 
{
    while(1) {
        switch(rail_mode){
            case LOCK_N:
                lights = ALL;
                Thread::yield();
                break;
            case CALIBRATE:
                //blink twice
                blink_leds(2,150,ALL);
                
                toggle = true;
                while(!home_set){
                    if(toggle)
                        lights = L2;
                    else
                        lights = OFF;
                    
                    toggle = !toggle;
                    Thread::wait(500);   
                }    
                blink_leds(2,150,L2);
                
                toggle = true;
                while(!away_set){
                    if(toggle)
                        lights = R2;
                    else
                        lights = OFF;
                    
                    toggle = !toggle;
                    Thread::wait(500);   
                }   
                blink_leds(2,150,R2);
                Thread::wait(500);
                
                while(!cal_done);
                    
                blink_leds(2,150,ALL);
                break;
            case GO_HOME:
                // blink thrice
                blink_leds(3,150,ALL);
                
                toggle = true;
                while(going_home){
                    if(toggle)
                        lights = ALL;
                    else
                        lights = OFF;
                    
                    toggle = !toggle;
                    Thread::wait(600);
                }
                
                // blink thrice for complete
                blink_leds(3,150,ALL);              
                
                break;
            case NORMAL: // no lights for normal opperation
            default:
                lights = OFF;
                Thread::yield();
                break;
        }
    }
}
    
    
/****************
* Main Function *
****************/

int main() {
    
    // Variables
    double cur_loc;         // current location in revolutions. used for GO_HOME
    
    //set defaults for global variables
    rail_state  = STOP;
    rail_mode   = NORMAL;
    cal_stat    = GOOD;
    home        = ABSOLUTE_MIN;
    away        = ABSOLUTE_MAX;
    speed       = '5';
    rot         = .25;
    
    going_home  = false;
    home_set    = true;
    away_set    = true;
    cal_done    = true;
    toggle      = true;
    
    // Start Threads
    Thread input(read_input);
    Thread lights(status_lights);

    wait(.001);;
    
    // set up motor
    mtr.set_min_rev_cnt(home);
    mtr.set_max_rev_cnt(away);
       
    while(1) {
        switch(rail_mode) {
            case NORMAL:
                switch(rail_state) {
                    case MV_L:
                        mtr.rotate(LinStepMtr::CW,rot);
                        break;
                    case MV_R:
                        mtr.rotate(LinStepMtr::CCW,rot);
                        break;
                    case STOP:
                    default:
                        break;
                }
                break;
            case LOCK_N:
                // do nothing
                break;
            case CALIBRATE:
                switch(cal_stat) {
                    case START:
                        // reset stats
                        mtr.RESET_rev_cnts();
                        cal_stat = HOME;
                        break;
                    case GOOD:
                        // save software bounds to rotation library
                        if(away < home) { //away is right of home
                            mtr.set_min_rev_cnt(away);
                            mtr.set_max_rev_cnt(home);
                        } else { // away is left of home
                            mtr.set_min_rev_cnt(home);
                            mtr.set_max_rev_cnt(away);
                        }                            
                        
                        cal_done = true;
                        send_ack();
                        rail_mode = NORMAL;
                        break;
                    default:
                        break;
                }
                switch(rail_state) {
                    case MV_L:
                        mtr.rotate(LinStepMtr::CW,rot);
                        break;
                    case MV_R:
                        mtr.rotate(LinStepMtr::CCW,rot);
                        break;
                    case STOP:
                    default:
                        break;
                }
                break;
            case GO_HOME:
                Thread::wait(1000);
                
                // get currecnt location
                cur_loc = mtr.get_rev();
                
                mtr.set_speed(MAX_SPEED);
                speed = '0';
                
                if(home < cur_loc) { // home is right of current location
                    mtr.rotate(LinStepMtr::CCW,cur_loc - home);                    
                } else { // home is to the left of current location
                    mtr.rotate(LinStepMtr::CW, home - cur_loc);
                }
                going_home = false;
                rail_state = STOP;
                rail_mode = NORMAL;
                send_ack();
                Thread::wait(500);
                break;
               
            default:
                break;
        }
            
        Thread::yield();
    }
}