Arnov Sharma
Published © MIT

Zenkai Engine

A Dragon Ball–Inspired Device That Turns Failure Into Fuel

BeginnerFull instructions provided3 hours210

Things used in this project

Hardware components

DFRobot unihiker K10
×1
NextPCB  Custom PCB Board
NextPCB Custom PCB Board
×1

Software apps and online services

Fusion
Autodesk Fusion
Arduino IDE
Arduino IDE

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)

Story

Read more

Custom parts and enclosures

STEP FILE

Schematics

SCH

Code

code

C/C++
#include "unihiker_k10.h"

UNIHIKER_K10 k10;
Music music;

// -------- SCREEN --------
uint8_t screen_dir = 2;
#define ORANGE 0xFFA500
#define BLACK  0x000000

// -------- BUTTON --------
#define EXT_BUTTON_PIN 2   // P2 (INPUT_PULLUP)

// -------- TIMING --------
#define FRAME_DELAY        100
#define AUDIO_DURATION     63000      // 1 min 3 sec
#define DISPLAY_OFF_TIME   180000     // 3 minutes

// -------- FRAMES --------
const char* frames[] = {
  "S:/IMG01.jpg",
  "S:/IMG02.jpg",
  "S:/IMG03.jpg",
  "S:/IMG04.jpg"
};
const int frameCount = 4;

// -------- STATE --------
enum DeviceState {
  DISPLAY_OFF,
  IDLE_ON,
  PLAYING
};

DeviceState state = IDLE_ON;
unsigned long lastActivityTime = 0;

// -------- AUDIO TASK --------
void audioTask(void *param) {
  music.playTFCardAudio("S:/WAVE01.wav");
  vTaskDelete(NULL);
}

// -------- UI --------
void showOrange() {
  k10.canvas->canvasRectangle(0, 0, 240, 320, ORANGE, ORANGE, true);
  k10.canvas->updateCanvas();
}

void showBlack() {
  k10.canvas->canvasRectangle(0, 0, 240, 320, BLACK, BLACK, true);
  k10.canvas->updateCanvas();
}

// -------- SETUP --------
void setup() {
  k10.begin();
  k10.initScreen(screen_dir);
  k10.creatCanvas();
  k10.initSDFile();

  pinMode(EXT_BUTTON_PIN, INPUT_PULLUP);

  showOrange();
  state = IDLE_ON;
  lastActivityTime = millis();
}

// -------- LOOP --------
void loop() {
  unsigned long now = millis();

  // -------- DISPLAY TIMEOUT --------
  if (state == IDLE_ON && (now - lastActivityTime >= DISPLAY_OFF_TIME)) {
    showBlack();
    state = DISPLAY_OFF;
  }

  // -------- BUTTON PRESS --------
  if (digitalRead(EXT_BUTTON_PIN) == LOW) {

    while (digitalRead(EXT_BUTTON_PIN) == LOW); // wait release
    delay(200);

    lastActivityTime = millis();

    // ---- CASE 1: DISPLAY OFF → TURN ON ONLY ----
    if (state == DISPLAY_OFF) {
      showOrange();
      state = IDLE_ON;
      return;
    }

    // ---- CASE 2: IDLE ON → START PLAYBACK ----
    if (state == IDLE_ON) {
      state = PLAYING;

      xTaskCreate(audioTask, "AudioTask", 4096, NULL, 1, NULL);

      unsigned long startTime = millis();
      int frameIndex = 0;

      while (millis() - startTime < AUDIO_DURATION) {
        k10.canvas->canvasDrawImage(0, 0, frames[frameIndex]);
        k10.canvas->updateCanvas();
        frameIndex = (frameIndex + 1) % frameCount;
        delay(FRAME_DELAY);
      }

      showOrange();
      state = IDLE_ON;
      lastActivityTime = millis();
    }
  }
}

Credits

Arnov Sharma
375 projects • 391 followers
I'm Arnov. I build, design, and experiment with tech—3D printing, PCB design, and retro consoles are my jam.

Comments