The controller for a NERF turret, allowing it to track and fire at a human face with visual input gotten by polling a web server. This is part of the final project of the EE149 course of UC Berkeley. The project name is "Pew Pew".

Dependencies:   HTTPClient TSI cc3000_hostdriver_mbedsocket mbed

main.cpp

Committer:
impguard
Date:
2014-12-19
Revision:
0:4a30986db2fb

File content as of revision 0:4a30986db2fb:

/**
*
*   Controller for the NERF turret, allowing for tracking of target (human face) via visual input.
*
*   authors: Leo Kam
**/

#include "mbed.h"
#include "camera.h"
#include "TSISensor.h"

//Relays for firing the NERF gun.
DigitalOut flywheel(PTE5);
DigitalOut trigger(PTE4);
//Relays for turning the turret.
DigitalOut step1(PTE2);
DigitalOut step2(PTE3);
//Relays for tilting the gun up and down.
DigitalOut h_bridge1(PTB8);
DigitalOut h_bridge2(PTB9);
DigitalOut h_bridge3(PTB10);
DigitalOut h_bridge4(PTB11);


double x, y, z;                          //The coordinates of the target, relative to the barrel of the gun.
double x_offset, y_offset, z_offset;     //The offsets to transform the camera data into a coordinate system relative to barrel of the gun.
TSISensor tsi;                           //The touch sensor of the mbed.
double eps = 40;                         //The error margin.
double interval = 200;                   //The time between each poll of the server, in ms.
bool safety = true;                      //Whether the safety of the NERF gun is on or off.

void initialize();
void calibrateCamera();
bool getCoordinates(double&, double&, double&);
bool onTarget(double);
void stepMotorStates(int state);
void turnLeft(double);
void turnRight(double);
void tiltUp(double);
void tiltDown(double);
void trackTarget();
void safetyOn();
void safetyOff();
bool fire();

int main() {
    initialize();
    double hysteresis = 0;
    while(1) {
        getCoordinates(x, y, z);
        if(!onTarget(eps + hysteresis)) {
            hysteresis = 0;
            pc.printf("Tracking target...\r\n");
            safetyOn();
            trackTarget();  
        } else {
            pc.printf("Target acquired!\r\n");
            if(safety) {
                safetyOff();
            }
            fire();
            wait(3);
            hysteresis = 0.5 * eps;
        }
    }

}

/* All the initialization are done here. */
void initialize() {
    x = 0;
    y = 0;
    z = 0;
    x_offset = 0;
    y_offset = 0;
    z_offset = 0;
    initializeWiFi();
    calibrateCamera();
    
    wait(3);
    led_red = 0;
    led_green = 1;
    pc.printf("Tap when ready.\r\n");
    while(1) {
        if (tsi.readPercentage() > 0.001) {break;}
    }
    pc.printf("It's hunting season.\r\n");
    led_red = 1;
    led_green = 0;
}

/* Calibrate the camera to calculate the offsets for transforming the camera coordinates into gun coordinates. */
void calibrateCamera() {
    //Put someone's face right in front of the gun barrel.
    
    double x0, y0, z0;
    x0 = 0;
    y0 = 0;
    z0 = 0;
    wait(3);
    pc.printf("Tap to start calibration of camera.\r\n");
    while(1) {
        //Wait for user to tap in order to start the calibration.
        led_red = 0;
        led_green = 1;
        if (tsi.readPercentage() > 0.001) {break;}
    }
    led_red = 1;
    led_green = 0;
    wait(3);
    pc.printf("Put face in front of gun barrel and tap when centered.\r\n");
    while(1) {
        //Continuously poll data from camera until mbed's slider is tapped.
        getCameraData(x0, y0, z0);
        led_red = 0;
        led_green = 1;
        if (tsi.readPercentage() > 0.001) {break;}
    }
    x_offset = -x0;
    y_offset = -y0;
    z_offset = -z0;
    pc.printf("Offests: %f %f %f\r\n", x_offset, y_offset, z_offset);
    //Green led on.
    led_red = 1;
    led_green = 0;
}

/* Get the coordinates of the target, relative to gun barrel. Return true if successfully retrieve data, else return false and do not change parameters. */
bool getCoordinates(double &x, double &y, double &z) {
    if (getCameraData(x, y, z)) {
        x += x_offset;
        y += y_offset;
        z += z_offset;
        pc.printf("Offsetted position: %f %f %f\r\n", x, y, z);
        return true;   
    } else {
        //Fail to connect to server. Maybe track to last known target location?
        return false;    
    }
}

/* Check if the gun is aiming at a square area centered on the target, with TOLERANCE as the side length. */
bool onTarget(double tolerance) {
    //Ignore depth for now.
    return abs(x) <= tolerance && abs(y) <= tolerance;
}

/* Helper function for using the stepper motor. */
void stepMotorStates(int state) {
    switch(state) {
        case 0:
            step1 = 0;
            step2 = 0;
            break;
        case 1:
            step1 = 1;
            step2 = 0;
            break;
        case 2:
            step1 = 1;
            step2 = 1;
            break;
        case 3:
            step1 = 0;
            step2 = 1;
            break;
        default:
            break;
    }
}

/* Turn the turret left for the given milliseconds. */
void turnLeft(double ms) {
    stepMotorStates(3);
    wait_ms(ms);
    stepMotorStates(2);
    wait_ms(ms);
    stepMotorStates(1);
    wait_ms(ms);
    stepMotorStates(0);
    wait_ms(ms);
}

/* Turn the turret left for the given milliseconds. */
void turnRight(double ms) {
    stepMotorStates(0);
    wait_ms(ms);
    stepMotorStates(1);
    wait_ms(ms);
    stepMotorStates(2);
    wait_ms(ms);
    stepMotorStates(3);
    wait_ms(ms);
}

/* Tilt the gun up for the given milliseconds. */
void tiltUp(double ms) {
    h_bridge1 = 1;
    h_bridge2 = 0;
    h_bridge3 = 0;
    h_bridge4 = 1;
    wait_ms(ms);
    h_bridge1 = 0;
    h_bridge2 = 0;
    h_bridge3 = 0;
    h_bridge4 = 0;
}

/* Tilt the gun down for the given milliseconds. */
void tiltDown(double ms) {
    h_bridge1 = 0;
    h_bridge2 = 1;
    h_bridge3 = 1;
    h_bridge4 = 0;
    wait_ms(ms);
    h_bridge1 = 0;
    h_bridge2 = 0;
    h_bridge3 = 0;
    h_bridge4 = 0;
}

/* Move the turret to aim at the target. */
void trackTarget() {
    if (x < -eps) {
        pc.printf("Turning left.\r\n");
        turnLeft(200);
    } else if(x >= eps) {
        pc.printf("Turning right.\r\n");
        turnRight(200);    
    } else
    if(y < -eps) {
        pc.printf("Tilting down.\r\n");
        tiltDown(500);        
    } else if(y >= eps) {
        pc.printf("Tilting up.\r\n");
        tiltUp(1000);
    }
    
    
}

/* Turn the safety of the NERF gun off (firewheel on). */
void safetyOff() {
    flywheel = 1;
    safety = false;
    wait(0.3);
}

/* Turn the safety on (firewheel off). */
void safetyOn() {
    flywheel = 0;
    safety = true;
}

/* Fire the gun. Return true if successfully pull trigger, else false. */
bool fire() {
    if (!safety) {
        trigger = 1;
        wait(0.4);
        trigger = 0;
        return true;
    }
    return false;
}