Caja registradora inteligente

Autores: Jorge Lozoya Astudillo, Alejandro Pradas Liquete y Raúl Sanz Cuesta

Introducción: Ideas y Objetivos

Uno de los requisitos que queríamos que tuviera nuestro proyecto es que fuera algo cotidiano, algo que se utilizase en el día a día, pero incluyéndole alguna mejora. Por eso, la idea de hacer una caja registradora no nos pareció mal. Era algo que todos los integrantes del grupo sabríamos plasmar en código, sólo nos faltaba el conocimiento necesario para implementarlo con Arduino.

Al tener el proyecto en mente, la idea de implementar la nueva funcionalidad se nos ocurrió de forma espontánea: la caja registradora tendrá cuatro cajones, cada uno con billetes de distinto valor. De esta forma, sólo los cajones de los billetes que se utilicen se abrirán y se cerrarán automáticamente, haciendo las compras más sencillas y rápidas.

Durante la realización del esquema con todas las funcionalidades básicas de la caja registradora y de los componentes necesarios para llevarlo a cabo, se nos fueron ocurriendo más funcionalidades, pero por su complejidad o por la incapacidad de implementarlas, las descartamos. El resultado de nuestro proyecto cumple con todos los objetivos y las ideas que teníamos en mente aunque, durante el desarrollo de la práctica, fueron surgiendo algunos problemas que comentaremos más adelante.

Materiales y presupuesto

  • Placa ELEGOO UNO R3
  • Resistencias de 220 ohmios (2 unidades)
  • Micro servomotor
  • Placa de inserción
  • Pantalla LCD 16×2
  • Cableado

Todos los componentes estaban incluidos en la caja excepto:

ElementosPrecio (€)Referencia
Placa Arduino MEGA_Prestada
Micro servomotor (3 unidades)10,99Amazon
Placa de inserción6,5Tienda de electrónica
Cableado adicional3,5Tienda de electrónica

En total, el coste de los componentes adquiridos ha sido 20,99€.

Implementación software (código)

#include <LiquidCrystal.h>  // Includes LCD library
#include <Servo.h>          // Includes servo library

// Definition of LCD connection pins
const int rs = 13, en = 12, d4 = 8, d5 = 5, d6 = 4, d7 = 2;

// Password
const int pwd = 1234;

// Number of bills
int oneBills = 10;
int fiveBills = 11;
int tenBills = 12;
int fiftyBills = 13;

// Servos
Servo oneServo;
Servo fiveServo;
Servo tenServo;
Servo fiftyServo;

// Other variables
int option;
int password;
int logged = 0;
String text;

// Create a LiquidCrystal object to control the LCD
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

int readInput() {
    int num;

    while (Serial.available() == 0) {  // Program stops until buffer has something to read
    }
    num = Serial.parseInt();
    return num;
}

void setServos() {
    oneServo.write(0);
    delay(1500);
    fiveServo.write(0);
    delay(1500);
    tenServo.write(0);
    delay(1500);
    fiftyServo.write(0);
    delay(1500);
}

void showLogin() {
    char cursor = 95;

    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Enter password:");
    while (Serial.available() == 0) {
        lcd.setCursor(0, 1);
        lcd.print(" ");
        delay(500);
        lcd.setCursor(0, 1);
        lcd.write(cursor);
        delay(500);
    }
}

void showPassword(int password) {
    lcd.setCursor(0, 1);
    for (int i = 0; i < String(password).length(); i++) {
        lcd.print("*");
    }
    delay(1000);
}

int checkPassword(int pin) {
    return pin == pwd;
}

void scrollText(String text) {
    int i = 0;
    int stop = 0;

    if (text.length() <= 16) {
        lcd.print(text);
        return;
    }

    // Add spaces at the end of the text so that it repeats itself in the scrolling
    for (int i = 0; i < 16; i++) {
        text += " ";
    }

    while (stop != 1 && i < text.length() - 15) {
        if (i == text.length() - 16) {  // If it reaches the end, the i is restarted so that it does it again
            i = 0;
        }
        lcd.setCursor(0, 0);
        lcd.print(text.substring(i, i + 16));
        if (i == 0) {
            delay(1000);
        }
        if (Serial.available() > 0) {
            stop = 1;
            Serial.read();
        }
        delay(200);
        i++;
    }
}

void openCashDrawers(int numOne, int numFive, int numTen, int numFifty, int operationType) {
    /*operationType == 1 -> addMoney
      operationType == 0 -> giveChange*/
    if (numOne > 0) {
        if (operationType == 1) {
            Serial.println("Abro oneServo");
            oneServo.write(90);
            delay(1500);
        } else {
            Serial.println("Cierro oneServo");
            oneServo.write(0);
            delay(1500);
        }
    }
    if (numFive > 0) {
        if (operationType == 1) {
            Serial.println("Abro fiveServo");
            fiveServo.write(90);
            delay(1500);
        } else {
            Serial.println("Cierro fiveServo");
            fiveServo.write(0);
            delay(1500);
        }
    }
    if (numTen > 0) {
        if (operationType == 1) {
            Serial.println("Abro tenServo");
            tenServo.write(90);
            delay(1500);
        } else {
            Serial.println("Cierro tenServo");
            tenServo.write(0);
            delay(1500);
        }
    }
    if (numFifty > 0) {
        if (operationType == 1) {
            Serial.println("Abro fiftyServo");
            fiftyServo.write(90);
            delay(1500);
        } else {
            Serial.println("Cierro fiftyServo");
            fiftyServo.write(0);
            delay(1500);
        }
    }
}

int addMoney(int& oneBills, int& fiveBills, int& tenBills, int& fiftyBills) {
    int added = 0;
    int payment = 0;
    int numOne = 0;
    int numFive = 0;
    int numTen = 0;
    int numFifty = 0;

    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.write("Billetes de 1:");
    added = readInput();
    oneBills += added;
    payment += added;
    numOne = added;
    lcd.setCursor(0, 1);
    lcd.print(String(added));
    delay(1000);

    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.write("Billetes de 5:");
    added = readInput();
    fiveBills += added;
    payment += added * 5;
    numFive = added;
    lcd.setCursor(0, 1);
    lcd.print(String(added));
    delay(1000);

    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.write("Billetes de 10:");
    added = readInput();
    tenBills += added;
    payment += added * 10;
    numTen = added;
    lcd.setCursor(0, 1);
    lcd.print(String(added));
    delay(1000);

    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.write("Billetes de 50:");
    added = readInput();
    fiftyBills += added;
    payment += added * 50;
    numFifty = added;
    lcd.setCursor(0, 1);
    lcd.print(String(added));
    delay(1000);

    if (payment != 0) {
        openCashDrawers(numOne, numFive, numTen, numFifty, 1);
        text = "Cerrar cajones:0";
        showMoney(numOne, numFive, numTen, numFifty, text);
        openCashDrawers(numOne, numFive, numTen, numFifty, 0);
    }

    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Cantidad sumada:");
    lcd.setCursor(0, 1);
    lcd.print(String(payment));
    delay(2000);
    return payment;
}

void showMoney(int oneBills, int fiveBills, int tenBills, int fiftyBills, String text) {
    int option;
    String message;

    lcd.clear();
    lcd.setCursor(0, 1);
    lcd.print(text);
    lcd.setCursor(0, 0);
    message = "(1s): " + String(oneBills) + "  (5s): " + String(fiveBills) + "  (10s): " + String(tenBills) + "  (50s): " + String(fiftyBills);
    scrollText(message);
}

void purchase() {
    int price = 0;
    String text;

    lcd.clear();
    lcd.setCursor(0, 0);
    scrollText("Importe total:");
    price = readInput();
    lcd.setCursor(0, 1);
    lcd.print(price);
    delay(1000);
    int payment = addMoney(oneBills, fiveBills, tenBills, fiftyBills);
    // Function to open the corresponding drawers (change)
    if (price != payment) {
        giveChange(price, payment, oneBills, fiveBills, tenBills, fiftyBills);
    }
    lcd.clear();
    lcd.print("     Compra     ");
    lcd.setCursor(0, 1);
    lcd.print("   finalizada   ");
    delay(2000);
}

void giveChange(int price, int payment, int& oneBills, int& fiveBills, int& tenBills, int& fiftyBills) {
    String text;
    int numOne = 0;
    int numFive = 0;
    int numTen = 0;
    int numFifty = 0;
    int change = payment - price;
    if (payment < price) {
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("Falta dinero");
        lcd.clear();
        addMoney(oneBills, fiveBills, tenBills, fiftyBills);
    }
    while (change > 0) {
        if ((change >= 50) && (fiftyBills >= numFifty)) {
            fiftyBills--;
            change -= 50;
            numFifty++;
        } else if ((change >= 10) && (tenBills >= numTen)) {
            tenBills--;
            change -= 10;
            numTen++;
        } else if ((change >= 5) && (fiveBills >= numFive)) {
            fiveBills--;
            change -= 5;
            numFive++;
        } else if ((change >= 1) && (oneBills >= numOne)) {
            oneBills--;
            change -= 1;
            numOne++;
        }
    }
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Abriendo cajones");
    openCashDrawers(numOne, numFive, numTen, numFifty, 1);
    text = "Cerrar cajones:0";
    showMoney(numOne, numFive, numTen, numFifty, text);
    openCashDrawers(numOne, numFive, numTen, numFifty, 0);
    lcd.clear();
    lcd.setCursor(0, 0);
}

void showOptions() {
    while (Serial.available() == 0) {
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.write("1: Compra");
        lcd.setCursor(0, 1);
        lcd.write("2: Meter dinero");
        delay(1500);

        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.write("3: Ver dinero");
        lcd.setCursor(0, 1);
        lcd.write("4: Cerrar sesion");
        delay(1500);
    }
}

void byePrompt() {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("     Sesion     ");
    lcd.setCursor(0, 1);
    lcd.print("    terminada   ");
    delay(2000);
}

void logOut(int& logged) {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Quieres salir?");
    lcd.setCursor(0, 1);
    lcd.print("Si: 1   No: 0");
    option = readInput();
    if (option) {
        byePrompt();
        logged = 0;
    }
}

void showLoginSuccess() {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.write("     Sesion     ");
    lcd.setCursor(0, 1);
    lcd.write("    iniciada    ");
    delay(2000);
}

void showLoginError() {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.write("    Fallo al    ");
    lcd.setCursor(0, 1);
    lcd.write(" iniciar sesion ");
    delay(2000);
}

void setup() {
    // Starts LCD connection
    lcd.begin(16, 2);

    // Starts serial port connection
    Serial.begin(9600);

    // Servos port configuration
    oneServo.attach(11);   // One dollar bill servo
    fiveServo.attach(10);  // Five dollar bill servo
    tenServo.attach(9);    // Ten dollar bill servo
    fiftyServo.attach(7);  // Fifty dollar bill servo
}

void loop() {
    // Input password
    while (logged != 1) {
        showLogin();
        password = readInput();
        showPassword(password);
        if (checkPassword(password) == 1) {
            showLoginSuccess();
            logged = 1;
            setServos();  // Sets all servos to 0 degrees
        } else {
            showLoginError();
        }
    }

    // User logged
    showOptions();
    option = readInput();
    Serial.print("Opcion elegida: ");
    Serial.println(option);
    switch (option) {
        case 1:
            purchase();
            break;
        case 2:
            addMoney(oneBills, fiveBills, tenBills, fiftyBills);
            break;
        case 3:
            text = "Salir: 0";
            showMoney(oneBills, fiveBills, tenBills, fiftyBills, text);
            break;
        case 4:
            logOut(logged);
            break;
    }
}

Casos de uso

Nuestro proyecto puede realizar las siguientes funcionalidades:

  • Iniciar sesión: Para poder acceder al resto de funciones es necesario introducir una contraseña, en este caso la contraseña es 1234. Al iniciar el Arduino nos aparece por pantalla el mensaje “Enter password:”. Por teclado escribimos la contraseña y al dar a la tecla intro aparece por pantalla un asterisco por cada carácter que hayamos escrito. Si la contraseña es incorrecta, nos aparece el mensaje “Fallo al iniciar sesión” y nos pide la contraseña de nuevo. Si la contraseña es correcta,  nos aparece el mensaje “Sesion iniciada” y nos muestra el resto de las funcionalidades disponibles.
  • Compra: Esta funcionalidad nos permite realizar la compra. Seleccionamos esta opción, después de iniciar sesión, escribiendo 1 por teclado. Nos aparece por pantalla el mensaje “Importe total:” y nos pide que indiquemos el valor de la compra. Después de esto, tendremos que introducir cuántos billetes de 1, de 5, de 10 y de 50 vamos a usar para pagar. Una vez hecho esto, se abrirán los cajones de los billetes que vamos a introducir y nos mostrará por pantalla un recordatorio de qué billetes hemos indicado que vamos a introducir y cuántos de cada tipo. Debajo de ese mensaje también nos aparece por pantalla “Cerrar cajones:0”. Cuando hayamos metido todos los billetes en la caja registradora, escribimos 0 por teclado y al dar al intro se cerrarán los cajones. Al cerrar los cajones, nos mostrará por pantalla el mensaje “Cantidad Sumada:”, y debajo la cantidad que hemos introducido en la caja. Si hemos entregado la cantidad exacta nos mostrará por pantalla el mensaje “Compra finalizada”. Si no hemos especificado la cantidad exacta, calculará el valor de la vuelta y se abrirán los cajones de los billetes que nos tenga que devolver.
  • Meter dinero: Esta funcionalidad nos permite añadir dinero a la caja registradora. Seleccionamos esta opción, después de iniciar sesión, escribiendo 2 por teclado. Nos pide que le indiquemos cuántos billetes de cada tipo vamos a introducir en la caja. Después de eso, se abren los cajones correspondientes y nos muestra por pantalla los billetes que vamos a introducir de cada tipo y el mensaje “Cerrar cajones:0”. Al cerrar los cajones, te indica la cantidad que has introducido y vuelve al menú principal.
  • Ver dinero: Esta funcionalidad nos muestra el dinero que hay dentro de la caja registradora. Seleccionamos esta opción, después de iniciar sesión, escribiendo 3 por teclado. Nos muestra los billetes de cada tipo que hay dentro de la caja y el mensaje “Salir:0” para que volvamos a nuestro menú principal pulsando 0 e intro.
  • Cerrar sesión: Esta funcionalidad nos permite cerrar sesión. Seleccionamos esta opción, después de iniciar sesión, escribiendo 4 por teclado. Al elegir esta opción, nos muestra el mensaje “Quieres salir?” y nos muestra dos opciones “Si: 1 No: 0” para que confirmemos que queremos elegir esta opción. Si pulsamos 1 nos muestra el mensaje “Sesion terminada” y nos vuelve a enseñar el mensaje inicial “Enter password:”. Si pulsamos 0 volvemos al menú principal.

Posibles mejoras

  • Habíamos pensado añadir un teclado numérico, un 4 Digit 7 Segment-Display, un zumbador para usarlo como alarma y unos leds para indicar si se estaba ejecutando alguna funcionalidad.
  • Nos habría gustado mejorar la forma en la que se abren los cajones de la caja registradora, ya que los servos solo nos permiten levantar ligeramente los cajones.

Problemas

  • Los elementos que nos gustaría haber añadido no hemos podido añadirlos porque no teníamos suficientes entradas a las que poder conectarlos.
  • Para los servo motores que utilizamos en nuestro proyecto necesitábamos alimentación externa, ya que los 5 voltios que nos proporciona el Arduino no era suficiente para alimentar los servos y el resto de nuestro circuito. Intentamos usar una pila de 9 voltios para alimentarlos pero no conseguimos que funcionaran. La solución que encontramos fue utilizar un Arduino extra como fuente de alimentación, porque si conectábamos los servos a nuestro Arduino sí que funcionaban pero si los conectábamos a nuestra pila no.

Demostración del funcionamiento

https://drive.google.com/file/d/1ntIndO3Kne8UTrzbIt_y9XLdYcUBH3ja/view?usp=sharing

También te podría gustar...

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *