FIFAduino

INTEGRANTES


Nombre

Correo de la Universidad

Paula Fernández Pérez

p.fernandezp.2022@alumnos.urjc.es

Maria Martín Mullor

m.martinmul.2021@alumnos.urjc.es

Rubén Camacho Rodríguez
r.camacho.2022@alumnos.urjc.es

Wenhao Zhang
w.zhang.2022@alumnos.urjc.es

INTRODUCCIÓN

¿Te imaginas un futbolín que no solo entretenga, sino que también eleve la emoción del juego con marcador automático y cuenta atrás integrada? 

En este proyecto de Arduino hemos llevado el clásico futbolín al siguiente nivel, combinando la pasión por el juego con la tecnología. Diseñado para hacer cada partida más competitiva y dinámica, este sistema convierte el futbolín tradicional en una experiencia interactiva que todos querrán tener en casa. ¡Descubre cómo lo hicimos y por qué este invento no pasa desapercibido!

OBJETIVOS DEL PROYECTO

  • Automatizar la detección de goles : Hemos implementado sensores capaces de identificar automáticamente cuándo se marca un gol, eliminando la necesidad de que los jugadores lleven la cuenta manualmente y garantizando mayor precisión en el juego.
  • Mostrar el marcador y el tiempo : Diseñamos una interfaz visual con pantallas que muestran en tiempo real el resultado del partido y una cuenta atrás programable, lo que aporta un mejor desarrollo de las partidas.
  • Abrir y cerrar la compuerta automáticamente : Para controlar el flujo de la pelota, automatizamos el mecanismo de una compuerta que se abre para liberar la bola cuando se introduce una moneda y se cierra cuando finaliza el temporizador.
  • Dar señales sonoras cuando haya un gol : Incluimos una alerta sonora que se activa cada vez que se detecta un gol, facilitando la identificación del tanto, incluso si los jugadores no están mirando el marcador. Además, hemos incluido una señal sonora al finalizar el partido. 

Con este proyecto, no solo buscamos aplicar nuestros conocimientos en programación y electrónica, sino también ofrecer una versión mejorada del futbolín tradicional que resulte atractiva tanto para usuarios particulares como para negocios de ocio.

FUNCIONALIDAD

En primer lugar, empezamos realizando un diagrama de flujo para poder orientarnos durante el desarrollo del proyecto y poder dar comienzo teniendo las ideas claras.

Diagrama de flujo

El siguiente diagrama representa el flujo general de funcionamiento del sistema automatizado del futbolín, desde que el usuario introduce una moneda hasta el final de la partida.

  1. Introducir moneda
     El sistema se activa cuando se detecta la inserción de una moneda. Este evento da comienzo a todo el proceso automatizado.
  2. Inicialización del sistema
     De forma simultánea, se ejecutan tres acciones: se abre la compuerta que libera la pelota, se inicia el temporizador que controla la duración del partido y se pone a cero el marcador
  3. Durante el partido
     Una vez iniciado el juego, el sistema entra en un bucle en el que comprueba de forma continua si se ha anotado un gol. En caso afirmativo, se actualiza automáticamente el marcador (además de producir una señal sonora) y el juego continúa.
  4. Fin del partido
    Una vez acabado el tiempo del partido se producirá un pitido dando por finalizado el partido. El sistema cierra la compuerta para impedir que se siga jugando, volviendo al estado inicial y esperando la próxima moneda.

MATERIALES

CIRCUITERIA

NOMBRE CANTIDAD PRECIO
Arduino UNO110 €
Sensor ultrasonido43 €
Zumbador10,5 €
Servomotor11,20 €
Pantallas led44 €
Final de carrera10,35 €
Placa protoboard15 €
Cables3 €

OTROS MATERIALES

NOMBRE CANTIDAD PRECIO
Contrachapado615 €
Cartón1
Pelota10,5 €
Corchos de botellas9
Bolsa lavadora10,85 €
Pinzas de la ropa141.50 €
Pajitas20,2 €
Palos redondos61 €

MONTAJE

CONSTRUCCIÓN DEL FUTBOLÍN

Para la construcción del futbolín, utilizamos una estructura de madera hecha a medida, concretamente de contrachapado. La base del proyecto se compone de dos niveles: una parte superior, donde se encuentran los jugadores y las porterías, y una parte inferior, donde se aloja todo el sistema electrónico.

En cuanto a los jugadores, decidimos fabricarlos con pinzas de la ropa, que fueron recortadas y pintadas para representar a cada equipo. Estas pinzas están sujetas a palos redondos de madera que actúan como las barras del futbolín. Para los mangos de las barras, reutilizamos corchos de botellas, que forramos con cinta aislante de colores para distinguir fácilmente los equipos.

Las porterías se construyeron con palos cuadrados de madera que cortamos a medida y fijamos a la estructura. Para simular la red, utilizamos una bolsa de lavadora recortada y pegada a la parte trasera. Justo encima de cada portería colocamos un trozo de cartón adaptado, donde encajamos las pantallas LED del marcador. Esto nos permitió dejar ocultos los cables, haciendo que bajaran directamente a la parte inferior sin quedar visibles.

Las rampas por donde cae la pelota están pegadas directamente a la base inferior del futbolín. De esta forma, cuando la pelota entra por la portería, cae por la rampa e interrumpe el haz del sensor ultrasónico. Para que los sensores midieran distancias lógicas y no quedaran apuntando al vacío, colocamos cartones como fondo de las rampas, ayudando a que la detección fuera más precisa. Algunas piezas de madera las fijamos con tornillos y otras con cola blanca o silicona caliente, en función del tipo de material o de la estabilidad que necesitábamos.

Para permitir la salida controlada de la pelota al inicio de cada partida, fabricamos una compuerta con una pajita reforzada con un palo redondo. Además, añadimos bisagras a uno de los laterales de la estructura para poder abrir el futbolín fácilmente y acceder al interior si necesitábamos revisar o modificar algo. 

En definitiva, optamos por una construcción artesanal, reutilizando materiales donde fue posible y combinando funcionalidad, bajo coste y una estética cuidada para conseguir un sistema automatizado completo y visualmente atractivo.

CONEXIONES CON ARDUINO

ORIGEN PIN
zumbador A1
trigger sensor A110
echo sensor A111
trigger sensor A212
echo sensor A213
trigger sensor B12
echo sensor B13
trigger sensor B2A4
echo sensor B2A5
servomotor9
final de carrera A0
dataPin marcador 5
clkPin marcador 4
csPin marcador A3
dataPin temporizador8
clkPin temporizador 7
dataPin temporizador6

DESARROLLO DEL CÓDIGO

Una vez probadas todas las piezas, podemos ir con la construcción de la lógica del código, es decir, el funcionamiento del futbolín en sí. 

Inicialmente empezamos desarrollando el código de los sensores, una parte fundamental del futbolín. Para ello necesitábamos ajustar frecuentemente a qué distancia debía pasar la pelota para que detectara un gol, por lo que imprimir por pantalla los valores que devuelven era crucial. Una vez se detectan correctamente los goles procedemos a ir añadiendo el resto de las piezas poco a poco en el código.

El código se basa en 3 partes principales: el momento en el que se introduce la moneda, el desarrollo del partido y el final del partido.

En el momento en el que se introduce la moneda se inicializa todo. Se resetea el marcador, se inicializan las matrices led en sus valores correspondientes y se mueve el servomotor dejando caer las pelotas. Además, se recoge el tiempo de inicio con milis() y se cambia de valor a una variable booleana (“iniciado”) para dar paso a la siguiente parte del código sin que vuelva a entrar en esta.

Una vez se ha iniciado el partido y mientras quede tiempo, el programa calculará el tiempo restante para escribirlo en la matriz del temporizador y los sensores tomarán una medida. Si no se ha marcado un gol recientemente (hemos puesto un delay de 3 segundos entre gol y gol), se comprobará que estas medidas de los sensores se encuentren por debajo de un rango. Si esto sucede, se añadirá un gol al marcador correspondiente, sonará el zumbador y se activará el delay de gol.

Transcurrido el tiempo del partido, sonará un pitido de final de partido y se cerrará la puerta por donde pasan las pelotas. También se cambiará el valor de la variable “iniciado” para permitir detectar otra moneda y volver a empezar un nuevo partido.

Para la implementación de este código se ha empleado dos librerías, una para poder controlar el servomotor (Servo.h) y otra para las matrices led (MatrizLed.h). También hemos necesitado 4 funciones auxiliares:

  • medirDistancia : se toma la medida que recoge el sensor y se transforma a centímetros para la detección de goles.
  • getChar : pasa una cifra a carácter para poder pasarlo a la matriz led.
  • playGolSound : reproduce el sonido de gol.
  • playEndSound : reproduce el sonido de final de partido
#include <Servo.h>
#include <MatrizLed.h>


#define NOTE_C5 523  // Do5
#define NOTE_E5 659  // Mi5


// Pin Buzzer
const int buzzerPin = A1;


// Variables matrices led
MatrizLed temporizador;
MatrizLed marcador;


// Pines sensores
const int triggerA1 = 10, echoA1 = 11;
const int triggerA2 = 12, echoA2 = 13;


const int triggerB1 = 2, echoB1 = 3;
const int triggerB2 = A4, echoB2 = A5;


// Pines servo y botón
const int servoPin = 9;
const int botonPin = A0;


//Variable servo
Servo miServo;


// Contadores de goles
int golesA = 0;
int golesB = 0;


const int tiempoEsperaGol = 3000;         // 3 segundos bloqueo tras un gol (delay)
unsigned long ultimaDeteccionGlobal = 0;  // Tiempo último gol
unsigned long inicio = 0;                 // Tiempo inicio
bool iniciado = false;                    // Boolean para control de inicio


void setup() {
  Serial.begin(9600);


  pinMode(buzzerPin, OUTPUT);


  temporizador.begin(8, 7, 6, 2);
  marcador.begin(5, 4, A3, 2);


  pinMode(triggerA1, OUTPUT); pinMode(echoA1, INPUT);
  pinMode(triggerA2, OUTPUT); pinMode(echoA2, INPUT);
  pinMode(triggerB1, OUTPUT); pinMode(echoB1, INPUT);
  pinMode(triggerB2, OUTPUT); pinMode(echoB2, INPUT);


  pinMode(botonPin, INPUT_PULLUP);
  miServo.attach(servoPin);
  miServo.write(150); // Servo cerrado
}


void loop() {
  // Esperar a que caiga la moneda para empezar
  if (!iniciado && digitalRead(botonPin) == LOW) {
    Serial.println("¡Comienza el partido! Marca goles en 90                         segundos...");


    // Inicializar contadores a 0
    golesA = 0;
    golesB = 0;


    // Inicializar ultimo gol a 0
    ultimaDeteccionGlobal = 0;


    // Restablecer matrices led
    marcador.borrar();
    temporizador.borrar();


    miServo.write(50); // Abrir servo
    delay(500); // Pequeño retardo tras abrir
   
    // Marcador 0 : 0
    marcador.escribirCaracter('0', 0);
    marcador.escribirCaracter('0', 8);


    // Temporizar 90 s
    temporizador.escribirCaracter('9', 0);
    temporizador.escribirCaracter('0', 8);


    // Comienzo del partido
    inicio = millis();
    iniciado = true;
  }


  // Mientras dure el partido (90 segundos)
  if (iniciado && millis() - inicio < 90000) {
    unsigned long tiempoRestante = 90000 - (millis() - inicio); // Tiempo restante
    int t0 = tiempoRestante / 10000;          // Digito matriz 1
    int t1 = (tiempoRestante % 10000) / 1000; // Digito matriz 2


    char ct0 = getChar(t0);
    char ct1 = getChar(t1);


    // Mostrar temporizador
    temporizador.escribirCaracter(ct0, 0);
    temporizador.escribirCaracter(ct1, 8);




    Serial.print("Tiempo restante: ");
    Serial.print(tiempoRestante / 1000);
    Serial.println(" s");


    // Medir distancias
    float distA1 = medirDistancia(triggerA1, echoA1);
    float distA2 = medirDistancia(triggerA2, echoA2);
    float distB1 = medirDistancia(triggerB1, echoB1);
    float distB2 = medirDistancia(triggerB2, echoB2);


    Serial.println("Distancias:");
    Serial.print("  Sensor A1: "); Serial.print(distA1); Serial.println(" cm");
    Serial.print("  Sensor A2: "); Serial.print(distA2); Serial.println(" cm");
    Serial.print("  Sensor B1: "); Serial.print(distB1); Serial.println(" cm");
    Serial.print("  Sensor B2: "); Serial.print(distB2); Serial.println(" cm");


    if (millis() - ultimaDeteccionGlobal > tiempoEsperaGol) {
      bool golDetectado = false;


      // Gol para equipo B
      if ((distB1 >= 0 && distB1 < 18) || (distB2 >= 0 && distB2 < 20)) {
        golesB++;
        golDetectado = true;
        playGolSound();
        Serial.print("¡GOL DEL EQUIPO B! Total B: ");
        Serial.println(golesB);
        char gB = getChar(golesB);
        marcador.escribirCaracter(gB, 0);




      }


      // Gol para equipo A
      if (!golDetectado && ((distA1 >= 0 && distA1 <19) || (distA2 >= 0 && distA2 < 21))) {
        golesA++;
        golDetectado = true;
        playGolSound();
        Serial.print("¡GOL DEL EQUIPO A! Total A: ");
        Serial.println(golesA);
        char gA = getChar(golesA);
        marcador.escribirCaracter(gA, 8);
      }


      if (golDetectado) {
        ultimaDeteccionGlobal = millis();
        Serial.println("Bloqueo de 3 segundos activado");
      }
    }


    Serial.println("-------------------------------");
    delay(100);
  }


  // Fin del partido
  else if (iniciado) {
    playEndSound();
    Serial.println("¡Tiempo finalizado!");
    Serial.print("MARCADOR FINAL => Equipo A: ");
    Serial.print(golesA);
    Serial.print(" | Equipo B: ");
    Serial.println(golesB);


    miServo.write(150); // Cerrar servo
    iniciado = false;


    // Esperar que se suelte el botón antes de permitir otra partida
    while (digitalRead(botonPin) == LOW);
    delay(300);
  }
}


float medirDistancia(int trig, int echo) {
  digitalWrite(trig, LOW);
  delayMicroseconds(2);
  digitalWrite(trig, HIGH);
  delayMicroseconds(10);
  digitalWrite(trig, LOW);


  long duracion = pulseIn(echo, HIGH, 5000); // Timeout 5ms
  if (duracion == 0) return -1;


  return duracion * 0.0343 / 2.0;
}




char getChar(int n){
  switch (n){
    case 1:
      return '1';
    case 2:
      return '2';
    case 3:
      return '3';
    case 4:
      return '4';
    case 5:
      return '5';
    case 6:
      return '6';
    case 7:
      return '7';
    case 8:
      return '8';
    case 9:
      return '9';
    case 0:
      return '0';
    default:
      return '0';
  }
}


void playGolSound() {


  int melody[] = { NOTE_C5, NOTE_E5 };   // Notas ascendentes
  int durations[] = { 100, 150 };        // Duración en milisegundos


  for (int i = 0; i < 2; i++) {
    tone(buzzerPin, melody[i], durations[i]);  // Reproducir nota
    delay(durations[i] + 50);                  // Pausa después de la nota
  }


  noTone(buzzerPin);  // Detener el sonido por si acaso
}


void playEndSound() {


  int melody[] = { 1000, 1000, 1000 };   // Notas ascendentes
  int durations[] = { 500, 500, 750 };        // Duración en milisegundos


  for (int i = 0; i < 3; i++) {
    tone(buzzerPin, melody[i], durations[i]);  // Reproducir nota
    delay(durations[i] + 50);                  // Pausa después de la nota
  }


  noTone(buzzerPin);  // Detener el sonido por si acaso
}


Vídeos

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 *