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
Revision 0:4a30986db2fb, committed 2014-12-19
- Comitter:
- impguard
- Date:
- Fri Dec 19 11:49:27 2014 +0000
- Commit message:
- Final version of the controller for the NERF turret.
Changed in this revision
diff -r 000000000000 -r 4a30986db2fb HTTPClient.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HTTPClient.lib Fri Dec 19 11:49:27 2014 +0000 @@ -0,0 +1,1 @@ +http://developer.mbed.org/users/nebgnahz/code/HTTPClient/#25e3d3516a03
diff -r 000000000000 -r 4a30986db2fb TSI.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TSI.lib Fri Dec 19 11:49:27 2014 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/TSI/#1a60ef257879
diff -r 000000000000 -r 4a30986db2fb camera.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/camera.h Fri Dec 19 11:49:27 2014 +0000 @@ -0,0 +1,111 @@ +/** +* +* Code to get data from the camera by connecting to a web server via WiFi (using Adafruit CC3000). +* +* author: Leo Kam +* +* +* The code to connect to the web via Adafruit is adapted from the code by Ben Zhang and Antonio Iannopollo, found at +* http://developer.mbed.org/users/nebgnahz/code/CC3000_demo/ +* The following libraries are used: +* - cc3000_hostdriver_mbedsocket +* (http://developer.mbed.org/users/Kojto/code/cc3000_hostdriver_mbedsocket/) +* - HTTPClient (http://developer.mbed.org/users/donatien/code/HTTPClient/) +* +**/ + + +#include "mbed.h" +#include "cc3000.h" +#include "HTTPClient.h" + +// KL25Z wifi connection +// we need to define connection pins for: +// - IRQ => (pin D3) +// - Enable => (pin D5) +// - SPI CS => (pin D10) +// - SPI MOSI => (pin D11) +// - SPI MISO => (pin D12) +// - SPI CLK => (pin D13) +// plus wifi network SSID, password, security level and smart-configuration flag. +mbed_cc3000::cc3000 wifi(D3, D5, D10, SPI(D11, D12, D13), + "EECS-PSK", "Thequickbrown", WPA2, false); + +// create an http instance +HTTPClient http; + +// str is used to hold the response data +char str[512]; +char * p; + +// setup the serial connection, and LEDs +Serial pc(USBTX, USBRX); +DigitalOut led_red(LED_RED); +DigitalOut led_green(LED_GREEN); + +void initializeWiFi() { + // by default, it's red + led_red = 0; + led_green = 1; + + //print message to indicate the program has started + pc.printf("CC3000 Sample Program\r\n"); + wifi.init(); + pc.printf("Wifi Initialized\r\n"); + + // check connection status + while(wifi.is_connected() == false) { + // try to connect + if (wifi.connect() == -1) { + pc.printf("Failed to connect." + "Please verify connection details and try again.\r\n"); + led_red = 0; + led_green = 1; + } else { + pc.printf("IP address: %s \r\n", wifi.getIPAddress()); + + //once connected, turn green LED on and red LED off, and exit loop + led_red = 1; + led_green = 0; + break; + } + } +} + + +/* Get the x, y-coordinates and depth from camera. Return true if successfuly retrieve data from server, else return false and do not change parameters. */ +bool getCameraData(double &x, double &y, double &z, int timeout=2000) { + // check connection status + while(wifi.is_connected() == false) { + // try to connect + if (wifi.connect() == -1) { + pc.printf("Failed to connect." + "Please verify connection details and try again.\r\n"); + led_red = 0; + led_green = 1; + } else { + pc.printf("IP address: %s \r\n", wifi.getIPAddress()); + + //once connected, turn green LED on and red LED off, and exit loop + led_red = 1; + led_green = 0; + break; + } + } + int ret = http.get("https://pew-pew-pew.herokuapp.com/position", str, 512); + if (!ret) { + p = strtok(str, " "); + x = atof(p); + p = strtok(NULL, " "); + y = atof(p); + p = strtok(NULL, " "); + z = atof(p); + pc.printf("Camera data: %f %f %f\r\n", x, y, z); + return true; + } else { + /*pc.printf("Error - ret = %d - HTTP return code = %d\r\n", + ret, + http.getHTTPResponseCode());*/ + return false; + } +}
diff -r 000000000000 -r 4a30986db2fb cc3000_hostdriver_mbedsocket.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cc3000_hostdriver_mbedsocket.lib Fri Dec 19 11:49:27 2014 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/Kojto/code/cc3000_hostdriver_mbedsocket/#ca8c234997c0
diff -r 000000000000 -r 4a30986db2fb main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Fri Dec 19 11:49:27 2014 +0000 @@ -0,0 +1,264 @@ +/** +* +* 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; +} \ No newline at end of file
diff -r 000000000000 -r 4a30986db2fb mbed.bld --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Fri Dec 19 11:49:27 2014 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/4fc01daae5a5 \ No newline at end of file