This project is a collaborative build of a fully functional slot machine using an Arduino microcontroller. Our team — Wiktor, Mateusz, and Moamen — is developing it as part of our Microcontroller Programming coursework. The idea is to simulate a classic slot machine using hardware components and embedded logic, incorporating user input, feedback loops, and interactive sound and visuals.

motivation

The project was born out of our shared interest in:

  • Building something fun and rewarding with embedded systems

  • Gaining hands-on experience with motors, sensors, and signal control

  • Exploring how real-time user interaction can be implemented with Arduino

  • Making our Microcontroller class more exciting (and chaotic) - main motivation

Also — who doesn’t love the thrill of a slot machine?

theory

The slot machine operates on basic embedded system principles:

  • Input: A potentiometer simulates the “lever” action, read through an analog input pin.

  • Processing: The Arduino reads the input, starts the motor, and triggers a musical sequence.

  • Output:

    • A servo motor spins the slots

    • A buzzer plays Faded by Alan Walker

    • Color detectors check the slots after the spin

    • An LCD screen displays messages — including the ultimate JACKPOT!

We aim to combine hardware control and timing with user feedback, ensuring synchronization between spin, music, and result evaluation.

tech stack

  • Arduino Uno (main board)

  • Potentiometer (input control)

  • DC Motor (spins the slots)

  • Photoresistors / Color Detectors (detect slot symbols)

  • LCD 16x2 Display (shows results)

  • Piezo Buzzer (plays music)

  • Breadboards, resistors, jumper wires (for circuit building)

progress logs

  • 2025-05-27: We brainstormed the main components and divided responsibilities
  • 2025-05-29: Wiktor successfully got the buzzer to play Faded — vibes confirmed.
  • 2025-06-04: We menaged to assemble a semi-final version of wiring, changed servo motor into DC motor.
  • 2025-06-05: Color detection working!
  • 2025-06-09: Final assembly is upon us - everything seems to be in order and working…
  • 2025-06-11: Last minuts on the project, tommorow - the grand reveal during the labs. Most things are working…

technical difficulties:

  • DC motor cannot be plugged directly into arduino and we are missing a transistor - we have to manually turn it on and off - unsatisfactory.
  • Color detection works through a simple heuristic and a series of if-elses with the green being the last if before “Unknown” - thus green detection is buggy. Overall, any color detection with these is buggy, sometimes it works sometimes it doesn’t.
  • The box that the project is in could have some better aesthetics and fitting for all the parts.

summary

code

#include <Wire.h> // Library for I2C communication 
#include <LiquidCrystal_I2C.h> // Library for I2C LCD display #include <pitches.h> // Library with musical note frequencies
LiquidCrystal_I2C lcd(0x27, 16, 2); // Initialize LCD at I2C address 0x27, 16 columns, 2 rows 
 
// Define pin numbers for color sensor control and output 
#define s0 8 
#define s1 9 
#define s2 10 
#define s3 11 
#define motorPin 12 // Pin that controls the motor (spinning effect) 
#define out1 5 // Sensor 1 output pin 
#define out2 6 // Sensor 2 output pin 
#define out3 7 // Sensor 3 output pin 
const int potentiometerPin = A0; // Analog input pin for potentiometer 
 
// Melody notes to be played during spin effect 
int melody[] = { NOTE_F4, NOTE_F4, NOTE_F4, NOTE_A4, NOTE_D4, NOTE_D4, NOTE_D4, NOTE_C4, NOTE_A4, NOTE_A4, NOTE_A4, NOTE_A4, NOTE_E4, NOTE_E4, NOTE_E4, NOTE_D4 }; 
 
// Duration values corresponding to melody notes 
int noteDurations[] = { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }; 
 
// Time tracking for non-blocking loop (unused now, but good practice) 
unsigned long previousMillis = 0; const unsigned long interval = 50; // Interval to check potentiometer value 
 
// Flags and variables 
bool effectActive = false; // Flag to trigger spin & color reading 
bool isPlaying = false; // Tracks whether music is currently playing 
int lastPotValue = 0; // Last recorded potentiometer value 
 
// Structure to hold RGB color readings struct 
Rgb { int red; int green; int blue; }; 
 
void setup() { 
	Serial.begin(9600); // Start serial monitor for debugging 
 
	pinMode(s0, OUTPUT); // Set up pins controlling the color sensor 
	pinMode(s1, OUTPUT); 
	pinMode(s2, OUTPUT); 
	pinMode(s3, OUTPUT); 
	pinMode(out1, INPUT); // Set color sensor output pins as inputs 
	pinMode(out2, INPUT); 
	pinMode(out3, INPUT); 
	pinMode(motorPin, OUTPUT); // Motor pin as output 
 
	digitalWrite(s0, HIGH); // Set frequency scaling for sensor 
	digitalWrite(s1, HIGH); 
} 
void readPotentiometer() { // Read current potentiometer value and check for significant change 
	int currentPotValue = analogRead(potentiometerPin); 
	if (abs(currentPotValue - lastPotValue) > 200) { 
		Serial.print("Potentiometer: "); 
		Serial.println(currentPotValue); 
		lastPotValue = currentPotValue; // Update last known value 
		effectActive = true; // Trigger effect on large change 
	}
} 
void playSpinEffect() { // Play music and turn motor on/off every other note for visual effect 
	isPlaying = true; 
	for (int i = 0; i < 16; i++) { 
	if (i % 2 == 0) digitalWrite(motorPin, HIGH); // Motor ON for even notes 
	else digitalWrite(motorPin, LOW); // Motor OFF for odd notes 
	int duration = 2500 / noteDurations[i]; // Calculate note duration 
	tone(3, melody[i], duration); // Play note on pin 3 
	delay(duration * 1.05); // Wait until note finishes 
	noTone(3); // Stop playing note 
	} 
	digitalWrite(motorPin, LOW); // Ensure motor is off at end 
	isPlaying = false; 
} 
Rgb getColors(int outPin) { // Measure RGB values from color sensor connected to given output pin 
	Rgb color; 
	digitalWrite(s2, LOW); 
	digitalWrite(s3, LOW); 
	color.red = pulseIn(outPin, digitalRead(outPin) == HIGH ? LOW : HIGH); // Measure red 
	delay(20); 
	digitalWrite(s3, HIGH); 
	color.blue = pulseIn(outPin, digitalRead(outPin) == HIGH ? LOW : HIGH); // Measure blue 
	delay(20); 
	digitalWrite(s2, HIGH); 
	color.green = pulseIn(outPin, digitalRead(outPin) == HIGH ? LOW : HIGH); // Measure green 
	delay(20); 
	return color; 
} 
String getStableColor(int outPin, int repeatCount = 5) { 
	String lastColor = ""; 
	int sameCount = 0; 
	while (sameCount < repeatCount) { 
		RGB rgb = getColors(outPin); 
		String currentColor = classifyColor(rgb); 
		if (currentColor == lastColor && currentColor != "Unknown") { 
			sameCount++; 
		} else { 
			sameCount = 1; // reset 
		lastColor = currentColor; 
		} 
		delay(50);
	} 
	return lastColor; 
} 
String classifyColor(Rgb c) { // Convert raw RGB values into a named color using simple heuristics 
	if (c.red <= 15 && c.green <= 15 && c.blue <= 15) return "White"; 
	else if (c.red < c.blue && c.red <= c.green && c.red < 23) return "Red"; 
	else if (c.blue < c.green && c.blue < c.red && c.blue < 20) return "Blue"; 
	else if (c.green < c.red && (c.green - c.blue <= 8)) return "Green"; 
	else return "Unknown"; 
} 
void showEffect(String color1, String color2, String color3) {// Display result of color comparison on LCD 
	lcd.init(); 
	lcd.backlight(); 
	lcd.setCursor(0, 0); 
	lcd.print("sUpEr JaCkPoT"); 
	delay(3000); // Show splash screen for fun 
	lcd.clear(); 
	lcd.setCursor(0, 0); 
	if (color1 == color2 && color2 == color3) { 
		lcd.print("Win"); // All three sensors detected same color 
	} else { 
		lcd.print("Lose"); // At least one color is different 
	} 
}
void loop() { // Main program loop 
	unsigned long currentMillis = millis(); // Get current time (for future expansions) 
	readPotentiometer(); // Check if potentiometer was turned 
	if (effectActive) { 
		playSpinEffect(); // Play sound and motor effect
// Read RGB values from all three sensors 
		Rgb rgb1 = getColors(out1); 
		Rgb rgb2 = getColors(out2); 
		Rgb rgb3 = getColors(out3); // Convert raw RGB to color names 
 
		String color1 = getStableColor(out1); 
		String color2 = getStableColor(out2); 
		String color3 = getStableColor(out3); 
 
// Debug output to Serial Monitor 
		Serial.print("C1: "); 
		Serial.println(color1); 
		Serial.print("C2: "); 
		Serial.println(color2); 
		Serial.print("C3: "); 
		Serial.println(color3); 
		showEffect(color1, color2, color3); // Show result on LCD 
		effectActive = false; // Reset effect trigger 
	}
}

wiring (courtesy of mateusz)

A veeery simplified wiring :)

lessons learned

  • What starts as a simple “digital output HIGH” in class becomes a whole different beast when you’re wiring a real DC motor in a shoebox. This project pushed me to apply textbook concepts — signal timing, voltage thresholds, component tolerance — in real-world conditions where perfection is optional and duct tape is king.

  • There’s nothing like watching your circuit fail because you didn’t include a transistor. Working with motors taught me more than just electronics — it taught me respect for safe power delivery and how one small oversight can compromise your entire setup. Lesson learned: always plan your circuit like it wants to explode.

  • Sensors don’t behave like the datasheets promise — especially not when ambient light, electrical noise, and sketchy jumper wires get involved. This project forced me to embrace iterative debugging, patience, and the joy of realizing that the problem wasn’t your fault this time. Probably.

  • No PCB? No proper motor driver? No problem. I built the prototype with what I had — a shoebox, a soldering iron, and some stubbornness. It was the perfect reminder that engineering is creativity under constraints, and good design starts at “minimum viable” before it gets fancy.

  • Everything might work perfectly on its own, but once you combine it all… chaos. I learned the hard way that system integration needs its own love: wiring stability, power distribution, fallback logic, even basic UX if you want people to use it without panic. Building a device means building an experience.