Cyber Clock 2.0 (Stainless Steel Exoskeleton)
by DataSlayer in Circuits > Clocks
1369 Views, 18 Favorites, 0 Comments
Cyber Clock 2.0 (Stainless Steel Exoskeleton)
Forget mass-produced toys! This hands-on guide will walk you through building a miniature Cybertruck packed with real tech – from 3D printed parts to a powerful microcontroller brain. We'll tap into the DIY revolution, where open-source designs and accessible tools empower anyone to create amazing things.
Even if you've never soldered a wire or seen a circuit board, you CAN do this. Follow along as we demystify electronics, conquer 3D printing hurdles, and write code like a pro (with a little help from AI).
This isn't just about a cool project – it's about unlocking a world of possibilities. Embrace the maker spirit, challenge your limits, and witness the magic of bringing your ideas to life! Are you in?
This is a replica of the original Cyber Clock Project by Gokux.
Supplies
3D Printed Parts
You can order these from commercial grade PCB manufacturers or you can print them yourself.
Flash Firmware to the Xiao
I've created a PlatformIO Project you should be able to use.
GitHub Repository (PlatformIO Project)
Credit: Gokux
https://github.com/dataslayermedia/Cybertruck-Clock
main.cpp
#include <WiFi.h>
#include <SPI.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <DHT.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define ANALOG_PIN D1 // Analog pin connected to the voltage divider
#define ADC_MAX 4095 // 12-bit ADC
#define REF_VOLTAGE 2.8 // Reference voltage of ADC (3.3V for Xiao ESP32C3)
// WiFi credentials
const char* ssid = "FreeWiFi";//your ssid
const char* password = "JustKiddingNoway!";//your wifi password
// OLED display SPI pins
#define OLED_MOSI D10
#define OLED_CLK D8
#define OLED_DC D4
#define OLED_CS D7
#define OLED_RESET D5
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT,
OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);
#define DHTPIN D0
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
// NTP client to get time
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", 19800, 0);
//bit ui bitmap
static const unsigned char PROGMEM image_paint_1_bits[] = {0x60,0xf0,0x90,0x90,0x90,0x90,0xf0};
static const unsigned char PROGMEM image_paint_0_bits[] = {0x7e,0x3f,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xfc,0x7e,0xc1,0x3e,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x7c,0x83,0xd5,0x3c,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x3c,0xab,0xd5,0x39,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0xab,0xd5,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4c,0xab,0x95,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x24,0xa9,0x25,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0xa4,0x49,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x92,0x93,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0xc9,0xa6,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x65,0xac,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x35,0xa8,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x15,0xa8,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x15,0xa8,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x15,0xa8,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x15,0xa8,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x15,0xa8,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x15,0xa8,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x15,0xa8,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x15,0xa8,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x15,0xa8,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x15,0xa8,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x15,0xa8,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x15,0xa8,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x15,0xa8,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x15,0xa8,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x15,0xa8,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x15,0xa8,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x15,0xa8,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x15,0xa8,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x15,0xa8,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x15,0xa8,0x26,0x04,0x92,0x48,0x3f,0xff,0xff,0xff,0xff,0xfc,0x12,0x49,0x20,0x64,0x15,0x88,0x29,0x09,0x24,0x90,0x7f,0xff,0xff,0xff,0xff,0xfe,0x09,0x24,0x90,0x94,0x11,0xa8,0x29,0x12,0x49,0x20,0xf0,0x00,0x00,0x00,0x00,0x0f,0x04,0x92,0x48,0x94,0x15,0x88,0x26,0x24,0x92,0x41,0xe0,0x00,0x00,0x00,0x00,0x07,0x82,0x49,0x24,0x64,0x11,0xa8,0x10,0x00,0x00,0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xc0,0x00,0x00,0x08,0x15,0x88,0x0f,0xff,0xff,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0xff,0xff,0xf0,0x11,0xa8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0xa8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0xa8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0xa8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0xa8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0xa8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x2f,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,0x01,0xff,0xff,0xff,0xff,0xff,0xff,0xf4,0xa8,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0xa8,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0xa8,0x00,0x80,0x00,0x00,0x00,0x00,0x02,0x08,0x20,0x00,0x00,0x00,0x00,0x00,0x15,0xa8,0x01,0xc0,0x00,0x00,0x00,0x00,0x01,0x10,0x50,0x00,0x00,0x00,0x00,0x00,0x15,0xa8,0x02,0xe0,0x00,0x00,0x00,0x00,0x00,0xa0,0x50,0x00,0x00,0x00,0x00,0x00,0x15,0xa8,0x03,0xe0,0x00,0x00,0x00,0x00,0x00,0x40,0x50,0x00,0x00,0x00,0x00,0x00,0x15,0xa8,0x05,0xf0,0x00,0x00,0x00,0x00,0x00,0x40,0x50,0x00,0x00,0x00,0x00,0x00,0x15,0xa8,0x05,0xf0,0x00,0x00,0x00,0x00,0x00,0x40,0x88,0x00,0x00,0x00,0x00,0x00,0x15,0xa8,0x03,0xe0,0x00,0x00,0x00,0x00,0x00,0x40,0xf8,0x00,0x00,0x00,0x00,0x00,0x15,0xac,0x01,0xc0,0x00,0x00,0x00,0x00,0x00,0x40,0xf8,0x00,0x00,0x00,0x00,0x00,0x35,0xa6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x70,0x00,0x00,0x00,0x00,0x00,0x65,0xa3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0xc5,0x91,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x89,0x49,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x92};
float readBatteryVoltage() {
int analogValue = analogRead(ANALOG_PIN);
float voltage = (analogValue / (float)ADC_MAX) * REF_VOLTAGE;
// Voltage divider scaling
voltage = voltage * (10.5 + 10) / 10.0; // (R1 + R2) / R2
return voltage;
}
// Function to calculate battery percentage
float calculateBatteryPercentage(float voltage) {
float percentage;
// Assuming a linear relationship between voltage and percentage
if (voltage >= 4.2) {
percentage = 100.0;
} else if (voltage <= 2.5) {
percentage = 0.0;
} else {
percentage = (voltage - 2.5) / (4.2 - 2.5) * 100.0;
}
return percentage;
}
void setup() {
// Start serial communication
Serial.begin(115200);
dht.begin();
analogReadResolution(12); // Set ADC resolution to 12-bit
// Initialize OLED display
if(!display.begin(SSD1306_SWITCHCAPVCC)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever;
}
//display.display();
// Connect to Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi");
// Initialize time client
timeClient.begin();
}
void loop() {
// Update time from NTP server
timeClient.update();
unsigned long epochTime = timeClient.getEpochTime();
struct tm *ptm = gmtime ((time_t *)&epochTime);
int monthDay = ptm->tm_mday;
int currentMonth = ptm->tm_mon+1;
int currentYear = ptm->tm_year+1900;
int currentHour = ptm->tm_hour;
int currentMinute = ptm->tm_min;
int currentSecond = ptm->tm_sec;
float batteryVoltage = readBatteryVoltage();
float batteryPercentage = calculateBatteryPercentage(batteryVoltage);
// Get temperature and humidity
float t = dht.readTemperature();
float h = dht.readHumidity();
// Convert time to 12-hour format
String period = "AM";
if (currentHour >= 12) {
period = "PM";
if (currentHour > 12) {
currentHour -= 12;
}
} else if (currentHour == 0) {
currentHour = 12;
}
// Display data on OLED
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
// Display time
display.setCursor(19,6);
display.setTextSize(3);
if (currentHour < 10) display.print('0');
display.print(currentHour);
display.print(':');
if (currentMinute < 10) display.print('0');
display.print(currentMinute);
display.setTextSize(1);
display.setCursor(108, 39);
display.print(period);
// Display date
display.setCursor(36, 39);
if (monthDay < 10) display.print('0');
display.print(monthDay);
display.print('/');
if (currentMonth < 10) display.print('0');
display.print(currentMonth);
display.print('/');
display.print(currentYear);
// Display temperature
display.setCursor(79, 53);
display.print(t);
display.print("C");
// Display humidity
display.setCursor(22, 53);
display.print(h);
display.print("%");
display.drawBitmap(0, 0, image_paint_0_bits, 128, 64, 1);
display.setCursor(14, 39);
display.print(batteryPercentage,0);
display.drawBitmap(8, 39, image_paint_1_bits, 4, 7, 1);
display.display();
// Delay before the next update
delay(1000);
}
Plug the Xiao into your computer and connect over the PlatformIO Serial Terminal or Arduino IDE Serial Terminal.
Build the PlatformIO Project
Upload the Build to the Xiao
Assembly
Diagram
3.1 - Kapton Tape
Apply a piece of Kapton tape under the plus and minus battery terminal pads.
3.1 - D1 Battery Data
Solder a wire connecting D1 to both the battery terminal pads separated by 10kohm SM resistors. Also connect the 3.7V battery and power switch.
3.2 - DHT Module
Trim the DHT11's pins to the needed length. Connect a 10k resistor between its VCC and DATA pins (I'm using a through-hole type). Then, solder three wires to VCC, GND, and DATA, making them long enough to reach the Xiao's corresponding pins.
3.3 - Additional Assembly
3.4 - Add the OLED windshield
Connect all the components and validate that the screen is rendering correctly.
3.5 - Enclose the Components
3.6 - Add Roof Top Panels, Axels, and Wheels