This project is a hardware and software replica of the kinetic art piece "ClockClock 24" by Humans Since 1982, inspired by and building upon the work of Vallasc with several hardware modifications and improvements. The clock features 24 double-shaft stepper motors arranged in an 8x3 matrix, with motors grouped in sets of three on custom PCBs, of which there are eight in total. Each board is controlled by a Raspberry Pi Pico microcontroller acting as a slave, while all slave boards communicate with a central ESP32 master via the I2C protocol. The ESP32 also provides a web interface for remote control and configuration.
ClockClock 24 Replica/
├── 3D files/
│ ├── final/
│ └── test/
├── docs/
│ ├── datasheets/
│ └── images/
├── firmware/
│ ├── arduino/
│ │ ├── AdvancedBoardTest/
│ │ ├── BoardTest/
| | ├── SerialBoardTest/
│ │ └── SpeedoDriveTest/
│ ├── platformio/
│ │ ├── master/
│ │ └── slave/
│ └── README.md
├── pcb/
│ ├── Clock PCB/
│ └── Motor Driver/
└── README.md
To drive the clock hands, the BKA30D-R5 (equivalent to VID28-05) stepper motors were chosen. They have a total of 4 coils, allowing for two concentric drive shafts which makes them perfect for this application. These motors were originally designed for dashboard applications in the automotive industry. There are a number of other options with concentric shafts, but this one seemed to be most suitable as other similar projects also used it. Furthermore, it is cheaply available (around 4$ on Aliexpress) and draws little current.
The BKA30D-R5 allows for microstepping up to 1/12 degrees per microstep, which is ideal to achieve smooth movement of the clock hands. See datasheet for more details: BKA30D-R5 Datasheet.
Note: As standard, this motor comes with mechanical endstops. On Aliexpress there are some vendors that sell it without endstops, otherwise you will need to cut off the endstops yourself.
The steppers could in theory be driven directly from the microcontroller. However, the GPIO pins are limited and it is usually best practice to use a dedicated motor driver. For this reason, the VID6606 motor driver was chosen. It is specifically designed for the BKA30D-R5 (VID28-05) motor. One VID6606 can drive 4 motors (8 coils) in total. Per motor, it only needs two inputs: f(SCX) and DIR. As standard, this controller has built-in microstepping, which means with each rising edge of the SCX input the motor will perform one microstep in the direction specified by the DIR input.
The VID6606 Datasheet specifically recommends the use of smoothing capacitors to reduce electrical noise. Therefore, this Motor-Controller-PCB from Hackaday was used. I didn't make any changes to it because it was already tested by doctek. Thus, it is designed to be used as a breakout board on the custom Clock PCB.
Rendered image of the motor driver PCB
During testing, the steppers were quite noisy. I first suspected the motor drivers and tried some alternatives (DRV8834, TMC2208), but that didn't help much, so I stayed with the VID6606.
The real cause turned out to be mechanical play in the motor shafts. I also noticed the noise only appears at certain speeds, at full speed it mostly goes away. So adjusting the acceleration profile in software might help. For now I decided to leave the mechanical play as-is, since adding a bearing would be quite complex.
An ESP32 was chosen to run the master code, while multiple Raspberry Pi Picos are used as slave controllers. The ESP32 sends all the commands via I2C protocol to the slave boards. The main reason for this choice is that almost the same controllers were used in the reference project (Vallasc/clockclock24-replica). Since I want to copy the software as closely as possible, I stuck with the same controllers. They are also widely available for a reasonable price and are easy to work with.
Raspberry Pi Pico (left) and ESP32 (right)
For the project, a custom Clock PCB was designed to hold three BKA30D-R5 motors, which is the maximum number of motors that can be driven by one Raspberry Pi Pico regarding available GPIO pins. In total, there are eight of these PCBs, resulting in an 8x3 matrix of 24 motors. Each Clock PCB has two VID6606 motor driver breakout boards, of which one output is unused.
As a design choice, the PCB uses header pins to connect the motor drivers and the microcontroller. This makes it easy to replace components in case they break. While testing, this happened multiple times. Since the motor controllers were directly soldered onto the PCB in the beginning, I ended up throwing away the whole PCB each time a motor driver broke. The header pins solve this problem. As a bonus, the Picos can be switched out easily. This proved useful to quickly run a test program by replacing the "normal" slave controller with a test controller running different firmware.
Rendered image of the Clock PCB. See PCB directory for more info
Assembled Clock PCB
All the PCBs are connected by a JST-XH 4-pin connector in a daisy chain. Two wires are used for power (5V and ground) and two wires are used for I2C communication (SDA and SCL). In theory, it should be possible to power all eight PCBs from one Raspberry Pi Pico connected to a power supply via USB-C. However, in reality this didnt work (see below).
| Device | Normal Current (mA) | Peak Current (mA) | Quantity | Total Normal (mA) | Total Peak (mA) |
|---|---|---|---|---|---|
| Raspberry Pi Pico | 50 | 100 | 8 | 400 | 800 |
| Stepper Motor | 20 | 20 | 24 | 480 | 480 |
| ESP32 | 260 | 700 | 1 | 260 | 700 |
| Total | 1140 | 1980 |
This table shows the estimated current draw for each device during normal use and at peak. The totals are for 8 Raspberry Pi Picos, 24 stepper motors, and 1 ESP32.
A Raspberry Pi Pico can provide up to 2 A via the VBUS pin when powered over USB-C, which should be enough even at peak load.
In practice I ran into power problems. When all motors start up at the same time, they draw a lot of current and the Pico's supply couldn't keep up, causing the ESP32 or some Picos to randomly shut down. To fix this, each PCB has an extra 2-pin JST power input. I disconnected the +5V lines on the JST-XH 4-pin connectors (GND and I2C stay connected) and wired the 2-pin terminals with 18 AWG wire and WAGO clamps to a separate supply.
The worst-case current draw is around 4 A, so I chose a 5 V / 6 A (30 W) PSU from Amazon, which gives a 2 A safety margin. It connects via a standard barrel jack that came with the PSU.
Image of the connected PCBs
All mechanical parts are modeled in CAD. See the 3D files README for the full assembly and a list of all printable parts.
For the front panel I wanted a clean matte white look. After exploring several options (PVC, painted MDF, Corian), I found expresszuschnitt.de where you can order custom laser-cut materials. I ordered some samples and went with matte white acrylic (PERSPEX® Frost). The quality is excellent and the finish looks great. The front panel is bonded to the wooden frame with 3M VHB tape.
The frame itself is made from four wooden beams (see BOM for dimensions), connected at the corners by 3D-printed brackets that are screwed onto the beams.
Wooden frame with acrylic front panel
To give the clock a picture-frame look, I added medium oak ledges glued onto the main frame with mitered corners. Cutting accurate miters with basic tools was tricky, but after some sanding and oiling the result looks quite nice.
Gluing the outer oak frame
Finished outer frame
The motors are grouped into 2×3 arrays. Each array consists of two PCBs connected by PCB mounts. Screw spacers raise the PCBs to the correct depth so the clock hands sit at the right position on the front. Everything is held together with M3 hex screws and threaded inserts.
Exploded view (left) and front view (right) of a 2×3 clock array
The arrays are aligned with the holes in the front panel using the mounting_aid.stl and then screwed to the wooden frame. The PSU barrel jack is clamped to the bottom of the frame with a 3D-printed bracket. A small cutout in the outer frame lets the power cable pass through.
Clock arrays mounted to the frame
After mounting everything, I noticed a visible air gap between the 3D-printed PCB mounts and the front plate. This comes from slightly bent 3D-printed parts. The front panel also has quite a bit of flex.

Gap between clock arrays and front panel
To fix this, I designed a clamp to press the PCB holders onto the front plate. I tried different solutions, but none gave satisfying results. In the end, I settled on 3D-printed clamps that are screwed onto the main frame and use a spring section to press the PCB holders against the front plate.
Section view of clamps
Because of build-volume restrictions on my 3D printer, each clamp consists of multiple parts that are screwed together. As a result, and because the 3D-printed springs are quite strong, the clamp bends slightly. This can be seen in the image below. The bending causes the clamp to sit slightly higher than the outer frame. As a result, when the clock is mounted on a wall, the outer frame is not fully flush because the clamps push the clock outward. I decided to treat this as a design feature: it protects the rest of the clock, and the gap between the frame and the wall allows a bit of airflow, which helps cool the microcontrollers.
Assembled clock with clamps
| Component | Description | Quantity | Source | Link |
|---|---|---|---|---|
| Clock PCB | Custom PCB holding 3 motors and a Raspberry Pi Pico. See PCB directory for the electronic BOM | 8 | JLCPCB, parts from AliExpress | PCB README |
| PCB Mount (3D printed) | Mounts two PCBs together into one 2×3 array. 3 pieces per array | 9 | Self-printed | 3D files README |
| PCB Mount Bottom (3D printed) | Same as PCB Mount but with corrected hole positions for the bottom PCB | 3 | Self-printed | 3D files README |
| Mounting Bracket (3D printed) | Connects a 2×3 clock array to the wooden frame | 6 | Self-printed | 3D files README |
| PSU Bracket (3D printed) | Clamps the PSU barrel jack to the wooden frame | 1 | Self-printed | 3D files README |
| Frame Connector (3D printed) | Connects the outer frame corners. Parts are mirrored for each corner | 4 | Self-printed | 3D files README |
| Screw Spacer (3D printed) | Raises PCBs slightly off the mounting brackets | 80 | Self-printed | 3D files README |
| Lower Hand (3D printed) | Hour clock hand | 24 | Self-printed | 3D files README |
| Upper Hand (3D printed) | Minute clock hand | 24 | Self-printed | 3D files README |
| Wall Mount (3D printed) | Wall mounting part | 2 | Self-printed | 3D files README |
| Outer Clamp (3D printed) | Outer clamp part | 5 | Self-printed | 3D files README |
| Middle Clamp (3D printed) | Middle clamp part | 3 | Self-printed | 3D files README |
| Y-Clamp (3D printed) | Y-clamp part | 1 | Self-printed | 3D files README |
| Leaf Spring (3D printed) | Spring element used in the clamp assembly | 9 | Self-printed | 3D files README |
| Edge Clamp (3D printed) | Edge clamp part for the right and left sides | 2 | Self-printed | 3D files README |
| ESP32 mount (3D printed) | Mounting part for the ESP32 microcontroller | 1 | Self-printed | 3D files README |
| Acrylic Front Panel | PERSPEX® Frost matte white acrylic, 900×400×5 mm | 1 | Imported from Germany | expresszuschnitt.de |
| Main Frame Long | 20×45×900 mm wood beam | 2 | Hardware store | Jumbo |
| Main Frame Short | 20×45×400 mm wood beam | 2 | Hardware store | Jumbo |
| Outer Frame Long | 8×40×920 mm oak ledge | 2 | Hardware store | Jumbo |
| Outer Frame Short | 8×40×420 mm oak ledge | 2 | Hardware store | Jumbo |
| Power Supply | 5 V / 6 A (30 W) PSU | 1 | Amazon | Amazon |
| Power Wire | 18 AWG | ~3 m | AliExpress | |
| WAGO Clamps | Model 221-413 (3-conductor) | 14 | AliExpress | |
| 3M VHB Tape | 19 mm width | ~1 m | Hardware store | 3M Switzerland |
| Countersunk Wood Screw | 4×16 mm | 24 | Hardware store | Jumbo |
| Hex Screw | M3×8 mm | 96 | AliExpress | |
| Threaded Insert | M3×4×4 mm (for 3D-printed parts) | 96 | AliExpress |
The master firmware runs on an ESP32 microcontroller and acts as the central brain of the clock. Its main responsibilities include:
- Time Synchronization: Automatically connects to WiFi to retrieve the current time, ensuring the clock is always accurate and handles time zones and daylight saving time seamlessly.
- Clock Logic: Orchestrates the movements of all clock hands, deciding exactly what positions they need to be in to display the time or play animations.
- Communication: Sends synchronized instructions to all eight slave boards so the 24 motors move perfectly together.
- Web Server: Hosts a web interface that allows you to configure and control the clock from any device.
The master code is built using PlatformIO with the Arduino framework.
The slave firmware runs on each of the eight Raspberry Pi Pico microcontrollers, with each board responsible for controlling three BKA30D-R5 stepper motors (six individual clock hands). Key features include:
- I2C Communication: Listens for commands from the ESP32 master via I2C protocol
- Motor Control: Uses the AccelStepper library to provide smooth, accelerated motor movements with precise positioning
- Automatic Addressing: Determines its I2C address automatically based on DIP switch configuration (see below)
Each slave board operates independently once it receives position commands from the master, managing the acceleration profiles and step timing for its three motors in parallel.
Each slave board (Raspberry Pi Pico) determines its I2C address automatically based on four DIP switch pins (ADDR_1 through ADDR_4) defined in board_config.h. The address is calculated in board.cpp by reading the state of these pins, which use INPUT_PULLUP logic. When a DIP switch is ON (connected to ground), it represents a binary 1. When OFF (open/floating), it represents a binary 0.
The master controller sends commands to each board sequentially as seen in clock_manger.cpp, where I2C address 15 corresponds to the rightmost board. The first address is 0x08, because in the I2C protocol 0x01 to 0x07 are reserved.
| I2C Address | Binary | DIP 1 | DIP 2 | DIP 3 | DIP 4 |
|---|---|---|---|---|---|
| 8 | 1000 | 1 | 0 | 0 | 0 |
| 9 | 1001 | 1 | 0 | 0 | 1 |
| 10 | 1010 | 1 | 0 | 1 | 0 |
| 11 | 1011 | 1 | 0 | 1 | 1 |
| 12 | 1100 | 1 | 1 | 0 | 0 |
| 13 | 1101 | 1 | 1 | 0 | 1 |
| 14 | 1110 | 1 | 1 | 1 | 0 |
| 15 | 1111 | 1 | 1 | 1 | 1 |
The web interface is hosted directly on the ESP32 and provides an intuitive control panel for the ClockClock 24. To access it, simply connect to the same WiFi network as the ESP32 and navigate to its IP address in your browser.
The UI provides the following features:
- Live Preview: View a real-time digital representation of what the physical clock is currently displaying.
- Mode & Animation Selection: Easily switch between the normal time display, various choreographies, or run test animations.
- Sleep Time Configuration: Define specific days and hours when the clock should stop moving to save power and reduce noise.
- Wireless Configuration: Seamlessly switch between the clock's own Hotspot mode or connect it to your home WiFi network.
- Firmware Update: Perform Over-The-Air (OTA) firmware updates directly from your browser.
The web interface is built using standard HTML, CSS, and JavaScript. Because the ESP32 has limited storage, a custom Node.js script is used to compress the web files. Before building the firmware, running npm run minimize minifies the UI files and converts them into a single, optimized C++ header file, which is then flashed onto the microcontroller.
For more technical details about the firmware, see the firmware README.
The clock can operate in three distinct modes, which can be selected via the web interface:
- OFF: All clock hands move to a resting position (pointing straight down) and remain stationary.
- LAZY: A minimalist mode where the clock hands take the shortest, most direct path to the new time every minute, without any complex choreographies.
- ANIMATED: Every minute, the clock performs a choreography before settling on the new time. You can choose a specific animation or use the Cycle mode.
When the Cycle animation is selected, the clock rotates through the available choreographies instead of playing the same one every minute. You have two options for how it cycles:
- SEQ (Sequential): Plays the animations in a fixed order, cycling to the next one every minute.
- RAND (Random): Plays a "random" animation each minute. Interestingly, this randomness is deterministic and based on the current time (a hash of the current minute of the day). This means the clock will always play the exact same animation, as the Web Interface.
| Description | Animation |
|---|---|
| Chaos | ![]() |
| Waves | ![]() |
| Circle | ![]() |
| Spiral | ![]() |
| Loom | ![]() |
| Star | ![]() |
ClockClock 24 is an original kinetic art piece created by Humans Since 1982. All design rights, intellectual property, and artistic authorship of the ClockClock concept belong exclusively to them. This project is a non-commercial personal replica built out of admiration for their work. I make no claim to the design, the concept, or any related intellectual property.u are considering a similar project, please be aware of this and respect their rights.
The firmware and PCB design of this project are largely based on the work of Vallasc. His open-source replica served as the primary reference for the software architecture, I2C communication protocol, clock logic, and overall system design. Without his work this project would have taken significantly longer to build.
The motor driver breakout board design is taken from the Stepper Driver for Dashpanel Instruments project by doctek on Hackaday.io. The board was used without modifications. The SpeedoDriveTest.ino test sketch is also taken from that project.
This repository is released under the GNU General Public License v3.0. You are free to use, modify, and distribute it under the same terms, but the design concept of ClockClock 24 remains the exclusive property of Humans Since 1982 and this license does not grant any rights to it.



















