Arduino Ethernet shield et Processing (serveur UDP)

Dans cet article on va voir comment régler la luminosité de deux LED avec le montage suivant :

– sur le PC tourne un programme processing qui présente deux sliders chacun contrôlant la luminosité d’une LED
– le PC est relié à un réseau Ethernet
– l’Arduino est équipé d’un shield Ethernet lui aussi relié au réseau
– Sur cet Arduino un programme « écoute » les commandes en provenance du PC

Fichier hébergé par Archive-Host.com

Pour les spécialistes réseau, on a monté sur l’Arduino et son shield un petit serveur UDP. Le programme de base à bien étudier se trouve ici. Il y a, dans ce super exemple, à la fois un programme pour l’Arduino et un programme processing pour le PC.

Voici les programmes adaptés pour commander les deux LED.

Coté Arduino d’abord :


*
  Eth_slider 1
  
  Inspiré de 
  ========================
  UDPSendReceive.pde:
  This sketch receives UDP message strings, prints them to the serial port
  and sends an "acknowledge" string back to the sender
  
  A Processing sketch is included at the end of file that can be used to send 
  and received messages for testing with a computer.
  
  created 21 Aug 2010
  by Michael Margolis
  
  This code is in the public domain.
  
  ============================
  
  Retravaillé pour commander à distance depuis un PC
  connecté au réseau, faisant tourner un code
  processing. Ce code permet de controler deux sliders
  chacun réglant la luminosité d'une LED
  
  */


#include <SPI.h>           // needed for Arduino versions later than 0018
#include <Ethernet.h>
#include <EthernetUdp.h>   // UDP library from: bjoern@cs.stanford.edu 12/30/2008

// les librairies sont deja presentes dans l'IDE 1.0.2


// Adresse Mac du shield Ethernet
// voir etiquette collée en dessous
byte mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0x99, 0x39 };

// adresse ip que vous decidez d'attribuer à votre shield   
IPAddress ip(10, 0, 0, 177);

unsigned int localPort = 8888;     // on écoute sur le port 8888

int tab_Pin[2] = {5,9} ; // la led1 est sur la Pin 5 , la led 2 sur la pin 9


byte donnee_0 = 0; // entete pour savoir quelle est la LED concernée
byte donnee_1 = 0; // brillance LED

// buffers for receiving and sending data
char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet,

char  ReplyBuffer[] = "Reception OK";      // a string to send back

// An EthernetUDP instance to let us send and receive packets over UDP

EthernetUDP Udp;
 

void setup() {
   // start the Ethernet and UDP:
   Ethernet.begin(mac,ip);
   Udp.begin(localPort);   
   Serial.begin(9600);
}

void loop() {
   
  
   // if there's data available, read a packet
   int packetSize = Udp.parsePacket();
   
   if(packetSize)
   {
    
     // read the packet into packetBufffer
     Udp.read(packetBuffer,UDP_TX_PACKET_MAX_SIZE);             
 
  // on va chercher le prefixe qui sera rangé dans donnee_0
  // 1 : commande pour la LED1
  // 2 : commande pour la LED2
     
     donnee_0 = packetBuffer[0] - 48; // 48 est le code Ascii de zéro
     
  // on va chercher la valeur d'intensité de la LED 
  // qui sera rangée dans donnee_1
     
  // explorer le buffer seulement sur la longueur du packet reçu
  // et donc ignorer le reste en queue de buffer
  // on va chercher le chiffre des unités
  // puis celui des dizaines
     
     donnee_1 = 0;
     
     int j = 1;
     
     for ( int i = packetSize -1;  i > 1 ; i--)
          {
                   
            donnee_1 = donnee_1 + j* (packetBuffer[i] - 48);
            
            j = 10 *j;
            
          }                   
   
     if (donnee_0 == 1) controle(1,donnee_1);              
                                     
         else 
              if (donnee_0 == 2) controle(2,donnee_1);         
                   
     // send a reply, to the IP address and port that sent us the packet we received    
     // Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
     // Udp.write(ReplyBuffer);
     // Udp.endPacket();
     
   } // fin if (packetSize) 
   

} // fin loop


// fonction qui règle la luminosite d'une LED
void controle (int pin , int pwm) {
  
 pwm = map(pwm, 0,20, 0,255);
 
 if ( pwm < 2) pwm = 0 ;
 
 pin = tab_Pin[pin -1] ;
 
 analogWrite (pin,pwm);

}

Côté PC maintenant (code processing) :


///////////////////////////////////////////////////////
  
// Eth_slider1

// inspiré de l'exemple UDPSendReceive

// Deux sliders pour commander la luminosité de deux led 

// la librairie hypermedia.net est à mettre dans un dossier   
// libraries situé sous le dossier sketchbook
// http://ubaa.net/shared/processing/udp/
  
// importer les librairies nécessaires 

import controlP5.*; // il faut l'installer

import hypermedia.net.*; // il faut l'installer
  
UDP udp;  // define the UDP object
  
String ip       = "10.0.0.177"; // l'adresse du shield Ethernet
  
int port        = 8888;        // le port destination à atteindre


ControlP5 controlP5;


String prefixe_led1 = "1#" ; // ce prefixe indique que la commande 
                             // qui va suivre  concerne la led1

String prefixe_led2 = "2#" ; // ce prefixe indique que la commande
                             // qui va suivre concerne la led2
                         

void setup() {
  
  udp = new UDP( this, 6000 );  // create a new datagram connection on port 6000
  //udp.log( true );         // <-- printout the connection activity
  udp.listen( true );           // and wait for incoming message  
  
  // On dessine la fenetre de l'interface graphique
  size(400,350);
  
   
  controlP5 = new ControlP5(this); 
  
  // Creer un premier slider horizontal
  
  //("Nom du Slider", min,max, pos de depart, xpos,ypos, largeur,hauteur);
  controlP5.addSlider("LED1", 0,20, 0, 100,50, 200,20);
  
  // Configure les propriétés du Slider
  Slider s1 = (Slider)controlP5.controller("LED1");
  s1.setSliderMode(Slider.FLEXIBLE);
  s1.setNumberOfTickMarks(11);
  s1.showTickMarks(true);
  s1.snapToTickMarks(false);

  // Crer un second slider horizontal

  //("Nom du Slider", min,max, pos de depart, xpos,ypos, largeur,hauteur);
  controlP5.addSlider("LED2", 0,20, 0, 100,150, 200,20);
  
  // Configure les propriétés du Slider
  Slider s2 = (Slider)controlP5.controller("LED2");
  s2.setSliderMode(Slider.FLEXIBLE);
  s2.setNumberOfTickMarks(11);
  s2.showTickMarks(true);
  s2.snapToTickMarks(false);
}

// Dessine les objets choisis
void draw() {
  background(100); // 100 : fond gris
}

// Dans cette methode
// on recupère la valeur 
// renvoyée par le slider LED1
// et on l'envoie à l'Arduino

void LED1(float valeur_slider) {
  
  // Récupérer la valeur envoyée par le slider entre 0 et 20
  
  int brillance_LED = round(valeur_slider);   
  
  // envoyer cette valeur à l'Arduino
  // en commençant par le prefixe
  // qui permet de savoir quelle LED
  // est concernée
  
  
  udp.send(prefixe_led1 + str(brillance_LED) , ip, port );  
  
  // pour controle dans la fenetre du bas de processing
  print ("LED1 ");
  println(str(brillance_LED));
  
 
}

// Dans cette methode
// on recupère la valeur 
// renvoyée par le slider LED2
// et on l'envoie à l'Arduino
void LED2(float valeur_slider) {
  
  // Récupérer la valeur envoyée par le slider entre 0 et 20
  
  int brillance_LED = round(valeur_slider);  
  
  // envoyer cette valeur à l'Arduino 
  
  udp.send(prefixe_led2 + str(brillance_LED) , ip, port );   
  
 
  // pour controle dans la fenetre du bas de processing
  
  print ("LED2 ");  
  println(str(brillance_LED)); 
 
}

 
//void receive( byte[] data ) {          // <-- default handler
   //void receive( byte[] data, String ip, int port ) {   // <-- extended handler
  
//  for(int i=0; i < data.length; i++) 
//  print(char(data[i]));  
//  println();   
//  }

Arduino et Xbee (partie 3)

Dans ce précédent article nous avions vu comment il était possible en utilisant Processing de contrôler la position d’un potentiomètre à la souris.

Sur le PC s’executait le code processing, et, en fonction des mouvements de la souris, des commandes étaient envoyées par le câble USB vers l’Arduino. Grâce à un sketch implanté sur l’Arduino les commandes arrivant par le câble USB étaient interprétées et exécutées.

Fichier hébergé par Archive-Host.com

Si on supprime le câble USB liant directement PC et Arduino et que l’on installe les modules Xbee comme expliqué dans l’article précédent, les mêmes programmes (Code Processing pour le PC et code Arduino pour l’Arduino) fonctionnent. Il faut simplement porter la vitesse du port série à 9600 dans les deux programmes (car c’est la vitesse par défaut employée par les modules Xbee).

Du coup, après quelques mois de travail, je peux proposer aujourd’hui à mon ami Yves une commande à la souris et sans fil de moteurs pour animer une superbe grue de sa confection en meccano !

Arduino et Xbee (partie 2)

Fort bien, nous avons équipé dans l’article précédent un DFRduino d’un module Xbee. Mais… comment communiquer avec lui ? Si on a un ordinateur portable avec le wifi est-ce qu’on peut parler à ce module Xbee ? En fait le module Xbee choisi est bien sans-fil mais pas wifi : le wifi est une norme particulière de communication radio et le module Xbee choisi ne suit pas cette norme.

Bref pour communiquer avec ce module Xbee… rien de tel qu’un autre module Xbee identique. Et pour brancher ce deuxième module sur le PC on va utiliser un petit adaptateur qui va accueillir le module Xbee et se brancher en USB sur le PC.

Fichier hébergé par Archive-Host.com

La liste des courses pour cette partie est la suivante :

1 module Xbee identique au précédent XB24-AWI-001
1 câble USB A mâle B mini USB
1 adaptateur Xbee USB adapter V2 (DFR0174)

Une fois l’adaptateur branché au PC, un nouveau port série est crée sur le PC. Sur mon PC sous Linux (Ubuntu 12.10), il est reconnu immédiatement, je ne sais pas si, sous Windows il faut utiliser ou non un driver (je pense que non car le driver est le même que celui de l’Arduino).

Il reste à sélectionner dans l’interface de développement Arduino ce nouveau port série, lancer le moniteur série. Quand on saisit un ‘a’ la LED, s’allume !

Fichier hébergé par Archive-Host.com

A noter : aucune modification n’a été apportée au programme précédent : que l’on soit avec une liaison USB par câble ou avec cette liaison wifi, c’est pareil ! (si vous réutilisez d’anciens programmes, vérifiez tout de même que la vitesse est de 9600 bauds).

Si l’on devait apporter une modification au programme, il faudrait faire deux choses : basculer le petit interrupteur situé sur le shield vers la position USB (il est actuellement sur la position micro), brancher un câble USB. Une fois le nouveau programme transféré, rebasculer le petit interrupteur sur la position micro afin que la transmission wifi fonctionne. Ce petit interrupteur est situé près des broches 1,2,3 du shield.

A noter qu’aucune configuration n’a été faite sur les modules Xbee ; on pourrait modifier la vitesse, attribuer un identifiant au réseau. Ce dernier point pourrait être une bonne idée si vous exposez des modèles avec des modules Xbee à proximité d’un autre exposant utilisant lui aussi des modules Xbee.

Ces modules sont les plus simples à utiliser mais il existe de très nombreux modèles de modules Xbee qui demandent généralement une configuration avant d’être utilisés.

Arduino et Xbee : comment débuter ? (partie 1)

Les Xbee sont de sympathiques modules sans-fil, de la taille d’un timbre poste. Il y en a de nombreux types (pas facile de se décider lors du choix…) et ils peuvent se configurer de nombreuses manières. Pour débuter, j’ai choisi un modèle simple et ne nécessitant aucune configuration.

Pour commencer, nous allons charger sur un Arduino Uno un petit sketch, trouvé sur ce super article

L’Arduino n’est pour l’instant pas équipé de module Xbee.



//////////////////////////////////////////////////////////////////
//©2011 bildr
//Released under the MIT License - Please reuse change and share
//Monitors the serial port to see if there is data available.
//'a' turns on the LED on pin 13. 'b' turns it off.
//////////////////////////////////////////////////////////////////

void setup() {
  Serial.begin(9600);    	//initialize serial
  pinMode(13, OUTPUT);   	//set pin 13 as output
}

void loop() {
  while(Serial.available()){  //is there anything to read?
	char getData = Serial.read();  //if yes, read it

	if(getData == 'a'){  	 
  	  digitalWrite(13, HIGH);
	}else if(getData == 'b'){
  	  digitalWrite(13, LOW);
	}
  }
}

On charge donc le sketch sur l’Arduino comme d’habitude, on ouvre le moniteur série et, comme on peut s’y attendre, si on saisit un ‘a’ dans le moniteur série et que l’on clique sur le bouton envoyer la LED 13 s’allume tandis que la saisie d’un ‘b’ entraîne son extinction. Pour fonctionner, ce petit programme a besoin du câble USB qui lui fournit les données tapées au clavier. Si l’on supprime le câble, on ne peut plus transmettre de données (a ou b) à l’Arduino.

Euh en fait…on va essayer de supprimer ce câble USB, de le remplacer par un équivalent sans fil et de maintenir le fonctionnement du programme en utilisant des modules Xbee.

Ces modules ne peuvent pas se monter directement sur un Arduino ou un DFRduino V1.1, ne serait-ce que parce que l’écartement de leur petites pattes n’est pas le même que celui de l’Arduino: il faut installer sur l’Arduino un « shield » une sorte de seconde peau. Sur ce shield, des connecteurs prêts à accueillir le module Xbee sont présents.

Voilà une première liste de courses :

1 module Xbee XB24-AWI-001
1 Arduino Wireless SD shield

Quatre bonnes sources d’approvisionnement : Gotronic, Zartronic, Lextronic et.. Ebay (vendeur dfrobotcom notamment)

Voici ce que ça donne, monté sur un DFRduino Roméo V1.1 :

Fichier hébergé par Archive-Host.com

Remarque : DFRduino Roméo V2 est maintenant disponible, il comporte des connecteurs Xbee donc dispenserait d’acheter un shield, je le testerai bientôt.

Télecommande infrarouge – IR remote

Fichier hébergé par Archive-Host.com

Une nouvelle application qui utilise une télécommande DFRobot, DFR0107. C’est un kit qui contient une petite télécommande et un récepteur infrarouge. La télécommande émet, pour chaque touche, un signal qu’il faut décoder. Heureusement, on trouve sur le site de DFRobot un programme qui fait le travail de décodage. Ce programme a été légèrement modifié pour permettre la commande de deux moteurs à partir d’un DFRduino Roméo.

Les fonctions disponibles dans ce petit programme de démo :

touche 0 : arrêt des moteurs
touche 1 : le moteur 1 est sélectionné
touche 2 : le moteur 2 est sélectionné
touche flèche vers le haut : augmenter la vitesse du moteur sélectionné
touche flèche vers le bas : diminuer la vitesse du moteur sélectionné

Avec la flèche vers le bas on peut obtenir des vitesses négatives et faire tourner un moteur en marche arrière.

Voici le programme qui fait le travail :


// IR_telecommande3
// Programme de controle de deux moteurs avec une télecommande IR
// ok pour DFRduino Romeo
// se base sur un programme trouvé sur le site de DFRobot
// http://www.dfrobot.com/wiki/index.php/IR_Kit(SKU:DFR0107)

// fonctions disponibles
// touche 0 : arret des moteurs
// touche 1 : sélectionner moteur 1
// touche 2 : selectionnner moteur 2
// touche flèche vers le haut : augmenter vitesse
// touche flèche vers le bas  : diminuer vitesse
// Quand la vitesse devient négative, le moteur change de sens

// =====================================================================


// 0.1 by pmalmsten http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1176098434
// 0.2 by farkinga
// 0.3 by farkinga - adds cool behaviors
/* 0.4 by pstrobl 
   changed the original program to use on IR Kit For Arduino Model: DFR0107 32 bit controller. 
   All keypresses are sent to the serial monitor at 9600 baud.
   pulseIn is always HIGH. The phototransistor in the kit does not invert the signal.
   uses pin 13 for heartbeat debug
   32 bits requires a long variable, so divided up into two 15 bit so can use integer variables
   use the first 15 bits of the 32 bits for remote and data stream verification. This code is always the same for every button press
   use the last 15 of the 32 bits for button press selection. This code changes for each button.
   ignore the middle 2 bits, it never changes.  
*/
 
#define IR_BIT_LENGTH 32    // number of bits sent by IR remote
#define FirstLastBit 15     // divide 32 bits into two 15 bit chunks for integer variables. Ignore center two bits. they are all the same.
#define BIT_1 1500          // Binary 1 threshold (Microseconds)
#define BIT_0 450           // Binary 0 threshold (Microseconds)
#define BIT_START 4000      // Start bit threshold (Microseconds)
 
#define IR_PIN 2            // IR Sensor pin
#define LED_PIN 13          // LED goes off when signal is received
 
int debug = 0;              // flag as 1 to output raw IR pulse data stream length in microseconds
int output_verify = 0;      // flag as 1 to print decoded verification integers. same number for all buttons
int output_key = 0;         // flag as 1 to print decoded key integers
int remote_verify = 16128;  // verifies first bits are 11111100000000 different remotes may have different start codes

// =====================================================================
 
// Ajout pour controle deux moteurs sur DFRduino

int tab_Pin_sens[2] = {4,7} ; // le sens du moteur 1 est commandé par la Pin 4 
                              // le sens du moteur 2 est commandé par la Pin 7

int tab_Pin_pwm[2] = {5,6} ; // la vitesse du moteur 1 est commandée par la Pin 5 
                             // la vitesse du moteur 2 est commandée par la Pin 6
                             
int tab_vitesse[2] = {0,0} ; // on va y sauver la vitesse demandée pour chaque moteur
                             
int moteur=0;

// =====================================================================

void setup() {
  pinMode(LED_PIN, OUTPUT); //This shows when ready to recieve
  pinMode(IR_PIN, INPUT);
  digitalWrite(LED_PIN, LOW);
  Serial.begin(9600);
}
 
void loop() {
  digitalWrite(LED_PIN, HIGH);
  int key = get_ir_key();
   
  digitalWrite(LED_PIN, LOW);  // turn LED off while processing response
  do_response(key);
  delay(130);                  // 2 cycle delay to cancel duplicate keypresses
  
  Serial.print("Loop * moteur :") ; Serial.println (moteur);
  Serial.print("Loop * vitesse : ") ; Serial.println (tab_vitesse[moteur-1]);
}
 
/*
  wait for a keypress from the IR remote, and return the
  integer mapping of that key (e.g. power button on remote returns 
  the integer 1429)
*/
 
int get_ir_key() 
{
  int pulse[IR_BIT_LENGTH];
  int bits[IR_BIT_LENGTH];
 
  do {} //Wait for a start bit
  while(pulseIn(IR_PIN, HIGH) < BIT_START);
 
  read_pulse(pulse);
  pulse_to_bits(pulse, bits);
  RemoteVerify(bits);
  return bits_to_int(bits);
}
 
 
/*
  use pulseIn to receive IR pulses from the remote.
  Record the length of these pulses (in ms) in an array
*/
 
void read_pulse(int pulse[])
{
  for (int i = 0; i < IR_BIT_LENGTH; i++)
  {
    pulse[i] = pulseIn(IR_PIN, HIGH);
  }
}
 
/*
  IR pulses encode binary "0" as a short pulse, and binary "1"
  as a long pulse.  Given an array containing pulse lengths,
  convert this to an array containing binary values
*/
 
void pulse_to_bits(int pulse[], int bits[])
{
  if (debug) { Serial.println("-----"); }
  for(int i = 0; i < IR_BIT_LENGTH; i++) 
  {
    if (debug) { Serial.println(pulse[i]); }
    if(pulse[i] > BIT_1) //is it a 1?
    {
      bits[i] = 1;
    }  
    else if(pulse[i] > BIT_0) //is it a 0?
    {
      bits[i] = 0;
    } 
    else //data is invalid...
    {
      Serial.println("Error");
    }
  }
}
 
/*
  check returns proper first 14 check bits
*/
 
void RemoteVerify(int bits[])
{
  int result = 0;
  int seed = 1;
   
  //Convert bits to integer
  for(int i = 0 ; i < (FirstLastBit) ; i++) 
  {       
    if(bits[i] == 1) 
    {
    result += seed;
    }
     
    seed *= 2;
  }
        if (output_verify)
      {
        Serial.print("Remote ");
        Serial.print(result);
        Serial.println(" verification code");
      }
 if (remote_verify != result) {delay (60); get_ir_key();} //verify first group of bits. delay for data stream to end, then try again.
}
 
 
/*
  convert an array of binary values to a single base-10 integer
*/
 
int bits_to_int(int bits[])
{
  int result = 0;
  int seed = 1;
   
  //Convert bits to integer
  for(int i = (IR_BIT_LENGTH-FirstLastBit) ; i < IR_BIT_LENGTH ; i++) 
  {       
    if(bits[i] == 1) 
    {
    result += seed;
    }   
    seed *= 2;
  }
  return result;
}
 
 
/* 
  respond to specific remote-control keys with different behaviors
*/
 
void do_response(int key)
{  
   
  if (output_key)
   {
      Serial.print("Key ");
      Serial.println(key);
   }
   
  switch (key)
  {
    case 32640:  // turns on UUT power
      Serial.println("POWER");
      break;
 
    case 32385:  // FUNC/STOP turns off UUT power
      Serial.println("FUNC/STOP");
      break;
 
    case 32130:  // |<< ReTest failed Test
      Serial.println("|<<");
      break;
 
    case 32002:  // >|| Test
      Serial.println(">||");
      break;
 
    case 31875:  // >>| perform selected test number
      Serial.println(">>|");
      break;
 
    case 32512:  // VOL+ turns on individual test beeper
      Serial.println("VOL+");
      break;
 
    case 31492:  // VOL- turns off individual test beeper
      Serial.println("VOL-");
      break;
 
    case 31620:  // v scroll down tests
      Serial.println("v");
     
       // ajout atelierjcm
      traite_touche ('-');  // diminuer vitesse
      
      break;
 
    case 31365:  // ^ scroll up tests
      Serial.println("^");
      
     // ajout atelierjcm
      traite_touche ('+');  // augmenter vitesse     
      
      break;
 
    case 30982:  // EQ negative tests internal setup
      Serial.println("EQ");
      break;
 
    case 30855:  // ST/REPT Positive tests Select Test and Repeat Test
    Serial.println("ST/REPT");
      break;
 
    case 31110:  // 0
      Serial.println("0");
      
      // ajout atelierjcm
      traite_touche ('0');      // arret des 2 moteurs
           
      break;
 
    case 30600:  // 1
      Serial.println("1");
      
      // ajout atelierjcm
      traite_touche ('1');      // selectionner moteur 1   
    
      break;
 
    case 30472:  // 2
      Serial.println("2");
      
     // ajout atelierjcm      
      traite_touche ('2');      // selectionner moteur 2    
      
      break;
 
    case 30345:  // 3
      Serial.println("3");
      break;
 
    case 30090:  // 4
      Serial.println("4");
      break;
 
    case 29962:  // 5
      Serial.println("5");
      break;
 
    case 29835:  // 6
      Serial.println("6");
      break;
 
    case 29580:  // 7
      Serial.println("7");
      break;
 
    case 29452:  // 8
      Serial.println("8");
      break;
 
    case 29325:  // 9
      Serial.println("9");
      break;
      
    default:
      {
        Serial.print("Key ");
        Serial.print(key);
        Serial.println(" not programmed");
      }
    break;
  }
}

// =====================================================================

// la procedure de controle des moteurs

void controle (int m, int v)          // m : 1 ou 2 pour moteur 1 ou moteur 2,                                                                                              
                                      // v : vitesse de -255 à 255 
                                      // vitesse negative : marche arrière
{
   
  int sens = 0;
  
  int pwm = 0;
  
  if ((moteur == 1) || (moteur == 2)) {    
         
        if (v < 0) {
          sens = 0;
          pwm = -v;
        } else {
          sens = 1;
          pwm = v;
        }
        
        Serial.println("Ici controle moteur =======");
        
        Serial.print ("moteur : ") ; Serial.println(m);
        
        Serial.print ("vitesse : ") ; Serial.println(v);
        
        Serial.print ("pwm : ") ; Serial.println(pwm);
        
        Serial.print ("sens :") ; Serial.println(sens);
          
        digitalWrite(tab_Pin_sens[m-1],sens);  // fixer sens
        
        analogWrite (tab_Pin_pwm[m-1],pwm);    // fixer vitesse   
        
        Serial.println("Fin controle moteur =======");
  }        

}

// =====================================================================

// La procédure de traitement des touches

void traite_touche (char touche) {
  
  switch (touche) {
    
    case '0':

      moteur=1;
      tab_vitesse[moteur -1] = 0;           
      controle(moteur,tab_vitesse[moteur -1]);
      
      moteur=2;
      tab_vitesse[moteur -1] = 0;           
      controle(moteur,tab_vitesse[moteur -1]);
      
      break;
      
    case '1':
      
      moteur= 1;    
      
      break;
      
    case '2':
      
      moteur= 2;    
      
      break;      
      
     case '+':      
      
      if ((moteur == 1) || (moteur == 2))
         {
          
          if (tab_vitesse[moteur -1 ] <= 240) {
                      tab_vitesse[moteur - 1] = tab_vitesse[moteur -1 ] + 10;           
                      controle(moteur,tab_vitesse[moteur -1]);
          }
      }
      
      break;
      
      case '-':
           
      if ((moteur == 1) || (moteur == 2))
         {
          if ( tab_vitesse[moteur-1 ] >= - 240) {
                      tab_vitesse[moteur -1 ] = tab_vitesse[moteur -1] - 10;
                       controle(moteur,tab_vitesse[moteur -1]);
          }
      }
      
      break;
      
  } // switch
  
} // traite_touche

Detecter la coupure d’un faisceau infrarouge avec une photodiode (barrière infrarouge)

Une autre méthode : utiliser une LED infrarouge et une photodiode infrarouge. Le signal n’est plus pulsé mais continu.

La diode IR émettrice est une SFH4546, la photodiode réceptrice une BPV10NF (trouvées chez Gotronic).

La diode émettrice est montée en série avec une résistance de 180 ohms, l’ensemble est alimenté en 5V. La patte longue de la diode est côté resistance.

Côté récepteur, on a un montage classique comportant une résistance de 47000 ohms : une des extrémités de la résistance est reliée à la masse, l’autre est reliée à la fois à la Pin A0 de l’Arduino et une extrémité de la photodiode. L’autre extrémité de la photodiode est reliée au 5V. La patte longue de la photodiode est côté A0.

Faire attention car les deux composants IR ont visuellement des apparences très proches, il est très facile de les confondre !

Cette méthode est beaucoup plus simple à mettre en oeuvre que la méthode de l’article précédent mais elle devrait être un peu plus sensible aux perturbations et nécessite d’autre part un bon alignement émetteur/récepteur. Une distance de 10 cm entre les deux parait raisonnable. (on pourrait aller jusqu’à environ 30 cm mais le signal devient alors vraiment faible)

Fichier hébergé par Archive-Host.com


// PhotodiodeIR

// IR_led + photodiode 
 
// une LED IR emet de la lumière vers une photodiode
// si le faisceau lumineux est coupé
// une LED de controle s'allume

// Diode emettrice SFH4546 (+ resistance 180 ohms)
// Photodiode BPV10NF (+ resistance 47000 ohms)
// faire attention à bien aligner émetteur et récepteur
 
int photodiodePin = 0;                   

int ledcontrolePin = 11;
                          
int photomesure = 0;  // la valeur lue de 0 à 1023

int nblect=5; // nb de lectures faites, on va faire une moyenne

long somme=0;

int seuil = 50 ; // si la valeur analogique lue est inférieure à 50
                  // on allume la LED de controle

void setup(void) {
  
  Serial.begin(19200);   
}
 
void loop(void) {    

  int i;
  
 somme=0; // on va faire la moyenne de plusieurs mesures
  
  for (i=0 ; i < nblect ; i++) {      
  
  somme = somme +  analogRead(photodiodePin);
 
  } 
  
  photomesure = somme / nblect;
    
  Serial.print("Mesure = ");
  Serial.println(photomesure);       
  
  if (photomesure < seuil) { // faisceau coupé !
      digitalWrite(ledcontrolePin, HIGH);
  } else {
       digitalWrite(ledcontrolePin, LOW);
  }   
 
} // loop

Détecter la coupure d’un faisceau infrarouge (partie 3)

Côté récepteur infra-rouge, il faut relier le fil rouge du DFR0094 au +5v, le fil noir à la masse (GND) et le fil vert à une des entrées digitales libres.

Pour améliorer encore le montage on peut prévoir un buzzer qui sonne quand le faisceau est coupé ou alors des LED ordinaires pour visualiser quel récepteur a détecté une coupure.

Voici un sketch pour Arduino où on a choisi de brancher 2 émetteurs IR derrière un MOSFET et deux récepteurs IR ; deux diodes bleues visualisent la rupture de chaque faisceau et on peut suivre également les évènements en regardant l’affichage du moniteur série.


#include <IRremote.h> // librairie à installer

#define PIN_IR 3 // l'emetteur IR, forcément en pin 3

#define COUPURE 1

#define nb_capteurs 2

int tab_Pin_LED[nb_capteurs] = {10,11};

// si coupure detectée sur capteur 0 la LED sur la Pin 10 s'allume

// si coupure detectée sur capteur 1 la LED sur la Pin 11 s'allume

int tab_Pin_RCV[nb_capteurs] = {2,7} ; 

// le premier recepteur (numéro 0) est connecté à la Pin 2

// le deuxième recepteur (numéro 1) est connecté à la Pin 7

// ok pour 2 couples de capteurs DFR0094 DFR0095

// on utilise un MOSFET pour amplifier les LED emettrices

// IMPORTANT /////////////////////////////////////////

// pour une distance emetteur/recepteur de 15 cm,

//  2 V suffisent pour alimenter les diodes emettrices

// si 5 V sont utilisés, le dispositif manque de sensibilité


IRsend irsend; // objet qui permet de generer le signal pulsé


void setup()
{   
  int i=0;
  
  // mettre les LED de visualisation de rupture en OUTPUT
  
  for (i=0 ; i < nb_capteurs ; i++) {
   
         pinMode(tab_Pin_LED[i], OUTPUT);   
       
  }
  irsend.enableIROut(38); // créer une sortie modulée à 38 Khz  
 
  Serial.begin (19200);
}

////////////////////

void loop() {
  
 int i=0; 
 
 for (i=0 ; i < nb_capteurs ; i++) {
   
       irsend.mark(0); // envoi signal modulé de façon continue
       
       delay(5);    
   
       lire_capteur(i);
       
       irsend.space(0); // arret signal modulé
       
 } 
 
 delay(15);
  
}

//////////////////

void lire_capteur (int num_capteur)
{

  if ( digitalRead(tab_Pin_RCV[num_capteur] == COUPURE ) {    
    
      digitalWrite(tab_Pin_LED[num_capteur], HIGH);          
          
      // Serial.print( "Coupure !"); Serial.println(num_capteur);    
         
  } else {
          
      // Serial.print( "---------OK----------- !"); Serial.println(num_capteur);  
      
      digitalWrite(tab_Pin_LED[num_capteur], LOW);      
  }
  
}  



Le code ci-dessus correspond au montage représenté au dessous. On voit à droite la partie émission avec le MOSFET sur la breadboard blanche et les deux LED émettrices. A gauche de la photo, c’est la partie réceptrice, avec les deux récepteurs IR. Le montage comporte aussi, disposée sur la breadboard rouge de gauche, deux LED bleues, chacune visualisant la coupure d’un faisceau. (Pour mieux voir les détails de la photo, enregistrez-la sur votre PC).

Fichier hébergé par Archive-Host.com

Détecter la coupure d’un faisceau infrarouge (partie 2) barrière infrarouge

Avec la librairie IRremote, c’est la Pin 3 qui est choisie pour émettre un signal pulsé à 38 khz. C’est très bien pour alimenter une LED émettrice IR mais… si on veut en alimenter plusieurs ça se complique un peu… En effet la Pin 3 ne peut pas fournir assez d’intensité pour alimenter directement plusieurs LED.

Une solution : employer un transistor qui sera piloté par la Pin 3 mais qui disposera en sortie de toute l’intensité voulue. Le montage utilise ici un MOSFET avec le même schéma que celui de l’alimentation d’un moteur déjà publié ici (on a même laissé la diode anti-retour qui ne sert à rien ici). Un MOSFET pour 3 diodes c’est sans doute un canon pour écraser une mouche mais c’est simple à monter et… ça fonctionne ! Le MOSFET fabrique en sortie un signal pulsé à 38 khz : il suit la cadence imposée par la Pin3 reliée sa patte Gate.

En variant la tension d’alimentation des diodes émettrices on peut ajuster la sensibilité du détecteur en fonction de la distance. Avec les diodes DFR0095, c’est avec peu de volts (2 volts seulement !) qu’on obtient une très bonne sensibilité pour une distance émetteur/récepteur de 15 cm environ. Pour fournir 2 volts, j’ai utilisé une alim variable mais 2 piles 1,2 V en série, voire une seule, fournissent une tension tout à fait utilisable.

Seuls les fils verts et rouge de la diode emettrice DFR0095 sont reliés à la sortie du MOSFET (le fil noir n’est pas relié).

Sur le schéma suivant, c’est juste la partie émission qui est représentée ; on a mis ici 3 diodes émettrices qui ont vocation à faire face à 3 diodes réceptrices (non représentées).

Fichier hébergé par Archive-Host.com