Introduction: Rabbit Ears on a Cap
We are students from Singapore Polytechnic.
After looking at the famous Necomimi Arduino Cat Ears, we decided to give it a try to help us familiarise ourselves with the accelerometer and the arduino.
Using the materials that we had on hand, we managed to produce a set of moving rabbit ears that is similar but not as fantastic. :)
We made a pair of rabbit ears on a cap that move according to the direction your head turns using an accelerometer, servo motors and an Arduino Uno.
After looking at the famous Necomimi Arduino Cat Ears, we decided to give it a try to help us familiarise ourselves with the accelerometer and the arduino.
Using the materials that we had on hand, we managed to produce a set of moving rabbit ears that is similar but not as fantastic. :)
We made a pair of rabbit ears on a cap that move according to the direction your head turns using an accelerometer, servo motors and an Arduino Uno.
Step 1: Components & Tools & Software
The componets and tools that we used to create the Rabbit Ears on a Cap
(Hopefully we didn't miss out any thing.)
The rabbit ears and the cap were bought from the shop where everything costs $2, DAISO. Our friend had kindly given us one of her hairbands. The other tools and components were provided by our FYP supervisor Teo Shin Jen.
Components:
1. Arduino Uno
2. MMMA7361L 3-Axis Accelerometer ±1.5/6g with Voltage Regulator http://www.pololu.com/catalog/product/1251
3. Servo motors x2
4. Molex pins ( 2 pin & 5 pin )
5. Cable ties
6. Stripboard
7. Single core wire
8. Rabbit Ears ( bought from DAISO)
9. Hairband
10.Acrylic board
11.Cap ( bought from DAISO )
12. Breadboard ( for testing servo and accelerometer)
Tools:
1.Glue gun
2.Soldering Iron
3.Wire stripper
4.Wire cutter
5.Pliers
6.Molex Crimp tool
Software:
1. Arduino IDE
(Hopefully we didn't miss out any thing.)
The rabbit ears and the cap were bought from the shop where everything costs $2, DAISO. Our friend had kindly given us one of her hairbands. The other tools and components were provided by our FYP supervisor Teo Shin Jen.
Components:
1. Arduino Uno
2. MMMA7361L 3-Axis Accelerometer ±1.5/6g with Voltage Regulator http://www.pololu.com/catalog/product/1251
3. Servo motors x2
4. Molex pins ( 2 pin & 5 pin )
5. Cable ties
6. Stripboard
7. Single core wire
8. Rabbit Ears ( bought from DAISO)
9. Hairband
10.Acrylic board
11.Cap ( bought from DAISO )
12. Breadboard ( for testing servo and accelerometer)
Tools:
1.Glue gun
2.Soldering Iron
3.Wire stripper
4.Wire cutter
5.Pliers
6.Molex Crimp tool
Software:
1. Arduino IDE
Step 2: Testing of Motor
We first planned out what we intended to do, which was to have the ears turn to the left and back to the middle repeatedly when you turn your head left , the ears to turn to the right and back to middle repeatedly when you turn your head right and have the ears remain still when you look straight.
Once we gathered all the items we needed, we noticed that there was a single iron wire inside each ear to give it its shape. It will prove extremely useful when we need to mount the ears on the motors.
The next thing to do was to test the two servo motors.
This is the code we wrote to test the motors, we fine-tuned the values to have the motors turn to the direction we need it to be.
Using the same setup as the Sweep servo example which can be found here :http://arduino.cc/it/Tutorial/Sweep
----------------------------------------------------
TestingMotor Code:
#include <Servo.h>
Servo myservoLeft;
Servo myservoRight;
int i;
void setup()
{
myservoLeft.attach(9);
myservoRight.attach(10);
}
void loop()
{
for ( i = 0 ; i < 90 ; i+=10)
{
myservoLeft.write(i);
myservoRight.write(i);
delay(100);
}
for ( i = 90 ; i > 0 ; i-=10)
{
myservoLeft.write(i);
myservoRight.write(i);
delay(100);
}
{
for ( i = 90 ; i < 180 ; i+=10)
{
myservoLeft.write(i);
myservoRight.write(i);
delay(100);
}
for ( i = 180 ; i > 90 ; i-=10)
{
myservoLeft.write(i);
myservoRight.write(i);
delay(100);
}
}
}
----------------------------------------------------------------------------
Once we gathered all the items we needed, we noticed that there was a single iron wire inside each ear to give it its shape. It will prove extremely useful when we need to mount the ears on the motors.
The next thing to do was to test the two servo motors.
This is the code we wrote to test the motors, we fine-tuned the values to have the motors turn to the direction we need it to be.
Using the same setup as the Sweep servo example which can be found here :http://arduino.cc/it/Tutorial/Sweep
----------------------------------------------------
TestingMotor Code:
#include <Servo.h>
Servo myservoLeft;
Servo myservoRight;
int i;
void setup()
{
myservoLeft.attach(9);
myservoRight.attach(10);
}
void loop()
{
for ( i = 0 ; i < 90 ; i+=10)
{
myservoLeft.write(i);
myservoRight.write(i);
delay(100);
}
for ( i = 90 ; i > 0 ; i-=10)
{
myservoLeft.write(i);
myservoRight.write(i);
delay(100);
}
{
for ( i = 90 ; i < 180 ; i+=10)
{
myservoLeft.write(i);
myservoRight.write(i);
delay(100);
}
for ( i = 180 ; i > 90 ; i-=10)
{
myservoLeft.write(i);
myservoRight.write(i);
delay(100);
}
}
}
----------------------------------------------------------------------------
Step 3: Prototype
Once the motors were up and moving, we placed the motors on the hairband , arranging it to the perfect spot! Using lots of Blue-Tack and masking tape to hold everything in place.
Step 4: Testing of Accelerometer
Now, the most difficult part, testing of the accelerometer.This was the first time we were working with accelerometers hence the tremendous amount of time spent experimenting and trying to understand the values.
We found a great website that helped provide us with a basic understanding of accelerometers as well as a great code.
http://bildr.org/2011/04/sensing-orientation-with-the-adxl335-arduino/
This is the code they provided and what we used.
=================================================
//////////////////////////////////////////////////////////////////
//©2011 bildr
//Released under the MIT License - Please reuse change and share
//Simple code for the ADXL335, prints calculated orientation via serial
//////////////////////////////////////////////////////////////////
//Analog read pins
const int xPin = 0;
const int yPin = 1;
const int zPin = 2;
//The minimum and maximum values that came from
//the accelerometer while standing still
//You very well may need to change these
int minVal = 265;
int maxVal = 402;
//to hold the caculated values
double x;
double y;
double z;
void setup(){
Serial.begin(9600);
}
void loop(){
//read the analog values from the accelerometer
int xRead = analogRead(xPin);
int yRead = analogRead(yPin);
int zRead = analogRead(zPin);
//convert read values to degrees -90 to 90 - Needed for atan2
int xAng = map(xRead, minVal, maxVal, -90, 90);
int yAng = map(yRead, minVal, maxVal, -90, 90);
int zAng = map(zRead, minVal, maxVal, -90, 90);
//Caculate 360deg values like so: atan2(-yAng, -zAng)
//atan2 outputs the value of -π to π (radians)
//We are then converting the radians to degrees
x = RAD_TO_DEG * (atan2(-yAng, -zAng) + PI);
y = RAD_TO_DEG * (atan2(-xAng, -zAng) + PI);
z = RAD_TO_DEG * (atan2(-yAng, -xAng) + PI);
//Output the caculations
Serial.print("x: ");
Serial.print(x);
Serial.print(" | y: ");
Serial.print(y);
Serial.print(" | z: ");
Serial.println(z);
delay(100);//just here to slow down the serial output - Easier to read
=======================================================
We found a great website that helped provide us with a basic understanding of accelerometers as well as a great code.
http://bildr.org/2011/04/sensing-orientation-with-the-adxl335-arduino/
This is the code they provided and what we used.
=================================================
//////////////////////////////////////////////////////////////////
//©2011 bildr
//Released under the MIT License - Please reuse change and share
//Simple code for the ADXL335, prints calculated orientation via serial
//////////////////////////////////////////////////////////////////
//Analog read pins
const int xPin = 0;
const int yPin = 1;
const int zPin = 2;
//The minimum and maximum values that came from
//the accelerometer while standing still
//You very well may need to change these
int minVal = 265;
int maxVal = 402;
//to hold the caculated values
double x;
double y;
double z;
void setup(){
Serial.begin(9600);
}
void loop(){
//read the analog values from the accelerometer
int xRead = analogRead(xPin);
int yRead = analogRead(yPin);
int zRead = analogRead(zPin);
//convert read values to degrees -90 to 90 - Needed for atan2
int xAng = map(xRead, minVal, maxVal, -90, 90);
int yAng = map(yRead, minVal, maxVal, -90, 90);
int zAng = map(zRead, minVal, maxVal, -90, 90);
//Caculate 360deg values like so: atan2(-yAng, -zAng)
//atan2 outputs the value of -π to π (radians)
//We are then converting the radians to degrees
x = RAD_TO_DEG * (atan2(-yAng, -zAng) + PI);
y = RAD_TO_DEG * (atan2(-xAng, -zAng) + PI);
z = RAD_TO_DEG * (atan2(-yAng, -xAng) + PI);
//Output the caculations
Serial.print("x: ");
Serial.print(x);
Serial.print(" | y: ");
Serial.print(y);
Serial.print(" | z: ");
Serial.println(z);
delay(100);//just here to slow down the serial output - Easier to read
=======================================================
Step 5: Integration of the Servos and Accelerometer and Accelerometer Values
We decided that by mounting the circuits on the cap, we would be able to get the accurate values.
We needed to combine both circuits on a stripboard as small as possible as we wanted to place it between both motors. We connected the output pins of both the servo motors into one pin.
Here is the schematic of the combined circuit.
We took advantage of one the few acrylic boards we found lying around in our FYP lab, using it mount our circuit and motors. Using the glue gun , we glued the motors and circuit board on the acrylic board and the acrylic board on the hair band. Securing the hairband to the cap using cable ties.
Now that the accelerometer is firmly placed, we can get accurate values. Using the accelerometer code from the previous step, here are the values we collected. Wearing the cap,we took note of the values when we turn left, right and the original position.
Here are our findings :
We needed to combine both circuits on a stripboard as small as possible as we wanted to place it between both motors. We connected the output pins of both the servo motors into one pin.
Here is the schematic of the combined circuit.
We took advantage of one the few acrylic boards we found lying around in our FYP lab, using it mount our circuit and motors. Using the glue gun , we glued the motors and circuit board on the acrylic board and the acrylic board on the hair band. Securing the hairband to the cap using cable ties.
Now that the accelerometer is firmly placed, we can get accurate values. Using the accelerometer code from the previous step, here are the values we collected. Wearing the cap,we took note of the values when we turn left, right and the original position.
Here are our findings :
Step 6: Final Step
We combined both the servo code and accelerometer code. From the values we found earlier , we added it to the code to make the motors turn at the correct value.
The values are not very accurate. We found it difficult to pinpoint an exact value,it still isn't a perfect set of "ears" as it doesn't turn everytime we turn our heads.
Final code:
===================================================
#include <Servo.h>
int i;
const int xPin = 0;
const int yPin = 1;
const int zPin = 2;
int minVal = 265;
int maxVal = 402;
double x;
double y;
double z;
Servo myservoLeft;
// the setup routine runs once when you press reset:
void setup() {
Serial.begin(9600);
myservoLeft.attach(9);
}
// the loop routine runs over and over again forever:
void loop() {
int xRead = analogRead(xPin);
int yRead = analogRead(yPin);
int zRead = analogRead(zPin);
//convert read values to degrees -90 to 90 - Needed for atan2
int xAng = map(xRead, minVal, maxVal, -90, 90);
int yAng = map(yRead, minVal, maxVal, -90, 90);
int zAng = map(zRead, minVal, maxVal, -90, 90);
//Caculate 360deg values like so: atan2(-yAng, -zAng)
//atan2 outputs the value of -π to π (radians)
//We are then converting the radians to degrees
x = RAD_TO_DEG * (atan2(-yAng, -zAng) + PI);
y = RAD_TO_DEG * (atan2(-xAng, -zAng) + PI);
z = RAD_TO_DEG * (atan2(-yAng, -xAng) + PI);
Serial.print("x: ");
Serial.print(x);
Serial.print(" | y: ");
Serial.print(y);
Serial.print(" | z: ");
Serial.println(z);
delay(100);
if (z >=76){ //right
delay(100);
for ( i = 0 ; i < 90 ; i+=10)
{
myservoLeft.write(i);
delay(100);
}
for ( i = 90 ; i > 0 ; i-=10)
{
myservoLeft.write(i);
delay(100);
}
}
if ( (z >= 50 )&&(z <= 75)){ //middle
myservoLeft.write(60);
delay(100);
}
if ( z <= 49){ //left
delay(100);
for ( i = 90 ; i < 180 ; i+=10)
{
myservoLeft.write(i);
delay(100);
}
for ( i = 180 ; i > 90 ; i-=10)
{
myservoLeft.write(i);
delay(100);
}
}
}
===================================================
It's done!
The values are not very accurate. We found it difficult to pinpoint an exact value,it still isn't a perfect set of "ears" as it doesn't turn everytime we turn our heads.
Final code:
===================================================
#include <Servo.h>
int i;
const int xPin = 0;
const int yPin = 1;
const int zPin = 2;
int minVal = 265;
int maxVal = 402;
double x;
double y;
double z;
Servo myservoLeft;
// the setup routine runs once when you press reset:
void setup() {
Serial.begin(9600);
myservoLeft.attach(9);
}
// the loop routine runs over and over again forever:
void loop() {
int xRead = analogRead(xPin);
int yRead = analogRead(yPin);
int zRead = analogRead(zPin);
//convert read values to degrees -90 to 90 - Needed for atan2
int xAng = map(xRead, minVal, maxVal, -90, 90);
int yAng = map(yRead, minVal, maxVal, -90, 90);
int zAng = map(zRead, minVal, maxVal, -90, 90);
//Caculate 360deg values like so: atan2(-yAng, -zAng)
//atan2 outputs the value of -π to π (radians)
//We are then converting the radians to degrees
x = RAD_TO_DEG * (atan2(-yAng, -zAng) + PI);
y = RAD_TO_DEG * (atan2(-xAng, -zAng) + PI);
z = RAD_TO_DEG * (atan2(-yAng, -xAng) + PI);
Serial.print("x: ");
Serial.print(x);
Serial.print(" | y: ");
Serial.print(y);
Serial.print(" | z: ");
Serial.println(z);
delay(100);
if (z >=76){ //right
delay(100);
for ( i = 0 ; i < 90 ; i+=10)
{
myservoLeft.write(i);
delay(100);
}
for ( i = 90 ; i > 0 ; i-=10)
{
myservoLeft.write(i);
delay(100);
}
}
if ( (z >= 50 )&&(z <= 75)){ //middle
myservoLeft.write(60);
delay(100);
}
if ( z <= 49){ //left
delay(100);
for ( i = 90 ; i < 180 ; i+=10)
{
myservoLeft.write(i);
delay(100);
}
for ( i = 180 ; i > 90 ; i-=10)
{
myservoLeft.write(i);
delay(100);
}
}
}
===================================================
It's done!