Ralph Yamamoto
Published © MIT

Duplo Train Blinky

My grandson recently got a used Duplo train set as a present. He wanted blinking lights on the train. How hard would it be to add an LED?

BeginnerShowcase (no instructions)4 hours44
Duplo Train Blinky

Things used in this project

Hardware components

M5StickC PLUS ESP32-PICO Mini IoT Development Kit
M5Stack M5StickC PLUS ESP32-PICO Mini IoT Development Kit
×1
RGB Diffused Common Cathode
RGB Diffused Common Cathode
×1

Software apps and online services

Arduino IDE
Arduino IDE
OpenSCAD

Hand tools and fabrication machines

Anycubic Kobra 2 3D Printer

Story

Read more

Custom parts and enclosures

Duplo M5StickC Plus RGB LED Housing

Mount Unit to 2x4 Duplo brick

Sketchfab still processing.

M5StickC Plus Power Button

Power Button Extension

Sketchfab still processing.

RGB LED Clip

Secures the LED bezel to case

Sketchfab still processing.

Schematics

Duplo Train LED

RGB LED connections to M5StickC Plus

Code

M5StickC_Duplo_LCD_Test.ino

Arduino
Controls LED blinking. Cycles through Red-Green-Off with presses of btnA.
#include <M5StickCPlus.h>
#include "time.h"  // Required for time functions

#define RED_PIN   25
#define GREEN_PIN 26

// Button A is GPIO 39 on M5StickC Plus
#define BTN_A     39

int colorState = 0;         // 0 = Red, 1 = Green
bool ledOn = false;
unsigned long previousMillis = 0;
const long interval = 500;  // blink interval in ms

void setup() {
  M5.begin();
  M5.Lcd.setRotation(3);
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setCursor(10, 10, 2);
  M5.Lcd.setTextSize(2);
  M5.Lcd.printf("Duplo Train");
  pinMode(RED_PIN, OUTPUT);
  pinMode(GREEN_PIN, OUTPUT);

  // Start with both LEDs off
  digitalWrite(RED_PIN, LOW);
  digitalWrite(GREEN_PIN, LOW);
 }

void loop() {
  M5.update(); // update button states

  // Check for button press to toggle color
  if (M5.BtnA.wasPressed()) {
    colorState++;
    if (colorState > 2) colorState = 0;
    ledOn = false;               // reset blink
    previousMillis = millis();
    // ensure both off immediately
    digitalWrite(RED_PIN, LOW);
    digitalWrite(GREEN_PIN, LOW);
  }

  // Non-blocking blink
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    ledOn = !ledOn;  // toggle blink

    // Only toggle the selected color
    if (colorState == 1) {        // Red
      digitalWrite(RED_PIN, ledOn ? LOW : HIGH);
      digitalWrite(GREEN_PIN, LOW); // green always off
    } else if (colorState == 2) {   // Green
      digitalWrite(GREEN_PIN, ledOn ? LOW : HIGH);
      digitalWrite(RED_PIN, LOW);   // red always off
    } else {                       // Off
      digitalWrite(GREEN_PIN, LOW); // green always off
      digitalWrite(RED_PIN, LOW);   // red always off
    }
  }


}

Credits

Ralph Yamamoto
14 projects • 26 followers

Comments