Vidéo-projection Interactive

Wikis > Wiki > Nos projets collaboratifs > Vidéo-projection Interactive

I. Partie « Hardware »

1. Communication sans-fil

a. nRF24L01+

le circuit

On va utiliser la bibliothèque NRF24 de TMRh20 disponible ici.
Le module nRF24L01+ utilise le protocole de communication SPI, il a donc un branchement particulier que la documentation de la bibliothèque décrit en bas de cette page.

Voici le schéma de branchement (les broches CS et CE du module peuvent être connectées ailleurs sur l’Arduino à condition de l’indiquer dans le code…) :
Image de connexion du module nRF24L01+ à l'Arduino

le code

Ce code permet simplement de voir si la communication entre deux Arduino fonctionne.
En connectant le pin 4 au GND on informe l’Arduino qu’il s’agit du récepteur, sinon il s’agit de l’émetteur

cliquez pour dérouler le code de communication entre deux Arduino

/*
  Sene
  Code pour nRF24L01+ radios
  Connectez le pin 4 au gnd pour passer en recepteur, laisser libre pour etre en emetteur

  Sources : https://github.com/maniacbug/RF24.git & https://github.com/TMRh20/RF24.git
  Mise à jour : Oct 2016 by Paolo
*/

#include <SPI.h>
#include "RF24.h"

/* Configuration du Hardware : connectez nRF24L01 radio sur le bus SPI et sur les pins 7 & 8 */
RF24 radio(7, 8);
/*********************************************************************************************/

byte addresses[][6] = {"1Node", "2Node", "3Node", "4Node", "5Node", "6Node", "7Node"};
char donnees;
char anciennesDonnees;
char c;
bool allumage = 0;
bool role = 0;

const int pinLed = 2;
const int pinRole = 4;


void setup() {

  pinMode(pinRole, INPUT);
  pinMode(pinLed, OUTPUT);
  digitalWrite(pinRole, HIGH);
  digitalWrite(pinLed, allumage);
  if (digitalRead(pinRole)) {
    role = 0;
  }
  else {
    role = 1;
  }
  delay(20);
  Serial.begin(115200);
  if (role) Serial.println("radio reception");
  else Serial.println("radio emission");
  radio.begin();
  radio.setPALevel(RF24_PA_HIGH);
  radio.setDataRate(RF24_250KBPS);
  if (role) {
    radio.openWritingPipe(addresses[0]);
    radio.openReadingPipe(1, addresses[1]);
    radio.openReadingPipe(2, addresses[2]);
    radio.openReadingPipe(3, addresses[3]);
    radio.openReadingPipe(4, addresses[4]);
    radio.openReadingPipe(5, addresses[5]);
    radio.openReadingPipe(6, addresses[6]);
    radio.startListening();
  }
  else {
    radio.openWritingPipe(addresses[1]);
    radio.openReadingPipe(1, addresses[0]);
    radio.stopListening();
  }

}


void loop() {
  if (role) {
    while (radio.available()) {
      anciennesDonnees = donnees;
      radio.read( &donnees, sizeof(donnees) );
      Serial.print("anciennes donnees : ");
      Serial.print(anciennesDonnees);
      Serial.print(" / donnees : ");
      Serial.print(donnees);
      if (anciennesDonnees != donnees) {
        allumage = 1 - allumage;
        digitalWrite(pinLed, allumage);
      }
      Serial.print(" / allumage : ");
      Serial.println(allumage);

    }
  }
  else {
    while (Serial.available()) {
      char c = Serial.read();
      Serial.read();
      radio.stopListening();

      Serial.print(F("J envoie : "));
      Serial.println(c);

      if (!radio.write( &c, sizeof(c) )) {
        Serial.println(F("echec"));
      }
      else
        Serial.println("reussit");
      delay(1000);
    }
  }
}

 

II. Partie « software »

1. Processing

I. Gestion des sprites

https://youtu.be/QL-VrBpdeWo

J’ai bidouillé un code existant (à voir ici) qui va loader successivement des fichiers de type « Marche_00.png » jusqu’à « Marche_08.png » et les jouer sur place.

Les 8 étapes de la marche du lemmings que j'ai découpé en 8 images png.
Les 8 étapes de la marche du lemmings que j’ai découpé en 8 images png. Télécharger les sprites ici.

J’ai cleané un peu le code existant et rajouté un test de collision avec les bords extérieurs de mon écran que j’ai appelé collisionBord (qui est une valeur booléenne, soit « True », soit « False »). Si on change la largeur de l’écran, le lemming réagit bien aux bords nouvellement définis. Rajout également, à l’initialisation il tombe.

Animation marcheD, marcheG, tombe;

float xPos;   // La position en abscisse du sprite
float yPos;   // La position en ordonnée du sprite
float solPos; 
int speedPix;   // La vitesse de déplacement du sprite 

boolean collisionBord = false; // Test la collision avec le bord de l'écran 
boolean collisionSol = false; // Test la collision avec le sol 

void setup() {
  size(100, 400); // On défini la taille de l'écran
  frameRate(12); // images par secondes, comme au cinéma

  xPos = (width/2)-12; // On centre la position x par rapport à la largeir de l'écran et du sprite
  yPos = 0;
  solPos = height-50; // Position du sol en y
  speedPix = 4; 
  
  marcheD = new Animation("MarcheD_", 8);  // le 8 représente le nombre d'images à boucler.
  marcheG = new Animation("MarcheG_", 8);
  tombe = new Animation("Tombe_", 4);
}

void draw() { 

    background(0, 0, 0);   // dans cette boucle on efface l'écran (ici noir) avant de redessiner
    if (yPos < solPos) {
    tombe.display(xPos, yPos);yPos = yPos+8;}
    
    else {
    
    if (xPos > width-24) {
    collisionBord = true;background(100, 0, 0);
    } // Si mon sprite atteind le bord droit de l'écran ( moins la largeur du sprite de 24px) alors il y a collision
    
    if (xPos < 0) {
    collisionBord = false;background(100, 0, 0);
    } // Si mon sprite atteind le bord gauche de l'écran (sous 0) alors il n'y a pas de collision (une façon de boucler)
    
    if (!collisionBord) { 
    marcheD.display(xPos, yPos);xPos = xPos+speedPix;
    } // Si il n'y a pas de collision avec le bord droit de l'écran, alors je joue l'animation de marche vers la droite, en déplaçant de tant de pixels vers la droite
    
    if (collisionBord) {
    marcheG.display(xPos, yPos);xPos = xPos-speedPix;
    } // Si il Y A EU une collision avec le bord droit de l'écran, alors je joue l'animation de marche vers la gauche, en déplaçant de tant de pixels vers la gauche
    }
}


// Class pour l'animation des fichiers .png 

class Animation {
  PImage[] images;
  int imageCount;
  int frame;
  
  Animation(String imagePrefix, int count) {
    imageCount = count;
    images = new PImage[imageCount];

    for (int i = 0; i < imageCount; i++) {
      String filename = imagePrefix + nf(i, 2) + ".png"; // nf() sert à intégrer 1 zero avant le compteur d'image pour passer de "MarcheD_09.png" à "MarcheD_10.png" et non "MarcheD_010.png"
      images[i] = loadImage(filename);
    }
  }

void display(float xPos, float yPos) {
frame = (frame+1) % imageCount;
image(images[frame], xPos, yPos);
}  

}

 

Enregistrer