A real-time vehicle dashboard built on the Arduino Uno, displaying speed, voltage, time, and date on a 128×64 SSD1306 OLED — styled as a motorcycle instrument cluster with an arc speedometer and segmented battery bar.
vaidyuthi-cluster/
├── Vaidyuthi_Cluster_v3.ino # Main Arduino sketch
└── README.md # This file
+--------------------------------------+
| 12:34 01/06 |
| ╭──────────╮ ┊ BATT |
| │ 52 │ ┊ [████░░░░░░] |
| │ KM/H │ ┊ 12.4V 74% |
| ╰──────────╯ ┊ |
| AUTO |
+--------------------------------------+
| Zone | Content |
|---|---|
| Top-left | Live time HH:MM from DS3231 RTC |
| Top-right | Live date DD/MM from DS3231 RTC |
| Left panel | Arc speedometer with tick marks + big speed number |
| Right panel | BATT label + 6-segment battery bar + voltage + % |
| Bottom-left | Current mode (AUTO) |
- Arc speedometer - 270° sweep with dotted track, 3px thick fill, major/minor tick marks, and a dominant large speed number at the centre
- Segmented battery bar - 6-segment horizontal bar with positive terminal nub; fills proportionally to input voltage (10.2V–14.8V range)
- Live voltage readout - displays actual measured voltage (e.g.
12.4V) and charge percentage below the battery bar - Low voltage warning - a blinking
!appears at the bottom-right when battery drops below 20% - Live RTC clock - time and date pulled from DS3231 on every refresh
- IIR sensor smoothing - both speed and voltage are low-pass filtered (α = 0.2) to prevent needle jitter
- Help screen - hold the button for 2 seconds to show a contact/support screen & release to return instantly
- One-time boot splash - "Hi, Rohith" and "Welcome to VAIDYUTHI" screens shown once on power-up and never again
- ~12 fps refresh - redraws every 80 ms using
millis(); no blocking code in the main loop
| Component | Details |
|---|---|
| MCU | Arduino Uno (ATmega328P) |
| Display | SSD1306 OLED 128×64 (I2C, address 0x3C) |
| RTC | DS3231 (I2C) |
| Voltage sensor | Resistive voltage divider -> Pin A0 |
| Speed sensor | Analog voltage output -> Pin A1 |
| Button | Tactile switch -> Pin D2 (active LOW, internal pull-up) |
| Arduino Pin | Connects To |
|---|---|
| A4 (SDA) | SSD1306 SDA + DS3231 SDA |
| A5 (SCL) | SSD1306 SCL + DS3231 SCL |
| 5V | VCC of both modules |
| GND | GND of both modules |
| Arduino Pin | Connects To |
|---|---|
| A0 | Voltage divider midpoint (wiper) |
| A1 | Speed sensor analog output |
| Arduino Pin | Connects To |
|---|---|
| D2 | One leg of tactile button |
| GND | Other leg of tactile button |
Internal pull-up is enabled in firmware — no external resistor needed.
Vin ──── R1 (30kΩ) ──┬── R2 (7.5kΩ) ──── GND
│
A0 (Arduino)
Supported input range: up to ~25V
Battery percentage range: 10.2V = 0% → 14.8V = 100%
Adjust
R1,R2,VOLT_MIN, andVOLT_MAXin the sketch to match your resistors and battery chemistry.
Install all three via Arduino IDE → Tools → Manage Libraries:
| Library | Author |
|---|---|
Adafruit SSD1306 |
Adafruit |
Adafruit GFX Library |
Adafruit |
RTClib |
Adafruit |
⚠️ Do not add#include <math.h>to this sketch. The Arduino core already providescos()andsin(). Including<math.h>explicitly causes a silent hang on AVR targets after the splash screens finish.
1. Clone the repository
git clone https://github.com/Rohith-Kalarikkal/vaidyuthi-cluster-firmware.git2. Install the three libraries listed above via the Arduino Library Manager.
3. Set the RTC time
Open vaidyuthi_cluster_v1.ino and uncomment this line near the bottom of setup():
// rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));Upload once. The RTC will sync to your computer's compile time. Then immediately re-comment the line and upload again — this prevents the clock from resetting on every reboot.
4. Calibrate your sensors
Edit these constants near the top of the sketch:
const float R1 = 30.0f; // upper voltage-divider resistor (kΩ)
const float R2 = 7.5f; // lower voltage-divider resistor (kΩ)
const float VREF = 5.0f; // Arduino Vcc
const float VOLT_MIN = 10.2f; // voltage shown as 0% battery
const float VOLT_MAX = 14.8f; // voltage shown as 100% battery
const float SPD_MAX = 100.0f; // speed (km/h) at full ADC reading5. Upload and run.
Power on
│
▼
"Hi, Rohith"
(2 seconds)
│
▼
"Welcome to VAIDYUTHI"
(2 seconds)
│
▼
Main Dashboard ◄──────────────────────────────┐
│ │
│ Button held ≥ 2s │ Button released
▼ │
Help Screen ───────────────────────────────────┘
Splash screens run exactly once inside setup() using delay(). After setup() returns, loop() contains no splash logic whatsoever — it is impossible for the splashes to reappear without a full power cycle.
| Action | Result |
|---|---|
| Hold ≥ 2 seconds on main screen | Switch to Help screen |
| Release button while on Help screen | Return to main dashboard |
| Constant | Default | Description |
|---|---|---|
R1 |
30.0 |
Upper resistor of voltage divider (kΩ) |
R2 |
7.5 |
Lower resistor of voltage divider (kΩ) |
VREF |
5.0 |
Arduino ADC reference voltage (V) |
VOLT_MIN |
10.2 |
Voltage mapped to 0% battery |
VOLT_MAX |
14.8 |
Voltage mapped to 100% battery |
SPD_MAX |
100.0 |
Speed at full ADC reading (km/h) |
REFRESH_MS |
80 |
Display refresh interval in ms (~12 fps) |
HOLD_MS |
2000 |
Button hold duration to enter Help (ms) |
| Condition | Behaviour |
|---|---|
| SSD1306 not detected at boot | Built-in LED blinks rapidly and halts |
| DS3231 not detected at boot | OLED shows RTC FAIL and halts |
| Battery charge below 20% | Blinking ! at bottom-right of dashboard |
- Frequency-based speed sensor — replace the linear ADC mapping with a pulse-counting ISR using
attachInterrupt()on D2 or D3 for Hall-effect wheel sensors - Mode cycling — add a short-press handler to toggle between display modes (e.g. trip meter, temperature); a
modeIndexvariable and aswitchinsidedrawMain()is all you need - Different battery chemistry — change
VOLT_MIN/VOLT_MAXto match your pack (e.g.6.0/8.4for 2S LiPo,9.0/12.6for 3S LiPo,11.0/14.6for LiFePO4) - Higher speed range — increase
SPD_MAXto 150 or 200 and recalibrate the sensor
Released under the MIT License.