Introduction: Arduino King Cobra Game
Step 1: The Search for Serpent Parts
A list of bits and pieces required to make your wildest dreams come true:
1. One Arduino Whatever (any model should work). I used a Micro
2. One analog servo motor. Mine is a Tower Pro SG90 with 180 degree sweep
3. One PING ultrasonic distance sensor
4. One battery holder with batteries. Mine is 6V total, but Arduino recommends 7-12 volts for stability
5. A bread board or PCB for wiring
6. Wiring
7. One small zip-tie
8. One snake head
9. Some tape
1. One Arduino Whatever (any model should work). I used a Micro
2. One analog servo motor. Mine is a Tower Pro SG90 with 180 degree sweep
3. One PING ultrasonic distance sensor
4. One battery holder with batteries. Mine is 6V total, but Arduino recommends 7-12 volts for stability
5. A bread board or PCB for wiring
6. Wiring
7. One small zip-tie
8. One snake head
9. Some tape
Step 2: Snake Brains
My snake runs on an Arduino Micro. You can use any Arduino though, just adjust your pins accordingly.
The way it works is the following:
1. Ping ultrasonic sensor reads the distance of your hands or objects in front of it 50 times per second
2. If close enough, the servo motor is rotated down towards your hand.
As the code works now, the "Cobra head" does not sit and wait for your hand to get too close, but instead it moves based on your distance. So the closer you get, the lower it drops to get you.
The way it works is the following:
1. Ping ultrasonic sensor reads the distance of your hands or objects in front of it 50 times per second
2. If close enough, the servo motor is rotated down towards your hand.
As the code works now, the "Cobra head" does not sit and wait for your hand to get too close, but instead it moves based on your distance. So the closer you get, the lower it drops to get you.
Step 3: Snake Eyes
The "eyes" are actually an ultrasonic distance sensor. These are available in Radio Shack and online.
They work by sending a high pitched "ping" out and then measuring how long it takes to hear it bounce back. Since the speed of sound is known, it can determine within a cm or so how far away the object is that it hit. Cool!
It has 3 pins:
A ground pin (GND)
A 5 volts in pin (5V)
A signal pin (SIG)
The first two power it. The signal pin is responsible for sending out the ping and then listening for it to return.
They work by sending a high pitched "ping" out and then measuring how long it takes to hear it bounce back. Since the speed of sound is known, it can determine within a cm or so how far away the object is that it hit. Cool!
It has 3 pins:
A ground pin (GND)
A 5 volts in pin (5V)
A signal pin (SIG)
The first two power it. The signal pin is responsible for sending out the ping and then listening for it to return.
Step 4: Snake Muscle
This is a typical hobby mini servo motor. They are great to use when you have to rotate a motor to an exact position.
They are pretty fast and have a good amount of torque, but be careful not to yank on them or the gears can strip over time.
They have three wires:
brown/black: ground -
red/orange: positive voltage +
yellow: signal (typically sends a value between 0-180 degrees)
They are pretty fast and have a good amount of torque, but be careful not to yank on them or the gears can strip over time.
They have three wires:
brown/black: ground -
red/orange: positive voltage +
yellow: signal (typically sends a value between 0-180 degrees)
Step 5: The Cobra Code (not Python) HAH!
Here is the Arduino code that I'm running. It's a modification of their Ping ultrasonic sensor sample.
Adjusting the variable "numReadings" to a higher value will result in less noisy readings, but also a larger lag in reaction time.
Enjoy!
//Copy from here...
#include <Servo.h>
Servo myservo; // create servo object to control a servo
int val; // range-mapped value for servo control
const int pingPin = 7; // Parallax ping sensor's signal pin
const int numReadings = 5; // set higher to smooth more, also causes more latency
int readings[numReadings]; // the readings from the analog input
int index = 0; // the index of the current reading
int total = 0; // the running total
int average = 0; // the average
int lastValue = 0;
void setup() {
// initialize serial communication:
Serial.begin(9600);
myservo.attach(9); // attaches the servo on pin 9 to the servo object
//clear the smoothing value buffer
for (int thisReading = 0; thisReading < numReadings; thisReading++)
readings[thisReading] = 0;
}
void loop()
{
// establish variables for duration of the ping,
// and the distance result in inches and centimeters:
long duration, inches, cm;
int fadeValue = 0;
// The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
// Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
pinMode(pingPin, OUTPUT);
digitalWrite(pingPin, LOW);
delayMicroseconds(2);
digitalWrite(pingPin, HIGH);
delayMicroseconds(5);
digitalWrite(pingPin, LOW);
// The same pin is used to read the signal from the PING))): a HIGH
// pulse whose duration is the time (in microseconds) from the sending
// of the ping to the reception of its echo off of an object.
pinMode(pingPin, INPUT);
duration = pulseIn(pingPin, HIGH);
// convert the time into a distance
inches = microsecondsToInches(duration);
cm = microsecondsToCentimeters(duration);
//smoothing code starts here
// subtract the last reading:
total= total - readings[index];
// read from the sensor:
readings[index] = cm;//analogRead(inputPin);
// add the reading to the total:
total= total + readings[index];
// advance to the next position in the array:
index = index + 1;
// if we're at the end of the array...
if (index >= numReadings)
// ...wrap around to the beginning:
index = 0;
// calculate the average:
average = total / numReadings;
//smoothing code ends here
//remap value range and move the servo
val = average;
val = map(val, 10, 40, 0, 179); // scale value to use it with the Tower Pro half turn analog servo (value between 0 and 180)
if(average < 25)
{myservo.write(val);} // sets the servo position according to the scaled value if within a certain distance
delay(10); //let the servo cool down, or something
}
long microsecondsToInches(long microseconds)
{
// According to Parallax's datasheet for the PING))), there are
// 73.746 microseconds per inch (i.e. sound travels at 1130 feet per
// second). This gives the distance travelled by the ping, outbound
// and return, so we divide by 2 to get the distance of the obstacle.
// See: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf
return microseconds / 74 / 2;
}
long microsecondsToCentimeters(long microseconds)
{
// The speed of sound is 340 m/s or 29 microseconds per centimeter.
// The ping travels out and back, so to find the distance of the
// object we take half of the distance travelled.
return microseconds / 29 / 2;
}
//To here...
Adjusting the variable "numReadings" to a higher value will result in less noisy readings, but also a larger lag in reaction time.
Enjoy!
//Copy from here...
#include <Servo.h>
Servo myservo; // create servo object to control a servo
int val; // range-mapped value for servo control
const int pingPin = 7; // Parallax ping sensor's signal pin
const int numReadings = 5; // set higher to smooth more, also causes more latency
int readings[numReadings]; // the readings from the analog input
int index = 0; // the index of the current reading
int total = 0; // the running total
int average = 0; // the average
int lastValue = 0;
void setup() {
// initialize serial communication:
Serial.begin(9600);
myservo.attach(9); // attaches the servo on pin 9 to the servo object
//clear the smoothing value buffer
for (int thisReading = 0; thisReading < numReadings; thisReading++)
readings[thisReading] = 0;
}
void loop()
{
// establish variables for duration of the ping,
// and the distance result in inches and centimeters:
long duration, inches, cm;
int fadeValue = 0;
// The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
// Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
pinMode(pingPin, OUTPUT);
digitalWrite(pingPin, LOW);
delayMicroseconds(2);
digitalWrite(pingPin, HIGH);
delayMicroseconds(5);
digitalWrite(pingPin, LOW);
// The same pin is used to read the signal from the PING))): a HIGH
// pulse whose duration is the time (in microseconds) from the sending
// of the ping to the reception of its echo off of an object.
pinMode(pingPin, INPUT);
duration = pulseIn(pingPin, HIGH);
// convert the time into a distance
inches = microsecondsToInches(duration);
cm = microsecondsToCentimeters(duration);
//smoothing code starts here
// subtract the last reading:
total= total - readings[index];
// read from the sensor:
readings[index] = cm;//analogRead(inputPin);
// add the reading to the total:
total= total + readings[index];
// advance to the next position in the array:
index = index + 1;
// if we're at the end of the array...
if (index >= numReadings)
// ...wrap around to the beginning:
index = 0;
// calculate the average:
average = total / numReadings;
//smoothing code ends here
//remap value range and move the servo
val = average;
val = map(val, 10, 40, 0, 179); // scale value to use it with the Tower Pro half turn analog servo (value between 0 and 180)
if(average < 25)
{myservo.write(val);} // sets the servo position according to the scaled value if within a certain distance
delay(10); //let the servo cool down, or something
}
long microsecondsToInches(long microseconds)
{
// According to Parallax's datasheet for the PING))), there are
// 73.746 microseconds per inch (i.e. sound travels at 1130 feet per
// second). This gives the distance travelled by the ping, outbound
// and return, so we divide by 2 to get the distance of the obstacle.
// See: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf
return microseconds / 74 / 2;
}
long microsecondsToCentimeters(long microseconds)
{
// The speed of sound is 340 m/s or 29 microseconds per centimeter.
// The ping travels out and back, so to find the distance of the
// object we take half of the distance travelled.
return microseconds / 29 / 2;
}
//To here...