Orbit - World's First Orbital Clock. Fully Customizable

by Anton_F in Circuits > Clocks

414 Views, 4 Favorites, 0 Comments

Orbit - World's First Orbital Clock. Fully Customizable

ClockRunningDemo-ezgif.com-video-to-gif-converter.gif
WhatsApp Image 2025-12-01 at 09.57.56 (3).jpeg
ezgif.com-animated-gif-maker.gif
Screenshot 2025-12-01 104800.png
ClockRunningDemo-ezgif.com-video-to-gif-converter.gif

What if a clock would not only be a tool to track time, but also a medium that inspires people for something greater than one self?


With this clock design, I aim to inspire the observer to reach for the stars and wonder about the beauty of the universe. Be it our solar system, a star and its planet trapped in the orbit of a black hole, or the never ending birth and destruction of Cixin Liu´s Trisolarian civilization.


Create and customize this clock and tell your own story!


Supplies

Screenshot 2025-12-01 105156.png

This project ended up to be way more complex than I expected. So make sure to have a lot of patience in your toolbox!

What you need:

  1. For the brain:
  2. ESP32 controller
  3. 0,96 inch OLED Dysplay
  4. 2 x KY-035 Hall Sensor
  5. 2 x 10x3mm Magnets
  6. 2 x 10k Ω Ohm resistor
  7. For the hour hand:
  8. 670:1 Worm geared Nema 17 motor
  9. TMC2209 Stepper driver
  10. Connecting cables for the motor (mostly included with the motor)
  11. 5 mm diameter brass tube, 500mm length
  12. 8x1mm steel tube, 45mm long
  13. 8x1mm steel tube, 30mm long
  14. 2 x 20 tooth GT2 pulley, 8mm inner bore
  15. 6mm, 140mm, 707 tooth GT2 Belt (GT2-6-140-A)
  16. 2 x 8mm skate bearings
  17. 1 x M10 plain washer
  18. For the minute hand:
  19. 28BYJ-48 Stepper Motor + Drive Controller
  20. 8 channel cable
  21. 8 channel slip ring
  22. 3 mm diameter brass tube, 200mm length
  23. Power delivery:
  24. DC-DC Buck Converter 3,2-46V
  25. 5,5mm DC power connector
  26. 12V 2A power supply
  27. Tools & other supplies:
  28. Screwdriver set
  29. Hex screws + nuts from M2 to M4 (get a set, it's easier)
  30. Hot glue
  31. Zip ties (for cable management)
  32. Fire resembling LEDs + flexible LED
  33. Pipe cutting tool
  34. Cordless drill (optional)
  35. Soldering iron + soldering supplies
  36. Shrink tube
  37. Colored cables for soldering everything together
  38. Patience
  39. 3D printer+
  40. Aquarelle colors (cheap ones are enough)
  41. Brushes
  42. 3mm steel rods
  43. 3D printed parts:
  44. Base
  45. Washer adapter
  46. Hour arm coupling
  47. Minute arm coupling
  48. Minute planet coupling
  49. End planet coupling
  50. Planet models
  51. Personal Skills:
  52. Soldering skills
  53. Arduino/ESP + basic electronics and programming knowledge
  54. Painting with aquarelle
  55. 3D printing

How to Read the Clock

Screenshot 2025-12-01 123138.png
clock 12.png
Screenshot 2025-12-01 123545.png
Screenshot 2025-12-01 123314.png
Screenshot 2025-12-01 123408.png
ClockRunningDemo-ezgif.com-video-to-gif-converter.gif

The clock is based on a "piggy bag" principle, where the minute hand is carried on with the hour hand. The movements are continuos, so you wont see the clock making an abrupt movement from one minute to the other.


To read Orbit, you read it as every other normal clock, by first reading the minute hand -which in this case is the moon that orbits around the earth-; then you read the hour - which is the earth rotating around the sun-.


To better understand how to read it, I attached some schematic drawings.

  1. In the first case, we have 12 O´clock, as both the minute and the hour are at position 12
  2. As time passes, the minutes rotate around the hour. In the 2nd picture, we read, in this case 15 minutes past 12
  3. As time passes, both minute and hour move, reaching half past 3 (03:30); a quarter to 7 (06:45); 9 O´clock (09:00).



Preparing for Soldering the Electronics

Screenshot 2025-12-01 132837.png
Screenshot 2025-12-01 133111.png
Screenshot 2025-12-01 132859.png
Screenshot 2025-12-01 132923.png
Screenshot 2025-12-01 133231.png
Screenshot 2025-12-01 133144.png
Screenshot 2025-12-01 133153.png
Screenshot 2025-12-01 132826.png
Screenshot 2025-12-01 132817.png
Screenshot 2025-12-01 132753.png
Screenshot 2025-12-01 132743.png
Screenshot 2025-12-01 132826.png

Before you start connecting everything together, we have to prepare the minute motor for the assembly.

For that:

  1. Insert the 8 channel wire in the 5mm brass tube, with enough wire length looking out from both sides for easier handling when soldering
  2. mount the washer on the base, where the bearings go
  3. mount the bearings on the base. 1 goes all the way to the bottom; the other just on the surface
  4. insert the 8mm 45mm long steel pipe in the bearings
  5. mount the slip ring (it needs 3x M3x10mm screws). Make sure to put the cables of the twisting side through the steel pipe


Soldering

Screenshot 2025-12-01 133101.png
Screenshot 2025-12-01 132725.png
Screenshot 2025-12-01 132743.png
Screenshot 2025-12-01 132753.png
Screenshot 2025-12-01 132956.png
Screenshot 2025-12-01 133239.png
Screenshot 2025-12-01 133202.png
Screenshot 2025-12-01 133120.png
Screenshot 2025-12-01 133051.png
Screenshot 2025-12-01 133211.png
Screenshot 2025-12-01 133034.png
Screenshot 2025-12-01 133025.png
Screenshot 2025-12-01 133007.png
Screenshot 2025-12-01 132826.png
Screenshot 2025-12-01 132932.png
Screenshot 2025-12-01 132817.png
Screenshot 2025-12-01 132802.png
Screenshot 2025-12-01 133358.png
Screenshot 2025-12-01 133408.png

Ok, this is the most difficult task of the entire assembly. But don't worry. It just needs some patience and some soldering. Go slow ad take your time.

Solder the components together like this:


Power and Logic Distribution


  1. Connect the NEMA 17 Driver (TMC2209) VS (or VM) pin to the 12V DC rail from your Power Supply Unit (PSU).
  2. Connect the ESP32 Breakout VCC pin to the 5V DC rail (from your Buck Converter).
  3. Connect the TMC2209 VIO pin to the ESP32 3V3 pin.
  4. Connect the ULN2003 Driver + (VCC) pin directly to the ESP32 3V3 pin. This is essential for the ULN2003 to reliably accept the ESP32's 3.3V logic signals.
  5. Connect the Hall Sensors VCC pin (middle pin) to the ESP32 3V3 pin.
  6. Connect all GND pins (PSU, ESP32, Drivers, Sensors) together to the Common Ground rail.


Signal Wiring (Direct Connections)

  1. Hour Motor (NEMA 17 / TMC2209)
  2. ESP32 GPIO 25 connects to the TMC2209 STEP pin.
  3. ESP32 GPIO 26 connects to the TMC2209 DIR pin.
  4. ESP32 GPIO 27 connects to the TMC2209 EN (Enable) pin.


  1. Minute Motor (28BYJ-48 / ULN2003)
  2. ESP32 GPIO 16 connects to the ULN2003 IN1 pin.
  3. ESP32 GPIO 17 connects to the ULN2003 IN2 pin.
  4. ESP32 GPIO 18 connects to the ULN2003 IN3 pin.
  5. ESP32 GPIO 19 connects to the ULN2003 IN4 pin.


Hall Sensors (End-stops)

  1. ESP32 GPIO 34 (Hour Sensor) connects to the Hour Sensor Signal (S) pin. You must install a 10kΩ Pull-Up Resistor between GPIO 34 and 3V3.
  2. ESP32 GPIO 35 (Minute Sensor) connects to the Minute Sensor Signal (S) pin. You must install a 10kΩ Pull-Up Resistor between GPIO 35 and 3V3.


Motor Connections

  1. NEMA 17 Motor: Connect the two coil pairs to the TMC2209's A1/A2 and B1/B2 terminals.
  2. 28BYJ-48 Motor: Plug the 5-pin connector directly into the ULN2003 driver board's socket.


NOTE: The 28BYJ-48 Motor and 1 Hall Sensor are connected through the slip ring. So make sure to respect the color codes of the cables to keep track of everything.

Assemble the Components on the Base

Screenshot 2025-12-01 132932.png
Screenshot 2025-12-01 133120.png
Screenshot 2025-12-01 132947.png
Screenshot 2025-12-01 132938.png
Screenshot 2025-12-01 133305.png
Screenshot 2025-12-01 133257.png
Screenshot 2025-12-01 133007.png
Screenshot 2025-12-01 133315.png
Screenshot 2025-12-01 133325.png
Screenshot 2025-12-01 133239.png
Screenshot 2025-12-01 133211.png
Screenshot 2025-12-01 133202.png
Screenshot 2025-12-01 133051.png
Screenshot 2025-12-01 133043.png
Screenshot 2025-12-01 133034.png
Screenshot 2025-12-01 133025.png
Screenshot 2025-12-01 132956.png
Screenshot 2025-12-01 133016.png
Screenshot 2025-12-01 133358.png

Once everything is soldered together, you can proceed and assemble everything on the base. (As this task is easier to understand with the pictures, I write up the sequence I used)


NOTE: Soldering and assembly on the base can also be done gradually and fluently. You can also first assemble one component on the base and then solder it. This will eventually help with cable management (not like me, thou)

  1. Start with the DC-DC converter
  2. Mount then the ESP
  3. then the OLED schreen
  4. The TMC2009
  5. The hall sensors (base + minute arm)
  6. The controller for the 28BYJ-48 Motor
  7. The Nema 17 and its drive assembly (see pictures)
  8. Add the coupling for the minute motor. It has openings on the sides, so that you can first solder everything and then assemble. Makes the task of adjusting easier later on
  9. the lights.
  10. the couplings on the minute motor and on the minute arm
  11. Bend the hour and the minute arms in the shape you like and that works for you to make it turn 360°
  12. Glue the magnets on the arms to trigger the hall sensors

Upload the Code

IMG_9689.jpg
IMG_9691.jpg
IMG_9695.jpg
IMG_9694.jpg
IMG_9696.jpg
IMG_9701.jpg
IMG_9703.jpg

Congratulations! You are done with the hard part. Now it´s just a matter of uploading the code and customize your clock!


Before uploading the code, I´ll explain briefly how it works, so that you can understand it:


Step 1: Initialization and Homing


Once you turn on the clock:

  1. The ESP32 starts up and immediately runs the Homing sequence.
  2. Both the NEMA 17 (Hour Hand) and the 28BYJ-48 (Minute Hand) motors move backward until they trigger their respective Hall Sensors.
  3. The moment the sensors are triggered, the clock knows the absolute zero position for both hands.
  4. I installed the hall sensors in such a way, that they point at 12:00. But you can customize that if needed


Step 2: Time Setting


After the hands are homed:

  1. The ESP32 connects to your Wi-Fi network and contacts an NTP server to fetch the current atomic time.
  2. The code calculates the shortest path (in steps) from the zero position to the current time.
  3. Both motors move quickly to the correct current time position.
  4. The ESP32 then disconnects from Wi-Fi to save power.


Step 3: Normal Run Mode


Once the time is set, the clock is running:

  1. The motors receive constant small step commands to track the time.
  2. The clock continues to run without Wi-Fi, relying on the ESP32's internal timer.
  3. Every few hours (e.g., 6 hours), the clock automatically reconnects to Wi-Fi for a moment to resynchronize the time and correct any minor drift, ensuring long-term accuracy.


Step 4: Demo Mode Toggle


  1. Pressing the BOOT button once activates Demo Mode. Both motors start spinning quickly for a fun display.
  2. Pressing the BOOT button a second time immediately stops the demo, forces the clock to re-Home, and then quickly resets the hands to the current, correct time.


The code (just copy and past it):


#include <WiFi.h>

#include <NTPClient.h>

#include <WiFiUdp.h>

#include <AccelStepper.h>


// --- WiFi & Time Settings ---

const char* ssid = "YOUR_WIFI_NETWORK_NAME";

const char* password = "YOUR_WIFI_PASSWORD";

const long utcOffsetInSeconds = 3600; // Germany (CET, UTC+1)


// NTP client setup

WiFiUDP ntpUDP;

NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds);


// --- 1. HOUR HAND (NEMA 17 + TMC2209) ---

#define HOUR_STEP_PIN 25

#define HOUR_DIR_PIN 26

#define HOUR_EN_PIN 27

#define HOUR_SENSOR_PIN 34 // Input-only pin

const long HOUR_HAND_STEPS_PER_REVOLUTION = 1072000; // Calibrate this value

AccelStepper stepperHour(AccelStepper::DRIVER, HOUR_STEP_PIN, HOUR_DIR_PIN);


// --- 2. MINUTE HAND (28BYJ-48 + ULN2003) ---

#define MINUTE_IN1_PIN 16

#define MINUTE_IN2_PIN 17

#define MINUTE_IN3_PIN 18

#define MINUTE_IN4_PIN 19

#define MINUTE_SENSOR_PIN 35 // Input-only pin (requires 10k pull-up)

const long MINUTE_HAND_STEPS_PER_REVOLUTION = 2038; // Calibrate this value


// Manual Stepper Variables

long minute_target_steps = 0;

long minute_current_position = 0;

int minute_step_number = 0;

// Speed control for manual motor

const int MIN_STEP_DELAY_MICROS = 1200;

unsigned long lastStepTime = 0;


// Task handle and Demo Mode Flag

TaskHandle_t MotorControlTask;

volatile bool demoModeActive = false;


// --- Manual 8-Step Logic (Your Working Code) ---

void stepMinuteMotor(bool forward) {

if (forward) {

minute_step_number++;

if (minute_step_number == 8) { minute_step_number = 0; }

} else {

minute_step_number--;

if (minute_step_number < 0) { minute_step_number = 7; }

}


switch (minute_step_number) {

case 0: digitalWrite(MINUTE_IN1_PIN, HIGH); digitalWrite(MINUTE_IN2_PIN, LOW); digitalWrite(MINUTE_IN3_PIN, LOW); digitalWrite(MINUTE_IN4_PIN, LOW); break;

case 1: digitalWrite(MINUTE_IN1_PIN, HIGH); digitalWrite(MINUTE_IN2_PIN, HIGH); digitalWrite(MINUTE_IN3_PIN, LOW); digitalWrite(MINUTE_IN4_PIN, LOW); break;

case 2: digitalWrite(MINUTE_IN1_PIN, LOW); digitalWrite(MINUTE_IN2_PIN, HIGH); digitalWrite(MINUTE_IN3_PIN, LOW); digitalWrite(MINUTE_IN4_PIN, LOW); break;

case 3: digitalWrite(MINUTE_IN1_PIN, LOW); digitalWrite(MINUTE_IN2_PIN, HIGH); digitalWrite(MINUTE_IN3_PIN, HIGH); digitalWrite(MINUTE_IN4_PIN, LOW); break;

case 4: digitalWrite(MINUTE_IN1_PIN, LOW); digitalWrite(MINUTE_IN2_PIN, LOW); digitalWrite(MINUTE_IN3_PIN, HIGH); digitalWrite(MINUTE_IN4_PIN, LOW); break;

case 5: digitalWrite(MINUTE_IN1_PIN, LOW); digitalWrite(MINUTE_IN2_PIN, LOW); digitalWrite(MINUTE_IN3_PIN, HIGH); digitalWrite(MINUTE_IN4_PIN, HIGH); break;

case 6: digitalWrite(MINUTE_IN1_PIN, LOW); digitalWrite(MINUTE_IN2_PIN, LOW); digitalWrite(MINUTE_IN3_PIN, LOW); digitalWrite(MINUTE_IN4_PIN, HIGH); break;

case 7: digitalWrite(MINUTE_IN1_PIN, HIGH); digitalWrite(MINUTE_IN2_PIN, LOW); digitalWrite(MINUTE_IN3_PIN, LOW); digitalWrite(MINUTE_IN4_PIN, HIGH); break;

}

}


// Function to move the minute motor one step towards its target

void minuteMotorRun() {

if (minute_current_position == minute_target_steps) return;


if (micros() - lastStepTime >= MIN_STEP_DELAY_MICROS) {

lastStepTime = micros();


bool forward = (minute_target_steps > minute_current_position);

stepMinuteMotor(forward);

if (forward) {

minute_current_position++;

} else {

minute_current_position--;

}

}

}


// --- Homing Function ---

void homeClock() {

Serial.println("Homing Minute Hand...");

// Homing for manual motor (move backwards until sensor hit)

while (digitalRead(MINUTE_SENSOR_PIN) == HIGH) {

stepMinuteMotor(false); // Move backward (false)

delayMicroseconds(MIN_STEP_DELAY_MICROS * 2);

}

minute_current_position = 0;

// Move slightly off the sensor

for (int i=0; i<100; i++) {

stepMinuteMotor(true);

delayMicroseconds(MIN_STEP_DELAY_MICROS * 2);

minute_current_position++;

}

Serial.println("Minute Hand homed.");


Serial.println("Homing Hour Hand...");

stepperHour.setMaxSpeed(2000);

stepperHour.moveTo(-HOUR_HAND_STEPS_PER_REVOLUTION);

while (digitalRead(HOUR_SENSOR_PIN) == HIGH) {

stepperHour.run();

}

stepperHour.setCurrentPosition(0);

stepperHour.moveTo(1000);

while(stepperHour.distanceToGo() != 0) stepperHour.run();

Serial.println("Hour Hand homed.");


// Restore normal speeds

stepperHour.setMaxSpeed(5000);

}


// --- WiFi Connection Function ---

void connectToWiFi() {

Serial.print("Connecting to ");

Serial.println(ssid);

WiFi.mode(WIFI_STA);

WiFi.begin(ssid, password);


int timeout = 30;

while (WiFi.status() != WL_CONNECTED) {

delay(1000);

Serial.print(".");

timeout--;

if (timeout == 0) {

Serial.println("\nFailed to connect to WiFi. Clock will run from 12:00.");

return;

}

}

Serial.println("\nWiFi connected.");

}


// --- Time Setting Function ---

void moveToCurrentTime() {

if (WiFi.status() != WL_CONNECTED) {

Serial.println("No WiFi. Cannot set time.");

return;

}


timeClient.begin();

if (!timeClient.forceUpdate()) {

Serial.println("Failed to get time from server.");

return;

}


Serial.print("Current Time: ");

Serial.println(timeClient.getFormattedTime());


int hours = timeClient.getHours();

int minutes = timeClient.getMinutes();

if (hours >= 12) hours -= 12;

if (hours == 0) hours = 12;


long targetMinuteSteps = (minutes / 60.0) * MINUTE_HAND_STEPS_PER_REVOLUTION;

float totalMinutes = (hours * 60.0) + minutes;

long targetHourSteps = (totalMinutes / 720.0) * HOUR_HAND_STEPS_PER_REVOLUTION;


Serial.println("Moving hands to correct time...");

stepperHour.moveTo(targetHourSteps);

minute_target_steps = targetMinuteSteps;

// Block and wait until both steppers are in position

while (stepperHour.distanceToGo() != 0 || minute_current_position != minute_target_steps) {

stepperHour.run();

minuteMotorRun();

}

Serial.println("Hands are set.");

}


// --- Core 0: Motor Control Loop (Specialist) ---

void motorLoop(void * pvParameters) {

for (;;) {

if (demoModeActive) {

// Demo mode: spin minute motor fast

stepMinuteMotor(true);

vTaskDelay(1); // Small delay for speed

} else {

// Normal mode: move minute motor to target

minuteMotorRun();

}

// NEMA 17 is managed by Core 1 (loop())

vTaskDelay(1);

}

}


// --- Core 1: Main Setup (Boss) ---

void setup() {

Serial.begin(115200);

Serial.println("\nClock Booting Up...");


// --- 1. Setup Pins ---

pinMode(HOUR_EN_PIN, OUTPUT);

digitalWrite(HOUR_EN_PIN, LOW);

pinMode(HOUR_SENSOR_PIN, INPUT);

pinMode(MINUTE_SENSOR_PIN, INPUT);

pinMode(MINUTE_IN1_PIN, OUTPUT);

pinMode(MINUTE_IN2_PIN, OUTPUT);

pinMode(MINUTE_IN3_PIN, OUTPUT);

pinMode(MINUTE_IN4_PIN, OUTPUT);

pinMode(0, INPUT_PULLUP); // BOOT button check


// --- 2. Setup Steppers ---

stepperHour.setMaxSpeed(5000);

stepperHour.setAcceleration(500);


// --- 3. Home The Clock ---

homeClock();


// --- 4. Connect to WiFi & Get Time ---

connectToWiFi();

// --- 5. Move to Correct Time ---

moveToCurrentTime();

// --- 6. Disconnect WiFi ---

Serial.println("Disconnecting WiFi.");

WiFi.disconnect(true);

WiFi.mode(WIFI_OFF);


// --- 7. Start the Motor Control Loop on Core 0 ---

Serial.println("Homing complete. Starting main loop on Core 0.");

xTaskCreatePinnedToCore(

motorLoop,

"MotorControlTask",

10000,

NULL,

1,

&MotorControlTask,

0);

}


// --- Core 1: Main Loop (Boss) ---

void loop() {

// This loop handles NEMA 17 movement, time updates, and button press

stepperHour.run();

// Check BOOT button for demo mode toggle

if (digitalRead(0) == LOW) {

delay(50); // Debounce

if (digitalRead(0) == LOW) {

demoModeActive = !demoModeActive;

if (demoModeActive) {

// Activate Demo Mode

Serial.println("Demo Mode Activated.");

stepperHour.setMaxSpeed(7000);

stepperHour.moveTo(stepperHour.currentPosition() + 10000000);

} else {

// Return to Homing Mode (Your requested logic)

Serial.println("Demo Mode Deactivated. Re-homing...");

homeClock();

connectToWiFi();

moveToCurrentTime();

WiFi.disconnect(true);

WiFi.mode(WIFI_OFF);

stepperHour.setMaxSpeed(5000); // Restore normal speed

}

while (digitalRead(0) == LOW); // Wait for release

}

}


// Time update logic

static unsigned long lastTimeUpdate = 0;

if (millis() - lastTimeUpdate > 10000 && !demoModeActive) {

lastTimeUpdate = millis();


// Re-sync time every 6 hours (reliability fix)

if (WiFi.status() != WL_CONNECTED && timeClient.getHours() % 6 == 3 && timeClient.getMinutes() == 0) {

connectToWiFi();

}


if (WiFi.status() == WL_CONNECTED) {

if(timeClient.update()) {

Serial.println("Periodic time sync complete.");

}

WiFi.disconnect(true);

WiFi.mode(WIFI_OFF);

}

// Calculate New Target Positions

int hours = timeClient.getHours();

int minutes = timeClient.getMinutes();

if (hours >= 12) hours -= 12;

if (hours == 0) hours = 12;


long targetMinuteSteps = (minutes / 60.0) * MINUTE_HAND_STEPS_PER_REVOLUTION;

float totalMinutes = (hours * 60.0) + minutes;

long targetHourSteps = (totalMinutes / 720.0) * HOUR_HAND_STEPS_PER_REVOLUTION;


// Send New Targets

stepperHour.moveTo(targetHourSteps);

minute_target_steps = targetMinuteSteps;

}

delay(1);

}


NOTE: You have to add your own WIFI login data in the code, so that the ESP connects automatically:


// --- WiFi & Time Settings ---

const char* ssid = "YOUR_WIFI_NETWORK_NAME";

const char* password = "YOUR_WIFI_PASSWORD";


Customize It!

Screenshot 2025-12-01 144830.png
Screenshot 2025-12-01 144852.png
Screenshot 2025-12-01 144956.png
Screenshot 2025-12-01 142342.png
Screenshot 2025-12-01 142354.png
RYIE1547.JPG
KKZB4582 - Kopie.JPG
WhatsApp Image 2025-12-01 at 09.57.55 (5).jpeg
WhatsApp Image 2025-12-01 at 14.30.35.jpeg
WhatsApp Image 2025-12-01 at 14.30.15.jpeg
WhatsApp Image 2025-12-01 at 14.30.14.jpeg
ezgif.com-animated-gif-maker.gif

You are ready to customize your clock! Download some planets, print them and have fun with your fantasy! :)

Here some quick tips:

  1. You can just download any planets you want. I used this ones:
  2. Just half them in the slicer and print them with as little layer height you can
  3. Don't worry about screwing up a paint job. With aquarelle, it's super easy: just brush the error with some water and it goes away! :)
  4. You can use some magnets and/or some 3mm Bearings, glued on the back of your planets to attach them on the clock.


Have Fun!

Done! Enjoy your clock! :)