New smaller slits code

Dependencies:   PID

Fork of ES_CW2_Starter by Edward Stott

main.cpp

Committer:
Iswanto
Date:
2017-03-18
Revision:
4:a436ddb6e57e
Parent:
3:60009a5ed1dc
Child:
5:07b2e414d174

File content as of revision 4:a436ddb6e57e:

#include "mbed.h"
#include "PID.h"



/////////////////////
// Pin definitions //
/////////////////////

//Photointerrupter input pins
#define I1pin D2
#define I2pin D11
#define I3pin D12

DigitalIn I1(I1pin);
DigitalIn I2(I2pin);
DigitalIn I3(I3pin);

InterruptIn I1intr(I1pin);
InterruptIn I2intr(I2pin);
InterruptIn I3intr(I3pin);

//Incremental encoder input pins
#define CHA   D7
#define CHB   D8  

DigitalIn CHAR(CHA);
DigitalIn CHBR(CHB);

InterruptIn CHAintr(CHA);
InterruptIn CHBintr(CHB);

//Status LED
DigitalOut led1 (LED1);
DigitalOut led2 (LED2);
DigitalOut led3 (LED3);

//Motor Drive output pins   //Mask in output byte
#define L1Lpin D4           //0x01
#define L1Hpin D5           //0x02
#define L2Lpin D3           //0x04
#define L2Hpin D6           //0x08
#define L3Lpin D9           //0x10
#define L3Hpin D10          //0x20

PwmOut L1L(L1Lpin);
PwmOut L1H(L1Hpin);
PwmOut L2L(L2Lpin);
PwmOut L2H(L2Hpin);
PwmOut L3L(L3Lpin);
PwmOut L3H(L3Hpin);

//Mapping from sequential drive states to motor phase outputs
/*
State   L1  L2  L3
0       H   -   L
1       -   H   L
2       L   H   -
3       L   -   H
4       -   L   H
5       H   L   -
6       -   -   -
7       -   -   -
*/

//Drive state to output table
const int8_t driveTable[] = {0x12,0x18,0x09,0x21,0x24,0x06,0x00,0x00};

//Mapping from interrupter inputs to sequential rotor states. 0x00 and 0x07 are not valid
const int8_t stateMap[] = {0x07,0x05,0x03,0x04,0x01,0x00,0x02,0x07};  
//const int8_t stateMap[] = {0x07,0x01,0x03,0x02,0x05,0x00,0x04,0x07}; //Alternative if phase order of input or drive is reversed

//Phase lead to make motor spin
const int8_t lead = 2;  //2 for forwards, -2 for backwards



//////////////////////
// Global variables //
//////////////////////

volatile float targetSpeed; // User defined instantaneous speed
volatile float revPerSec; // Instantaneous speed estimate
volatile float previousTime = 0; // Used to calculate revPerSec
volatile float previousSpeed = 0; // Previous value of revPerSec
volatile float dutyCycle; // PWM duty cycle between 0 and 1
volatile float timeMap[] = {0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 }; // Keep track of last state
Timer t; // To keep track of time
Serial pc(SERIAL_TX,SERIAL_RX); // Serial connection
PID controller(5.0, 0.0, 0.000001, 0.001); // Arguments are Kp, Ki, Kd and interval



///////////////
// Functions //
///////////////

// THREAD: Blink LED1 every 0.5 seconds
void blinkLED1(){ 
    while(1){
        led1 = 0;   
        wait(0.5);
        led1 = 1;
        wait(0.5);
    }
}

// THREAD: Print instantaneous speed
void printStatus() {
    while(1){
        led3 = !led3;
        //pc.printf("%f\n\r",revPerSec);
        wait(2);
    }
}

// THREAD: Control loop
void controlLoop(void){
    while(true){
        controller.setProcessValue(revPerSec);
        dutyCycle = controller.compute();
        wait(0.001);
    }
}

// Measure speed using slits
void measureSpeedSlits(){
    float currentTime = t.read();
    revPerSec = 0.4*previousSpeed + 0.6*((0.0021367521)/(currentTime-previousTime));
    previousTime = currentTime;
    previousSpeed = revPerSec;
}

// Measure speed using photointerrupters
void measureSpeedPhoto(){
    led3 = !led3;
    float speedTime;
    speedTime = t.read();
    revPerSec = 1.0/(speedTime - timeMap[I1 + 2*I2 + 4*I3]);
    timeMap[I1 + 2*I2 + 4*I3] = speedTime;
}          
    
// Set motor states
void motorOut(int8_t driveState, float dutyCycle){
    //Lookup the output byte from the drive state.
    int8_t driveOut = driveTable[driveState & 0x07];
      
    //Turn off first
    if (~driveOut & 0x01) L1L.write(0);         // = 0
    if (~driveOut & 0x02) L1H.write(dutyCycle); // = 1;
    if (~driveOut & 0x04) L2L.write(0);         // = 0;
    if (~driveOut & 0x08) L2H.write(dutyCycle); // = 1;
    if (~driveOut & 0x10) L3L.write(0);         // = 0;
    if (~driveOut & 0x20) L3H.write(dutyCycle); // = 1;
    
    //Then turn on
    if (driveOut & 0x01) L1L.write(dutyCycle);  // = 1;
    if (driveOut & 0x02) L1H.write(0);          // = 0;
    if (driveOut & 0x04) L2L.write(dutyCycle);  // = 1;
    if (driveOut & 0x08) L2H.write(0);          // = 0;
    if (driveOut & 0x10) L3L.write(dutyCycle);  // = 1;
    if (driveOut & 0x20) L3H.write(0);          // = 0;
}
    
//Convert photointerrupter inputs to a rotor state
inline int8_t readRotorState(){
    return stateMap[I1 + 2*I2 + 4*I3];
}

//Basic synchronisation routine    
int8_t motorHome() {
    //Put the motor in drive state 0 and wait for it to stabilise
    motorOut(0,1);
    wait(3.0);
    
    //Get the rotor state
    return readRotorState();
}

    

//////////
// Main //
//////////     

int main() {
    
    // Initialize threads
    Thread status;
    Thread controlLoopThread;
    status.start(printStatus);
    controlLoopThread.start(controlLoop);
    t.start();
    
    // Set control loop parameters
    controller.setInputLimits(0, 200);
    controller.setOutputLimits(0.0, 1.0);
    controller.setBias(0.0);
    controller.setMode(0);
    controller.setSetPoint(50.0);
    
    //Initialize the serial port
    Serial pc(SERIAL_TX, SERIAL_RX);
    pc.printf("Device on \n\r");
    
    int8_t orState = 0;    //Rotot offset at motor state 0
    int8_t intState = 0;
    int8_t intStateOld = 0;
    float PWM_period = 0.001f; 
    dutyCycle = 1;
    
    L1L.period(PWM_period);
    L1H.period(PWM_period);
    L2L.period(PWM_period);
    L2H.period(PWM_period);
    L3L.period(PWM_period);
    L3H.period(PWM_period);
    
    // Slits interrupts
    CHAintr.rise(&measureSpeedSlits);
    CHBintr.rise(&measureSpeedSlits);
    CHAintr.fall(&meeasureSpeedSlits);
    CHBintr.fall(&measureSpeedSlits);
    
    // USE FOR PHOTOINTERRUPTERS
    // Photointerrupters interrupts
    //I1intr.rise(&measureSpeedPhoto);
    //I2intr.rise(&measureSpeedPhoto);
    //I3intr.rise(&measureSpeedPhoto);
    //I1intr.fall(&measureSpeedPhoto);
    //I2intr.fall(&measureSpeedPhoto);
    //I3intr.fall(&measureSpeedPhoto);
    
    //Run the motor synchronisation
    orState = motorHome();
    
    //Poll the rotor state and set the motor outputs accordingly to spin the motor
    while (1) {
        
        // Read serial input
        if (pc.readable()){
            char buffer[128];
            pc.gets(buffer, 6);
            targetSpeed = atof(buffer); 
            pc.printf("Target speed: '%f'\n\r", targetSpeed); 
            controller.setSetPoint(targetSpeed);
            orState = motorHome();
        }
        
        intState = readRotorState();
        if (intState != intStateOld) {
            intStateOld = intState;
            motorOut((intState-orState+lead+6)%6, dutyCycle); //+6 to make sure the remainder is positive
        }
    }
}