Mesmerizing Magnetic Wall Clock
by tomatoskins in Circuits > Clocks
114406 Views, 1064 Favorites, 0 Comments
Mesmerizing Magnetic Wall Clock
Mechanical clocks have always fascinated me. The way all of the internal gears, springs, and escapements work together to result in a constant reliable timepiece has always seemed out of reach for my limited skill set. Thankfully modern electronics and 3D printed parts can bridge the gap to create something simple that doesn't rely on small precise metallic parts.
This minimalist wall clock hides a pair of 3D printed ring gears driven by inexpensive stepper motors that rotate magnets behind a classic walnut veneer.
Initially inspired by STORY Clock, I wanted a time piece that indicated the time of day using ball bearings only vs the digital readout and slow moving ball bearing their product uses.
Tools and Materials
Materials:
- 13 x 13 x 2 in. Plywood/Particle Board (I glued together 3 pieces of scrap wood)
- 13 x 13 in. Hardboard
- Arduino Nano
- Real Time Clock
- Stepper Motors and Drivers
- Hall Effect Sensors
- Magnets
- Power Cable
- AC Adapter
- Plug
- Assorted Machine Screws
- Assorted Wood Screws
- 3D Printed Parts (Last Step)
- Veneer (12 x 12 in. - face, 40 in. long strip)
- Spray Lacquer
- Black Spray Paint
Tools:
- 3D Printer
- Compass
- X-acto Knife
- Glue
- Clamps
- Circle Cutting Jig
- Hack Saw
- Disc Sander
- Ratchet Clamp
- Chisel
- Ruler
- Sander
- Drills
- Screwdrivers
- Soldering Iron
- Hot Glue Gun
Glue Together Wood Frame
Glue together three pieces of wood that will form the frame of the clock. I used reclaimed particle board from an old bed frame.
Cut Frame Using Circle Cutting Jig
Mark the center of the board and mount to a circle cutting jig. Cut five circles with the following diameters:
- 12 in.
- 11 1/4 in.
- 9 1/4 in.
- 7 1/4 in.
- 5 3/8 in.
Print and Assemble Gears
The ring gears are broken into segments so they can be printed on a small printer and snapped together. All parts were printed in ABS to aid in the fusing process shown in the next step. Sand all edges and surfaces of the parts.
Print the following quantities of parts found in step 22:
- 1 - Hour Ring Gear Segment Magnet
- 6 - Hour Ring Gear Segment Basic
- 1 - Hour Retaining Ring Segment Stepper Mount
- 6 - Hour Retaining Ring Segment Basic
- 1 - Hour Hall Effect Sensor Holder
- 1 - Minute Ring Gear Segment Magnet
- 7 - Minute Ring Gear Segment Basic
- 1 - Minute Retaining Ring Segment Stepper Mount
- 6 - Minute Retaining Ring Segment Basic
- 1 - Minute Hall Effect Sensor Holder
- 2 - Spur Gear
- 1 - Electronics Mount
"Glue" Sections Together
In a glass bottle with some acetone, dissolve failed prints old support material, etc. Paint the acetone mixture on each seam to fuse the pieces together. Once cured, sand each seam flat.
Cut Reliefs in Frame
Place the ring gears and retaining rings in the frame and cut out reliefs for the stepper motors. I measured and cut the inner ring too large so I shimmed it to size using some maple edge banding I had around the shop.
Cut Clearance for Hall Effect Sensors
Cut a clearance hole through the inner ring for the minute hall effect sensor and slot for the hour hall effect sensor. I used a chisel, file, and small hand saw to cut these clearances.
Glue Outer Ring
Glue and tape the outer ring the size of the minute retaining ring.
Cut Hall Effect Sensor Adjustment Screws
Cut machine screws with a hack saw so they are just longer than the thickness of the retaining ring and hall effect sensor holder. Cut a slot in the threads so it can be adjusted from the threaded end with a flat screwdriver.
Glue Rings to Hardboard
Cut a circle of hardboard just larger than the outer ring. Glue outer and inner ring to hardboard face. Use the minute retaining ring and ring gear to place the inner ring. Pay better attention than I did to not glue the inner ring on backwards. Image two shows a new slot cut for minute hall effect sensor.
Use a disc sander to trim the hardboard down to the size of the outer ring.
Glue Inner Disc
Glue inner disc in place using the hour retaining ring and ring gear to place the inner disc.
Attach Veneer
Cut a strip of veneer wider than the clock is deep and long enough to wrap around the clock (3.14 * diameter of the clock, will return the length needed. Add an inch to be sure that you have enough.) Dry fit the veneer to cut to length. Applying ample glue to the veneer and clamp in place with a strap clamp. Let dry a couple hours to ensure adhesion.
Trim Veneer
Using a sharp chisel, trim the excess veneer from the front and back of the clock.
Cut Veneer
My veneer had some cracks in it. To make it easier to work with, I applied painters tape to hold it together. Using an x-acto knife in a compass, cut the veneer just larger than the face of the clock.
Glue Veneer
Use the off cut rings to spread out the pressure across the face of the clock. Apply ample glue to the non tape side of the veneer. Orient the grain vertically on the clock face and apply many clamps tightening each one a little at a time. This will ensure the veneer doesn't shift and has even pressure across the face.
I used a couple flat boards on the face side of the clock and some cauls on the back.
Sand and Finish
Using sandpaper, carefully remove the excess veneer from the face of the clock and sand starting at 220 grit up to 600 grit.
Apply between 10 and 20 coats of lacquer. This will build up the surface that the ball bearing will ride along. Inevitably due to dust and other particles in the air, I think that lines will appear along the path of each ball bearing. Applying more coats of finish should delay this as long as possible. It will also make future refinishing easier. I will update this step if lines ever appear on my clock.
Install Power
Using a 27/64 in. drill bit, drill a hole in the bottom of the clock and screw the power plug in place.
Assemble Electronics
Attach stepper drivers and real time clock to the electronic board. I needed to find a way to secure the Arduino so holes were drilled and a slot was cut for a zip tie. These features have been added to the file found in step 22.
Solder and Connect Electronics
Following the block diagram, solder all components together. Hot glue the rings in place and secure any stray wires with hot glue as well.
Back Plate
Create the back plate by cutting another circle 1/2 in. larger than the face of the clock and a ring with the inner diameter the same as the back of the clock. Glue the ring and circle together with some spring clamps.
Once dry, scribe a line 1/8 in. larger than the inner ring and trim to size using the band saw or disc sander.
Cut a slot 1 in. long 1/4 in. wide at the top of the back using a router or drill bits. Countersink four holes to secure the back into the frame of the clock.
Apply black spray paint and attach to the clock once dry.
Arduino Code
The arduino code is commented as well as possible. Keep in mind that I'm not a programmer, I have minimal arduino experience (be kind). The code runs continually checking to see if the current time matches the "Reset Time". Because I couldn't think of a way to translate the current time into steps, it only corrects itself once daily (midnight by default). At midnight the gears rotate to the midnight position then wait until 00:01 moving to that time then continues from there. As it currently sits, the clock only loses about 5 seconds over a 24 hour period.
You will need the Stepper and RTClib libraries installed.
I know the code can be optimized by someone with more experience than myself. If you are up to the challenge, please recreate this project for yourself and share your knowledge.
#include <Stepper.h> #include "RTClib.h" RTC_DS1307 rtc; #define oneRotation 2038 // the number of steps in one revolution of 28BYJ-48 stepper motor Stepper hourHand(oneRotation, 3, 5, 4, 6); Stepper minuteHand(oneRotation, 7, 9, 8, 10); #define hourStopSensor 12 #define minuteStopSensor 11 int endStep = 0; // Time dealy for speed of the clock. int setDelay1 = 168; int setDelay2 = 166; int setDelay3 = 5; // Current time to do math with. float hr = 0; float mn = 0; float sc = 0; // Set the time of day to reset clock (24 hour format). int resetHour = 0; int resetMinute = 0; // Variables to set correct time at startup and reset. float setTimeStepHour = 0; float setTimeStepMinute = 0; float handDelay = 0; float hourTest = 0; float minuteTest = 0; void setup() { Serial.begin(115200); // Setup real time clock and reset hall effect sensors. pinMode(hourStopSensor, INPUT_PULLUP); pinMode(minuteStopSensor, INPUT_PULLUP); rtc.begin(); // Uncomment line below to set time. // rtc.adjust(DateTime(2020, 2, 19, 23, 40, 30)); // rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // Set top speed of stepper motors. hourHand.setSpeed(15); minuteHand.setSpeed(15); // Loop until minute and hour hand are at noon while (digitalRead(hourStopSensor) == LOW || digitalRead(minuteStopSensor) == LOW) { if (digitalRead(hourStopSensor) == LOW ) { hourHand.step(2); } else { delay(3); } if (digitalRead(minuteStopSensor) == LOW) { minuteHand.step(3); } else { delay(4); } } while (digitalRead(hourStopSensor) != LOW || digitalRead(minuteStopSensor) != LOW) { if (digitalRead(hourStopSensor) != LOW ) { hourHand.step(2); } else { delay(3); } if (digitalRead(minuteStopSensor) != LOW) { minuteHand.step(3); } else { delay(4); } } // Get current time DateTime now = rtc.now(); hr = now.hour(); mn = now.minute(); sc = now.second(); // Change to 12 hour format if (hr >= 12) { hr = hr - 12; } // See what hand must travel across the face further and use that distance // to adjust set time accordingly. hourTest = hr / 12; minuteTest = mn / 60; if (hourTest > minuteTest) { handDelay = hourTest; } else { handDelay = minuteTest; } // Set current hour setTimeStepHour = (hr * 498) + (mn * 8.3) + ((sc + (handDelay * 36)) * .1383); // Set current minute setTimeStepMinute = (mn * 114) + ((sc + (handDelay * 45)) * 1.9); // Test which hand will need more steps and set that to the longest step count for the for loop. if (setTimeStepHour > setTimeStepMinute) { endStep = setTimeStepHour; } else { endStep = setTimeStepMinute; } for (int i = 0; i <= endStep; i++) { if (i < setTimeStepHour) { hourHand.step(2); } else { delay(3); } if (i < setTimeStepMinute) { minuteHand.step(3); } else { delay(4); } } // Set clock running RPM hourHand.setSpeed(1); minuteHand.setSpeed(1); } void loop() { // Start clock running loop. for (int i = 0; i < 22; i++) { minuteHand.step(1); delay(setDelay1); // Test for reset time, if ready to be reset, break. if (rtc.now().hour() == resetHour && rtc.now().minute() == resetMinute) { break; } } delay(setDelay3); for (int i = 0; i < 38; i++) { hourHand.step(1); delay(setDelay1); // Test for reset time, if ready to be reset, break. if (rtc.now().hour() == resetHour && rtc.now().minute() == resetMinute) { break; } for (int i = 0; i < 20; i++) { minuteHand.step(1); delay(setDelay2); // Test for reset time, if ready to be reset, break. if (rtc.now().hour() == resetHour && rtc.now().minute() == resetMinute) { break; } } } // Reset clock at reset time if (rtc.now().hour() == resetHour && rtc.now().minute() == resetMinute) { // Change speed of clock hourHand.setSpeed(10); minuteHand.setSpeed(10); // Loop till minute and hour hand reach noon. while (digitalRead(hourStopSensor) == LOW || digitalRead(minuteStopSensor) == LOW) { if (digitalRead(hourStopSensor) == LOW ) { hourHand.step(2); } else { delay(3); } if (digitalRead(minuteStopSensor) == LOW) { minuteHand.step(3); } else { delay(4); } } while (digitalRead(hourStopSensor) != LOW || digitalRead(minuteStopSensor) != LOW) { if (digitalRead(hourStopSensor) != LOW ) { hourHand.step(2); } else { delay(3); } if (digitalRead(minuteStopSensor) != LOW) { minuteHand.step(3); } else { delay(4); } } // Wait here until the reset time has passed. while (rtc.now().minute() == resetMinute) { delay(1000); } // Get current time DateTime now = rtc.now(); hr = now.hour(); mn = now.minute(); sc = now.second(); // Change to 12 hour format if (hr >= 12) { hr = hr - 12; } // See what hand must travel across the face further and use that distance // to adjust set time accordingly. hourTest = hr / 12; minuteTest = mn / 60; if (hourTest > minuteTest) { handDelay = hourTest; } else { handDelay = minuteTest; } // Set current hour setTimeStepHour = (hr * 498) + (mn * 8.3) + ((sc + (handDelay * 36)) * .1383); // Set current minute setTimeStepMinute = (mn * 114) + ((sc + (handDelay * 45)) * 1.9); // Test which hand will need more steps and set that to the longest step count for the for loop. if (setTimeStepHour > setTimeStepMinute) { endStep = setTimeStepHour; } else { endStep = setTimeStepMinute; } for (int i = 0; i <= endStep; i++) { if (i < setTimeStepHour) { hourHand.step(2); } else { delay(3); } if (i < setTimeStepMinute) { minuteHand.step(3); } else { delay(4); } } hourHand.setSpeed(1); minuteHand.setSpeed(1); } }
Downloads
STL Files
You will need to print the following quantities of the files:
- 1 - Hour Ring Gear Segment Magnet
- 6 - Hour Ring Gear Segment Basic
- 1 - Hour Retaining Ring Segment Stepper Mount
- 6 - Hour Retaining Ring Segment Basic
- 1 - Hour Hall Effect Sensor Holder
- 1 - Minute Ring Gear Segment Magnet
- 7 - Minute Ring Gear Segment Basic
- 1 - Minute Retaining Ring Segment Stepper Mount
- 6 - Minute Retaining Ring Segment Basic
- 1 - Minute Hall Effect Sensor Holder
- 2 - Spur Gear
- 1 - Electronics Mount
Downloads
Solidworks Files
These are the original Solidworks files used to create the STLs found in the previous step. Feel free to edit and change my files as you see fit.
Downloads
Conclusion
This clock turned out better than I had anticipated. Having minimal Arduino experience, I'm glad with how it turned out and how accurate it is. It looks great and functions just as I'd hoped.