The subsystem design/basis for the final project

Dependencies:   mbed-rtos mbed-src pixylib

robot.cpp

Committer:
balsamfir
Date:
2016-03-25
Revision:
8:b0478286ad21
Parent:
7:5ef312aa2678
Child:
9:62fbb69b612c

File content as of revision 8:b0478286ad21:

#include "robot.h"
#include "global.h"

// Global Definitions
// ----------------------------------------------------------------

// Function prototypes
// ----------------------------------------------------------------
void MotorISR(void);
void NavigationISR(void);
void CollisionISR(void);
void WatchdogISR(void const *n);
void MotorThread(void const *argument);
void NavigationThread(void const *argument);

// Interrupt and thread control
osThreadId motorId, navigationId, wdtId;
osThreadDef(MotorThread, osPriorityRealtime, DEFAULT_STACK_SIZE); 
osThreadDef(NavigationThread, osPriorityAboveNormal, DEFAULT_STACK_SIZE); 
osTimerDef(Wdtimer, WatchdogISR);
int32_t motorSignal, navigationSignal;
Ticker motorPeriodicInt;  
Ticker navigationPeriodicInt;   

// Mutex to protect left and right motor setpoints
osMutexId motorMutex;
osMutexDef(motorMutex);

// Set points and display variables
float leftMotor, rightMotor;
int x, height;
float speed, steering;
bool isInitialized;

// Functions
// ----------------------------------------------------------------
void AutoTrack() { 
    RunMotor();
    RunNavigation();
    
    while (1) {
        
        ResetWatchDog();

        pc.printf("X Coordinate: %d, Height: %d \r\n", x, height);
        pc.printf("Speed Set: %f, Steering Set: %f \r\n", speed, steering);
        pc.printf("Left Motor Set: %f, Right Motor Set: %f \n\r", leftMotor, rightMotor);
        
        Thread::wait(500); // Go to sleep for 500 ms
    }
}

void RunMotor(void) {
    // TODO: Optimize interrupt time for motor... Currently too fast
    InitializeRobot();
    motorPeriodicInt.attach(&MotorISR, MOTOR_PERIOD);
}

void RunNavigation(void) {
    InitializeRobot();
    navigationPeriodicInt.attach(&NavigationISR, NAVIGATION_PERIOD);
}

void ManualControl(void) {

}

// Setup the robot threads and data if needed
void InitializeRobot(void) {
    if (isInitialized) return;
    
    motorMutex = osMutexCreate(osMutex(motorMutex));
    
    bumper.rise(&CollisionISR); // Attach interrupt handler to rising edge of Bumper
    
    // Create MotorThread and NavigationThread:
    navigationId = osThreadCreate(osThread(NavigationThread), NULL);
    motorId = osThreadCreate(osThread(MotorThread), NULL);
 
    // Start the watch dog timer and enable the watch dog interrupt
    osTimerId oneShotId = osTimerCreate(osTimer(Wdtimer), osTimerOnce, (void *)0);
    led3 = 0; // Clear watch dog led3 status
    
    //SPI Initialization
    pc.printf("\n\rStarting SPI...");
    deSpi.format(16,1); // 16 bit mode 1
    ioReset = 0; ioReset = 1; 
    wait_us(10); ioReset = 0; spiReset = 0; spiReset = 1; 
    wait_us(10); spiReset = 0; 
    pc.printf("\n\rDevice Id: %d \r\n\r\n", deSpi.write(0x8004)); // Read count & time for both motors
    
    isInitialized = true;
}

// Timesout in 2 seconds
void ResetWatchDog(void) {
    osTimerStart(oneShotId, 2000);
}


// Threads
// ----------------------------------------------------------------
void NavigationThread(void const *argument) {
    int count;
    
    while (1) {
        osSignalWait(navigationSignal, osWaitForever); // Go to sleep until navigation signal is set high by ISR

        count = pixy.getBlocks(1);
        
        // If target returned
        if (count && (pixy.blocks[0].signature == TARGET_DECIMAL)) {
            height = pixy.blocks[0].height; //use this for now
            x = pixy.blocks[0].x;
            
            speed = heightPI.Run(HEIGHT_SETPOINT-height, SPEED_MAX);
            steering = xPI.Run(X_SETPOINT-x, SPEED_MAX);

            // Give setpoints to MotorThread
            osMutexWait(motorMutex, osWaitForever); 
            leftMotor = speed - steering;
            rightMotor = speed + steering;
            osMutexRelease(motorMutex); 
        }
    } 
}

void MotorThread(void const *argument) {
    float leftSet, rightSet, angVel;
    float timeOnLeft, timeOnRight;
    short dP, dt;

    while (1) {
        osSignalWait(motorSignal, osWaitForever); // Go to sleep until motor signal is set high by ISR
        led2= !led2; // Alive status - led2 toggles each time MotorControlThread is signaled.
        
        // Get setpoints from navigation
        osMutexWait(motorMutex, osWaitForever); 
        leftSet = leftMotor;
        rightSet = rightMotor;
        osMutexRelease(motorMutex); 
        
        // Run PI control on left motor
        dP = deSpi.write(0);
        dt = deSpi.write(0); 
        angVel = QE2RadsPerSec(dP, dt);
        timeOnLeft = leftMotorPI.Run(leftSet-angVel, PWM_PERIOD);
        
        // Run PI control on right motor
        dP = deSpi.write(0);
        dt = deSpi.write(0); 
        angVel = -QE2RadsPerSec(dP, dt); // motors have opposite orientations
        timeOnRight = rightMotorPI.Run(rightSet-angVel, PWM_PERIOD); //
        
        // Output new PWM and direction 
        if (timeOnLeft >= 0) leftDir = 1;   
        else leftDir = 0;
        
        if (timeOnRight >= 0) rightDir = 0;   
        else rightDir = 1;
        
        leftPwm.pulsewidth(fabs(timeOnLeft));
        rightPwm.pulsewidth(fabs(timeOnRight));
    } 
}


// Interrupt Service Routines
// ----------------------------------------------------------------

// TODO: Shutdown system
void WatchdogISR(void const *n) {
    led3=1; // Activated when the watchdog timer times out
}

void MotorISR(void) {
    osSignalSet(motorId,0x1); // Activate the signal, MotorControl, with each periodic timer interrupt
}

void NavigationISR(void) {
    osSignalSet(navigationId,0x1); // Activate the signal, SensorControl, with each periodic timer interrupt
}
    
// TODO: Shutdown system
void CollisionISR(void) {
    led4 = 1; // Activated on collision
}