contrôler servomoteurs avec joystick par le biais émetteur/récepteur 433MHz

Bonjour,
Je suis étudiant en classe préparatoire, je fabrique un hélicoptère radio-commandé. Mon problème est le suivant : je souhaite contrôler deux servomoteurs à l'aide d'un joystick, mais en passant par un émetteur/récepteur 433MHz. Aujourd'hui, j'arrive sans problème à contrôler ces deux servomoteurs avec mon joystick, mais sur une même carte arduino (uno).
Ainsi, le but est de transmettre les données du joystick reçues par une première carte arduino à une seconde carte, contrôlant les servomoteurs.

J'ai tout d'abord eu un problème de conflit, je crois, entre les bibliothèques VirtualWire et Servo :

libraries/VirtualWire/VirtualWire.cpp.o (symbol from plugin): In function vw_crc': (.text+0x0): multiple definition of __vector_11'
Plusieurs bibliothèque trouvées pour "Servo.h"
Utilisé : /Users/xxx/Documents/Arduino/libraries/Servo
libraries/Servo/avr/Servo.cpp.o (symbol from plugin):(.text+0x0): first defined here
Non utilisé : /Applications/Arduino.app/Contents/Java/libraries/Servo
collect2: error: ld returned 1 exit status
exit status 1
Erreur de compilation pour la carte Arduino Uno

problème que je n'ai jamais eu en utilisant la bibliothèque Servo seule (dans le programme de fonctionnement sur une carte arduino (cas sans transmission radio), par exemple).

Je me suis ensuite renseigné, et on m'a conseillé d'utiliser la bibliothèque ServoTimer2 pour manipuler les servomoteurs. Etait-ce un bon conseil ?

Mais rien à faire : lors du montage, je n'arrive ni à démarrer l'hélicoptère, ni à orienter les servomoteurs. Aucune commande ne répond.
Par ailleurs, mon module de transmission est bien opérationnel, j'ai pu le tester avec un code exemple.

Le module de transmission que j'utilise : https://www.amazon.fr/Émetteur-433Mhz-module-récepteur-Arduino/dp/B077L9TCL7/ref=sr_1_4_sspa?dchild=1&keywords=emetteur+recepteur+arduino&qid=1604154196&sr=8-4-spons&psc=1&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUE3UTRBREVZSjZFNzImZW5jcnlwdGVkSWQ9QTA4NjA3MjVWNjZRWFVCRDZQOU4mZW5jcnlwdGVkQWRJZD1BMDk0NTg4OTFBNTYwSkVVWDlXTDQmd2lkZ2V0TmFtZT1zcF9hdGYmYWN0aW9uPWNsaWNrUmVkaXJlY3QmZG9Ob3RMb2dDbGljaz10cnVl

Pour rédiger mon programme de fonctionnement sur deux cartes arduino (émetteur et récepteur), je me suis inspiré de celui décrit sur ce tuto : https://www.carnetdumaker.net/articles/communiquer-sans-fil-en-433mhz-avec-la-bibliotheque-virtualwire-et-une-carte-arduino-genuino/

Je joint mon programme de fonctionnement sur une carte arduino (cas sans transmission radio, qui est opérationnel), puis mon programme de fonctionnement sur deux cartes arduino (émetteur et récepteur, là où j'ai un problème).

Merci d'avance pour votre aide !

fonctionnement_complet_moteurs_1_carte_arduino_corrig_.ino (5.72 KB)

fonctionnement__moteurs_partie_r_cepteur.ino (6.47 KB)

fonctionnement_moteurs_partie__metteur.ino (6.13 KB)

Les modules 433MHz

Avant d'aller plus loin, ces modules sont de l'avis de pas mal de gens : de la daube.
Mais cela peut marcher, avec de la chance, beaucoup de chance.

Un module superheterodyne sera bien meilleur.

Ensuite le problème __vector_11 vient du fait que ces deux librairies utilisent le même vecteur d'interruption timer. Donc non, impossible.

Vous pensez que ce module, par exemple, serait meilleur ? https://www.amazon.fr/Démetteur-récepteur-Superheterodyne-Récepteur-Démetteur-Antennes/dp/B07VLM5CTN

Est-il différent de celui que j'utilise actuellement ? Puis-je utiliser la même bibliothèque VirtualWire ?

Puisqu'il y a bien conflit avec la bibliothèque Servo, la bibliothèque ServoTimer2 est-elle adaptée ?

Mis à part le module de transmission, avez-vous localisé des problèmes dans mon code ?

Merci pour votre aide !

Le module dont on entends parler le plus souvent ici il me semble : RXB6

https://forum.arduino.cc/?topic=679215

Mais d'autres personnes pourront confirmer ... ou pas.

ServoTimer2 : il me semble, en tous cas c'est comme cela qu'elle est présentée.

ServoTimer2 is a simple servo library for Arduino 1.x that does not use Timer1 in case of a conflict.

Puis-je utiliser la même bibliothèque VirtualWire ?

oui.

Dans un premier temps essaie avec le module que tu as. Ça doit au moins compiler avec ServoTimer2.

hbachetti:
Le module dont on entends parler le plus souvent ici il me semble : RXB6

J'ai regardé sur internet, on ne parle que de module "récepteur" pour le RXB6. Que dois-je utiliser comme émetteur ?

hbachetti:
oui.

http://qqtrading.com.my/rf-wireless-433-mhz-receiver-module-rxb6

Dans un premier temps essaie avec le module que tu as. Ça doit au moins compiler avec ServoTimer2.

Merci pour votre aide ! Mon programme vous semble-t-il correct ? J'ai eu un peu de mal pour rédiger la partie sur la transmission des données du joystick. En effet, une fois que l'hélicoptère à reçu l'ordre de bouger, il lui faut la valeur du degré d'inclinaison de ses servomoteurs. C'est ce point précis qui me bloque, je ne pense pas avoir rédigé cela correctement... Je vous laisse voir :

Partie émetteur :

//émetteur
#include <VirtualWire.h>
const int emetteur=xxx;
//servomoteurs
bool autor1=false;
bool autor2=false;
bool autor3=false;
bool autor4=false;
//fonctionnement moteurs
bool start=false;
//boutons
const int bouton_monte=xxx;
const int bouton_descend=xxx;
const int bouton_statique=xxx;
//fonctionnement statique
bool autor_principale=true;
//joystick
const int bouton_start=xxx;
const int lecture_x2=A4; //A
const int lecture_y2=A5; //A
//commandes
const char* CMD_BUTTON_M="BPM";
const char* CMD_BUTTON_D="BPD";
const char* EQUILIBRE="ECQ";
const char* AVANT="AVA";
const char* ARRIERE="ARR";
const char* DROITE="DRO";
const char* GAUCHE="GAU";
const char* AVANT_MAX="AVM";
const char* ARRIERE_MAX="ARM";
const char* DROITE_MAX="DRM";
const char* GAUCHE_MAX="GAM";
const char* DEMARRAGE="DEM";
const char* ARRET="ARE";
const char* STATIQUE="STA";
const char* SORTIE="SOR";
int x2_joy;
int y2_joy;

void setup() {
  //boutons
  pinMode(bouton_monte, INPUT_PULLUP);
  pinMode(bouton_descend, INPUT_PULLUP);
  pinMode(bouton_statique, INPUT_PULLUP);
  //joystick
  pinMode(bouton_start, INPUT_PULLUP);
  pinMode(lecture_x2, INPUT);
  pinMode(lecture_y2, INPUT);
  //émetteur
  vw_set_tx_pin(emetteur);
  vw_setup(2000);
}

void loop() {
  //données à émettre
  byte message[VW_MAX_MESSAGE_LEN];
  x2_joy=analogRead(lecture_x2);
  y2_joy=analogRead(lecture_y2);
  if(digitalRead(bouton_start)==LOW) {
    //start & stop
    if(start==false) {
      //allumage moteurs
      vw_send((byte*) DEMARRAGE, strlen(DEMARRAGE) + 1);
      vw_wait_tx();
      start=!start;
      delay(1000);
    }
    else {
      //extinction moteurs
      vw_send((byte*) ARRET, strlen(ARRET) + 1);
      vw_wait_tx();
      start=!start;
      delay(1000);
    }
  }
  if(start==true) {
    //lors du fonctionnement de l'hélicoptère
    if(autor_principale==true) {
      if(max(abs(analogRead(lecture_x2)-507), abs(analogRead(lecture_x2)-527))>max(abs(analogRead(lecture_y2)-501), abs(analogRead(lecture_y2)-521))) {
        //attribution des autorisations de mouvement des servomoteurs
        autor1=true;
        delay(10);
      }
      if(max(abs(analogRead(lecture_x2)-507), abs(analogRead(lecture_x2)-527))<max(abs(analogRead(lecture_y2)-501), abs(analogRead(lecture_y2)-521))) {
        //attribution des autorisations de mouvement des servomoteurs
        autor3=true;
        delay(10);
      }
      if(analogRead(lecture_x2)==analogRead(lecture_y2)) {
        //attribution des autorisations de mouvement des servomoteurs
        autor1=false;
        autor2=false;
        autor3=false;
        autor4=false;
        delay(10);
      }
      if(digitalRead(bouton_monte)==LOW) {
        //l'hélicoptère monte
        vw_send((byte*) CMD_BUTTON_M, strlen(CMD_BUTTON_M) + 1);
        vw_wait_tx();
        delay(100);
      }
      if(digitalRead(bouton_descend)==LOW) {
        //l'hélicoptère descend
        vw_send((byte*) CMD_BUTTON_D, strlen(CMD_BUTTON_D) + 1);
        vw_wait_tx();
        delay(100);
      }
      if(analogRead(lecture_x2)<510 and analogRead(lecture_x2)>=10 and autor1==true) {
        //l'hélicoptère va vers l'avant
        autor1=!autor1;
        autor2=true;
        vw_send((byte*) AVANT, strlen(AVANT) + 1);
        vw_wait_tx();
        vw_send((byte*) &x2_joy, sizeof(x2_joy));
        vw_wait_tx();
        delay(10);
      }
      if(analogRead(lecture_x2)>520 and analogRead(lecture_x2)<=1020 and autor1==true) {
        //l'hélicoptère va vers l'arrière
        autor1=!autor1;
        autor2=true;
        vw_send((byte*) ARRIERE, strlen(ARRIERE) + 1);
        vw_wait_tx();
        vw_send((byte*) &x2_joy, sizeof(x2_joy));
        vw_wait_tx();
        delay(10);
      }
      if(analogRead(lecture_x2)<=527 and analogRead(lecture_x2)>=507 and analogRead(lecture_y2)<=521 and analogRead(lecture_y2)>=501) {
        //l'hélicoptère reste à l'horizontale
        autor1=false;
        autor2=false;
        autor3=false;
        autor4=false;
        vw_send((byte*) EQUILIBRE, strlen(EQUILIBRE) + 1);
        vw_wait_tx();
        delay(10);
      }
      if(analogRead(lecture_x2)<10 and autor2==true) {
        //l'hélicoptère va vers l'avant au maximum
        vw_send((byte*) AVANT_MAX, strlen(AVANT_MAX) + 1);
        vw_wait_tx();
        delay(10);
      }
      if(analogRead(lecture_x2)>1020 and autor2==true) {
        //l'hélicoptère va vers l'arrière au maximum
        vw_send((byte*) ARRIERE_MAX, strlen(ARRIERE_MAX) + 1);
        vw_wait_tx();
        delay(10);
      }
      if(analogRead(lecture_y2)<510 and analogRead(lecture_y2)>=10 and autor3==true) {
        //l'hélicoptère va vers la droite
        autor3=!autor3;
        autor4=true;
        vw_send((byte*) DROITE, strlen(DROITE) + 1);
        vw_wait_tx();
        vw_send((byte*) &y2_joy, sizeof(y2_joy));
        vw_wait_tx();
        delay(10);
      }
      if(analogRead(lecture_y2)>520 and analogRead(lecture_y2)<=1020 and autor3==true) {
        //l'hélicoptère va vers la gauche
        autor3=!autor3;
        autor4=true;
        vw_send((byte*) GAUCHE, strlen(GAUCHE) + 1);
        vw_wait_tx();
        vw_send((byte*) &y2_joy, sizeof(y2_joy));
        vw_wait_tx();
        delay(10);
      }
      if(analogRead(lecture_y2)<10 and autor4==true) {
        //l'hélicoptère va vers la droite au maximum
        vw_send((byte*) DROITE_MAX, strlen(DROITE_MAX) + 1);
        vw_wait_tx();
        delay(10);
      }
      if(analogRead(lecture_y2)>1020 and autor4==true) {
        //l'hélicoptère va vers la gauche au maximum
        vw_send((byte*) GAUCHE_MAX, strlen(GAUCHE_MAX) + 1);
        vw_wait_tx();
        delay(10);
      }
      if(digitalRead(bouton_statique)==LOW) {
        //on passe en régime statique
        autor_principale=!autor_principale;
        delay(100);
      }   
    }
    if(autor_principale==false) {
      //l'hélicoptère est en régime statique
      vw_send((byte*) STATIQUE, strlen(STATIQUE) + 1);
      vw_wait_tx();
      delay(10);
      if(digitalRead(bouton_statique)==LOW) {
        //on sort du régime statique
        autor_principale=!autor_principale;
        vw_send((byte*) SORTIE, strlen(SORTIE) + 1);
        vw_wait_tx();
        delay(100);
      }
    }
  }
}

Personnellement j'utilise des modules 433MHz RFM69, sur bus SPI. Je peux difficilement aider en ce qui concerne RXB6 et VirtualWire.

Partie récepteur :

//moteur shield
int MAX_SPEED=150;
const int directionA=12;
const int directionB=13;
const int brakeA=9;
const int brakeB=8;
const int speedA=3;
const int speedB=11;
const int in2=A2;
const int in3=A3;
//ports disponibles : 0, 1, 2, 4, 5, 6, 7, 10, A0, A1, A4, A5
//servomoteurs
#include <ServoTimer2.h>
ServoTimer2 myservo_droit;
ServoTimer2 myservo_gauche;
const int servo_droit=xxx;
const int servo_gauche=xxx;
bool initservo=true;
//récepteur
#include <VirtualWire.h>
const int recepteur=xxx;
//capteur à ultrason
#include "SR04.h"
#define TRIG_PIN xxx
#define ECHO_PIN xxx
SR04 sr04 = SR04(ECHO_PIN,TRIG_PIN);
long altitude_ref;
long altitude;
//gyroscope
#include "Wire.h"
#include "I2Cdev.h"
#include "MPU6050.h"
#include "math.h"
MPU6050 accelgyro;
int16_t ax, ay, az;
int16_t gx, gy, gz;
uint8_t Accel_range;
uint8_t Gyro_range;
float angley=0;
float anglex=0;
//commandes
const char* CMD_BUTTON_M="BPM";
const char* CMD_BUTTON_D="BPD";
const char* EQUILIBRE="ECQ";
const char* AVANT="AVA";
const char* ARRIERE="ARR";
const char* DROITE="DRO";
const char* GAUCHE="GAU";
const char* AVANT_MAX="AVM";
const char* ARRIERE_MAX="ARM";
const char* DROITE_MAX="DRM";
const char* GAUCHE_MAX="GAM";
const char* DEMARRAGE="DEM";
const char* ARRET="ARE";
const char* STATIQUE="STA";
const char* SORTIE="SOR";

void setup() {
  //moteurs
  pinMode(directionA, OUTPUT);
  pinMode(brakeA, OUTPUT);
  pinMode(directionB, OUTPUT);
  pinMode(brakeB, OUTPUT);
  //servomoteurs
  myservo_droit.attach(servo_droit);
  myservo_gauche.attach(servo_gauche);
  //récepteur
  vw_set_rx_pin(recepteur);
  vw_setup(2000);
  vw_rx_start();
  //gyroscope
  Wire.begin();
  accelgyro.initialize();
}

void loop() {
  //données à recevoir
  byte message[VW_MAX_MESSAGE_LEN];
  byte taille_message = VW_MAX_MESSAGE_LEN;
  int valeurRecue;
  byte taille_message2=sizeof(valeurRecue);
  vw_wait_rx();
  if(vw_get_message(message, &taille_message)) {
    //quand on reçoit un message
    if(strcmp((char*) message, DEMARRAGE) == 0) {
      //allumage moteurs
      if(initservo==true) {
        //remise des pales à l'horizontale
        initservo=false;
        myservo_droit.write(90);
        myservo_gauche.write(90);
        delay(500);
        }
      dcForward();
    }
    if(strcmp((char*) message, ARRET) == 0) {
      //extinction moteurs
      initservo=true;
      dcStop();
      int MAX_SPEED=150;
    }
    if(strcmp((char*) message, CMD_BUTTON_M) == 0) {
      //l'hélicoptère monte
      int MAX_SPEED=255;
      dcForward();
      delay(100);
      int MAX_SPEED=150;
      dcForward();
    }
    if(strcmp((char*) message, CMD_BUTTON_D) == 0) {
      //l'hélicoptère descend
      int MAX_SPEED=100;
      dcForward();
      delay(100);
      int MAX_SPEED=150;
      dcForward();
    }
    if(strcmp((char*) message, AVANT) == 0) {
      //l'hélicoptère va vers l'avant
      vw_wait_rx();
      if(vw_get_message((byte*) &valeurRecue, &taille_message2)) {
        myservo_droit.write(90+(505-valeurRecue)*0.04);
        myservo_gauche.write(90-(505-valeurRecue)*0.04);
      }
    }
    if(strcmp((char*) message, ARRIERE) == 0) {
      //l'hélicoptère va vers l'arrière
      vw_wait_rx();
      if(vw_get_message((byte*) &valeurRecue, &taille_message2)) {
        myservo_droit.write(90-(valeurRecue-507)*0.04);
        myservo_gauche.write(90+(valeurRecue-507)*0.04);
      }
    }
    if(strcmp((char*) message, EQUILIBRE) == 0) {
      //l'hélicoptère reste à l'horizontale
      myservo_droit.write(90);
      myservo_gauche.write(90);
    }
    if(strcmp((char*) message, AVANT_MAX) == 0) {
      //l'hélicoptère va vers l'avant au maximum
      myservo_gauche.write(70);
      myservo_droit.write(110);
    }
    if(strcmp((char*) message, ARRIERE_MAX) == 0) {
      //l'hélicoptère va vers l'arrière au maximum
      myservo_droit.write(70);
      myservo_gauche.write(110);
    }
    if(strcmp((char*) message, DROITE) == 0) {
      //l'hélicoptère va vers la droite
      vw_wait_rx();
      if(vw_get_message((byte*) &valeurRecue, &taille_message2)) {
        myservo_droit.write(90-(505-valeurRecue)*0.04);
        myservo_gauche.write(90-(505-valeurRecue)*0.04);
      }
    }
    if(strcmp((char*) message, GAUCHE) == 0) {
      //l'hélicoptère va vers la gauche
      vw_wait_rx();
      if(vw_get_message((byte*) &valeurRecue, &taille_message2)) {
        myservo_droit.write(90+(valeurRecue-507)*0.04);
        myservo_gauche.write(90+(valeurRecue-507)*0.04);
      }
    }
    if(strcmp((char*) message, DROITE_MAX) == 0) {
      //l'hélicoptère va vers la droite au maximum
      myservo_droit.write(70);
      myservo_gauche.write(70);
    }
    if(strcmp((char*) message, GAUCHE_MAX) == 0) {
      //l'hélicoptère va vers la gauche au maximum
      myservo_droit.write(110);
      myservo_gauche.write(110);
    }
    if(strcmp((char*) message, STATIQUE) == 0) {
      //l'hélicoptère est en régime statique
      altitude_ref=sr04.Distance();
      while(strcmp((char*) message, SORTIE) != 0) {
        //on reste en régime statique tant que l'ordre d'en sortir n'a pas été donné
        vw_wait_rx();
        altitude=sr04.Distance();
        if(altitude<altitude_ref-10) {
          //il faut augmenter l'altitude
          ...
        }
        if(altitude>altitude_ref+10) {
          //il faut réduire l'altitude
          ...
        }
        accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
        angley=0.98*(angley+float(gy)*0.01/131) + 0.02*atan2((double)ax,(double)az)*180/PI; 
        anglex=0.98*(anglex+float(gx)*0.01/131) + 0.02*atan2((double)ay,(double)az)*180/PI;
        if(angley<0) {
          //il faut redresser l'appareil
          ...
        }
        if(angley>0) {
          //il faut redresser l'appareil
          ...
        }
        if(anglex<0) {
          //il faut redresser l'appareil
          ...
        }
        if(anglex>0) {
          //il faut redresser l'appareil
          ...
        }
        delay(10);  
      }
    }
  }
}

void dcForward() {
  //fonctionnement des moteurs quand ils sont allumés
  digitalWrite(directionA, HIGH);
  digitalWrite(brakeA, LOW);
  digitalWrite(directionB, HIGH);
  digitalWrite(brakeB, LOW);
  analogWrite(speedA, MAX_SPEED);
  analogWrite(speedB, MAX_SPEED);
}

void dcStop() {
  //arrêt des moteurs
  digitalWrite(brakeA, HIGH);
  analogWrite(speedA, 0);
  digitalWrite(brakeB, HIGH);
  analogWrite(speedB, 0);
}

hbachetti:
Personnellement j'utilise des modules 433MHz RFM69, sur bus SPI. Je peux difficilement aider en ce qui concerne RXB6 et VirtualWire.

Très bien, merci quand même pour votre aide et votre temps !

J'ai aussi une passerelle domotique RFLINK 433MHz avec un transceiver Aurel RTX-MID-5v.

Mais apparemment cette passerelle peut aussi utiliser le RXB6, avec un émetteur FS1000A, donc celui que tu possèdes.

http://www.rflink.nl/blog2/wiring

J'aurais tendance à dire que la partie réception est plus critique.

hbachetti:
J'ai aussi une passerelle domotique RFLINK 433MHz avec un transceiver Aurel RTX-MID-5v.

Mais apparemment cette passerelle peut aussi utiliser le RXB6, avec un émetteur FS1000A, donc celui que tu possèdes.

http://www.rflink.nl/blog2/wiring

Très utile merci beaucoup !
Si vous pouviez jeter un oeil à mes programmes, je vous en serai très reconnaissant.