The source code

#include <SoftwareServo.h>

SoftwareServo distanceServo; // create servo object to control a servo

SoftwareServo panServo; // create servo object to control a servo

int roomMap[60]; //array to save distances of the room

int roomFuzz[60]; //array to save the fuzzy-ness of each location in the room map

int roomTrys[60]; // number of tries it took to get a good measurement for this position

int n = 0;

int oldA = 0;

byte counter = 0;

int temp;

int menuPage = 0; //saves which page the user is on.

// 0 = Arm Turret

// 1 = SetScanRange

// 2 = Set Number of Shots

// 3 = Set Cool Down Period

//------OPTIONS ------//

int panMin = 60;

int panMax = 120;

int numOfShots = 1; //number of shots to shoot at the target

int coolDownTime = 10; //seconds to wait for target to fall on the floor after being shot

//------PINS ------//

//int potPin = 0; // select the input pin for the potentiometer

int distSensorPin = 0; //Ultrasonic distance sensor - analog pin 0

int encoderPinA = 6;

int encoderPinB = 7;

int encoderPushBtnPin = 5;

int reedSwitchPin = 4;

int redBtnPin = 3;

int speakerPin = 2;

int motionSensorPin = 8; //PIR motion sensor

int firingMotorPin = 9; //motor that shots the bullets

int triggerMotorPin = 10;

int panServoPin = 11;

int tiltServoPin = 12;

int distServoPin = 15;

void setup()

{

pinMode(speakerPin, OUTPUT);

pinMode(firingMotorPin, OUTPUT);

pinMode(triggerMotorPin, OUTPUT);

pinMode(redBtnPin, INPUT);

pinMode(encoderPinA, INPUT);

pinMode(encoderPinB, INPUT);

pinMode(encoderPushBtnPin, INPUT);

pinMode(reedSwitchPin, INPUT);

pinMode(motionSensorPin, INPUT);

digitalWrite(encoderPushBtnPin, HIGH); // turn on pullup resistor

digitalWrite(redBtnPin, HIGH); // turn on pullup resistor

digitalWrite(encoderPinA, HIGH); // turn on pullup resistor

digitalWrite(encoderPinB, HIGH); // turn on pullup resistor

digitalWrite(reedSwitchPin, HIGH); // turn on pullup resistor

digitalWrite(motionSensorPin, HIGH); // turn on pullup resistor

distanceServo.attach(distServoPin); // attaches the servo on pin 9 to the servo object

distanceServo.setMinimumPulse(700);

distanceServo.setMaximumPulse(2100);

panServo.setMaximumPulse(2000);

Serial.begin(9600);

Serial.println("ok, im ready");

delay(2000);

clearLCD();

printMenu(menuPage);

backlightOn();

delay(200);

backlightOff();

delay(200);

backlightOn();

delay(200);

backlightOff();

delay(200);

backlightOn();

playNote('d', 200);

playNote('c', 150);

}

void loop()

{

//main menu

switch (getButtonPress(false)) { //false means dont keep the servos active

case 0:

menuPage++;

menuPage = constrain(menuPage, 0, 5);

printMenu(menuPage);

break;

case 1:

menuPage--;

menuPage = constrain(menuPage, 0, 5);

printMenu(menuPage);

break;

case 2:

if(menuPage == 0){ //if arm turret

attackMode();

printMenu(menuPage);

}else if(menuPage == 1){ //if set scan limits

setScanRangeProcedure();

printMenu(menuPage);

}else if(menuPage == 2){ //if set number of shots

setNumShotsProcedure();

printMenu(menuPage);

}else if(menuPage == 3){ //if Set Cool Down Period

setCoolDownTimeProcedure();

printMenu(menuPage);

}else if(menuPage == 4){ //if test fire

panServo.attach(panServoPin); //so the pan servo doesnt jerk around

fire();

panServo.detach();

}else if(menuPage == 5){ //if booby trap mode

boobyTrapMode();

menuPage=0;

printMenu(menuPage);

}

break;

case 3:

break;

}

} //loop

int findTarget(){

clearLCD(); Serial.print("scanning for"); selectLineTwo(); Serial.print("target....");

unsigned long distance;

int threshold;

int counter;

int pos;

int val;

//distanceServo.write(0);

//delay(2000);

for(int i = 0; i < 2; i++){ //scan twice

pos = panMin;

counter = 0;

while(pos < panMax){

distanceServo.write(pos);

delay(10);

SoftwareServo::refresh();

counter++;

if(counter > 10){

counter = 0;

pos = pos + 3;

val = pos; //get pan angle

val = map(val, 0,180,0,50);

val = constrain(val, 0, 50); // limits range of sensor values to between 10 and 50

distance = getDistance(1); //get distance in inches

threshold = roomMap[val] - roomFuzz[val] - roomTrys[val]*10 - 5;

if(threshold < 0) { threshold = 0; } //bandage fix.

if( distance < threshold ) {

distance = getDistance(5); //get distance in inches

if( distance < threshold ) { //double check

//target found

Serial.println("Target found");

Serial.print(val);

Serial.print(",");

Serial.println(distance);

Serial.print("threshold = ");

Serial.println(threshold);

return (pos);

}

}

}//if

}//while

}//for

return 0;

}//findTarget()

void mapOutTheRoom(){

clearLCD();

Serial.print("Mapping out room...");

//clear everything

for(int i = 0; i < 60; i += 1){

roomMap[i] = 0;

roomFuzz[i] = 0;

roomTrys[i] = 0;

}

unsigned long distance;

int counter = 0;

int pos = panMin;

int val = 0;

int largestVal = 0;

int temp[3];

for (int i = 0; i < 20; i++){

distanceServo.write(pos);

SoftwareServo::refresh();

delay(20);

}

while(pos < panMax){

distanceServo.write(pos);

delay(10);

SoftwareServo::refresh();

counter++;

if(counter > 10){

counter = 0;

pos = pos + 3;

val = pos; //get pan angle

getDistanceWithErrorBars(4,temp);

//distance = getDistance(4); //get distance in inches

val = map(val, 0,180,0,50);

val = constrain(val, 0, 50); // limits range of sensor values to between 10 and 50

if (val > largestVal) { largestVal = val; }

roomMap[val] = temp[0];

roomFuzz[val] = temp[1];

roomTrys[val] = temp[2];

Serial.print(val);

Serial.print(",");

Serial.print(roomMap[val]);

Serial.print(",");

Serial.print(roomFuzz[val]);

Serial.print(",");

Serial.println(roomTrys[val]);

}//if

}//while

Serial.print("largestVal: ");

Serial.println(largestVal);

}//mapOutTheRoom

//returns the average distance taken over the specified number of measurements

int getDistance(byte measurements){

//if(measurements > 9) {return 0;}

int minDist = 5000;

int maxDist =0;

int avgDist = 0;

int temp = 0;

do{

minDist = 5000;

maxDist = 0;

for (int i = 0; i < measurements; i++){

do{

temp = (analogRead(distSensorPin) / 2) ; // read distance sensor

}while(temp < 12); //reject random low values

avgDist = avgDist + temp;

if (temp < minDist) { minDist = temp; }

if (temp > maxDist) { maxDist = temp; }

delay(50);

}//for

avgDist = avgDist / measurements; // average

if(maxDist - minDist > 30){

playNote('f',50);

}

}while(maxDist - minDist > 30);

//dist = dist / 2; // scale down to inches

return avgDist;

}//getDistance

//returns the average distance taken over the specified number of measurements, the error and number of trys it took to get a good measurement

void getDistanceWithErrorBars(int measurements, int result[]){

//if(measurements > 9) {return 0;}

int minDist = 5000;

int maxDist =0;

int avgDist = 0;

int temp = 0;

int numOfTrys = -1;

//do{

numOfTrys++;

minDist = 5000;

maxDist = 0;

for (int i = 0; i < measurements; i++){

do{

temp = (analogRead(distSensorPin) / 2) ; // read distance sensor

}while(temp < 12); //reject random 6's

avgDist = avgDist + temp;

if (temp < minDist) { minDist = temp; }

if (temp > maxDist) { maxDist = temp; }

delay(50);

}

avgDist = avgDist / measurements; // average

if(maxDist - minDist > 30){

playNote('f',50);

}

//}while(maxDist - minDist > 30);

//result[0] = avgDist;

result[0] = minDist;

result[1] = maxDist - minDist;

result[2] = numOfTrys;

//dist = dist / 2; // scale down to inches

}//getDistanceWithErrorBars

void playTone(int tone, int duration) {

for (long i = 0; i < duration * 1000L; i += tone * 2) {

digitalWrite(speakerPin, HIGH);

delayMicroseconds(tone);

digitalWrite(speakerPin, LOW);

delayMicroseconds(tone);

}

}

void playNote(char note, int duration) {

char names[] = { 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'C' };

int tones[] = { 1915, 1700, 1519, 1432, 1275, 1136, 1014, 956 };

// play the tone corresponding to the note name

for (int i = 0; i < 8; i++) {

if (names[i] == note) {

playTone(tones[i], duration);

}

}

}

void selectLineOne(){ //puts the cursor at line 0 char 0.

Serial.print(0xFE, BYTE); //command flag

Serial.print(128, BYTE); //position

}

void selectLineTwo(){ //puts the cursor at line 0 char 0.

Serial.print(0xFE, BYTE); //command flag

Serial.print(192, BYTE); //position

}

void goTo(int position) { //position = line 1: 0-15, line 2: 16-31, 31+ defaults back to 0

if (position<16){ Serial.print(0xFE, BYTE); //command flag

Serial.print((position+128), BYTE); //position

}else if (position<32){Serial.print(0xFE, BYTE); //command flag

Serial.print((position+48+128), BYTE); //position

} else { goTo(0); }

}

void clearLCD(){

Serial.print(0xFE, BYTE); //command flag

Serial.print(0x01, BYTE); //clear command.

}

void backlightOn(){ //turns on the backlight

Serial.print(0x7C, BYTE); //command flag for backlight stuff

Serial.print(157, BYTE); //light level.

//Serial.print(0x7C, BYTE); //command flag for backlight stuff

//Serial.print(0x0C, BYTE); //light level.

}

void backlightOff(){ //turns off the backlight

Serial.print(0x7C, BYTE); //command flag for backlight stuff

Serial.print(128, BYTE); //light level for off.

}

/* waits for a button press and returns which button was pressed:

0 - encoder up

1 - encoder down

2 - encoder push

3 - button push

*/

int getButtonPress(boolean keepServosActive ){

while( true ){

if(keepServosActive) {SoftwareServo::refresh(); } // keep the servo active

//check button

if (digitalRead(redBtnPin) == LOW) {

delay(50); //debounce button

while(digitalRead(redBtnPin) == LOW){ delay(1); } //wait for button to be released

return 3;

}

if (digitalRead(encoderPushBtnPin) == LOW) {

delay(50); //debounce button

while(digitalRead(encoderPushBtnPin) == LOW){ delay(1); } //wait for button to be released

return 2;

}

//check encoder

n = digitalRead(encoderPinA);

if ((oldA == LOW) & (n == HIGH)) {

oldA = n;

if (digitalRead(encoderPinB) == LOW) {

return 0;

} else {

return 1;

}

}

if ((oldA == HIGH ) & (n == LOW)) {

oldA = n;

if (digitalRead(encoderPinB) == LOW) {

return 1;

} else {

return 0;

}

}

oldA = n;

}//while

}//getButtonPress()

// 0 = Arm

// 1 = SetScanRange

// 2 = Set Number of Shots

// 3 = Set Cool Down Period

// 4 = test fire

// 5 = Booby Trap Mode

void printMenu(int page){

if(page == 0){

clearLCD();

Serial.print("Arm Turret");

}else if(page == 1){

clearLCD();

Serial.print("SetScanRange");

}else if(page == 2){

clearLCD();

Serial.print("Set Number of");

selectLineTwo();

Serial.print("Shots");

}else if(page == 3){

clearLCD();

Serial.print("Set Cool Down");

selectLineTwo();

Serial.print("Period");

}else if(page == 4){

clearLCD();

Serial.print("Test Fire");

}else if(page == 5){

clearLCD();

Serial.print("Booby Trap Mode");

}

}//printMenu

void setScanRangeProcedure(){

clearLCD(); Serial.print("Right Limit:"); selectLineTwo(); Serial.print(panMin); Serial.print(" ");

byte btnPressed;

panServo.attach(panServoPin);

distanceServo.write(panMin);

panServo.write(panMin);

do{

btnPressed = getButtonPress(true); //pass true to keep servos active

if(btnPressed == 1) { //if encoder up

panMin++; //future work: make sure the left limit doesnt pass the right limit

panMin = constrain(panMin, 0, 180);

selectLineTwo();

Serial.print(panMin); Serial.print(" ");

distanceServo.write(panMin);

panServo.write(panMin); //debug stuff

}

if(btnPressed == 0) { //if encoder down

panMin--;

selectLineTwo();

panMin = constrain(panMin, 0, 180);

Serial.print(panMin); Serial.print(" ");

distanceServo.write(panMin);

panServo.write(panMin); //debug stuff

}

SoftwareServo::refresh();

}while(btnPressed != 3 & btnPressed != 2); //while cancel and confirm buttons are not pushed

clearLCD();

Serial.print("Left Limit:");

selectLineTwo();

Serial.print(panMax); Serial.print(" ");

distanceServo.write(panMax);

do{

btnPressed = getButtonPress(true); //pass true to keep servos active

if(btnPressed == 1) { //if encoder up

panMax++;

panMax = constrain(panMax, 0, 180);

selectLineTwo();

Serial.print(panMax); Serial.print(" ");

distanceServo.write(panMax);

panServo.write(panMax); //debug stuff

}

if(btnPressed == 0) { //if encoder down

panMax--;

selectLineTwo();

panMax = constrain(panMax, 0, 180);

Serial.print(panMax); Serial.print(" ");

distanceServo.write(panMax);

panServo.write(panMax); //debug stuff

}

SoftwareServo::refresh();

}while(btnPressed != 3 & btnPressed != 2); //while cancel and confirm buttons are not pushed

panServo.detach();

menuPage = 0;

return;

}//setScanRangeProcedure()

void setNumShotsProcedure(){

//TODO: if cancel button is pressed restore old settings

byte btnPressed;

clearLCD();

Serial.print("Number of shots:");

selectLineTwo();

Serial.print(numOfShots); Serial.print(" ");

do{

btnPressed = getButtonPress(false); //false means dont keep the servos active

if(btnPressed == 0) { //if encoder up

numOfShots++; //future work: make sure the left limit doesnt pass the right limit

numOfShots = constrain(numOfShots, 1, 20);

selectLineTwo();

Serial.print(numOfShots); Serial.print(" ");

}

if(btnPressed == 1) { //if encoder down

numOfShots--;

selectLineTwo();

numOfShots = constrain(numOfShots, 1,20);

Serial.print(numOfShots); Serial.print(" ");

}

}while(btnPressed != 3 & btnPressed != 2); //while cancel and confirm buttons are not pushed

menuPage = 0;

return;

}//setNumShotsProcedure()

void setCoolDownTimeProcedure(){

//TODO: if cancel button is pressed restore old settings

byte btnPressed;

clearLCD();

Serial.print("Seconds To Wait:");

selectLineTwo();

Serial.print(coolDownTime); Serial.print(" ");

do{

btnPressed = getButtonPress(false); //false means dont keep the servos active

if(btnPressed == 0) { //if encoder up

coolDownTime++; //future work: make sure the left limit doesnt pass the right limit

coolDownTime = constrain(coolDownTime, 1, 60);

selectLineTwo();

Serial.print(coolDownTime); Serial.print(" ");

}

if(btnPressed == 1) { //if encoder down

coolDownTime--;

selectLineTwo();

coolDownTime = constrain(coolDownTime, 1,60);

Serial.print(coolDownTime); Serial.print(" ");

}

}while(btnPressed != 3 & btnPressed != 2); //while cancel and confirm buttons are not pushed

menuPage = 0;

return;

}//setNumShotsProcedure()

void fire(){

digitalWrite(firingMotorPin,HIGH);

delay(1000);

digitalWrite(triggerMotorPin,HIGH);

for(int i = 0; i < numOfShots; i++){

while(digitalRead(reedSwitchPin) == 0){ delay(2); } //wait for the trigger to move away

delay(200);

while(digitalRead(reedSwitchPin) == 1){ delay(2); } //wait for the trigger to come back

delay(20);

}

digitalWrite(triggerMotorPin,LOW);

digitalWrite(firingMotorPin,LOW);

}//fire()

void pullTrigger(){

//digitalWrite(firingMotorPin,HIGH);

delay(500);

digitalWrite(triggerMotorPin,HIGH);

for(int i = 0; i < numOfShots; i++){

while(digitalRead(reedSwitchPin) == 0){ delay(2); } //wait for the trigger to move away

delay(200);

while(digitalRead(reedSwitchPin) == 1){ delay(2); } //wait for the trigger to come back

delay(20);

}

digitalWrite(triggerMotorPin,LOW);

digitalWrite(firingMotorPin,LOW);

}//pullTrigger()

void slowPan(int location){

panServo.attach(panServoPin);

panServo.write(location); // sets the servo position according to the scaled value

for(int i = 0; i < 40; i++){

panServo.write(location);

delay(20); // waits for the servo to get there

SoftwareServo::refresh();

}

panServo.detach();

}//slowPan

int waitForMotion(){

// 1 = no motion

// 0 = motion

while( digitalRead(motionSensorPin) == 0){ //while motion

delay(200); //wait for sensor to report no motion

}

delay(500);

while( digitalRead(motionSensorPin) == 1 ){ //while no motion

delay(10); //wait for motion

if(digitalRead(redBtnPin) == 0){

return 0; //cancel button was pressed

}

}//while

return 1;

}//waitForMotion()

void attackMode(){

unsigned long timeA;

unsigned long timeB;

mapOutTheRoom();

while(true){

temp = waitForMotion();

if(temp == 0){

clearLCD(); Serial.print(" Turret is now"); selectLineTwo(); Serial.print(" **DISARMED**");

delay(1200);

return;

} //if cancel button was pressed while waiting for next target

temp = findTarget();

if(temp > 0){ //if target was found

digitalWrite(firingMotorPin,HIGH); //spin up motors

slowPan(temp);

pullTrigger();

timeA = millis();

timeB = timeA + coolDownTime*1000;

//cool down

while(timeB > timeA){

timeA = millis();

if(digitalRead(redBtnPin) == 0){

clearLCD(); Serial.print(" Turret is now"); selectLineTwo(); Serial.print(" **DISARMED**");

delay(1200);

return; //cancel button was pressed

}//if

}//while

}//if

clearLCD(); Serial.print("Waiting for"); selectLineTwo(); Serial.print("next target.");

}//while

}//atackMode()

void boobyTrapMode(){

clearLCD(); Serial.print("Waiting for"); selectLineTwo(); Serial.print("victim...");

unsigned long timeA;

unsigned long timeB;

while(true){

temp = waitForMotion();

if(temp == 0){ //if cancel button was pressed while waiting for next target

clearLCD(); Serial.print(" Turret is now"); selectLineTwo(); Serial.print(" **DISARMED**");

delay(1200);

return;

} //if

fire();

//cool down

timeA = millis();

timeB = timeA + coolDownTime*1000;

while(timeB > timeA){

timeA = millis();

if(digitalRead(redBtnPin) == 0){

clearLCD(); Serial.print(" Turret is now"); selectLineTwo(); Serial.print(" **DISARMED**");

delay(1200);

return; //cancel button was pressed

}//if

}//while

}//while

}//boobyTrapMode