Project Description

The white box has white waves inside and a boat, looking like the boat is in a lake or ocean. When the boat moves forward. When the boat inches forward, strange things happen. If you move the boat halfway down the slider, Nessie’s head pops up and she stares at you, blinking her eyes and waiting for you to make the next move. If you move all the way to the end, Nessie will dive underwater and reappear above your boat, ready to attack. If you move back, she returns to where she came from, happy that the intruders are gone. If you only move a little bit forward, Nessie will call for backup and try to intimidate you into leaving her alone. I guess you can say Nessie’s a bit cranky today but how would you feel if a stranger came into your bedroom and started causing a ruckus?

Progress Photos

Early idea sketches of what we wanted to do, back when the objective was to reverse a switch to its default state.

Attaching the heads onto the servos after the they’ve been screwed onto the servo mounts designed to keep them in place while in the box.

Testing Nessie after the servos and boat were glued to the box.  During this stage, we realized rotating her head enough to push the boat back would rip the Servo from the ground of the box so we adjusted the plan for her react to the boat location. Hidden state on the first image, attack state on the second image.

Super-gluing the rest of the waves to finish Nessie’s home.

Schematic

Nessie Schematic

Code

/*
 * 
 * 60-223 Project 1 Code 
 * by Rolando Garcia III (rolandog) and Lexi Yan (yany1)
 * 
 * Date: 9/14/18
 * 
 */
 #include<Servo.h>

#define SLIDER A0
#define BODYEYE 4
#define HEADEYE 5
#define BODYSERVO 10
#define HEADSERVO 11

Servo bodyServo;
Servo neckServo;

int previousDistanceFromWater;
int timeAnimationBegan = 0;
int animationDelay = 0;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);

  bodyServo.attach(BODYSERVO);
  neckServo.attach(HEADSERVO);
  pinMode(BODYEYE, OUTPUT);
  pinMode(HEADEYE, OUTPUT);
  pinMode(SLIDER, INPUT);

  bodyServo.write(0);
  neckServo.write(0);
  delay(500);

}

void loop() {

  //Record the current time
  int now = millis();

  //Check how close the boat is to the water
  int distanceFromWater = analogRead(SLIDER);

  //Check if the previous animation has completed
  if( (now - timeAnimationBegan) > animationDelay || (previousDistanceFromWater <  distanceFromWater) ){

    //Reset the timer if we are beginning a new animation
    timeAnimationBegan = now;
    
    //If the boat is closest to the water
    if(distanceFromWater < 100){

      //Delay
      animationDelay = 1000;
  
      //Move the body all the way around & blink eye on body
      bodyServo.write(180);
      digitalWrite(BODYEYE, HIGH);
      delay(500);
      
      //Move the head most of the way around & blink eye on head
      neckServo.write(90);
      digitalWrite(BODYEYE, LOW);
      digitalWrite(HEADEYE, HIGH);
      delay(500);

      //Blink the eye a couple of times
      animationDelay += 700;
      digitalWrite(HEADEYE, LOW);
      delay(500);
      digitalWrite(HEADEYE, HIGH);
      delay(200);
  
    } else if(distanceFromWater < 500) {

      //Delay
      animationDelay = 2100;
    
      //Move the body very small amount, make sure the head doesn't appear
      neckServo.write(0);
      delay(100);
      bodyServo.write(90);
      delay(500);

      //Blink the eye and hold there for a bit
      digitalWrite(BODYEYE,HIGH);
      delay(250);
      digitalWrite(BODYEYE,LOW);
      delay(250);
      digitalWrite(BODYEYE,HIGH);
      delay(250);
      digitalWrite(BODYEYE,LOW);
      delay(250);
      
    } else if(distanceFromWater < 750) {
      
      //Delay
        animationDelay = 3000;
      
      //Move the body small amount + blink eye on body
      bodyServo.write(90);
      digitalWrite(BODYEYE, HIGH);
      delay(500);

      //Move the body back
      bodyServo.write(0);
      delay(1000);

      //Move the head up + turn on eye on head + turn off eye on body
      neckServo.write(90);
      digitalWrite(BODYEYE, LOW);
      digitalWrite(HEADEYE, HIGH);
      delay(500);

      //Move the body back
      neckServo.write(0);
      delay(1000);
      digitalWrite(HEADEYE, LOW);

    //Reset head and body when boat returns back to start
    }  else {

      neckServo.write(0);
      digitalWrite(BODYEYE, LOW);
      digitalWrite(HEADEYE, LOW);
      delay(250);
  
      bodyServo.write(0);
      delay(250);
      animationDelay = 500;
    }

    //Record the last distance from the water read
    previousDistanceFromWater = distanceFromWater;
    
  }

}

 


Final Images

Overall photo for proportion and scale

 

Detail photo of the boat

 

Detail photo of Nessie Creeping

 

Action photos of Nessie Attacking

 

Discussion

This project was not difficult in a technical sense, but relatively difficult in terms of usability. Lexi wanted to keep the project once it was done, so it had to be designed to be a rugged as possible. We had to use external battery power for the Arduino and our servo motors, which required soldering a battery pack into our circuit. Two different voltage sources meant that we had to tie all of our grounding together. This was the source of our biggest headache. We believed that grounding to the servos’ power source was enough, but it caused strange behavior in our sliding potentiometer and servos. When we finally tied the Arduino’s ground in, the problem was solved, but not after about 45 minutes of annoyance.  We also discovered while testing that it wouldn’t be possible for Nessie to push the boat back to the origin as we originally planned without causing damage and had to adjust our expectations/goals as a result, The easy part of the assignment was constructing our enclosure, since both of us had laser-cutting experience. We also had access to some interesting scrap materials, which gave our project a unique visual flair.

Ultimately, we learned the virtue of patience. Neither of us had very consistent schedules, so our work sessions had to be very qualitative. As mentioned above, hardware debugging also caused some problems that could have been fixed with some more patience in making a schematic. In the future, we would have changed this project by making it have a bit more unpredictability, through the use of more user-responsive animations for Nessie, or more sophisticated animation triggers.