dimanche 19 janvier 2014

Modules RF 433 MHz, VirtualWire et Arduino

N.B.: Puisque la bibliothèque VirtualWire n'est plus mise à jour par son auteur, vous préférerez peut-être consulter cet article plus récent, dans lequel on utilise la bibliothèque RadioHead.

Aujourd'hui, je vous présente quelques expérimentations réalisées avec un émetteur et un récepteur radiofréquence à 433 MHz obtenus sur eBay pour un prix ridiculement bas (on parle d'environ 1 euro pour une paire émetteur/récepteur).

Contrairement aux modules NRF24L01 2,4 GHz (qui coûtent à peine plus cher mais sont plus sophistiqués), ces modules ne permettent qu'une communication unidirectionnelle:  l'émetteur peut envoyer un message au récepteur, mais ce dernier ne peut pas envoyer de réponse à l'émetteur, ne serait-ce que pour confirmer que le message a bel et bien été reçu (une communication bidirectionnelle est toutefois possible si vous disposez de deux paires émetteur-récepteur).

L'émetteur

Il est de forme carrée et porte les numéros XY-FST et FS1000A.  Il est muni de 3 pins: DATA transmettra les données à émettre et sera branché à la sortie 12 de votre Arduino.  Sans trop de surprise, vous branchez la pin "VCC" au 5 volts de l'Arduino et la pin "GND" à une des pins "GND" de l'Arduino.

Une connexion identifiée "ANT" vous permet de souder une antenne à votre émetteur.  Cette antenne n'est pas indispensable si votre émetteur est à proximité du récepteur.

Quelques tests m'ont permis de constater qu'en absence d'antenne, un nombre assez important de données émises n'atteignent pas le récepteur à partir d'une distance d'environ 2 m.

En ajoutant une antenne de 17 cm à l'émetteur et au récepteur, la portée atteint facilement une dizaine de mètres.

Le récepteur

Le récepteur est de forme rectangulaire et porte le numéro "XY-MK-5V".  Pour une raison qui m'échappe il est muni de 4 pins mais d'après ce que j'ai constaté les deux pins centrales identifiées "DATA" sont identiques et interchangeables.  Vous reliez donc une de ces deux pins "DATA" à l'entrée 11 d'un deuxième Arduino (ce deuxième Arduino peut très bien être branché au même ordinateur que l'Arduino qui contrôle l'émetteur).

Encore une fois, vous branchez la pin "VCC" du récepteur à la pin 5 V de l'Arduino, et vous reliez les masses (GND).

La bibliothèque VirtualWire

Assurez-vous d'installer la bibliothèque VirtualWire, qui va énormément nous simplifier la vie lors de la conception des sketches.

Les exemples qui accompagnent la bibliothèque VirtualWire montrent qu'il est très facile d'envoyer des chaînes de caractères de l'émetteur vers le récepteur (message du genre "Hello World").  Mais il est souvent beaucoup plus utile et pertinent d'émettre des valeurs numériques (des données provenant d'un capteur, par exemple) .  La lecture du blog Generic Nerd de Markus Ulfberg m'a rappelé l'importance des fonctions atoi et itoa pour transformer un nombre entier en chaîne de caractères et inversement.


Premier test:  envoi et réception de nombres croissants

Cette première paire de sketches est bien utile pour vérifier le bon fonctionnement de notre paire émetteur/récepteur:  plutôt qu'envoyer sans cesse le même message, l'Arduino émetteur envoi des nombres entiers en ordre croissants, et l'Arduino récepteur les affiche dans le moniteur série.   Vous pouvez donc vérifier si la totalité des  messages émis par l'émetteur sont bel et bien reçus par le récepteur.



Deuxième test:  contrôle à distance de la luminosité d'une LED au moyen d'un potentiomètre

Cette fois, un potentiomètre est branché à l'entrée A0 de l'Arduino émetteur, et une LED (accompagnée de sa résistance de protection) est branchée à la sortie 5 de l'Arduino.  L'émetteur envoie l'état du potentiomètre (entier entre 0 et 1023) et le récepteur utilise cette valeur pour contrôler la luminosité de la LED par PWM (la valeur doit toutefois être divisée par 4, puisque analogWrite accepte un paramètre entre 0 et 255).







Troisième test:  allumage à distance de 3 LEDs en appuyant sur 3 boutons

Finalement, 3 boutons branchés respectivement entre les entrées 2, 3 et 4 et  la masse (GND) de l'Arduino émetteur permettent d'allumer des LEDs branchées aux sorties 2, 3 et 4 de l'Arduino récepteur (la LED est allumée pendant que le bouton qui lui est associé est enfoncé).






Il ne reste plus qu'à adapter ces exemples pour satisfaire vos besoins:  afficher les mesures prises par un capteur distant, contrôler un moteur à distance (véhicule téléguidé), etc.

Lire aussi:

Yves Pelletier (Twitter:  @ElectroAmateur)

24 commentaires:

  1. Je viens de tout essayer, tout fonctionne parfaitement.
    Vous faites un excellent travail, Bravo!

    RépondreSupprimer
  2. Bonjour,

    J'ai actuellement un projet d'école sur la domotique avec ce type d'émetteur/récepteur, est-ce que tu pourrais me détailler l'installation de l'antenne notamment sur le récepteur, sur la photo j'ai l'impression que tu as transpercé la partie où il faut rajouter l'antenne.

    RépondreSupprimer
    Réponses
    1. J'ai simplement inséré un bout du fil conducteur dans le trou destiné à l'antenne, et j'ai soudé.

      Supprimer
    2. si tu ne sait pas comment faire, lit la doc.

      Supprimer
  3. Bonjour, j'ai actuellement la même chose que vous à faire donc j'aurais deux questions.
    Est il vraiment nécessaire d'avoir 2 cartes arduinos, une pour l'émission et l'autre la réception, il se trouve que j'ai branché mon émetteur et récepteur sur la même carte arduino nano.
    Seconde question, étant novice sur arduino je voudrais savoir le programme pour émettre un message. Et si ce n'est trop vous demandez le programme pour la réception.
    Merci du temps que vous m'accorderez.
    Antoine
    Si vous pouvez me répondre ici : pompier-du -51@live.fr

    RépondreSupprimer
    Réponses
    1. Bonjour,
      Mettre un récepteur avec l'émetteur sur la même carte est bon pour tester le code d'un projet.
      Mais en utilisation courante le sujet est justement de faire communiquer 2 microcontrôleurs à distance par ondes radio, donc il en faut deux oui, sinon aucun intérêt.

      Supprimer
  4. Bonjour,
    Question sur les antennes : leur longueur doit faire ~17cm, mais quelle section de fil est recommandée ?
    merci
    Thierry

    RépondreSupprimer
  5. Bonjour,
    C'est un billet très intéressant pour un débutant comme moi merci !
    Je me pose une question, est-il possible a partir d'une arduino d'y connecter 2 émetteurs qui contrôleraient leur récepteur respectif ?
    Du genre une paire pour allumer éteindre une led et l'autre paire pour alimenter un moteur ?

    Ou doit il y avoir une arduino par paire ? Mais dans ce cas risque de contrôler l'autre carte ou les paires sont faites pour fonctionner ensemble uniquement ?

    Merci d'avance pour la réponse.

    RépondreSupprimer
    Réponses
    1. Dans un tel cas, il faudrait plutôt utiliser un seul émetteur, et inclure une information à l'intérieur des messages émis pour indiquer si le message s'adresse au récepteur qui contrôle la LED ou au récepteur qui contrôle le moteur. Et programmer les Arduinos récepteurs pour qu'ils ne réagissent qu'aux messages qui les concernent.

      Supprimer
    2. Effectivement si une telle programmation est possible ça parait être mieux comme idée ! Merci

      Supprimer
    3. Bonjour, je viens de tester le premier code et lorsque je veux le vérifier ca me dit:

      error: variable 'prescalers' must be const in order to be put into read-only section by means of '__attribute__((progmem))'

      uint8_t prescalers[] PROGMEM = {0, 0, 3, 6, 8, 10, 12}; /* Must be outside the function */

      Erreur lors de la compilation.

      Supprimer
    4. Bonjour et merci pour votre site !!
      je débute avec Arduino, j'ai testé le sketch RX et TX 3 boutons ! ça fonctionne bien!!
      je me suis aperçu que si j'envoie le nombre 4,3,2 en maintenant les boutons appuyé , les LED restent allumés . par contre si j'appuie 2,3,4 il n'y a que la LED 1 qui s'allume .
      cela fait 2 jours que j'essaie de modifier le programme pour que 4,3,2 , n'allume pas les LED 3,2,1 mais je n'y arrive pas ;)
      cordialement

      Supprimer
  6. Bonjour, je me pose pas mal de questions à propos d'un projet que je vais présenter pour mon diplôme.
    C'est une lampe de poche sur batterie qui dispose d'un socle qui descend du plafond pour la recharger (et donc relier à un interrupteur).
    J'aimerai que la recharge se fasse que l'interrupteur soit en ON ou OFF.
    Je vais donc utiliser les Modules RF 433 MHz pour commander l'allumage de la lampe mais seulement lorsqu’elle est en charge.
    Comment puis-je faire?
    Merci d'avance pour vos réponses
    Cordialement

    RépondreSupprimer
  7. Bonjour,
    Trés bon tuto.

    Je bloque sur l'envoie de plusieurs float en une seule émission.
    Atoi renvoi un char* donc je peux pas m'en servir pour remplir mon tableau utilisé par virtualwire.

    Je suis capable d'en envoyer une seule à la fois. Peut-etre est-ce impossible?

    RépondreSupprimer
  8. bonjour,
    Je bloque quand j'utilise un int supérieur a 50000.
    C'est itoi ou virtualwire qui fait ce blocage?

    RépondreSupprimer
    Réponses
    1. La valeur maximale d'une variable de type int est de 32767.

      Supprimer
  9. bonsoir
    je cherche un programme sur pic16f876a en programe sur mikroC

    RépondreSupprimer
  10. bonjour tres bon tuto pour moi qui debute une question peut on mettre les rf et la carte bluetooh en meme temp

    RépondreSupprimer
  11. bonsoir , est il realisable avec arduino nano v3.0?

    RépondreSupprimer
  12. super article : merci pour le partage !
    je cherche à savoir si je peux piloter une carte en sortie qui consomme 15 mA

    RépondreSupprimer
  13. Bonjour, je suis en terminale et pour mon projet e dois m'occuper d'une télécommande, mais je n'arrive pas à faire fonctionner mes modules RF. Voici le code:
    const int SW_pin = 2;
    const int X_pin = 0;
    const int Y_pin = 1;
    int onoff = 0;
    #define BLUE 3
    #define GREEN 5
    #define RED 6
    #define buzzerPin 4
    #include
    int Nnombre;

    char Message[VW_MAX_MESSAGE_LEN];

    void setup() {
    vw_setup(2000);
    pinMode(SW_pin, INPUT);
    digitalWrite(SW_pin, HIGH);
    Serial.begin(9600);
    pinMode(4, OUTPUT);
    pinMode(RED, OUTPUT);
    pinMode(GREEN, OUTPUT);
    pinMode(BLUE, OUTPUT);
    digitalWrite(RED, HIGH);
    digitalWrite(GREEN, LOW);
    digitalWrite(BLUE, LOW);
    vw_rx_start();
    }

    int redValue;
    int greenValue;
    int blueValue;

    void loop() {
    int nombre=0;
    Serial.print("Avant envoi : ");
    if(digitalRead(SW_pin) == 0 ) {
    digitalWrite(BLUE,25);
    digitalWrite(GREEN,25);
    digitalWrite(RED,25);
    if(onoff==0) {
    while(digitalRead(SW_pin)==0) {
    digitalWrite(4,HIGH);
    delay(350);
    digitalWrite(4,LOW);
    delay(400);
    }
    onoff=1;
    } else {
    digitalWrite(4,LOW);
    onoff=0;
    }
    } else {
    digitalWrite(BLUE,LOW);
    digitalWrite(GREEN,LOW);
    digitalWrite(RED,LOW);
    }
    if ((analogRead(X_pin)>340)&&(analogRead(X_pin)<840)) {
    if (analogRead(Y_pin)<490) {
    digitalWrite(BLUE,HIGH);
    digitalWrite(GREEN,LOW);
    digitalWrite(RED,LOW);
    nombre=4;
    }
    else if (analogRead(Y_pin)>520){
    digitalWrite(BLUE,LOW);
    digitalWrite(GREEN,HIGH);
    digitalWrite(RED,LOW);
    nombre=2;
    }
    }
    if ((analogRead(Y_pin)>340)&&(analogRead(Y_pin)<840)) {
    if (analogRead(X_pin)<490) {
    digitalWrite(BLUE,LOW);
    digitalWrite(GREEN,LOW);
    digitalWrite(RED,HIGH);
    nombre=1;
    }
    else if (analogRead(X_pin)>520){
    digitalWrite(BLUE,1);
    digitalWrite(GREEN,1);
    digitalWrite(RED,1);
    nombre=3;
    }
    }
    delay(100);

    // convertion de l'int en tableau de char
    itoa(nombre,Message,10); // 10 car décimal

    vw_send((uint8_t *)Message, strlen(Message));
    vw_wait_tx(); // Wait until the whole message is gone
    delay(100);
    Serial.println(nombre);
    Serial.print("Apres envoi : ");
    uint8_t buf[VW_MAX_MESSAGE_LEN];
    uint8_t buflen = VW_MAX_MESSAGE_LEN;

    if (vw_get_message(buf, &buflen))
    {
    int i;

    for (i = 0; i < buflen; i++)
    {
    Message[i] = char(buf[i]);
    }

    Message[buflen] = '\0';

    // Conversion du tableau de chars en int:
    nombre = atoi(Message);
    Serial.println(nombre);
    }
    Serial.println(" ");
    }

    Si vous pouviez m'aider, ça serait génial :)
    Merci pour l'article d'ailleurs.

    RépondreSupprimer
  14. Bonjours je voudrais controler un thermostat pour faire allumer ma fournaise de ma roulotte
    Pourrier vous m'aider svp mon thermostat est digital et envoie un signal alors j'aimerais m'en servir comme switch et autre modules mettre un relais pour faire partir la fournaise merci
    Ve2dpg-gervais@hotmail.com
    Sa serais apprecier

    RépondreSupprimer
  15. bonjour j'ai commencé arduino il n'y a pas longtemps j'ai essayé le programme mais la communication entre les module rf ne se fait pas pouvez vous m'aidez merci d'avance

    RépondreSupprimer