Cuckoo Clock Design:
Our Halloween-themed cuckoo clock design uses a servo motor, lever and pulley system to lower a drawbridge door revealing the little Frankenstein cuckoo within. In addition, an RGB LED configuration emits an orange glow, and a spooky soundtrack is choreographed to the motion of the door opening.
Videos:
Mechanism video: http://youtu.be/HoQ6tPiJjig
Final video: http://youtu.be/kaBN8YUE9gw
Hardware Materials Used:
Wood Boards, Hinges, Eyelet Screws, Plastic Pillars, Twine, Cardboard, Paint, Duct Tape, Marshmallow Frankenstein, Assorted Candy...
Software Used:
We implemented our clock controller in Java, using Processing's serial library to move the servo. We used the badlogic audio-analysis library (http://code.google.com/p/audio-analysis/) to play a music file. The music is played by a separate thread (MusicPlayerThread.java) so that we can send serial messages while the music is playing. Finally, the Arduino controls the LEDs and door movement.
========
ClockController.java
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileNotFoundException;
import javax.swing.*;
import processing.serial.*;
import threads.MusicPlayerThread;
public class ClockController {
private static String musicFile = "/Users/nick/Documents/Courses/11Fall/I262/Labs/Cuckoo clock/Halloween TUI.mp3";
private static MusicPlayerThread mpt;
private static Serial port;
private static JButton playButton;
public static void createAndShowGUI() {
JFrame frame = new JFrame("Clock controller");
frame.setLayout(new FlowLayout());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton chooseButton = new JButton("Choose music");
chooseButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
}
});
try {
mpt = new MusicPlayerThread(musicFile);
} catch (FileNotFoundException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
} catch (Exception e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
playButton = new JButton("Play music");
playButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if(playButton.getText().equals("Play music")) {
//playButton.setText("Stop music");
// Play music
mpt.start();
// Send serial stuff
try {
Thread.sleep(5800);
port.write('2');
Thread.sleep(11000);
port.write('1');
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
else {
playButton.setText("Play music");
//mpt.cancel(true);
//mpt.interrupt();
//mpt.stop();
//port.write('0');
}
}
});
//frame.add(chooseButton);
frame.add(playButton);
frame.pack();
frame.setVisible(true);
// Initialize serial stuff
String portname = Serial.list()[0];
port = new Serial(portname, 9600);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
MusicPlayerThread.java
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileNotFoundException;
import javax.swing.*;
import processing.serial.*;
import threads.MusicPlayerThread;
public class ClockController {
private static String musicFile = "/Users/nick/Documents/Courses/11Fall/I262/Labs/Cuckoo clock/Halloween TUI.mp3";
private static MusicPlayerThread mpt;
private static Serial port;
private static JButton playButton;
public static void createAndShowGUI() {
JFrame frame = new JFrame("Clock controller");
frame.setLayout(new FlowLayout());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton chooseButton = new JButton("Choose music");
chooseButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
}
});
try {
mpt = new MusicPlayerThread(musicFile);
} catch (FileNotFoundException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
} catch (Exception e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
playButton = new JButton("Play music");
playButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if(playButton.getText().equals("Play music")) {
//playButton.setText("Stop music");
// Play music
mpt.start();
// Send serial stuff
try {
Thread.sleep(5800);
port.write('2');
Thread.sleep(11000);
port.write('1');
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
else {
playButton.setText("Play music");
//mpt.cancel(true);
//mpt.interrupt();
//mpt.stop();
//port.write('0');
}
}
});
//frame.add(chooseButton);
frame.add(playButton);
frame.pack();
frame.setVisible(true);
// Initialize serial stuff
String portname = Serial.list()[0];
port = new Serial(portname, 9600);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
Arduino clock controller:
/*
* INFO262 - Cuckoo Clock controller
*/
// Pin assignments
int doorServo = 7;
int rPin = 10;
int gPin = 9;
int bPin = 11;
int doorTime = 1000; // 1 second
long beginTime = 0;
// General servo variables
long lastPulse = 0; // the time in millisecs of the last pulse
int refreshTime = 20; // the time in millisecs needed in between pulses
int val; // variable used to store data from potentiometer
int openPulse = 520;
int closePulse = 2200;
char serInString[100]; // array that will hold the different bytes of the string. 100=100characters;
// -> you must state how long the array will be else it won't work properly
void setup() {
pinMode(doorServo, OUTPUT);
pinMode(rPin, OUTPUT);
pinMode(gPin, OUTPUT);
pinMode(bPin, OUTPUT);
moveDoor(closePulse);
Serial.begin(9600);
}
void loop() {
readSerialString(serInString);
if(serInString[0] == '1') {
Serial.println("Close door");
analogWrite(rPin,0);
analogWrite(gPin,0);
analogWrite(bPin,0);
moveDoor(closePulse);
} else if(serInString[0] == '2') {
Serial.println("Open door");
analogWrite(rPin,254);
analogWrite(gPin,20);
analogWrite(bPin,0);
moveDoor(openPulse);
}
memset(serInString,0,100);
}
void moveDoor(int pulseWidth) {
beginTime = millis();
while(millis() - beginTime < doorTime) {
updateServo(doorServo, pulseWidth);
}
}
// called every loop().
void updateServo(int pin, int pulseWidth) {
// pulse the servo again if the refresh time (20 ms) has passed:
if (millis() - lastPulse >= refreshTime) {
digitalWrite(pin, HIGH); // Turn the motor on
delayMicroseconds(pulseWidth); // Length of the pulse sets the motor position
digitalWrite(pin, LOW); // Turn the motor off
lastPulse = millis(); // save the time of the last pulse
}
}
//read a string from the serial and store it in an array
//you must supply the array variable
void readSerialString (char *strArray) {
int i = 0;
if(!Serial.available()) {
return;
}
while (Serial.available()) {
strArray[i] = Serial.read();
i++;
}
}