Introduction: Robot Snake
Purpose
This project was built for the Things that Think undergraduate/graduate class CSCI 4830-7 and CSCI 7000-7 for the University of Colorado at Boulder. Our group consisted of one graduate and two undergraduate students. We worked on the project for 8 weeks, most of the time trying to learn how to program the arduino and learning the basics of circuits. If you are looking to build this project, we do not anticipate this project taking nearly as long, but altogether could be completed in one weekend.
Description
The purpose of this instructable is to outline our development of this robot snake as well as provide instructions and tips for future engineers hoping to complete a similar project or use components of our project in theirs. The goal of this project was to create an automaton snake that reacted to its environment. The main functionality of the snake is for it to follow a light source. Some goals we had in conjunction to the movement of the snake was to have a tail that rattles and decorative LED lighting. This tutorial will start with a little background information, then show the development of the basic pieces, and finish by finalizing your design.
Video of the final product
Tools Needed
Soldering iron, laser-cutter, scissors, sewing needle, small screwdriver, wire cutter/stripper, strong flashlight
Materials Needed
Arduino Uno, Arduino Motor Shield, Breadboard, Wire, Tape, Solder, LEDs, 3 photocell sensors, 2 DC Hobby motors, vibrator motor, Bass Wood, resistors of various resistance, 9V batteries, Toy wheels, string, paperclip, Gorilla glue
This project was built for the Things that Think undergraduate/graduate class CSCI 4830-7 and CSCI 7000-7 for the University of Colorado at Boulder. Our group consisted of one graduate and two undergraduate students. We worked on the project for 8 weeks, most of the time trying to learn how to program the arduino and learning the basics of circuits. If you are looking to build this project, we do not anticipate this project taking nearly as long, but altogether could be completed in one weekend.
Description
The purpose of this instructable is to outline our development of this robot snake as well as provide instructions and tips for future engineers hoping to complete a similar project or use components of our project in theirs. The goal of this project was to create an automaton snake that reacted to its environment. The main functionality of the snake is for it to follow a light source. Some goals we had in conjunction to the movement of the snake was to have a tail that rattles and decorative LED lighting. This tutorial will start with a little background information, then show the development of the basic pieces, and finish by finalizing your design.
Video of the final product
Tools Needed
Soldering iron, laser-cutter, scissors, sewing needle, small screwdriver, wire cutter/stripper, strong flashlight
Materials Needed
Arduino Uno, Arduino Motor Shield, Breadboard, Wire, Tape, Solder, LEDs, 3 photocell sensors, 2 DC Hobby motors, vibrator motor, Bass Wood, resistors of various resistance, 9V batteries, Toy wheels, string, paperclip, Gorilla glue
Step 1: Motor Shield and Motors
Quick motor tutorial
We will go through the motor step quickly, so if it will help, here is the tutorial this step will be based off of: Motor Shield Tutorial. We will be using the same motor shield and a lot of the same code in our project, so it may be helpful to have a short introduction to what we will be doing in this step.
Setting up the motors
To get started, we used low-voltage motors with tape on the end of each axle to test whether our code was working or not. In the beginning, it is more important to get a prototype working, which can be expanded upon to get a final product. The motors we used in this step were not the final motors we used, but they worked the same and allowed us to work on the project until we could find motors that were better suited for our needs.
Attach wire into the Channel A and Channel B slots on the motor shield and attach the ends of the motors. You do not have to solder these yet, it will be easier if they are just twisted around the positive and negative tabs for easy removal in future steps.
Code
/*
void setup(void) {
Serial.begin(9600);
pinMode(12, OUTPUT); //Initiates Motor Channel A pin
pinMode(9, OUTPUT); //Initiates Brake Channel A pin
pinMode(13, OUTPUT); //Initiates Motor Channel B pin
pinMode(8, OUTPUT); //Initiates Brake Channel B pin
digitalWrite(13, LOW); //Establishes forward direction of Channel A
digitalWrite(8, LOW); //Disengage the Brake for Channel A
digitalWrite(12, LOW); //Establishes forward direction of Channel B
digitalWrite(9, LOW); //Disengage the Brake for Channel B
}
void loop(void) {
analogWrite(3, 125); //Set speed for Channel A
analogWrite(11, 125); //Set speed for Channel B
}
*/
Video of the motors working
Signals
Remember when using the motor shield in future steps that the motors take Analog 0 and Analog 1 for sending feedback back to the motor shield, so we can no longer use them. The direction of the motors also depends on how each of the Channel wires are connected to the motor. If a motor is spinning in the wrong direction, you can either change the direction in the code by changing the Digital Output 13 or 12 for Channels A and B, respectively. Or you can switch how the Channel wires are attached to the motor tabs, reversing the current direction and the direction of the motors.
We will go through the motor step quickly, so if it will help, here is the tutorial this step will be based off of: Motor Shield Tutorial. We will be using the same motor shield and a lot of the same code in our project, so it may be helpful to have a short introduction to what we will be doing in this step.
Setting up the motors
To get started, we used low-voltage motors with tape on the end of each axle to test whether our code was working or not. In the beginning, it is more important to get a prototype working, which can be expanded upon to get a final product. The motors we used in this step were not the final motors we used, but they worked the same and allowed us to work on the project until we could find motors that were better suited for our needs.
Attach wire into the Channel A and Channel B slots on the motor shield and attach the ends of the motors. You do not have to solder these yet, it will be easier if they are just twisted around the positive and negative tabs for easy removal in future steps.
Code
/*
void setup(void) {
Serial.begin(9600);
pinMode(12, OUTPUT); //Initiates Motor Channel A pin
pinMode(9, OUTPUT); //Initiates Brake Channel A pin
pinMode(13, OUTPUT); //Initiates Motor Channel B pin
pinMode(8, OUTPUT); //Initiates Brake Channel B pin
digitalWrite(13, LOW); //Establishes forward direction of Channel A
digitalWrite(8, LOW); //Disengage the Brake for Channel A
digitalWrite(12, LOW); //Establishes forward direction of Channel B
digitalWrite(9, LOW); //Disengage the Brake for Channel B
}
void loop(void) {
analogWrite(3, 125); //Set speed for Channel A
analogWrite(11, 125); //Set speed for Channel B
}
*/
Video of the motors working
Signals
Remember when using the motor shield in future steps that the motors take Analog 0 and Analog 1 for sending feedback back to the motor shield, so we can no longer use them. The direction of the motors also depends on how each of the Channel wires are connected to the motor. If a motor is spinning in the wrong direction, you can either change the direction in the code by changing the Digital Output 13 or 12 for Channels A and B, respectively. Or you can switch how the Channel wires are attached to the motor tabs, reversing the current direction and the direction of the motors.
Step 2: Photocell Sensors
Quick photocell tutorial
We will be going through this photocell step rather quickly, so if you need more information or details, look here: Photocell Tutorial, it is an instructable for setting up a simple photocell sensor. We will be using the same setup and similar code in our project.
Why we need sensors
In this step we will be setting up three photocell sensors, all of these will be needed to complete the snake. Two of these sensors will become directional sensors, controlling the motors. The more light either the right or left sensor will have will control how much power each of the motors will receive, controlling the speed and direction of the snake’s movement. The last sensor will become the ambient light sensor, detecting how much light is in the room. This is necessary for each of the directional sensors so they can tell how much more light is being directed at them; and it is necessary for the leds, if the room is dark, the leds will light up.
Setting up the circuit
We used a similar setup as the instructable example for our photocell sensors. When getting one sensor, it is exactly the same. Just make sure the analog pins are placed in pins 2-5, as the motors will be using 0 and 1 (even though they are not plugged into them). We have used analog pins 3, 4, and 5. Where 3 and 4 are the directional sensors and 5 is the ambient sensor.
When setting up multiple sensors, just use the same circuit example as the first one. Each sensor must have its own line to power and ground and cannot be a part of the same circuit; this will make finishing the snake easier in future steps. Also, make sure your resistors are the same, since this affects the analog readings, we need all the sensors to be reading similar values.
Code
/*
int photocellReading3; // the analog reading from the analog resistor divider
int photocellReading4; // the analog reading from the analog resistor divider
int photocellReading5; // the analog reading from the analog resistor divider
void setup(void) {
Serial.begin(9600);
}
void loop(void) {
photocellReading3 = analogRead(3); // base light reading
Serial.print("Analog reading 3 = ");
Serial.println(photocellReading3); // the raw analog reading
photocellReading4 = analogRead(4); // will go to motor 1
Serial.print("Analog reading 4 = ");
Serial.println(photocellReading4); // the raw analog reading
photocellReading5 = analogRead(5); // will go to motor 2
Serial.print("Analog reading 5 = ");
Serial.println(photocellReading5); // the raw analog reading
Serial.println("");
delay(1000);
}
*/
Again, the code is similar to the photocell instructable. We create photocellReading variables to store the analog readings from the pins and then start the main loop. We will set the variable to the analog reading and print it out to see if it is working. We pause for 1 second, or else the reading will print out so fast we will be unable to read them.
Play around with sensors. Shine a flashlight into them to make the readings spike, cover them to make the readings drop. Your readings may have different values than ours, this is okay. Each sensor is different and it depends on the ambient light in the room at the time.
In the next step we will use these values to control the motors.
We will be going through this photocell step rather quickly, so if you need more information or details, look here: Photocell Tutorial, it is an instructable for setting up a simple photocell sensor. We will be using the same setup and similar code in our project.
Why we need sensors
In this step we will be setting up three photocell sensors, all of these will be needed to complete the snake. Two of these sensors will become directional sensors, controlling the motors. The more light either the right or left sensor will have will control how much power each of the motors will receive, controlling the speed and direction of the snake’s movement. The last sensor will become the ambient light sensor, detecting how much light is in the room. This is necessary for each of the directional sensors so they can tell how much more light is being directed at them; and it is necessary for the leds, if the room is dark, the leds will light up.
Setting up the circuit
We used a similar setup as the instructable example for our photocell sensors. When getting one sensor, it is exactly the same. Just make sure the analog pins are placed in pins 2-5, as the motors will be using 0 and 1 (even though they are not plugged into them). We have used analog pins 3, 4, and 5. Where 3 and 4 are the directional sensors and 5 is the ambient sensor.
When setting up multiple sensors, just use the same circuit example as the first one. Each sensor must have its own line to power and ground and cannot be a part of the same circuit; this will make finishing the snake easier in future steps. Also, make sure your resistors are the same, since this affects the analog readings, we need all the sensors to be reading similar values.
Code
/*
int photocellReading3; // the analog reading from the analog resistor divider
int photocellReading4; // the analog reading from the analog resistor divider
int photocellReading5; // the analog reading from the analog resistor divider
void setup(void) {
Serial.begin(9600);
}
void loop(void) {
photocellReading3 = analogRead(3); // base light reading
Serial.print("Analog reading 3 = ");
Serial.println(photocellReading3); // the raw analog reading
photocellReading4 = analogRead(4); // will go to motor 1
Serial.print("Analog reading 4 = ");
Serial.println(photocellReading4); // the raw analog reading
photocellReading5 = analogRead(5); // will go to motor 2
Serial.print("Analog reading 5 = ");
Serial.println(photocellReading5); // the raw analog reading
Serial.println("");
delay(1000);
}
*/
Again, the code is similar to the photocell instructable. We create photocellReading variables to store the analog readings from the pins and then start the main loop. We will set the variable to the analog reading and print it out to see if it is working. We pause for 1 second, or else the reading will print out so fast we will be unable to read them.
Play around with sensors. Shine a flashlight into them to make the readings spike, cover them to make the readings drop. Your readings may have different values than ours, this is okay. Each sensor is different and it depends on the ambient light in the room at the time.
In the next step we will use these values to control the motors.
Step 3: Combine Motors and Photocell Sensors
Description
In this step we will be taking the three photocell sensors and using them to drive the motor speeds. In our code we will be refering the motors to Motor A or Motor B, based on where they are plugged into the motor shield, and the sensors will be Sensor 3, Sensor 4, and Sensor 5, based on where they are attached to the analog readings. Sensor 3 and Sensor 4 will be the directional sensors and Sensor 5 will be the ambient light sensor.
Algorithm
To control the motors, we will be getting the base reading from all three sensors first (these are stored in photocellReading#).
We then take the differences between Sensor 3 and Sensor 5 (and store it in photocellDifference1) as well as the difference between Sensor 4 and Sensor 5 (and store it in photocellDifference2). This will tell us how much brighter the directional sensors are from the ambient sensor. Since the light will be shinning on these sensors, the difference readings should tell us how much light is being directed at each sensor.
We then subtract photocellDifference1 and photocellDifference2 from each other and store it in lrValue. By taking this difference, we are able to tell how much more light each directional sensor is sensing. If this number is negative than it means Sensor 4 has less light than Sensor 3 and more speed should be directed at Motor B. If the lrValue is positive than it means that Sensor 3 has more light than Sensor 4 and more speed should be directed to Motor A.
Code
/*
int photocellReading3; // the analog reading from the analog resistor divider
int photocellReading4; // the analog reading from the analog resistor divider
int photocellReading5; // the analog reading from the analog resistor divider
int photocellDifference1;
int photocellDifference2;
int lrValue;
void setup(void) {
Serial.begin(9600);
pinMode(12, OUTPUT); //Initiates Motor Channel A pin
pinMode(9, OUTPUT); //Initiates Brake Channel A pin
pinMode(13, OUTPUT); //Initiates Motor Channel B pin
pinMode(8, OUTPUT); //Initiates Brake Channel B pin
digitalWrite(13, LOW); //Establishes forward direction of Channel A
digitalWrite(8, LOW); //Disengage the Brake for Channel A
digitalWrite(12, LOW); //Establishes forward direction of Channel B
digitalWrite(9, LOW); //Disengage the Brake for Channel B
}
void loop(void) {
photocellReading3 = analogRead(3); // base light reading
photocellReading4 = analogRead(4); // base light reading
photocellReading5 = analogRead(5); // base light reading
//get differences between sensors for motors and ambient light sensor
photocellDifference1 = (photocellReading3 - photocellReading5);
photocellDifference2 = (photocellReading4 - photocellReading5);
// get difference between the two readings
lrValue = photocellDifference2 - photocellDifference1;
// control speed to each motor based on lrValue
if (lrValue <= -120 ) {
analogWrite(11, 255);
analogWrite(3, 100);
} else if (lrValue <= -90) {
analogWrite(11, 224);
analogWrite(3, 100);
}else if (lrValue <= -60) {
analogWrite(11, 193);
analogWrite(3, 100);
}else if (lrValue <= -40) {
analogWrite(11, 162);
analogWrite(3, 100);
}else if (lrValue <= -25) {
analogWrite(11, 131);
analogWrite(3, 100);
}else if (lrValue < 25) {
analogWrite(11, 100);
analogWrite(3, 100);
} else if (lrValue < 40) {
analogWrite(11, 100);
analogWrite(3, 131);
} else if (lrValue < 60) {
analogWrite(11, 100);
analogWrite(3, 162);
} else if (lrValue < 90) {
analogWrite(11, 100);
analogWrite(3, 193);
} else if (lrValue < 120) {
analogWrite(11, 100);
analogWrite(3, 224);
} else {
analogWrite(11, 100);
analogWrite(3, 255);
}
}
Video of the light sensors controlling the motors
Speed Break Down
In the code, you can see we have a long list of if else statements controlling the speed of each motor. This code works for our snake and our photocell sensor/motor combination. If you have changed the materials for your snake or find that these values don't work for you, when feel free to change the values until you find speed control that works for you. Our snake is meant to work in low light and at a pretty fast speed. If you want your snake slower, for example, you may want to widen your range of lrValues in the if else statements, so that it will take a high powered light directed at one sensor before the motors reach highest speed.
We also found that each motor needed a minimum value of speed (ours was 100) to be able to pull the weight of the snake. There could never be a speed value of 0 going to a motor. If a motor would completely stop, it would then take too much work to get the motor moving again.
We found it was easiest to plan the speed controls out in a table before writing the if else statements. This was our table:
Motor A Motor B
lrValue Analog 3 Analog 11
-∞ → -120 225 100
-119 → -90 224 100
-89 → -60 193 100
-59 → -40 162 100
-39 → -25 131 100
-24 → 24 100 100
25 → 39 100 131
40 → 59 100 162
60 → 89 100 193
90 → 119 100 224
120 → ∞ 100 225
In this step we will be taking the three photocell sensors and using them to drive the motor speeds. In our code we will be refering the motors to Motor A or Motor B, based on where they are plugged into the motor shield, and the sensors will be Sensor 3, Sensor 4, and Sensor 5, based on where they are attached to the analog readings. Sensor 3 and Sensor 4 will be the directional sensors and Sensor 5 will be the ambient light sensor.
Algorithm
To control the motors, we will be getting the base reading from all three sensors first (these are stored in photocellReading#).
We then take the differences between Sensor 3 and Sensor 5 (and store it in photocellDifference1) as well as the difference between Sensor 4 and Sensor 5 (and store it in photocellDifference2). This will tell us how much brighter the directional sensors are from the ambient sensor. Since the light will be shinning on these sensors, the difference readings should tell us how much light is being directed at each sensor.
We then subtract photocellDifference1 and photocellDifference2 from each other and store it in lrValue. By taking this difference, we are able to tell how much more light each directional sensor is sensing. If this number is negative than it means Sensor 4 has less light than Sensor 3 and more speed should be directed at Motor B. If the lrValue is positive than it means that Sensor 3 has more light than Sensor 4 and more speed should be directed to Motor A.
Code
/*
int photocellReading3; // the analog reading from the analog resistor divider
int photocellReading4; // the analog reading from the analog resistor divider
int photocellReading5; // the analog reading from the analog resistor divider
int photocellDifference1;
int photocellDifference2;
int lrValue;
void setup(void) {
Serial.begin(9600);
pinMode(12, OUTPUT); //Initiates Motor Channel A pin
pinMode(9, OUTPUT); //Initiates Brake Channel A pin
pinMode(13, OUTPUT); //Initiates Motor Channel B pin
pinMode(8, OUTPUT); //Initiates Brake Channel B pin
digitalWrite(13, LOW); //Establishes forward direction of Channel A
digitalWrite(8, LOW); //Disengage the Brake for Channel A
digitalWrite(12, LOW); //Establishes forward direction of Channel B
digitalWrite(9, LOW); //Disengage the Brake for Channel B
}
void loop(void) {
photocellReading3 = analogRead(3); // base light reading
photocellReading4 = analogRead(4); // base light reading
photocellReading5 = analogRead(5); // base light reading
//get differences between sensors for motors and ambient light sensor
photocellDifference1 = (photocellReading3 - photocellReading5);
photocellDifference2 = (photocellReading4 - photocellReading5);
// get difference between the two readings
lrValue = photocellDifference2 - photocellDifference1;
// control speed to each motor based on lrValue
if (lrValue <= -120 ) {
analogWrite(11, 255);
analogWrite(3, 100);
} else if (lrValue <= -90) {
analogWrite(11, 224);
analogWrite(3, 100);
}else if (lrValue <= -60) {
analogWrite(11, 193);
analogWrite(3, 100);
}else if (lrValue <= -40) {
analogWrite(11, 162);
analogWrite(3, 100);
}else if (lrValue <= -25) {
analogWrite(11, 131);
analogWrite(3, 100);
}else if (lrValue < 25) {
analogWrite(11, 100);
analogWrite(3, 100);
} else if (lrValue < 40) {
analogWrite(11, 100);
analogWrite(3, 131);
} else if (lrValue < 60) {
analogWrite(11, 100);
analogWrite(3, 162);
} else if (lrValue < 90) {
analogWrite(11, 100);
analogWrite(3, 193);
} else if (lrValue < 120) {
analogWrite(11, 100);
analogWrite(3, 224);
} else {
analogWrite(11, 100);
analogWrite(3, 255);
}
}
Video of the light sensors controlling the motors
Speed Break Down
In the code, you can see we have a long list of if else statements controlling the speed of each motor. This code works for our snake and our photocell sensor/motor combination. If you have changed the materials for your snake or find that these values don't work for you, when feel free to change the values until you find speed control that works for you. Our snake is meant to work in low light and at a pretty fast speed. If you want your snake slower, for example, you may want to widen your range of lrValues in the if else statements, so that it will take a high powered light directed at one sensor before the motors reach highest speed.
We also found that each motor needed a minimum value of speed (ours was 100) to be able to pull the weight of the snake. There could never be a speed value of 0 going to a motor. If a motor would completely stop, it would then take too much work to get the motor moving again.
We found it was easiest to plan the speed controls out in a table before writing the if else statements. This was our table:
Motor A Motor B
lrValue Analog 3 Analog 11
-∞ → -120 225 100
-119 → -90 224 100
-89 → -60 193 100
-59 → -40 162 100
-39 → -25 131 100
-24 → 24 100 100
25 → 39 100 131
40 → 59 100 162
60 → 89 100 193
90 → 119 100 224
120 → ∞ 100 225
Step 4: Blinking LEDs
Quick LED tutorial
In this step we will be setting up a blinking LED, similar to this instructable tutorial. Though this is a simple step, it might be useful to learn more information about how the setup works, as we will not be going through specifics in this step.
Setup one LED
By using the circuit diagram, set up the one LED to the breadboard and arduino. For this step, we removed the photocell sensors, so it would be easier to see the LED circuit. We recommend doing this also, it makes it easier to complete each step without previous work getting in the way of the breadboard, and eventually we wanted to reorganize the breadboard so it was configured as optimally as we could get it. Most likely, you will need to reorganize your breadboard also.
We used the following code to get the LED blink. We first turn the LED on, then pause for one second to leave the LED on. We then turn the LED off and pause again for one second, so that the LED stays off. This then causes the blinking action to happen.
/*
void setup(void) {
Serial.begin(9600);
pinMode(5, OUTPUT); //initialize pin 5 for LED
}
void loop(void) {
digitalWrite(5, HIGH); //set LED on
delay(1000); //delay for 1 second
digitalWrite(5, LOW); // set LED off
delay(1000); //delay for 1 second
}
*/
Video of one LED
In this step we will be setting up a blinking LED, similar to this instructable tutorial. Though this is a simple step, it might be useful to learn more information about how the setup works, as we will not be going through specifics in this step.
Setup one LED
By using the circuit diagram, set up the one LED to the breadboard and arduino. For this step, we removed the photocell sensors, so it would be easier to see the LED circuit. We recommend doing this also, it makes it easier to complete each step without previous work getting in the way of the breadboard, and eventually we wanted to reorganize the breadboard so it was configured as optimally as we could get it. Most likely, you will need to reorganize your breadboard also.
We used the following code to get the LED blink. We first turn the LED on, then pause for one second to leave the LED on. We then turn the LED off and pause again for one second, so that the LED stays off. This then causes the blinking action to happen.
/*
void setup(void) {
Serial.begin(9600);
pinMode(5, OUTPUT); //initialize pin 5 for LED
}
void loop(void) {
digitalWrite(5, HIGH); //set LED on
delay(1000); //delay for 1 second
digitalWrite(5, LOW); // set LED off
delay(1000); //delay for 1 second
}
*/
Video of one LED
Step 5: Add Vibration Motor
Description
The vibration motor is added to simulate the a rattling tail on a snake. We were given our vibration motor from class, so we do not have a model number, but just like the other steps of this project, use the size motor that best fits the snake that you are building. We wanted the smallest motor possible, so that it would be able to fit on the small tail piece we were building.
Adding the vibration motor is very similar to the LEDs. It does not require to be connected to the 5V power supply on the arduino board, but gets it’s power from the Pin it connects to. We are connecting the vibration motor to Pin 10. It does not matter what pin you connect the vibration motor to, but we wanted to physically separate it from the LED groups for less confusion.
Code
/*
void setup(void) {
Serial.begin(9600);
pinMode(10, OUTPUT); //initialize pin 10 for the vibrator motor
}
void loop(void) {
digitalWrite(10, HIGH); //set vibrator motor on
delay(1000); //pause for 1 second
digitalWrite(10, LOW); // set vibrator motor off
delay(3000); //pause for 3 seconds
}
*/
Video of motor working
The vibration motor is added to simulate the a rattling tail on a snake. We were given our vibration motor from class, so we do not have a model number, but just like the other steps of this project, use the size motor that best fits the snake that you are building. We wanted the smallest motor possible, so that it would be able to fit on the small tail piece we were building.
Adding the vibration motor is very similar to the LEDs. It does not require to be connected to the 5V power supply on the arduino board, but gets it’s power from the Pin it connects to. We are connecting the vibration motor to Pin 10. It does not matter what pin you connect the vibration motor to, but we wanted to physically separate it from the LED groups for less confusion.
Code
/*
void setup(void) {
Serial.begin(9600);
pinMode(10, OUTPUT); //initialize pin 10 for the vibrator motor
}
void loop(void) {
digitalWrite(10, HIGH); //set vibrator motor on
delay(1000); //pause for 1 second
digitalWrite(10, LOW); // set vibrator motor off
delay(3000); //pause for 3 seconds
}
*/
Video of motor working
Step 6: Timing Groups of LEDs
Why the need for a timer
One of the main problems with the previous steps was that each piece of the project was constructed separately, but when added together it created problems in the programming. The photocell sensors required immediate reaction to control the motors, but the groups of LED and vibration motor needed different lengths of delays to control them. Also the LED groups blinked at the same time even though they are supposed to be three separate groups. To control everything in the code the way we need to, we require a timer.
Implementation
To add the timer, create an integer variable at the top near the other variables. We set it equal to 1 to begin with, and will increment it by 1 in the loop. After the timer reaches 24, we will reset it back to 1 so it does not increase infinitely. Each piece of the snake project will then be turned on or off based on what time it is. The delay is then added at the end to create that pause to hold the on/off settings of our pieces.
We played around with the timing of everything before we decided on the final controls. One of problems we encountered was the delay at the end, we needed a delay for the lights and vibration motor, however, the photocell sensors would also be affected by this delay, which was rather undesirable. We settled on a quarter of a second delay, this gave us enough time for the LEDs and vibration motor to stay on or off for and was a small enough delay to the photocell sensors, it was nearly unnoticeable.
Time Table
Again, in this step, we found it was easiest to draw out what we wanted timing wise, so we could easily see when to turn on and off each component.
Timer Vibration LEDs LEDs LEDs
Value Motor Group 1 Group 2 Group 3
1 ON off ON ON
2 ON ON off off
3 ON off off ON
4 off off ON ON
5 off off ON off
6 off ON off ON
7 off off off ON
8 off off ON off
9 off off ON ON
10 off off off ON
11 off off off off
12 off off ON ON
13 off off ON ON
14 off ON off off
15 off off off ON
16 off off ON ON
17 ON off ON off
18 ON ON off ON
19 ON off off ON
20 off off ON off
21 off off ON ON
22 off ON off ON
23 off off off off
24 off off ON ON
One of the main problems with the previous steps was that each piece of the project was constructed separately, but when added together it created problems in the programming. The photocell sensors required immediate reaction to control the motors, but the groups of LED and vibration motor needed different lengths of delays to control them. Also the LED groups blinked at the same time even though they are supposed to be three separate groups. To control everything in the code the way we need to, we require a timer.
Implementation
To add the timer, create an integer variable at the top near the other variables. We set it equal to 1 to begin with, and will increment it by 1 in the loop. After the timer reaches 24, we will reset it back to 1 so it does not increase infinitely. Each piece of the snake project will then be turned on or off based on what time it is. The delay is then added at the end to create that pause to hold the on/off settings of our pieces.
We played around with the timing of everything before we decided on the final controls. One of problems we encountered was the delay at the end, we needed a delay for the lights and vibration motor, however, the photocell sensors would also be affected by this delay, which was rather undesirable. We settled on a quarter of a second delay, this gave us enough time for the LEDs and vibration motor to stay on or off for and was a small enough delay to the photocell sensors, it was nearly unnoticeable.
Time Table
Again, in this step, we found it was easiest to draw out what we wanted timing wise, so we could easily see when to turn on and off each component.
Timer Vibration LEDs LEDs LEDs
Value Motor Group 1 Group 2 Group 3
1 ON off ON ON
2 ON ON off off
3 ON off off ON
4 off off ON ON
5 off off ON off
6 off ON off ON
7 off off off ON
8 off off ON off
9 off off ON ON
10 off off off ON
11 off off off off
12 off off ON ON
13 off off ON ON
14 off ON off off
15 off off off ON
16 off off ON ON
17 ON off ON off
18 ON ON off ON
19 ON off off ON
20 off off ON off
21 off off ON ON
22 off ON off ON
23 off off off off
24 off off ON ON
Step 7: What Everything Looks Like Together
Description
This step is not adding anything new to the arduino, but marking the end of the electrical portion of the project and beginning the materials portion. From here on out, all the pieces we mentioned separately in previous steps need to be brought together and starting to create a cohesive project. We give a picture of everything we have added to the breadboard and the arduino setup. We also have the finished code that we will be using to control the snake from here on out.
Final Code
/*
int photocellReading3; // the analog reading from the analog resistor divider
int photocellReading4; // the analog reading from the analog resistor divider
int photocellReading5; // the analog reading from the analog resistor divider
int photocellDifference1;
int photocellDifference2;
int lrValue;
int timer = 1;
void setup(void) {
Serial.begin(9600);
// ///////////////// //
// Set up motors //
// ///////////////// //
pinMode(12, OUTPUT); //Initiates Motor Channel A pin
pinMode(9, OUTPUT); //Initiates Brake Channel A pin
pinMode(13, OUTPUT); //Initiates Motor Channel B pin
pinMode(8, OUTPUT); //Initiates Brake Channel B pin
digitalWrite(13, LOW); //Establishes forward direction of Channel A
digitalWrite(8, LOW); //Disengage the Brake for Channel A
digitalWrite(12, LOW); //Establishes forward direction of Channel B
digitalWrite(9, LOW); //Disengage the Brake for Channel B
// /////////////////// //
// Set up all LEDs //
// /////////////////// //
pinMode(7, OUTPUT); //initialize pin 7 for LED Group 1
pinMode(6, OUTPUT); //initialize pin 6 for LED Group 2
pinMode(5, OUTPUT); //initialize pin 5 for LED Group 3
// ////////////////////////// //
// Set up vibration motor //
// ////////////////////////// //
pinMode(10, OUTPUT); //initialize pin 10 for the vibration motor
}
void loop(void) {
// /////////////////////////////// //
// photocell sensor readings //
// /////////////////////////////// //
photocellReading3 = analogRead(3); // will go to motor A
photocellReading4 = analogRead(4); // will go to motor B
photocellReading5 = analogRead(5); // base light reading
//get differences between sensors for motors and ambient light sensor
photocellDifference1 = (photocellReading3 - photocellReading5);
photocellDifference2 = (photocellReading4 - photocellReading5);
lrValue = photocellDifference2 - photocellDifference1;
// /////////////////////////////////// //
// turn on motors based on sensors //
// /////////////////////////////////// //
if (lrValue <= -120 ) {
analogWrite(11, 255);
analogWrite(3, 100);
} else if (lrValue <= -90) {
analogWrite(11, 224);
analogWrite(3, 100);
}else if (lrValue <= -60) {
analogWrite(11, 193);
analogWrite(3, 100);
}else if (lrValue <= -40) {
analogWrite(11, 162);
analogWrite(3, 100);
}else if (lrValue <= -25) {
analogWrite(11, 131);
analogWrite(3, 100);
}else if (lrValue < 25) {
analogWrite(11, 100);
analogWrite(3, 100);
} else if (lrValue < 40) {
analogWrite(11, 100);
analogWrite(3, 131);
} else if (lrValue < 60) {
analogWrite(11, 100);
analogWrite(3, 162);
} else if (lrValue < 90) {
analogWrite(11, 100);
analogWrite(3, 193);
} else if (lrValue < 120) {
analogWrite(11, 100);
analogWrite(3, 224);
} else {
analogWrite(11, 100);
analogWrite(3, 255);
}
// //////////////// //
// leds group 1 //
// ///////////// // //
if (((timer - 1) % 4) == 1)
digitalWrite(7, HIGH); //set LED on
else
digitalWrite(7, LOW); // set LED off
// //////////////// //
// leds group 2 //
// ///////////// // //
if ( (((timer - 3) % 4) == 2) || (((timer - 3) % 4) == 1) )
digitalWrite(6, HIGH); //set LED on
else
digitalWrite(6, LOW); // set LED off
// //////////////// //
// leds group 3 //
// ///////////// // //
if ( (((timer - 2) % 3) == 1) || (((timer - 2) % 3) == 2) )
digitalWrite(5, HIGH); //set LED on
else
digitalWrite(5, LOW); // set LED off
// ///////////////// //
// vibrator motor //
// ///////////////// //
if ( ((timer % 16) == 1) || ((timer % 15) == 2) || ((timer % 15) == 3) )
digitalWrite(10, HIGH); //set vibration motor on
else
digitalWrite(10, LOW); // set vibration motor off
// reset timer every 12 seconds
if (timer == 48)
timer = 1;
else
timer ++;
// delay for 0.25 seconds
delay(250);
}
*/
This step is not adding anything new to the arduino, but marking the end of the electrical portion of the project and beginning the materials portion. From here on out, all the pieces we mentioned separately in previous steps need to be brought together and starting to create a cohesive project. We give a picture of everything we have added to the breadboard and the arduino setup. We also have the finished code that we will be using to control the snake from here on out.
Final Code
/*
int photocellReading3; // the analog reading from the analog resistor divider
int photocellReading4; // the analog reading from the analog resistor divider
int photocellReading5; // the analog reading from the analog resistor divider
int photocellDifference1;
int photocellDifference2;
int lrValue;
int timer = 1;
void setup(void) {
Serial.begin(9600);
// ///////////////// //
// Set up motors //
// ///////////////// //
pinMode(12, OUTPUT); //Initiates Motor Channel A pin
pinMode(9, OUTPUT); //Initiates Brake Channel A pin
pinMode(13, OUTPUT); //Initiates Motor Channel B pin
pinMode(8, OUTPUT); //Initiates Brake Channel B pin
digitalWrite(13, LOW); //Establishes forward direction of Channel A
digitalWrite(8, LOW); //Disengage the Brake for Channel A
digitalWrite(12, LOW); //Establishes forward direction of Channel B
digitalWrite(9, LOW); //Disengage the Brake for Channel B
// /////////////////// //
// Set up all LEDs //
// /////////////////// //
pinMode(7, OUTPUT); //initialize pin 7 for LED Group 1
pinMode(6, OUTPUT); //initialize pin 6 for LED Group 2
pinMode(5, OUTPUT); //initialize pin 5 for LED Group 3
// ////////////////////////// //
// Set up vibration motor //
// ////////////////////////// //
pinMode(10, OUTPUT); //initialize pin 10 for the vibration motor
}
void loop(void) {
// /////////////////////////////// //
// photocell sensor readings //
// /////////////////////////////// //
photocellReading3 = analogRead(3); // will go to motor A
photocellReading4 = analogRead(4); // will go to motor B
photocellReading5 = analogRead(5); // base light reading
//get differences between sensors for motors and ambient light sensor
photocellDifference1 = (photocellReading3 - photocellReading5);
photocellDifference2 = (photocellReading4 - photocellReading5);
lrValue = photocellDifference2 - photocellDifference1;
// /////////////////////////////////// //
// turn on motors based on sensors //
// /////////////////////////////////// //
if (lrValue <= -120 ) {
analogWrite(11, 255);
analogWrite(3, 100);
} else if (lrValue <= -90) {
analogWrite(11, 224);
analogWrite(3, 100);
}else if (lrValue <= -60) {
analogWrite(11, 193);
analogWrite(3, 100);
}else if (lrValue <= -40) {
analogWrite(11, 162);
analogWrite(3, 100);
}else if (lrValue <= -25) {
analogWrite(11, 131);
analogWrite(3, 100);
}else if (lrValue < 25) {
analogWrite(11, 100);
analogWrite(3, 100);
} else if (lrValue < 40) {
analogWrite(11, 100);
analogWrite(3, 131);
} else if (lrValue < 60) {
analogWrite(11, 100);
analogWrite(3, 162);
} else if (lrValue < 90) {
analogWrite(11, 100);
analogWrite(3, 193);
} else if (lrValue < 120) {
analogWrite(11, 100);
analogWrite(3, 224);
} else {
analogWrite(11, 100);
analogWrite(3, 255);
}
// //////////////// //
// leds group 1 //
// ///////////// // //
if (((timer - 1) % 4) == 1)
digitalWrite(7, HIGH); //set LED on
else
digitalWrite(7, LOW); // set LED off
// //////////////// //
// leds group 2 //
// ///////////// // //
if ( (((timer - 3) % 4) == 2) || (((timer - 3) % 4) == 1) )
digitalWrite(6, HIGH); //set LED on
else
digitalWrite(6, LOW); // set LED off
// //////////////// //
// leds group 3 //
// ///////////// // //
if ( (((timer - 2) % 3) == 1) || (((timer - 2) % 3) == 2) )
digitalWrite(5, HIGH); //set LED on
else
digitalWrite(5, LOW); // set LED off
// ///////////////// //
// vibrator motor //
// ///////////////// //
if ( ((timer % 16) == 1) || ((timer % 15) == 2) || ((timer % 15) == 3) )
digitalWrite(10, HIGH); //set vibration motor on
else
digitalWrite(10, LOW); // set vibration motor off
// reset timer every 12 seconds
if (timer == 48)
timer = 1;
else
timer ++;
// delay for 0.25 seconds
delay(250);
}
*/
Step 8: Laser Cut Base
Get sizing
First, measure the size of arduino uno and breadboard. After acquiring the size of arduino uno and breadboard, sketch the snake’s base with little hole on them so they can be attached with each other later on. The base of head should be theoretically bigger than the other base pieces to have balanced weight since the wheels will be attached to the head. Total 7 bases were sketched for our project.
Remember to cut small portion on sides of snake head for the motors/wheels to be stuck on.
Create Base
Scan the paper, work with illustrator to make sketch look more clear and precise. Allow laser cutter to recognize illustrated sketch.
We recommend wood instead of plastic to reduce the weight. We used balsa wood that was thin but strong enough to hold weight for the arduino and breadboard.
Finally, laser cut the bases.
First, measure the size of arduino uno and breadboard. After acquiring the size of arduino uno and breadboard, sketch the snake’s base with little hole on them so they can be attached with each other later on. The base of head should be theoretically bigger than the other base pieces to have balanced weight since the wheels will be attached to the head. Total 7 bases were sketched for our project.
Remember to cut small portion on sides of snake head for the motors/wheels to be stuck on.
Create Base
Scan the paper, work with illustrator to make sketch look more clear and precise. Allow laser cutter to recognize illustrated sketch.
We recommend wood instead of plastic to reduce the weight. We used balsa wood that was thin but strong enough to hold weight for the arduino and breadboard.
Finally, laser cut the bases.
Step 9: Replace Wiring
What needs to be replaced
When setting up the project in previous steps, everything was attached pretty closely to the breadboard. If we want out snake to be the full length of the base, we will need to create wire extensions for various portions of the electrical.
The LEDs groups will each need to be put on their own strands so that the lights can be distributed down the snake body.
The vibration motor will need to be as long as the snake itself so it will be able to rattle the tail.
The ambient light sensor will need to be placed near the center or end of the snake, at least far enough away that it will not sense any light aimed towards the head.
Warnings
When attaching wiring to the LEDs, make sure that the wiring attaches to the long or short side of each LED. You cannot connect different sides of an LED together on the same circuit, they will not be able to turn on.
When we replaces the wiring, we just twisted the end of the electrical piece and the wire together to connect the circuit. If you can, we recommend soldering these pieces together, it will create a stronger bond and be less likely to break. We needed to return some of our materials to the classroom, so we twisted the wiring together and wrapped each end in electrical tape to hold the bond together.
Make sure there is no exposed wiring. When everything is hidden under the snake body, wires may cross and if some of the wiring is exposed, it will cross circuits and cause the snake to malfunction.
When setting up the project in previous steps, everything was attached pretty closely to the breadboard. If we want out snake to be the full length of the base, we will need to create wire extensions for various portions of the electrical.
The LEDs groups will each need to be put on their own strands so that the lights can be distributed down the snake body.
The vibration motor will need to be as long as the snake itself so it will be able to rattle the tail.
The ambient light sensor will need to be placed near the center or end of the snake, at least far enough away that it will not sense any light aimed towards the head.
Warnings
When attaching wiring to the LEDs, make sure that the wiring attaches to the long or short side of each LED. You cannot connect different sides of an LED together on the same circuit, they will not be able to turn on.
When we replaces the wiring, we just twisted the end of the electrical piece and the wire together to connect the circuit. If you can, we recommend soldering these pieces together, it will create a stronger bond and be less likely to break. We needed to return some of our materials to the classroom, so we twisted the wiring together and wrapped each end in electrical tape to hold the bond together.
Make sure there is no exposed wiring. When everything is hidden under the snake body, wires may cross and if some of the wiring is exposed, it will cross circuits and cause the snake to malfunction.
Step 10: Test Weight of Head
Why test?
Temporarily attach motors and wheels to the head base piece of the snake robot. Mount the arduino components, breadboard, and the batteries to the head base piece of the snake robot as well. Test run the motors; set them to full power to begin with, and see if the wheels can break the static friction all of the extra weight is causing. Although the motors may seem like they have enough power when the snake is in the air, the motors will have trouble starting off. If the motors do not pull the snake head forward with reasonable speed, they will not be able to pull the rest of the snake with it. Be sure to buy strong enough motors before permanently mounting them to the wooden base!
Video of first test
Temporarily attach motors and wheels to the head base piece of the snake robot. Mount the arduino components, breadboard, and the batteries to the head base piece of the snake robot as well. Test run the motors; set them to full power to begin with, and see if the wheels can break the static friction all of the extra weight is causing. Although the motors may seem like they have enough power when the snake is in the air, the motors will have trouble starting off. If the motors do not pull the snake head forward with reasonable speed, they will not be able to pull the rest of the snake with it. Be sure to buy strong enough motors before permanently mounting them to the wooden base!
Video of first test
Step 11: Attach Wheels
We acquired the wheels from a car toy. Extract the wheels from the toy. Hard glue the motor into wheels. give couple hours/ one-day for the wheels to dry with motor. Make sure wheels are bigger than the axel, so the movement of wheels are free. Test if wheels rotate well. If it does, try putting on some weight and make sure it has enough friction to pull all the boards.
Step 12: Attach/Mount Everything
Try using strings to attach the base boards together. Allow boards to have around half-inch space in between the board so the snake has some free movement in between the boards.
Mount arduino and breadboard with batteries onto the head base of snake. Attach 2 wires to batteries’ ends and tape them on bottom of the snake head. This lets you power on/off the snake easily. We recommend just duck-taping batteries/arduino/breadboard to the head of snake.
To mount motor/wheels, we recommend using a narrow plastic so that wheels become stable on motors.
After mounting major boards onto head, we cover the bases with fabric, then work on led lights and light sensors.
Mount arduino and breadboard with batteries onto the head base of snake. Attach 2 wires to batteries’ ends and tape them on bottom of the snake head. This lets you power on/off the snake easily. We recommend just duck-taping batteries/arduino/breadboard to the head of snake.
To mount motor/wheels, we recommend using a narrow plastic so that wheels become stable on motors.
After mounting major boards onto head, we cover the bases with fabric, then work on led lights and light sensors.
Step 13: Put Braces Under Head
Using a big base for the head of the snake is great for having space to mount all the components on one piece of wood. This also helps by supporting weight above the motors instead of pulling it behind. However, the snake’s head piece will be heavy once everything is mounted on it, and will be off balance. Use a lightweight piece of metal (such as a paper clip) to form a supporting leg for the head, and place it behind the motors to give the head more stability. This helps the motors put power down to the wheels, and pull the snake’s body behind it.
Step 14: Create Material Shells
Acquire fabric of prefered choice. We used green fabric to make it look like somewhat more snake looking. Measure the size of balsa wood base, sketch it on fabric.
Cut the fabric leaving 1 to 2 inch indent from the base sketch.
Allow the head base fabric to have extra 1 or 2 inch of indent so it has extra room for all the materials to be in the head.
Acquire velcro. Cut them into vertical length of balsa wood bases. Make 2 thin pieces for each base pieces. glue the velcro hook on the bottom of the wood base. Allow couple hours until the velcro gets stabled onto the wood.
We recommend gluing the hook part to wood, because it is much easier to sew the loop part of velcro into fabric.
Use the loop part of velcro, sew it into the fabric. Use strings to sew the velcro into fabric. Sew it by pleating the fabric, so fabric can surround the base in a spherical manner.
Try attaching the fabric to base, if the fabric is too big, pleating the fabric makes it look tighter and neat.
Cut the fabric leaving 1 to 2 inch indent from the base sketch.
Allow the head base fabric to have extra 1 or 2 inch of indent so it has extra room for all the materials to be in the head.
Acquire velcro. Cut them into vertical length of balsa wood bases. Make 2 thin pieces for each base pieces. glue the velcro hook on the bottom of the wood base. Allow couple hours until the velcro gets stabled onto the wood.
We recommend gluing the hook part to wood, because it is much easier to sew the loop part of velcro into fabric.
Use the loop part of velcro, sew it into the fabric. Use strings to sew the velcro into fabric. Sew it by pleating the fabric, so fabric can surround the base in a spherical manner.
Try attaching the fabric to base, if the fabric is too big, pleating the fabric makes it look tighter and neat.
Step 15: Make the Tail
In order to make the tail (the last link of the snake), find beads and string them loosely with string so they have enough space to make a “rattling” noise. Attach the last base piece to the snake body, and mount the vibrator motor in the middle of the base piece. Loosely mount the beaded string around the head of the vibrator motor, making sure that they are touching and do not have enough slack in the string to separate from the head of the vibrator motor. Test the rattling tail of the snake by engaging the vibrator motor. After ensuring that the tail makes noise and moves when the motor is turned on, secure all components permanently to the tail’s base piece.
Step 16: Place the Light Sensors and LEDs
Mounting the light sensors and LEDs is pretty simple. Follow wiring instructions in order to avoid mistakes while connecting them to the Arduino unit. In the head link, cut tiny holes in fabric where the front light sensors should be. A general fitting guide for the front light sensors is to mimic the positioning of the eyes of a snake. Then position the light sensors to face away from each other at an angle, so each can retrieve light signals from a more extreme angle from its respective side. Next, mount the ambient light sensor in the center piece of the snake’s body, and cut an appropriate hole in the fabric surrounding that body piece. This sensor needs to be far enough away to not be affected by the light that the front sensors are receiving. Now comes the fun part! Decorate your snake with the LED lighting by first deciding where you want each LED to be located on the snake. An important thing to remember is that light from an LED will affect the ambient and front light sensors; make sure the LEDs are positioned in a way that will not interfere with the readings taken by the light sensors. Next, mount LED’s to the body’s base piece. Finally, cut holes in the fabric and poke the LEDs through them lightly.