fbpx
ArduinoNovidade

Como montar o Jogo Pega LED

O Pega LED é um jogo interativo de rastreamento de luz, ideal para brincar com os amigos e testar a agilidade de cada participante. Para pontuar, participante precisa acionar um sensor LDR usando uma lanterna no local em que o LED verde aparecer. A cada ponto, o LED verde muda de posição. Por exemplo, se o LED verde acender na posição 3, o jogador deve direcionar a luz da lanterna para o LDR da posição 3. O jogo tem duração de 60 segundos e ganha quem conseguir fazer a maior pontuação nesse intervalo de tempo.

Jogo Pega LED
Figura 1- Jogo pega led montado na protoboard

O jogo é controlado por 6 LDRs que, quando saturados com a lanterna, agem como se fosse botões. Cada LDR é responsável por uma posição do LED endereçável. Desta forma, foram definidas 6 posições de 0 a 5, onde o LDR conectado ao pino A0 controla o LED da posição 0, o LDR no pino A1 controla o LED na posição 1, e assim sucessivamente, até o LDR no pino A5.

MATERIAIS NECESSÁRIOS

1 x Placa Uno SMD R3 Atmega328;
1 x Cabo USB Tipo A – B Compatível com Arduino;
1x Kit de LDR 5mm Fotoresistor;
1x Kit de Resistor 10 kΩ;
1x Termo retrátil;
1x Kit de cabo Jumper Macho x Macho 20 cm;
1x Fita de LED Endereçável.

ESQUEMATICO DE LIGAÇÃO

Certifique-se que o circuito esteja desenergizado e faça as ligações conforme o esquemático abaixo.

Esquemático de ligação do jogo.
Figura 2 – Esquemático de ligação do jogo.

Ao montar seu circuito na protoboard, preste atenção nos seguintes pontos:

  • Conecte o GND da fita ao GND do Arduino;
  • Conecte o Din (sinal da fita led), na porta digital 2 da placa UNO;
  • E o 5V da fita no 5V do Arduino;
  • Ligue também um pino de cada um dos LDRs ao 5 V do Arduino;
  • No outro pino do LDR, coloque um resistor de 10 kΩ conectado ao GND;
  • No pino do LDR ligado ao GND, conecte um jumper que irá para as portas analógicas correspondentes às posições. O jumper do LDR da primeira posição deve ser conectado à entrada A0 do Arduino, o segundo à A1, o terceiro à A2, o quarto à A3, o quinto à A4, e o sexto à A5.

Observação: Como o LDR é um sensor que é bastante sensível, a luz da lanterna pode interferir no LDR ao lado. Para garantir que a luz atinja apenas o LDR desejado, é importante colocar um tubo termo retrátil ou um canudo cobrindo suas laterais, protegendo-o da luz indesejada.

LDR com e sem termo retrátil.
Figura 3 – LDR sem e com o termo retrátil.

ELABORANDO O CÓDIGO

CÓDIGO TESTE

Antes de começar a programar o projeto, é importante testar a sensibilidade dos LDRs. Para isso, definimos a quantidade de LDRs e declaramos um array que armazena os números dos pinos analógicos aos quais os LDRs estão conectados: A0, A1, A2, A3, A4 e A5. Em seguida, utilizamos a função Serial.begin() no setup() para iniciar a comunicação serial. No loop(), foi criado um laço for para ler os valores dos LDRs e imprimi-los de maneira organizada.

O código testa todos os LDRs ao mesmo tempo, e identifica a quantidade de luz que o sensor está capturando no ambiente. O valor lido é exibido no monitor serial e serve de base para ajustar a sensibilidade no código principal.

O código teste ficou assim:

#define NUM_LDRS 6  // Número de LDRs
// Pinos dos LDRs
int ldrPinos[NUM_LDRS] = {A0, A1, A2, A3, A4, A5};
void setup() {
  Serial.begin(9600); // Inicializa a comunicação serial
}
void loop() {
  // Lê os valores dos LDRs
  for (int i = 0; i < NUM_LDRS; i++) {
    int valorLdr = analogRead(ldrPinos[i]);
    Serial.print("LDR");
    Serial.print(i);
    Serial.print(": ");
    Serial.print(valorLdr);
    Serial.print("\t"); // Tabulação para separar os valores na mesma linha
  }
  Serial.println(); // pula para a próxima linha após imprimir todos os valores
  delay(1000); // Atraso de 1 segundo entre as leituras
}

Lembre-se de testar os LDRs com e sem a lanterna. Além disso, verifique se, ao direcionar a lanterna para um LDR específico, não há interferência no LDR próximo. Evite posicioná-los muito próximos uns dos outros.

CÓDIGO COMPLETO

Agora, no código principal do projeto, incluímos a biblioteca Adafruit_NeoPixel.h, que é responsável pelo controle dos LEDs endereçáveis. Definimos o pino 2 para o sinal dos LEDs e a quantidade utilizada, além de criar uma variável para controlar o brilho.

Em seguida, criamos um objeto para o controle dos LEDs. Logo após, definimos um array contendo os pinos analógicos nos quais os LDRs estão conectados e a sensibilidade desses LDRs. Valores acima de 950 indicam maior sensibilidade à luz. Ajuste conforme o resultado obtido no código teste, esse passo é necessário para obter a melhor resposta do sensor.

Na linha unsigned long intervaloLedVerde = 2000;, configuramos o tempo em que o LED ficará aceso na cor verde, que neste caso é de 2000ms (2 segundos). Já a variável unsigned long contagemRegressiva = 60000; define o tempo total de duração do jogo em milissegundos, ou seja, 60000ms (1 minuto).

No setup(), o código inicializa a comunicação serial com Serial.begin(9600);, configura os LEDs com leds.begin(); e define o brilho com leds.setBrightness(BRILHO);. Em seguida, usamos a função randomSeed(analogRead(7)); para garantir que as posições aleatórias dos LEDs sejam aleatórias cada vez que o programa for iniciado.

No loop principal, monitoramos o tempo decorrido com millis() e atualizamos a contagem regressiva. Se o tempo se esgotar, o jogo termina e a pontuação é exibida no monitor serial. O LED verde muda de posição a cada intervaloLedVerde para manter o jogo dinâmico

A função mediaLeituraAnalogica(int pino) faz uma leitura média dos valores analógicos dos LDRs para suavizar as flutuações. Quando o valor lido pelo LDR do LED verde excede o limite definido, a pontuação é incrementada, e o LED verde é movido para uma nova posição aleatória com a função trocaLedVerde(unsigned long milissegundosAtuais). Este processo garante que o jogo permaneça interativo e desafiador, incentivando o jogador a reagir rapidamente para marcar pontos. A inclusão de pequenos atrasos com delay(20) ajuda no debounce das leituras dos LDRs, tornando a detecção mais precisa e confiável.

Ao final o código ficará assim:

#include <Adafruit_NeoPixel.h>
#include <Wire.h>

#define PIN            2 
#define NUM_LEDS       6

Adafruit_NeoPixel leds = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRB + NEO_KHZ800);
int ldrPinos[NUM_LEDS] = {A0, A1, A2, A3, A4, A5};  // Pinos dos LDRs
int limite = 950;  // Limite para os LDRs

int ledVerde = -1;  // Índice do LED que é verde
int pontuacao = 0;  // Variável para rastrear pontos
unsigned long ultimaTrocaLedVerde = 0;  // Tempo em que o LED verde foi trocado pela última vez
unsigned long intervaloLedVerde = 5000;  // Intervalo em milissegundos para a troca do LED verde
unsigned long contagemRegressiva = 60000;  // Temporizador em milissegundos
unsigned long milissegundosAnteriores = 0;
bool jogoTerminado = false;

void setup() {
  Serial.begin(9600); // Inicializa a comunicação serial
  leds.begin();
  leds.show(); // Inicializa todos os pixels como 'desligados'
  randomSeed(analogRead(7));  // Inicializa a semente aleatória
  ledVerde = random(NUM_LEDS);  // Seleciona um LED aleatório para ser verde
}

void loop() {
  if (jogoTerminado) return;

  unsigned long milissegundosAtuais = millis();

  // Manipula o temporizador regressivo
  if (milissegundosAtuais - milissegundosAnteriores >= 1000) {
    milissegundosAnteriores = milissegundosAtuais;
    contagemRegressiva -= 1000;
    if (contagemRegressiva <= 0) {
      jogoTerminado = true;
      Serial.println("Fim de Jogo");
      Serial.print("Pontos: ");
      Serial.println(pontuacao);
      return;
    } else {
      Serial.print("Tempo: ");
      Serial.println(contagemRegressiva / 1000);
    }
  }

  // Troca o LED verde em intervalos
  if (milissegundosAtuais - ultimaTrocaLedVerde > intervaloLedVerde) {
    int novoLedVerde;
    do {
      novoLedVerde = random(NUM_LEDS);  // Troca o LED verde para outra posição aleatória
    } while (novoLedVerde == ledVerde);  // Garante que a nova posição seja diferente da atual
    
    ledVerde = novoLedVerde;
    ultimaTrocaLedVerde = milissegundosAtuais;
  }

  // Atualiza as cores dos LEDs
  for (int i = 0; i < NUM_LEDS; i++) {
    leds.setPixelColor(i, (i == ledVerde) ? leds.Color(0, 255, 0) : leds.Color(255, 0, 0));
  }
  leds.show();

  // Lê e processa os valores dos LDRs
  int valorLdrVerde = mediaLeituraAnalogica(ldrPinos[ledVerde]);
  if (valorLdrVerde > limite) {
    pontuacao++;
    Serial.print("Pontos: ");
    Serial.println(pontuacao);
    trocaLedVerde(milissegundosAtuais);
  }

  delay(20);  // Pequeno atraso para debouncing da leitura dos LDRs
}

int mediaLeituraAnalogica(int pino) {
  int total = 0;
  for (int i = 0; i < 5; i++) {
    total += analogRead(pino);
    delay(10);
  }
  return total / 5;  // Média das leituras
}

void trocaLedVerde(unsigned long milissegundosAtuais) {
  int novoLedVerde;
  do {
    novoLedVerde = random(NUM_LEDS);
  } while (novoLedVerde == ledVerde);
  
  ledVerde = novoLedVerde;
  ultimaTrocaLedVerde = milissegundosAtuais;
}

Quando enviar o código, abra o monitor serial do Arduino IDE para acompanhar a pontuação. Confira o projeto finalizado no vídeo abaixo:

Você pode usar sua criatividade e expandir esse projeto, nós por exemplo, criamos uma estrutura de cano pvc para que o jogo ficasse mais esportivo e ainda mais divertido, veja o vídeo abaixo:

Obrigado a todos e, em caso de dúvidas, deixe seu comentário abaixo!

Estagiário no setor de desenvolvimento na Casa da Robótica

Graduando em Engenharia da Computação pela Faculdade Independente do Nordeste. Estagiário do setor de desenvolvimento da Casa da Robótica.

Raphael Christian

Graduando em Engenharia da Computação pela Faculdade Independente do Nordeste. Estagiário do setor de desenvolvimento da Casa da Robótica.