The code for this project took me a while to write and is kind of all over the place. I originally intended to use a different code for the tracking and standby modes, but issues with libraries and timer pins forced me to write a whole new section for each of those.

I also originally intended to have a sixth mode in which the creeper plays the Calm theme from Minecraft, but preliminary testing excluded that idea as the theme sounded terrible and conflicted with the Servo library.

Anyway, have a read through to get an idea as to what I am doing with it, then upload the code to your Arduino.

/* -------------------------------------------------------------------------------------------- This is a code for an Arduino sentry with ultrasound. The original design is intended to be a Creeper from Minecraft. There are several "modes" that can be selected through the use of pushbuttons and a potentiometer. The first pushbutton cycles through the modes, and the potentiometer adjusts the "active range". -------------------------------------- The modes are as follows: 1 - Standby Mode - 7-color "breathing" (basically a night light) 2 - Creeper Sentry - Will blink and hiss when someone gets within the active range 3 - Standard Sentry - Will beep when someone gets within the active range 4 - Object Tracking - Will track the first object it "sees" while within range -------------------------------------- Code written by Dangerously Explosive Not for commercial use. ----------------------------------------------------------------------------------------------- */ #include //initialize the libraries //servo vars Servo sentryServo; //init the servo int servoPosition = 0; // the servo position const int numReadings = 3; // the number of readings to take, make this bigger for a slower, more accurate scan int index = 0; // the index of the current reading int total; // the total value of the sum of all readings taken at one position. int angle = 1; //the number of degrees shifted during each scan while tracking an object //ultrasonic vars int echoPin = 5; // the HCSR04's echo pin int trigPin = 4; // the HCSR04's trig pin unsigned long pulseTime = 0; // variable for timing the pulse unsigned long distance = 0; // variable for distance int average; // for the avg. distance int minRange = 50; // the max distance in centimeters something must be to set off the alarm //light vars int RED = 6; // RED pin of the LEDs int GREEN = 11; // GREEN pin of the LEDs int BLUE = 3; // BLUE pin of the LEDs // it doesn't really matter what pin you assign, you can always change it later. // debouncing vars const int buttonPin = A1; // the pushbutton pin const int potPin = A0; // the potentiometer pin int buttonState; // the current reading from the input pin int buttonState1; int lastButtonState = LOW; int lastButtonState1 = LOW;// the previous reading from the input pin int mode = 0; // the sentry mode int colorMode = 0; // the LED mode in standby long lastDebounceTime = 0; // the last time the output pin was toggled long lastDebounceTime1 = 0; long debounceDelay = 50; // the debounce time; increase if the output flickers // Other vars int buzzerPin = A5; //debounce function void debounce(){ // read the state of the switch into a local variable: int reading = digitalRead(buttonPin); if (reading != lastButtonState) { // reset the debouncing timer lastDebounceTime = millis(); } if ((millis() - lastDebounceTime) > debounceDelay) { // if the button state has changed: if (reading != buttonState) { buttonState = reading; // only toggle the mode if the new button state is LOW if (buttonState == LOW) { mode ++; tone(buzzerPin, 500, 50); //beep so I know something happened if (mode >= 5){ mode = 0; } } } } // save the reading. Next time through the loop, // it'll be the lastButtonState: lastButtonState = reading; } void getRange(){ // find the range at which the alarm should go off int rawRange = analogRead(potPin); // get the potentiometer readings minRange = map(rawRange, 0, 1023, 0, 150); // mapped to a value between 0 and 1.5 meters } void getAlert1 (){ getRange(); if (average <= minRange){ beep(); Alert(); }; } void getAlert(){ getRange(); if (average <= minRange){ blinky(); //blink red hiss(); // hiss // good explosion sounds are really hard to make, so I just have it hiss }; } void blinky(){ digitalWrite(GREEN, LOW); analogWrite(BLUE, 0); int duration = 100; for(int l = 0; l <= 10; l++){ analogWrite(RED, 255); delay(duration); analogWrite(RED, 0); delay(duration); duration = duration - 10; } } int var1; int var2; void hiss(){ for (int j = 0; j <= 100; j++){ var1 = random(300, 700); var2 = random(300, 700); tone(buzzerPin, var1); delay(2); tone(buzzerPin, var2); delay(2); } noTone(buzzerPin); digitalWrite(GREEN, HIGH); } int duration = 500; int i = 0; void beep(){ digitalWrite(GREEN, LOW); analogWrite(BLUE, 0); int frequency = 500; duration = 200; for(int i = 0; i <= 20; i++){ analogWrite(RED, 255); digitalWrite(GREEN, LOW); tone(buzzerPin, frequency); delay(duration); analogWrite(RED, 0); digitalWrite(GREEN,HIGH); delay(duration); noTone(buzzerPin); frequency = frequency + 10; duration = duration - 10; } tone(buzzerPin, frequency); delay(500); noTone(buzzerPin); } int q = 200; void Alert(){ digitalWrite(GREEN, LOW); tone(buzzerPin, 500); analogWrite(RED, 255); delay(q); analogWrite(RED, 0); delay(q); tone(buzzerPin, 300); analogWrite(RED, 255); delay(q); analogWrite(RED, 0); delay(q); tone(buzzerPin, 200); analogWrite(RED, 255); delay(q); analogWrite(RED, 0); delay(q); tone(buzzerPin, 100); analogWrite(RED, 255); delay(q); analogWrite(RED, 0); noTone(buzzerPin); delay(q); tone(buzzerPin, 100); analogWrite(RED, 255); delay(q); analogWrite(RED, 0); noTone(buzzerPin); delay(q); tone(buzzerPin, 100); analogWrite(RED, 255); delay(q); analogWrite(RED, 0); noTone(buzzerPin); digitalWrite(GREEN, HIGH); } int numReadings1 = 1; void getAverage(){ for (index = 0; index<=numReadings1; index++) { digitalWrite(trigPin, LOW); delayMicroseconds(50); digitalWrite(trigPin, HIGH); // send signal delayMicroseconds(50); // wait 50 microseconds for it to return digitalWrite(trigPin, LOW); // close signal pulseTime = pulseIn(echoPin, HIGH); // calculate time for signal to return distance = pulseTime/58; total = distance + total; delay(10); } average = total/numReadings; total = 0; } /* The tracking code is very simple. First, it determines if an object is in range. If it is, then it turns until it doesn't see the object, i.e. it is looking just past it on one side. Then, turn left until it sees the object again, and repeat. In this way, we can keep track of the object. This is basically using the old "The missile knows where it is" logic. If we know where the object is not, we can reasonably determine where it is. The way I have it set up is rather jittery, and I'm really just tracking the edge of an object than the object itself. If you are planning on tracking larger objects, you can increase the value of the variable "angle" so the servo will turn in larger increments, resulting in a faster, less detailed scan where small objects are more likely to be missed. I should mention this is a very primitive, finicky and easy-to-fool system, so I don't reccomend using it as a security measure or a targeting system. It is also not necessarily accurate. */ void track(){ sentryServo.write(servoPosition); // first get the servo going getAverage(); // then find the distance to target getRange(); // find the range within which we will track an object if (average <= minRange){ //if the object is in range, turn left servoPosition = servoPosition + angle; } if (average >= minRange){ //otherwise turn right servoPosition = servoPosition - angle; } if (servoPosition <= 10 || servoPosition >= 170){ // you can change these values so that your sentry makes a smaller sweep. angle = -angle; // if we hit the edge of our sweep, go the other way } } void setup() { sentryServo.attach(9); //servo is on pin 9 sentryServo.write(90); pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); pinMode(buttonPin, INPUT_PULLUP); // active low pinMode(RED, OUTPUT); pinMode(BLUE, OUTPUT); pinMode(GREEN, OUTPUT); analogWrite(GREEN, 255); // color sequence to notify of reset and to test LEDs delay(1000); analogWrite(GREEN, 0); delay(500); analogWrite(RED, 255); delay(1000); analogWrite(RED, 0); delay(500); analogWrite(BLUE, 255); delay(1000); analogWrite(BLUE, 0); delay(500); pinMode(buzzerPin, OUTPUT); } int fade = 5; int state = 0; int count = 0; int h = 50; void loop() { debounce(); while (mode == 0){ if (state == 0){ analogWrite(RED, colorMode); analogWrite(GREEN, 0); analogWrite(BLUE, 0); debounce(); colorMode = colorMode + fade; delay(h); if (colorMode >= 255 || colorMode <= 0){ fade = -fade; count ++; } if (count == 2){ count = 0; state ++; } } if (state == 1){ analogWrite(RED, 0); analogWrite(GREEN, colorMode); analogWrite(BLUE, 0); debounce(); colorMode = colorMode + fade; delay(h); if (colorMode >= 255 || colorMode <= 0){ fade = -fade; count ++; } if (count == 2){ count = 0; state ++; } } if (state == 2){ analogWrite(RED, 0); analogWrite(GREEN, 0); analogWrite(BLUE, colorMode); debounce(); colorMode = colorMode + fade; delay(h); if (colorMode >= 255 || colorMode <= 0){ fade = -fade; count ++; } if (count == 2){ count = 0; state ++; } } if (state == 3){ analogWrite(RED, colorMode); analogWrite(GREEN, colorMode); analogWrite(BLUE, 0); debounce(); colorMode = colorMode + fade; delay(h); if (colorMode >= 255 || colorMode <= 0){ fade = -fade; count ++; } if (count == 2){ count = 0; state ++; } } if (state == 4){ analogWrite(RED, colorMode); analogWrite(GREEN, 0); analogWrite(BLUE, colorMode); debounce(); colorMode = colorMode + fade; delay(h); if (colorMode >= 255 || colorMode <= 0){ fade = -fade; count ++; } if (count == 2){ count = 0; state ++; } } if (state == 5){ analogWrite(RED, 0); analogWrite(GREEN, colorMode); analogWrite(BLUE, colorMode); colorMode = colorMode + fade; delay(h); debounce(); if (colorMode >= 255 || colorMode <= 0){ fade = -fade; count ++; } if (count == 2){ count = 0; state ++; } } if (state == 6){ analogWrite(RED, colorMode); analogWrite(GREEN, colorMode); analogWrite(BLUE, colorMode); colorMode = colorMode + fade; delay(h); debounce(); if (colorMode >= 255 || colorMode <= 0){ fade = -fade; count ++; } if (count == 2){ count = 0; state ++; } } if (state == 7){ debounce(); state = 0; } debounce(); }; while (mode == 1){ debounce(); analogWrite(GREEN, 255); analogWrite(BLUE, 0); analogWrite(RED, 0); for(servoPosition = 0; servoPosition < 180; servoPosition++) { debounce(); sentryServo.write(servoPosition); for (index = 0; index<=numReadings; index++) { // take readings from the sensor and average them digitalWrite(trigPin, LOW); delayMicroseconds(50); digitalWrite(trigPin, HIGH); // send signal delayMicroseconds(50); // wait 50 microseconds for it to return digitalWrite(trigPin, LOW); // close signal pulseTime = pulseIn(echoPin, HIGH); // calculate time for signal to return distance = pulseTime/58; // convert to centimetres total = distance + total; delay(10); } average = total/numReadings; // get our average getAlert(); // explode if too close total = 0; // reset our totals } debounce(); // reverse direction when we get to either side for(servoPosition = 180; servoPosition > 0; servoPosition--) { // going right to left debounce(); sentryServo.write(servoPosition); for (index = 0; index<=numReadings;index++) { digitalWrite(trigPin, LOW); delayMicroseconds(50); digitalWrite(trigPin, HIGH); delayMicroseconds(50); digitalWrite(trigPin, LOW); pulseTime = pulseIn(echoPin, HIGH); distance = pulseTime/58; total = distance + total; delay(10); } average = total/numReadings; getAlert(); total = 0; } }; while (mode == 2){ // still acting as a sentry, but with different sounds debounce(); for(servoPosition = 0; servoPosition < 180; servoPosition++) { debounce(); sentryServo.write(servoPosition); for (index = 0; index<=numReadings;index++) { // take readings from the sensor and average them digitalWrite(trigPin, LOW); delayMicroseconds(50); digitalWrite(trigPin, HIGH); // send signal delayMicroseconds(50); // wait 50 microseconds for it to return digitalWrite(trigPin, LOW); // close signal pulseTime = pulseIn(echoPin, HIGH); // calculate time for signal to return distance = pulseTime/58; // convert to centimetres total = distance + total; delay(10); } average = total/numReadings; // get our average getAlert1(); // explode if too close total = 0; // reset our totals } // reverse direction when we get to either side debounce(); for(servoPosition = 180; servoPosition > 0; servoPosition--) { // going right to left debounce(); sentryServo.write(servoPosition); for (index = 0; index<=numReadings;index++) { digitalWrite(trigPin, LOW); delayMicroseconds(50); digitalWrite(trigPin, HIGH); delayMicroseconds(50); digitalWrite(trigPin, LOW); pulseTime = pulseIn(echoPin, HIGH); distance = pulseTime/58; total = distance + total; delay(10); } average = total/numReadings; getAlert1(); total = 0; } }; // re-center the servo for the track function servoPosition = 90; while (mode == 3){ debounce(); analogWrite(BLUE, 255); analogWrite(GREEN, 0); track(); }; while(mode == 4){ sentryServo.write(90); debounce(); }; analogWrite(BLUE, 0); // turn off the blue light for the next time thru. delay(10); // let the processor rest a little }