Designing and building a clock from scratch
Gears
It took me a while to get my head around the concepts behind making a gear train. During a bout of sleeplessness, I tried to get back to sleep by focusing on gear ratios, and how I could make a gear train. I finally got past my mental block (and got back to sleep), and the next day I diagrammed out a gear train.

In CAD I started to make gears, and tried to mesh them together.

I got the necessary values that I needed for the gears, but after a while, I realized I needed a different way to visualize the overlapping gears because they started running into each other. I made this map in Inkscape:

After a few more iterations, I realized that I needed a spreadsheet to keep track of the gears and their relationships.


I found that I could import a CSV file into Fusion 360, so that made it a lot easier to work on the gear train. After more iterations I came up with a couple of possible plans.

Right now, I’m working on trying to compact the gear train down rather than make it one long line of gears.

Motor
At first I thought I’d use a stepper motor. I got an Arduino and a motor shield and a small stepper motor just to see what it would take. It seemed overly complex, so I started casting around for a simpler solution. I thought I could use a synchronous AC motor that I could just plug into the wall, but I bought one that was supposed to be 1 RPM and it wasn’t even close to 1 RPM when I measured it. So, I went back to the idea of using a stepper motor.
I have a collection of electronic junk, and I found a power supply that has both 12 VDC and 5 VDC output, and enough amperage to power the motor and Arduino. I ordered a DS3231 RTC (real time clock) because I read that the Arduino’s internal time keeping is not really accurate enough for a clock.
Right now I’m working on programming the Arduino to advance the stepper and check the RTC to correct any inaccuracy.
//set Board to Arduino Uno
//set Port to SLAB_USB to UART
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include <arduino-timer.h>
#include "RTClib.h"
RTC_DS3231 rtc;
auto timer = timer_create_default();
// Create the motor shield object with the default I2C address
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
// Connect a stepper motor with 200 steps per revolution (1.8 degree)
// to motor port #2 (M3 and M4)
Adafruit_StepperMotor *myMotor = AFMS.getStepper(200, 2);
long target_minute;
long target_minute_steps;
long target_hour;
long target_hour_steps;
long target_day;
long target_day_steps;
long total_steps = 0L;
long start_steps;
int interval = 150;
bool one_step(void *) {
DateTime now = rtc.now();
myMotor->onestep(FORWARD, INTERLEAVE);
total_steps++;
if (now.unixtime() == target_day) {
target_day = now.unixtime() + 86400L;
target_hour = now.unixtime() + 3600L;
target_minute = now.unixtime() + 60L;
time_check(target_day_steps);
target_day_steps = total_steps + (86400000/interval);
}
if (now.unixtime() == target_hour) {
target_hour = now.unixtime() + 3600L;
target_minute = now.unixtime() + 60L;
time_check(target_hour_steps);
target_hour_steps = total_steps + (3600000/interval);
}
if (now.unixtime() == target_minute) {
target_minute = now.unixtime() + 60L;
time_check(target_minute_steps);
target_minute_steps = total_steps + (60000/interval);
}
return true; // to repeat the action - false to stop
}
void time_check(int expected_steps) {
int x;
int steps;
Serial.println("time check!");
Serial.print("expected ");
Serial.println(expected_steps);
Serial.print("steps ");
Serial.println(total_steps - start_steps);
steps = total_steps - start_steps;
start_steps = total_steps;
if (steps < (expected_steps)) {
for (x = steps; x < (expected_steps); x++) {
myMotor->onestep(FORWARD, INTERLEAVE);
}
}
if (steps > (expected_steps)) {
for (x = steps; x > (expected_steps); x--) {
myMotor->onestep(BACKWARD, INTERLEAVE);
}
}
}
void setup() {
Serial.begin(9600); // set up Serial library at 9600 bps
Wire.begin();
rtc.begin();
AFMS.begin(); // create with the default frequency 1.6KHz
DateTime now = rtc.now();
// following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// call the one_step function every n millis
timer.every(interval, one_step);
target_minute = now.unixtime() + 60L;
target_minute_steps = total_steps + (60000/interval);
target_hour = now.unixtime() + 3600L;
target_hour_steps = total_steps + (3600000/interval);
target_day = now.unixtime() + 86400L;
target_day_steps = total_steps + (86400000/interval);
delay(3500);
}
void loop() {
timer.tick();
}
This is all still a work in progress. 🙂