Máquina Expendedora de Snacks con Arduino: Guía de Diseño y Construcción
Componentes y suministros
| Componente | Cantidad | Notas |
|---|---|---|
| Arduino UNO | 1 | Mejor usar Arduino Mega para más I/O |
| Sensor Shield | 1 | Facilita conexiones |
| Motor DC 6V con rueda | 3 | Mecanismo espiral entrega producto |
| Sensor infrarrojo reflectante / seguidor línea | 3 | Detección producto caído |
| Sensor proximidad electromagnético | 1 | Sensor moneda 1 |
| Sensor interrupción distancia (infrarrojo/optocoplador) | 1 | Sensor moneda 2 |
| Fuente alimentación 6V para motores DC | 1 | |
| Relé genérico (4 canales) | 1 | Control motores |
| LCD Nokia 5110 | 1 | Pantalla información |
| LED blanco genérico | 2 | Iluminación |
| Pulsadores (Rojo, Amarillo, Verde) | 3 | Selección producto |
Aplicaciones y servicios online
- Arduino IDE
- SolidWorks (o cualquier modelador 3D)
Sobre el proyecto
Introducción
Hola, saludos desde Indonesia.
Esta máquina expendedora de snacks es mi proyecto final. Se terminó a finales de 2015.
El objetivo: crear una máquina expendedora controlada por microcontrolador Arduino, usando componentes "baratos y fáciles de conseguir" en tiendas locales.
El video de abajo muestra la prueba final: pago/prueba monedas, selección producto y entrega.
Paso 1: Bosquejar el concepto
Primero lo primero: el concepto.
Este boceto fue mi primera idea. Sería una máquina de snacks, aceptando monedas, con carcasa de acrílico.
Elige y madura tu concepto, piensa en cualquier escenario, cualquier condición.
Intenta dibujar todo, no importa si dibujas mal, en serio mira mi dibujo. :D
El momento correcto para pensar en lo impensable es antes de empezar el proyecto.
Paso 2: Crear modelo 3D
Quizás no sea necesario para todos, pero para mí y este proyecto fue crucial.
Creé modelo completo en SolidWorks. Necesitaba determinar dimensiones: tamaño paquetes snacks, monedas aceptadas/rechazadas, ranura monedas, rampa monedas, pulsadores, casi todo. Incluye comparar, elegir y medir el Arduino, sensores, dónde colocarlos, dimensiones, dónde van monedas aceptadas, y dónde poner LCD monocromo (no necesario pero insistí).
Y en el modelo 3D, no olvides crear agujeros para tornillos en cada pieza.
La carcasa es acrílico cortado por láser. Por eso el modelo tan detallado y preciso: a más precisión, mejor corte.
Paso 3: Diseñar ranura de monedas
Para filtrar monedas, primero uso dimensiones de moneda. Diseñando la ranura determino qué tamaños de moneda pueden entrar.
Segundo filtro: determino qué monedas ruedan hasta el depósito.
Por gravedad, si el diámetro de la moneda es menor que la longitud de la rampa, cae y se rechaza.
- Moneda izquierda: no entra en ranura.
- Moneda central: cae y se rechaza.
- Moneda derecha: aceptada, baja al depósito.
Video prueba monedas muestra el funcionamiento.
Paso 4: Preparar y testear cada componente
Prepara Arduino y todo lo necesario.
Testea cada componente: LCD, pulsadores, relé, LED. Combina todo y aprende lógicas y código. Asegúrate de saber lo que haces. Testea al límite, encuentra el límite, pero no lo rompas.
¿Por qué resistencia? ¿Qué pasa si esto o aquello? ¿Por qué lecturas inestables? ¿Qué valor lee realmente el sensor? Testé y descubrí que lecturas del sensor de proximidad eran "sucias", necesitaba resistencia para estabilizar.
El sensor infrarrojo funciona muy mal bajo sol directo (lo sabía, pero nunca sentí el impacto hasta ahora). Solución: aislar la parte receptora del sensor infrarrojo con cinta americana, como en la foto.
Paso 5: Construir mecanismo espiral
Una de las partes más importantes: mecanismo de entrega.
Uso mecanismo espiral con hilo aluminio (2mm diámetro), moldeado manualmente en espiral ayudado por tubo PVC de 9cm diámetro.
El alambre espiral se ata a la rueda con bridas. Al girar el motor DC, la rueda rota y el alambre espiral gira.
El giro de la espiral convierte movimiento rotacional en lineal del producto.
Paso 6: Construir mecanismo identificación monedas
Primera foto: sensor moneda 1, sensor proximidad/inductivo. Al pasar moneda aceptada, dispara Arduino para empezar a contar tiempo (milisegundos).
if sensor1 activado then empezar cuenta tiempo en milisegundos
Al pasar sensor moneda 2 (interruptor distancia), Arduino para la cuenta y obtiene el tiempo que tardó esa moneda en ir del sensor 1 al 2.
if sensor2 activado then parar cuenta. "tiempo_viaje" = xxx milisegundos
No uses muchos imanes o la moneda se atasca en medio de la rampa. No queremos eso, necesitamos contar tiempo para cada moneda y obtener "tiempo_viaje" entre sensor 1 y 2. Este tiempo (en ms) determina el valor de la moneda aceptada.
si "tiempo_viaje" >= "yyy" ms, entonces moneda "aaa", sino moneda "bbb"
Video prueba identificación monedas con imanes.
Paso 7: Mecanismo detección producto
Uso 3 sensores infrarrojos para detectar producto al caer empujado por espiral.
Al caer producto, dispara sensor infrarrojo enviando señal OFF al motor DC (vía relé).
Video muestra detección funcionando.
Paso 8: LCD para información
El LCD muestra info (en rupias indonesias) sobre valor moneda aceptada cada vez que el cliente inserta una. También muestra saldo total e instrucciones paso a paso.
Al encender máquina:
- Pantalla principal = "Introduzca moneda".
- SI moneda insertada = "Muestra valor moneda y saldo total".
- SI no moneda = mantiene pantalla principal.
Tras identificar moneda:
- SI saldo >= precio producto = "Seleccione producto".
- SI saldo < precio = "Introduzca más monedas".
Tras activar espiral (entrega):
- SI detección producto activada = "Gracias", transacción terminada.
- Retraso y vuelta a pantalla principal.
Paso 9: Acabado y pruebas
Finalmente, máquina expendedora terminada ;)
Tras 3 meses, listo para pruebas finales: pago/monedas, selección, entrega.
Video prueba final.
Espero que este proyecto ayude e inspire para crear la próxima máquina expendedora con Arduino.
Paso 10: Mejoras futuras
Ideas para mejorar:
- Añadir mecanismo devuelve cambio.
- Aceptar billetes.
- Aceptar bitcoin/pagos digitales.
- Mostrar stock en LCD.
- IoT: Notificar por internet cada transacción.
- IoT: Avisar stock bajo/vacío.
Agradecimientos: ITENAS Bandung, Departamento Ingeniería Mecánica.
Código
Código fuente Máquina Snacks (Arduino)
Código usado en este proyecto:
const byte SIAP = 0;
const byte KOIN_MASUK1 = 1;
const byte KOIN_MASUK2 = 2;
const byte KOIN_MASUK3 = 3;
const byte KOIN_MASUK4 = 4;
const byte KOIN_MASUK5 = 5;
const byte KOIN_MASUK6 = 6;
const byte KOIN_MASUK7 = 7;
const byte SALDO_500 = 8;
const byte SALDO_500500 = 9;
const byte SALDO_500500500 = 10;
const byte SALDO_500500500500 = 11;
const byte SALDO_5005005001000 = 12;
const byte SALDO_5001000 = 13;
const byte SALDO_5001000500 = 14;
const byte SALDO_50010001000 = 15;
const byte SALDO_5005001000 = 16;
const byte SALDO_1000 = 17;
const byte SALDO_10001000 = 18;
const byte SALDO_1000500 = 19;
const byte SALDO_1000500500 = 20;
const byte SALDO_10005001000 = 21;
const byte KOIN_KELUAR = 22;
byte state = SIAP;
const float jeda_waktu = 876;
unsigned long time1, time2, time3, time4, time5, time6, time7;
#define PIN_SCE 7
#define PIN_RESET 6
#define PIN_DC 5
#define PIN_SDIN 4
#define PIN_SCLK 3
#define LCD_C LOW
#define LCD_D HIGH
#define LCD_X 84
#define LCD_Y 48
static const byte ASCII[][5] = {
{0x00, 0x00, 0x00, 0x00, 0x00}, // 20 espacio
{0x00, 0x00, 0x5f, 0x00, 0x00}, // 21 !
{0x00, 0x07, 0x00, 0x07, 0x00}, // 22 "
{0x14, 0x7f, 0x14, 0x7f, 0x14}, // 23 #
{0x24, 0x2a, 0x7f, 0x2a, 0x12}, // 24 $
{0x23, 0x13, 0x08, 0x64, 0x62}, // 25 %
{0x36, 0x49, 0x55, 0x22, 0x50}, // 26 &
{0x00, 0x05, 0x03, 0x00, 0x00}, // 27 '
{0x00, 0x1c, 0x22, 0x41, 0x00}, // 28 (
{0x00, 0x41, 0x22, 0x1c, 0x00}, // 29 )
{0x14, 0x08, 0x3e, 0x08, 0x14}, // 2a *
{0x08, 0x08, 0x3e, 0x08, 0x08}, // 2b +
{0x00, 0x50, 0x30, 0x00, 0x00}, // 2c ,
{0x08, 0x08, 0x08, 0x08, 0x08}, // 2d -
{0x00, 0x60, 0x60, 0x00, 0x00}, // 2e .
{0x20, 0x10, 0x08, 0x04, 0x02}, // 2f /
{0x3e, 0x51, 0x49, 0x45, 0x3e}, // 30 0
{0x00, 0x42, 0x7f, 0x40, 0x00}, // 31 1
{0x42, 0x61, 0x51, 0x49, 0x46}, // 32 2
{0x21, 0x41, 0x45, 0x4b, 0x31}, // 33 3
{0x18, 0x14, 0x12, 0x7f, 0x10}, // 34 4
{0x27, 0x45, 0x45, 0x45, 0x39}, // 35 5
{0x3c, 0x4a, 0x49, 0x49, 0x30}, // 36 6
{0x01, 0x71, 0x09, 0x05, 0x03}, // 37 7
{0x36, 0x49, 0x49, 0x49, 0x36}, // 38 8
{0x06, 0x49, 0x49, 0x29, 0x1e}, // 39 9
{0x00, 0x36, 0x36, 0x00, 0x00}, // 3a :
{0x00, 0x56, 0x36, 0x00, 0x00}, // 3b ;
{0x08, 0x14, 0x22, 0x41, 0x00}, // 3c <
{0x14, 0x14, 0x14, 0x14, 0x14}, // 3d =
{0x00, 0x41, 0x22, 0x14, 0x08}, // 3e >
{0x02, 0x01, 0x51, 0x09, 0x06}, // 3f ?
{0x32, 0x49, 0x79, 0x41, 0x3e}, // 40 @
{0x7e, 0x11, 0x11, 0x11, 0x7e}, // 41 A
{0x7f, 0x49, 0x49, 0x49, 0x36}, // 42 B
{0x3e, 0x41, 0x41, 0x41, 0x22}, // 43 C
{0x7f, 0x41, 0x41, 0x22, 0x1c}, // 44 D
{0x7f, 0x49, 0x49, 0x49, 0x41}, // 45 E
{0x7f, 0x09, 0x09, 0x09, 0x01}, // 46 F
{0x3e, 0x41, 0x49, 0x49, 0x7a}, // 47 G
{0x7f, 0x08, 0x08, 0x08, 0x7f}, // 48 H
{0x00, 0x41, 0x7f, 0x41, 0x00}, // 49 I
{0x20, 0x40, 0x41, 0x3f, 0x01}, // 4a J
{0x7f, 0x08, 0x14, 0x22, 0x41}, // 4b K
{0x7f, 0x40, 0x40, 0x40, 0x40}, // 4c L
{0x7f, 0x02, 0x0c, 0x02, 0x7f}, // 4d M
{0x7f, 0x04, 0x08, 0x10, 0x7f}, // 4e N
{0x3e, 0x41, 0x41, 0x41, 0x3e}, // 4f O
{0x7f, 0x09, 0x09, 0x09, 0x06}, // 50 P
{0x3e, 0x41, 0x51, 0x21, 0x5e}, // 51 Q
{0x7f, 0x09, 0x19, 0x29, 0x46}, // 52 R
{0x46, 0x49, 0x49, 0x49, 0x31}, // 53 S
{0x01, 0x01, 0x7f, 0x01, 0x01}, // 54 T
{0x3f, 0x40, 0x40, 0x40, 0x3f}, // 55 U
{0x1f, 0x20, 0x40, 0x20, 0x1f}, // 56 V
{0x3f, 0x40, 0x38, 0x40, 0x3f}, // 57 W
{0x63, 0x14, 0x08, 0x14, 0x63}, // 58 X
{0x07, 0x08, 0x70, 0x08, 0x07}, // 59 Y
{0x61, 0x51, 0x49, 0x45, 0x43}, // 5a Z
{0x00, 0x7f, 0x41, 0x41, 0x00}, // 5b [
{0x02, 0x04, 0x08, 0x10, 0x20}, // 5c ¥
{0x00, 0x41, 0x41, 0x7f, 0x00}, // 5d ]
{0x04, 0x02, 0x01, 0x02, 0x04}, // 5e ^
{0x40, 0x40, 0x40, 0x40, 0x40}, // 5f _
{0x00, 0x01, 0x02, 0x04, 0x00}, // 60 `
{0x20, 0x54, 0x54, 0x54, 0x78}, // 61 a
{0x7f, 0x48, 0x44, 0x44, 0x38}, // 62 b
{0x38, 0x44, 0x44, 0x44, 0x20}, // 63 c
{0x38, 0x44, 0x44, 0x48, 0x7f}, // 64 d
{0x38, 0x54, 0x54, 0x54, 0x18}, // 65 e
{0x08, 0x7e, 0x09, 0x01, 0x02}, // 66 f
{0x0c, 0x52, 0x52, 0x52, 0x3e}, // 67 g
{0x7f, 0x08, 0x04, 0x04, 0x78}, // 68 h
{0x00, 0x44, 0x7d, 0x40, 0x00}, // 69 i
{0x20, 0x40, 0x44, 0x3d, 0x00}, // 6a j
{0x7f, 0x10, 0x28, 0x44, 0x00}, // 6b k
{0x00, 0x41, 0x7f, 0x40, 0x00}, // 6c l
{0x7c, 0x04, 0x18, 0x04, 0x78}, // 6d m
{0x7c, 0x08, 0x04, 0x04, 0x78}, // 6e n
{0x38, 0x44, 0x44, 0x44, 0x38}, // 6f o
{0x7c, 0x14, 0x14, 0x14, 0x08}, // 70 p
{0x08, 0x14, 0x14, 0x18, 0x7c}, // 71 q
{0x7c, 0x08, 0x04, 0x04, 0x08}, // 72 r
{0x48, 0x54, 0x54, 0x54, 0x20}, // 73 s
{0x04, 0x3f, 0x44, 0x40, 0x20}, // 74 t
{0x01, 0x01, 0x7f, 0x01, 0x01}, // 75 u
{0x3c, 0x40, 0x40, 0x20, 0x7c}, // 76 v
{0x1c, 0x20, 0x40, 0x20, 0x1c}, // 77 w
{0x3c, 0x40, 0x30, 0x40, 0x3c}, // 78 x
{0x44, 0x28, 0x10, 0x28, 0x44}, // 79 y
{0x0c, 0x50, 0x50, 0x50, 0x3c}, // 7a z
{0x00, 0x08, 0x36, 0x41, 0x00}, // 7b {
{0x00, 0x00, 0x7f, 0x00, 0x00}, // 7c |
{0x00, 0x41, 0x36, 0x08, 0x00}, // 7d }
{0x10, 0x08, 0x08, 0x10, 0x08}, // 7e ←
{0x78, 0x46, 0x41, 0x46, 0x78} // 7f →
};
void LcdWrite(byte dc, byte data) {
digitalWrite(PIN_DC, dc);
digitalWrite(PIN_SCE, LOW);
shiftOut(PIN_SDIN, PIN_SCLK, MSBFIRST, data);
digitalWrite(PIN_SCE, HIGH);
}
void LcdCharacter(char character) {
LcdWrite(LCD_D, 0x00);
for (int index = 0; index < 5; index++) {
LcdWrite(LCD_D, ASCII[character - 0x20][index]);
}
LcdWrite(LCD_D, 0x00);
}
void LcdClear(void) {
for (int index = 0; index < LCD_X * LCD_Y / 8; index++) {
LcdWrite(LCD_D, 0x00);
}
}
void LcdInitialise(void) {
pinMode(PIN_SCE, OUTPUT);
pinMode(PIN_RESET, OUTPUT);
pinMode(PIN_DC, OUTPUT);
pinMode(PIN_SDIN, OUTPUT);
pinMode(PIN_SCLK, OUTPUT);
digitalWrite(PIN_RESET, LOW);
digitalWrite(PIN_RESET, HIGH);
LcdWrite(LCD_C, 0x21);
LcdWrite(LCD_C, 0xB1);
LcdWrite(LCD_C, 0x04);
LcdWrite(LCD_C, 0x14);
LcdWrite(LCD_C, 0x20);
LcdWrite(LCD_C, 0x0C);
}
void LcdString(char *characters) {
while (*characters) {
LcdCharacter(*characters++);
}
}
void setup() {
pinMode(11, INPUT); pinMode(12, INPUT); pinMode(14, INPUT);
pinMode(15, INPUT); pinMode(16, INPUT); pinMode(17, INPUT);
pinMode(18, INPUT); pinMode(19, INPUT);
pinMode(13, OUTPUT); pinMode(8, OUTPUT); pinMode(9, OUTPUT);
pinMode(10, OUTPUT); pinMode(2, OUTPUT);
digitalWrite(8, HIGH); digitalWrite(9, HIGH);
digitalWrite(10, HIGH); digitalWrite(13, LOW);
Serial.begin(9600);
Serial.println("=> Siap");
LcdInitialise(); LcdClear();
LcdString(" Masukkan Koin Rp500 atau Koin Rp1000 @ Rp2000");
delay(500);
}
void loop() {
int x = analogRead(14);
if (state == SIAP) {
if (x >= 33) {
state = KOIN_MASUK1; time1 = millis();
tone(2, 4200, 40);
Serial.println("snsr1,"); Serial.println("start wkt");
}
} else if ((state == KOIN_MASUK1) && (!(digitalRead(13)))) {
if ((digitalRead(12)) && (state == KOIN_MASUK1)) {
unsigned long diff1 = (millis() - time1);
Serial.println("snsr2,"); Serial.println("stop wkt");
Serial.print("jeda wkt: "); Serial.print(diff1); Serial.println(" ms");
if (diff1 > jeda_waktu) {
state = SALDO_1000;
LcdInitialise(); LcdClear();
LcdString(" diterima Saldo=Rp1000 Tambah Koin Koin Rp1000");
digitalWrite(13, HIGH);
Serial.println("koin=Rp 1000, Saldo: Rp1000");
tone(2, 4200, 299);
} else if (diff1 < jeda_waktu) {
state = SALDO_500;
digitalWrite(13, HIGH);
LcdInitialise(); LcdClear();
LcdString(" diterima Saldo= Rp500 Tambah Koin Koin Rp500");
Serial.println("koin=Rp 500, Saldo: Rp500");
tone(2, 4200, 299);
}
}
}
// ... (resto de estados de saldo y lógica de monedas idéntica al original)
// Estados SALDO_500, SALDO_500500, SALDO_500500500, SALDO_5001000,
// SALDO_1000, SALDO_1000500, SALDO_10001000, etc.
// Cada uno replica la lógica: leer sensor1, medir tiempo a sensor2,
// comparar con jeda_waktu (876ms) para distinguir moneda 500 vs 1000,
// actualizar estado saldo y LCD.
// Lógica botones productos y motores:
else if ((state == SALDO_500500500500) || (state == SALDO_5005005001000) ||
(state == SALDO_5001000500) || (state == SALDO_50010001000) ||
(state == SALDO_5005001000) || (state == SALDO_10001000) ||
(state == SALDO_1000500500) || (state == SALDO_10005001000)) {
// Producto 1 (botón pin 17, sensor caída pin 11, motor pin 8)
if (((digitalRead(13) && (digitalRead(9) && digitalRead(10))) && digitalRead(17)) && digitalRead(8)) {
LcdInitialise(); LcdClear(); LcdString(" Mohon Menunggu");
Serial.println("pb1"); tone(2, 4200, 200); delay(2500);
digitalWrite(8, LOW); Serial.println("motor1");
} else {
if ((!digitalRead(8) && !digitalRead(11))) {
digitalWrite(8, HIGH);
LcdInitialise(); LcdClear(); LcdString(" Terima Kasih");
tone(2, 4200, 100); delay(150); tone(2, 4200, 100);
Serial.println("produk1 jatuh"); delay(4000);
digitalWrite(13, LOW); state = KOIN_KELUAR;
}
}
// Producto 2 (botón pin 18, sensor pin 15, motor pin 9)
if (((digitalRead(13) && (digitalRead(8) && digitalRead(10))) && digitalRead(18)) && digitalRead(9)) {
LcdInitialise(); LcdClear(); LcdString(" Mohon Menunggu");
Serial.println("pb2"); tone(2, 4200, 200); delay(2500);
digitalWrite(9, LOW); Serial.println("motor2");
} else {
if ((!digitalRead(9) && !digitalRead(15))) {
digitalWrite(9, HIGH);
LcdInitialise(); LcdClear(); LcdString(" Terima Kasih");
tone(2, 4200, 100); delay(150); tone(2, 4200, 100);
Serial.println("produk2 jatuh"); delay(4000);
digitalWrite(13, LOW); state = KOIN_KELUAR;
}
}
// Producto 3 (botón pin 19, sensor pin 16, motor pin 10)
if (((digitalRead(13) && (digitalRead(8) && digitalRead(9))) && digitalRead(19)) && digitalRead(10)) {
LcdInitialise(); LcdClear(); LcdString(" Mohon Menunggu");
Serial.println("pb3"); tone(2, 4200, 200); delay(2500);
digitalWrite(10, LOW); Serial.println("motor3");
} else {
if ((!digitalRead(10) && !digitalRead(16))) {
digitalWrite(10, HIGH);
LcdInitialise(); LcdClear(); LcdString(" Terima Kasih");
tone(2, 4200, 100); delay(150); tone(2, 4200, 100);
Serial.println("produk3 jatuh"); delay(4000);
digitalWrite(13, LOW); state = KOIN_KELUAR;
}
}
} else if (state == KOIN_KELUAR) {
if (((x <= 33) && !digitalRead(12)) && !digitalRead(13)) {
state = SIAP;
LcdInitialise(); LcdClear();
LcdString(" Masukkan Koin Rp500 atau Koin Rp1000 @ Rp2000");
Serial.println("=> Siap");
}
}
}
Piezas personalizadas y cajas
Capturas de mi modelo 3D SolidWorks para este proyecto.
Proceso de manufactura
- Máquinas expendedoras: Una industria de 36.600 millones de dólares en EE. UU.
- Sensor K30 CO₂: Monitorización en tiempo real de la calidad del aire interior
- Construye un estadiómetro digital: Controla tu altura con Arduino y sensor láser
- Integración del sensor de huella capacitivo DFRobot (ID809) con Arduino o ESP8266
- Construye una Torre de Sensores con Arduino Cloud: Temperatura, Movimiento y Gas
- Pistola de Agua Inteligente Activada por Movimiento con Arduino Nano
- Máquina de Vending Inverso (RVM): Kit DIY de Sistema Inteligente de Reciclaje
- Sistema Radar Compacto con Arduino Nano, Sensor HC-SR04 y Pantalla 1.8"
- Máquinas expendedoras de leche fresca: Cómodas, asequibles y ecológicas
- Descubre las Máquinas Expendedoras de Fideos: Funcionamiento y Qué Puedes Obtener
- Maximiza tu Beneficio: Fijando el Mejor Precio para Maquinaria Usada