How to Make a Musical, Motorized Glow-in-the-dark-ghost Mobile
by ridiculously.awesome in Workshop > 3D Printing
10067 Views, 47 Favorites, 0 Comments
How to Make a Musical, Motorized Glow-in-the-dark-ghost Mobile
The original plan was based on just this simple design, but my over caffeinated imagination couldn't stop there. It decided to go high-tech on this one. Added to the design was a motor to turn the mobile, a light to charge the glowing material and some additional components to trigger some action. The cherry on the cake is to synchronize this behavior with a spooky sound track.
This instructable will walk you through all of the steps to replicate the entire project. However, you can alway stop at any step from just printing off a ghost, to just building the mobile or taking it all the way to the end.
Tools and Materials
Tools:
3D Printer
3D CAD Program (I'm using AutoDesk Inventor)
Exacto Knife
Small Drill Bit and Drill
Wire Cutters
Needle Nose Pliers
Pen (for writing labels)
Digital Scale
Arduino SDK
Materials:
Glow-in-the-dark Printing Material (glowing ABS filament is available at amazon.com)
Sturdy Wire (you can use an old wire coat hanger, I'm using 1mm SS welding rod)
Small Hook (for hanging the mobile)
Masking Tape (for temporary labels)
Various Jumpers/Wires
Electronics:
Arduino Board
IR remote kit
IR LED
Stepper Motor and Controller
Remote Controlled CD Player with Spooky Sound Track CD
Sketching Out the Design
The original scale of this concept was to just design a glow-in-the-dark ghost. My over-caffeinated mind took this idea and ran with it. "Why stop there?" it said, "Many cute ghosts are better than just one! And why not make them fly?" So the idea of creating a mobile to make the glowing ghosts fly came to be; which led to the idea of motorizing the mobile; which led to the idea of using a beam-breaking detection circuit to start the motor; which led to the the idea of using a light to "charge" the glow effect that would turn off when the beam was broken; which led to the idea of adding a spooky sound-track that would start playing when this happened. And who am I to ignore myself?
The point of all of this is that putting your thoughts down on paper can lead to a much more interesting design than just jumping straight into making something. If you don't already do this, give it a try on your next project.
Now that the basic design is completed we can start making something!
Roughing Out the Ghost Body
Next create a work suface that is aligned with the vertical extrusion and the x,y plane. Draw a circle ~3/4" in diameter located at the top edge of the extrusion. Make sure that the circle is a little off center--you will see why in the following steps.
Now, using the spline tool create a moderately squiggly line that extends tangentially from the circle you drew down to the bottom corner of the furthest edge of the extrusion.
Draw a line that extends perdendicular from the top edge of the extrusion, through the center point of the circle and down to the bottom edge of the extrusion.
Next draw a line connecting the bottom point of the line you just drew to the bottom point of the spline you drew. This last line will create a closed shape that will be the profile of a revolving cut procedure to create the ghosts shape.
Trim away the remaing line segments we will not use for this profile.
A rotational cut of this profile should now be performed using the vertical line as the rotational axis and the "outside" shape as the face. You want to have a "lopsided" revolve such that there is a long flat region on one side of the extrusion. The illustration shows this more clearly. If this area is too small adjust the sketch that formed the template for the revolve operation to one side to increase this area.
Creating a Hollow Shell
After selecting the face and executing the shell operation your model should look something like this.
Making the Eyes and Mouth
Now create a new sketch with three ovals for the eyes and mouth. The mouth oval should be slightly larger than the eyes.
Now perform a cut extrusion that goes completely through one side of the ghost body but not through the back side of the form.
Smoothing the Edges Over
Select each edge one at a time and adjust the diameter of the fillet until there is a smooth transition. Make sure you do this for all portions of the model that have an abrubt transition or hard edge. The following images show where my model was smoothed out.
Adding Arms to Our Ghost
Now create a work plane based on the "Tangent to Surface Through Point" method. Select the model near the point you created followed by the point itself.
Create a new sketch on this work plane and draw a small circle on the body just below the center of the mouth.
Now extrude this circle so that it connects with the model and extends out from the model a little bit.
Repeat this process for the other side.
Finally smooth the joints where the arms meet the body using a fillet process and round out the "hands" using the same tool.
You now have your finished ghost!!!
Printing the Ghosts
Open the STL file you just saved in the printing program you are using (in my case the UP! 3D application) and place the model on the platform. Adjust the size of the model to a size of your preference.
For the UP! 3D printer I like to always perform a print preview before actually printing. This will tell you about how long the printing process will take as well as approximately how much material it will use up. After this completes configure the printer to print at high quality and kick off the actual printing process. Now sit back and watch the magic happen....
For the mobile you will need to print multiple copies of the model. For my project I've chosen to use 7 copies with slightly adjusted sizes for each copy. Some were printed skinny and tall, some short and fat and as well as other variations. You can do this with the UP! 3D printing software by first selecting the model and then using the scaling icon to selectively "stretch" each dimension by an appropriate amount.
Have some patients as it will take a number of hours to print them all of the ghosts. I had to spread the printing process over a few days to print all seven ghosts. With the UP! 3D it should take between 30 minutes to 2 hours depending on small or large each ghost is.
Drilling Holes in the Ghosts' Heads
How Much Does a Spirit Weigh?
As an example, if you have two ghosts--one weighing 3 grams and another weighing 9 grams--you will need to place the 3 gram ghost thrice as far from the fulcrum as the 9 gram ghost to balance this group. Each additional ghost added to a side will add to the equation. Example 2: 5g ghost at 5 inches plus 1g ghost at 15 inches will balance with a 4g ghost at 10 inches (5*5 + 1*15 == 4*10)
To figure out where the balance point is for each fulcrum will be you must first weigh each ghost. Since each model is slightly different in size each will be slightly different in weight. Measure and write the weight of each model on a piece of tape and stick this lable to each model. It does not need to be exact, just approximate to help when assembling the different groups of ghosts and their relative position with resect to their shared fulcrum.
Attaching Fasteners to the Ghosts
Once you have finished making a complete set you will use the needle nose pliers to hold the looped end of the fastener and feed it through the hole that was drilled through the hop of the head.
Now, use the same technique to bend another loop at the outside end of the fastener.
Now repeat for all of the remaining ghosts until they are all equipped with fasteners.
Placing the Ghosts
Start with the bottom tiers as you will need to take the total weight of each tier into account when balancing the tiers that they are attached to above. Once you have defined the groupings and approximate placement figure out where you want the fulcrum in the tier above it and add any additional ghosts that may be needed to balance out this level.
Remember that the total mass of a tier is what will be taken into account for the applied weight on the tier it is attached to. Include this in your sketch and it will help you to estimate where you can add weight to balance out the design.
For my design I stayed with a simple three tier design, but you can apply this process to as many tiers as you like.
Once you have the basic layout begin constructing each layer by bending small "gaps" on the lever where the inside and outside ghosts should be. Then place the ghosts in their position and add a third ghost in the approximate location you mapped out. Shift this ghost around a little until the whole tier balances perfectly around the fulcrum. Do this by adding a "bump" where the fulcrum should be and then support it with a vertical length of wire with a bend at the end. And one last bend where the middle ghost should be for perfect balance. Complete this for all of the tiers and assemble the mobile.
Adding the Motor
I did this in inventor and then printed out the piece. It fits perfectly and will do the job just fine.
You can see the gist of the design here. After printing it out I found that it popped right onto the axle with a snug fit. I added some through-holes to the opposite end where you will attach the mobile hanger.
After printing out the part you are ready to go mechanically, but you will still need something to hold the motor and need to program the Arduino to control the motion of the mobile. Since there are other items that will also interface with the Arduino we will cover all of this in one section near the end of the instructable.
Build a Haunted Housing for the Motor
The instructions to make this housing are very high level and will not go in to details--this will be described in greater detail in a future instructable. Feel free to use the attached STL files to print out a facsimile of my design, assuming you are using the same motor/controller combination.
I first designed the bottom half of the motor housing with mounting holes and an opening to accomodate the motor and the coupler that was designed earlier. There was also an opening to accomodate the chasis of the motor where the wire protruded.
Then I built the top half to house the stepper motor controller also with holes for mounting the board. A small opening a couple millimeters wide was added to allow the wires that will provide the control signals to exit the housing. At the top of this half a small eyelet was added to allow the housing to hang from a hook or chain.
Usign the STL files I printed out the housing and found that the motor and control board fit perfectly snug within the housing.
Clean up the printed object by removing the support material and insert the components into the appropriate half of the housing.
Now connect the stepper motor wires to the control board. Wrap the extra wire around and tuck them in so they stay within the housing.
Connect the power cables being careful not to connect them the wrong way! Then connect the data cable, again being careful to remember which wires map to which input pin on the controller.
Finally feed the controll and power wires through the narrow opening and close up the housing. You can design tabs to create a mechanical linkage between the top and bottom halves, however in my first attempt I designed these tabs to be to small to have sufficient durability and ended up removing them. In a rev 2 of this project I would redesign these to be about 3x the size of the originals. For now i'm just using masking tape to hold the two sides together.
The last thing I did was to print out a 4 AAA battery holder from thingiverse and attached it with tape to the housing. 4 AAA batteries in series will deliver 6V to the stepper motor providing sufficient power and elliminating the need to route power along with the data cables. This model was graciously provided by member obijaun of thingiverse--thanks!
Adding the Audio
First setup the IR receiver by following the instructions provided at Ken Shirriff's blog. Using the IRrecord example provided in the library point the remote control at the IR receiver and press the button corresponding to the signal you want to capture. The two buttons I used were "play" and "skip". You will need to have the serial monitor in the Arduino SDK up in order to read the code. Write these codes down and save them for the next step.
Now that you have the codes captured for the functions you wish to use we want to install an IR LED to the system that will be used to control the CD player.
Tying It All Together With an Arduino
-
Controls the stepper motor to rotate the ghost mobile
- Rotates in a sinusoidal pattern to make them look more "autonomous"
- Rotates for 10 seconds (aligned perfectly with the audio)
-
Converts IR codes from the remote control that came with the IR remote kit into the correct IR codes for the Kenwood CD player
- Provides an IR read function to capture and display the exact IR code data from the original remote
- Contains a hard-coded list of button press codes for use in translating the remote button pushes
- Sends the appropriate IR code based on the key press on the new remote
- Sends "Pause" and "Skip" codes 10 seconds after the play button is pushed
- The code also sends some debug messages to the serial port console in case you are interested in the details under the hood while it is running.
Originally I was planning to also control lighting to turn the lights off when a motion sensor was tripped. Unfortunately I broke the hardware I was using and did not have the time to replace it so the system will be controlled entirely by the remote control.
The following list maps the Arduino Mego 2560 board pins to the respective component:
- Status LED: PWM Pin 13
- IR Receiver Data Input: PWM Pin 11
- IR Emitter to CD Player: PWM Pin 8
- Stepper Motor Control Signals: PWM Pins 4, 5, 6 and 7
- Grounds routed to appropriate pins as necessary
Two existing pieces of code were used and heavily modified. These include the IRremote library provided by Ken Shirriff and the stepper motor sample code included in the Arduino SDK. And at last, here is the code (which leveraged and credited previous works):
/////////////////////////////////////////////////////////////////////////////////////////
/*
Stepper Motor Control - sinusoidal rotation
This program drives a unipolar or bipolar stepper motor.
The motor is attached to digital pins 4 - 7 of the Arduino.
The motor should revolve one direction
following a sinusoidal rate of rotation.
The program also allows the user to remotely activate and deactivate the
glowing ghost mobile of doom. It sends control signals to the mobile for 10
during which time the audio from the disk in the CD player will play 10
seconds of audio. After 10 seconds the code will send the pause and skip
command to go to the next track.
Created on Nov. 4th, 2012
(Some parts based on Stepper Motor Control program by Tom Igoe
Created 11 Mar. 2007
Modified 30 Nov. 2009)
(Some parts based on IRrecord program by Ken Shirriff
Created September, 2009)
*/
#define PAUSE_PLAY_BUTTON 0x6D92C837
#define REPEAT_BUTTON 0x6D929867
#define SKIP_BUTTON 0x6D92E817
#define POWER 0x00FFA25D
#define BUTTON_MODE 0x00FF629D
#define BUTTON_PAUSE_PLAY 0x00FF22DD
#define BUTTON_SKIP 0x00FFC23D
#define BUTTON_0 0x00FF6897
#define BUTTON_1 0x00FF30CF
#define BUTTON_2 0x00FF18E7
#define BUTTON_3 0x00FF7A85
#define BUTTON_4 0x00FF10EF
#define BUTTON_5 0x00FF38C7
#define BUTTON_6 0x00FF5AA5
#define BUTTON_7 0x00FF42BD
#define BUTTON_8 0x00FF4AB5
#define BUTTON_9 0x00FF52AD
#include <Stepper.h>
#include <IRremote.h>
int RECV_PIN = 11;
int BUTTON_PIN = 12;
int STATUS_PIN = 13;
IRrecv irrecv(RECV_PIN);
IRsend irsend;
decode_results results;
int step_enabled = LOW;
const int stepsPerRevolution = 2048; // change this to fit the number of steps per revolution for your motor
const float max_speed = 10; //sets the maximum rotational speed of the motor
const float resolution = 100; //sets the frequency by which the motor speed will change
float rotational_vel = 0; //holds the current rotational velocity scalar
// initialize the stepper library on pins 8 through 11:
Stepper myStepper(stepsPerRevolution, 4,5,6,7);
void setup() {
// initialize the serial port:
Serial.begin(9600);
irrecv.enableIRIn(); // Start the receiver
pinMode(BUTTON_PIN, INPUT);
pinMode(STATUS_PIN, OUTPUT);
}
// Storage for the recorded code
int codeType = NEC; // The type of code
unsigned long codeValue = 0x6D92C837; // The code value if not raw
int codeLen = 32; // The length of the code
int toggle = 0; // The RC5/6 toggle state
int buttonState = LOW; //virtual button press
// Stores the code for later playback
// Most of this code is just logging
void storeCode(decode_results *results)
{
codeType = results->decode_type;
int count = results->rawlen;
if (results->value == REPEAT)
{
// Don't record a NEC repeat value as that's useless.
Serial.println("repeat; ignoring.");
buttonState = LOW;
return;
}
Serial.print("storing code: ");
Serial.print(results->value, HEX);
codeValue = results->value;
codeLen = results->bits;
Serial.print("; code length: ");
Serial.println(codeLen);
buttonState = HIGH;
}
void sendCode(int repeat) {
if (repeat)
{
irsend.sendNEC(REPEAT, codeLen);
Serial.println("Sent NEC repeat");
buttonState = LOW; //turn off virtual button after sending code
}
else
{
Serial.println("Sending non-repeat code.");
switch (codeValue) {
case POWER:
irsend.sendNEC(PAUSE_PLAY_BUTTON, 32);
codeValue = PAUSE_PLAY_BUTTON;
Serial.print("Sent pause play code: ");
Serial.println(PAUSE_PLAY_BUTTON, HEX);
buttonState = LOW; //turn off virtual button after sending code
break;
case BUTTON_PAUSE_PLAY:
irsend.sendNEC(PAUSE_PLAY_BUTTON, 32);
Serial.print("Sent pause play code: ");
Serial.println(PAUSE_PLAY_BUTTON, HEX);
buttonState = LOW; //turn off virtual button after sending code
break;
case BUTTON_MODE:
irsend.sendNEC(REPEAT_BUTTON, 32);
Serial.print("Sent repeat code: ");
Serial.println(REPEAT_BUTTON, HEX);
buttonState = LOW; //turn off virtual button after sending code
break;
case BUTTON_SKIP:
irsend.sendNEC(SKIP_BUTTON, 32);
Serial.print("Sent skip code: ");
Serial.println(SKIP_BUTTON, HEX);
buttonState = LOW; //turn off virtual button after sending code
break;
}
}
}
int lastButtonState = LOW;
int i = 1;
void loop() {
if (i > resolution)
{
i = 1;
}
// If button pressed, send the code.
//buttonState = digitalRead(BUTTON_PIN);
if (lastButtonState == HIGH && buttonState == LOW) {
Serial.println("Released");
lastButtonState = LOW;
irrecv.enableIRIn(); // Re-enable receiver
}
if (buttonState) {
Serial.println("Sending IR code");
digitalWrite(STATUS_PIN, HIGH);
sendCode(lastButtonState == buttonState);
digitalWrite(STATUS_PIN, LOW);
step_enabled = HIGH;
lastButtonState = HIGH;
//delay(50); // Wait a bit between retransmissions
}
else if (irrecv.decode(&results)) {
Serial.println("Reading IR code");
digitalWrite(STATUS_PIN, HIGH);
storeCode(&results);
irrecv.resume(); // resume receiver
digitalWrite(STATUS_PIN, LOW);
}
//Serial.println("rotate the motor");
rotational_vel = abs(max_speed * sin(float(i)*3.14159/10) + 2); //program a sinusoidal velocity for the stepper motor
myStepper.setSpeed(rotational_vel);
if (abs(rotational_vel) > 0.001 && step_enabled == HIGH) //a velocity of 0 will lock up the stepper.h library.
{
Serial.println("valid stepper function entry");
if (i < resolution && step_enabled == HIGH)
{
Serial.print("iteration: ");
Serial.println(i);
Serial.print("Velocity: ");
Serial.println(rotational_vel);
myStepper.step(10 * rotational_vel);
i++;
}
else
{
step_enabled = LOW;
i = 0;
Serial.println("Pausing Playback and Skipping");
digitalWrite(STATUS_PIN, HIGH);
codeValue = BUTTON_PAUSE_PLAY;
sendCode(1 == 2);
delay(100); //Wait between transmissions
codeValue = BUTTON_SKIP;
sendCode(1 == 2);
digitalWrite(STATUS_PIN, LOW);
lastButtonState = HIGH;
}
}
}
Showtime!
As you may recall in the original design, I wanted to make this motion activated and also control the lights to turn off. I had to pull this feature at the last minute, but will continue on a second rev (when I have the time) to implement this feature. We are all familliar with dead lines and I really wanted to get this one in for the Halloween contest.
Thanks for making it to the end and please let me know if you make something similar or have suggestions for the future.