Pong

Jeu de pong 1D #

Ce TP est basé sur un Arduino Nano, et une bande de 72 LEDs RGB pilotées individuellement (WS2812B). Le montage contient également 2 boutons type borne d’arcade.

Les deux boutons permettent de relier les broches 2 et 3 à la masse. La bande de LEDs est pilotable à l’aide du module FastLED. La broche qui permet le pilotage est la broche 9.

Objectifs #

On pourra librement se fixer des objectifs utilisant le matériel à disposition. Une proposition est un jeu type Pong. Une navette est renvoyée par une pression sur le bouton, vers le joueur adverse. Pour renvoyer la navette, le bouton doit être pressé précisément lorsque la navette est suffisamment proche du joueur, sans toutefois avoir atteint sa cible. On peut matérialiser ce moment par un changement de couleur de la navette. La vitesse de la navette pourra augmenter au fur et à mesure de la partie.

Éléments techniques #

Utilisation de l’Arduino Nano #

On peut détecter le port sur lequel est connecté l’Arduino Nano (sous Windows) avec le gestionnaire de périphériques :

Pour uploader le code, utilisez ces réglages (avec le port approprié) :

Pilotage du ruban de LEDs #

Le pilotage du ruban de LEDs se fait avec le module FastLED. Pour utiliser ce module, on déclare un tableau contenant autant d’éléments qu’il y a de LEDs. Chaque élément de ce tableau contiendra la couleur de la LED associée. Une fois le tableau prêt, on demande au module de mettre à jour l’état des LEDs.

Veillez à ce que la bibliothèque FastLED soit bien installée :

Le code suivant permet d’allumer une LED au hasard, dans uen couleur aléatoire.

#include "FastLED.h"

// Nombre de LEDs sur la bande
#define NUM_LEDS 72
// broche de données du ruban de leds
#define DATA_PIN 9 

// Tableau contenant l'état des LEDs
CRGB leds[NUM_LEDS]; 

// ========================================================
void setup() {
    Serial.begin(115200);
    // Association du tableau au ruban de LEDs
    LEDS.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
    // Mise à 0 de tout le tableau
    memset(leds, 0, NUM_LEDS * sizeof(struct CRGB));
    Serial.println("Go");
}

int random_led() {
    int num;
    // mise à 0 du tableau (pas toujours nécessaire)
    memset(leds, 0, NUM_LEDS * sizeof(struct CRGB));
    // choix d'un numéro de LED 
    num = rand() % NUM_LEDS;
    // chaque composante est un entier sur un octet
    leds[num].r = rand() % 206 + 50;
    leds[num].g = rand() % 206 + 50;
    leds[num].b = rand() % 206 + 50;
    // Mise à jour des leds
    LEDS.show();
    return num;
}

void loop()
{
    int num;
    num = random_led();
    Serial.print("LED : ");
    Serial.println(num);
    delay(200);
}

Gestion des interruptions #

Gestion des interruptions sur le site officiel Arduino.

Si on souhaite que l’appui sur le bouton puisse interrompre tout calcul en cours, il faudra gérer les interruptions. On peut par exemple provoquer l’exécution d’une fonction d’interruption sur frond descendant de la broche 2 ainsi :

volatile int compteur = 0;

void setup() {
  Serial.begin(115200);
  // Activation de la résistance de PULLUP 
  // => niveau haut si le bouton est relaché, bas s'il est pressé
  pinMode(2,INPUT_PULLUP);  
  // Interruption sur front descendant de la broche 2
  attachInterrupt(digitalPinToInterrupt(2), clic_bouton, FALLING);
  Serial.println("Go...");
}


void clic_bouton() {
    // Serial.println("*");
    compteur++;
} 

void loop()
{
  Serial.println("Waiting 10 s");
  delay(10000);
  Serial.print("Compteur : ");
  Serial.println(compteur);
}

Attention, dans une fonction d’interruption, tout n’est pas permis :

  • le traitement doit être le plus court possible
  • les fonctions horaires ne sont pas disponibles
  • les variables accédées et modifiées doivent être déclarées volatile

Au passage, le code vous permettra d’expérimenter sur les problèmes de rebond (un seul appui souhaité sur le bouton, mais plusieurs appuis détectés).