Scan Your Hand Meet Your LEGO Minifigure

by rirmak in Circuits > Arduino

53 Views, 0 Favorites, 0 Comments

Scan Your Hand Meet Your LEGO Minifigure

lego_scan_002.png
3 Eylül 2024

Have you ever visited a LEGO store and used their fun hand scanner that "reads your palm" and shows you a random LEGO minifigure? In this project, I recreated that magical experience using Arduino!


This interactive scanner detects a hand placed above the sensor and randomly displays a LEGO minifigure suggestion—just like the ones found in official LEGO shops. It’s a great combination of technology and play, perfect for exhibitions, classrooms, or your own DIY LEGO display.


With a few basic components (an Arduino, IR or ultrasonic sensor, and a display), you can build your own Minifig Fortune Teller and add a playful surprise to any space.

Supplies

Arduino Uno – The main controller of the project

ST7735 1.8" TFT LCD (160x128) – Color display used to show LEGO minifigure images

ST7735 1.8" TFT LCD Wiring

birlestirilmis 001.png
birlestirilmis 002.png

ST7735 1.8" TFT LCD Wiring


The ST7735 1.8" TFT LCD module is connected to the Arduino Uno using SPI communication.


The VCC (or +) pin of the display is connected to 5V on the Arduino to provide power, and the GND pin is connected to GND.


The CS (Chip Select) pin is connected to digital pin 10,

the RESET (RST) pin to digital pin 9,

and the DC (Data/Command) pin to digital pin 8.


For SPI communication, the MOSI (SDA) pin is connected to digital pin 11,

and the SCK pin to digital pin 13.


The LED pin, which controls the backlight, can be connected directly to 5V or 3.3V, optionally through a current-limiting resistor. This setup allows the Arduino to control the display and render images from the SD card.

SD Card Module Wiring

The SD card module communicates with the Arduino Uno using the SPI protocol.


The VCC pin of the module is connected to the 5V pin on the Arduino to provide power, and the GND pin is connected to GND.


For SPI communication, the MOSI pin is connected to digital pin 11,

the MISO pin to digital pin 12,

and the SCK pin to digital pin 13.

The CS (Chip Select) pin, which allows the Arduino to select and communicate with the SD card, is connected to digital pin 4.


This configuration enables the Arduino to read BMP image files stored on the SD card and display them on the TFT screen.

Required Libraries

#include <TFT.h> // TFT screen library
#include <SPI.h> // SPI communication library
#include <SD.h> // SD card library

TFT.h lets us control the TFT display.

SPI.h is required because both the TFT screen and SD card use SPI communication.

SD.h allows us to access image files stored on an SD card.

Defining Pin Connections

#define TFT_CS 10
#define TFT_RST 9
#define TFT_DC 8
#define SD_CS 4

These #define statements assign the Arduino pins that connect to the TFT and SD card:


TFT_CS: Chip Select pin for the display

TFT_RST: Reset pin for the display

TFT_DC: Data/Command select for display communication

SD_CS: Chip Select pin for the SD card


Setup Functions

void setup() {
Serial.begin(9600); // Start serial monitor for debugging
tft.begin(); // Initialize TFT screen
tft.setRotation(2); // Rotate screen (0–3). “2” puts short side at top

if (!SD.begin(SD_CS)) {
Serial.println("SD initialization failed!");
while (1); // Freeze if SD card doesn't work
}

Serial.println("SD card initialized.");
tft.background(0, 0, 0); // Clear screen with black color
}


What happens here:

The serial monitor is started for debugging purposes.

The TFT screen is initialized and rotated for correct orientation.

The SD card is initialized. If it fails, the program stops.

The screen is cleared with a black background


Loop Function: Display BMP Images

void loop() {
for (int i = 1; i <= 5; i++) {
String filename = String(i, DEC);
while (filename.length() < 3) {
filename = "0" + filename;
}
filename += ".bmp";

A for loop runs from 1 to 5 (adjustable).

It creates filenames like "001.bmp", "002.bmp", etc.

This matches your image filenames stored on the SD card.

if (loadBitmap(filename.c_str())) {
Serial.println("Loaded: " + filename);
} else {
Serial.println("Failed: " + filename);
}
delay(3000); // Wait 3 seconds before showing next image
tft.background(0, 0, 0); // Clear screen
}
}

Calls the loadBitmap() function to draw the image.

Shows each image for 3 seconds.

Clears the screen between images.

LoadBitmap() – Custom Function to Read and Display BMP Files

bool loadBitmap(const char *filename) {
File bmpFile = SD.open(filename);

Tries to open the BMP file from the SD card.

if (!bmpFile) {
Serial.println("File could not be opened");
return false;
}

if (bmpFile.read() != 'B' || bmpFile.read() != 'M') {
bmpFile.close();
Serial.println("Invalid BMP file");
return false;
}

Checks if the file is a valid BMP format (must start with 'B' and 'M').

bmpFile.seek(2);
uint32_t fileSize = bmpFile.read() | (bmpFile.read() << 8) | (bmpFile.read() << 16) | (bmpFile.read() << 24);

Reads total file size (not critical for drawing, but helpful for verification).

bmpFile.seek(18);
int32_t width = bmpFile.read() | (bmpFile.read() << 8) | (bmpFile.read() << 16) | (bmpFile.read() << 24);
int32_t height = bmpFile.read() | (bmpFile.read() << 8) | (bmpFile.read() << 16) | (bmpFile.read() << 24);

Gets the width and height of the image from the BMP header.

bmpFile.seek(34);
uint32_t dataSize = bmpFile.read() | (bmpFile.read() << 8) | (bmpFile.read() << 16) | (bmpFile.read() << 24);
if (dataSize == 0) dataSize = fileSize - bmpFile.position();

Gets the size of the pixel data

int32_t screenWidth = tft.width();
int32_t screenHeight = tft.height();
int32_t xOffset = (screenWidth - width) / 2;
int32_t yOffset = (screenHeight - height) / 2;

Calculates how to center the image on the screen.


Reading Pixels and Drawing to the Screen

bmpFile.seek(54); // Skip the BMP header
for (int y = height - 1; y >= 0; y--) {
for (int x = 0; x < width; x++) {
uint8_t b = bmpFile.read();
uint8_t g = bmpFile.read();
uint8_t r = bmpFile.read();
uint16_t color = tft.Color565(r, g, b);
tft.drawPixel(x + xOffset, yOffset + (height - 1 - y), color);
}
}

Starts reading pixel data from the BMP file.

Reads BGR color bytes for each pixel (standard for BMP).

Converts them to 16-bit color using .Color565().

Draws each pixel to the screen, centered.

Final Cleanup

bmpFile.close();
return true;
}

Closes the file and returns success.

How to Improve This Project

You can improve this project by adding an LED push button that mimics the function of a hand scanner, enhancing the interactivity and making the experience more engaging for users