Connecter un Arduino à sa radio pour étendre ses possibilités

Introduction

Le but de cet article est de montrer comment connecter un Arduino au port écolage de votre radio pour en élargir les possibilités. Dans mon cas, ce sera pour choisir les modes de vol de l’APM qui contrôle mon drone.

Avantages :

  • Vous n’avez pas à démonter votre radio, le risque de l’abîmer est donc réduit. La seule précaution à prendre est de vérifier que le port écolage attend bien des signaux en 5V. C’est le cas sur la Turnigy 9X.
  • Vous bénéficiez de toutes les possibilités des « périphériques » Arduino, tant pour les entrées : interrupteur, potentiomètres, manche supplémentaire, que pour les sorties : led, afficheur LCD, voire même écran TV analogique.
  • Si votre montage dysfonctionne en plein vol, vous pouvez actionner la manette d’écolage de la radio pour le rendre inopérant facilement.

Limitations :

  • Comme on utilise la prise écolage, on est limité à ce qu’elle permet. C’est-à-dire envoyer un signal de commande de servo. On ne peut pas recevoir d’informations par son intermédiaire.

La radio utilisée ici est une Turnigy 9X, à savoir :

  • La prise écolage est une simple jack 3.5mm standard
  • En général, le moniteur doit activer un switch pour passer les commandes à l’élève. Sur cette radio c’est l’inverse, ce qui est bien pratique pour notre bricolage.
  • Dans les menus de la radio, il faut activer l’écolage et choisir les canaux que l’on souhaite déléguer à l’élève.

Matériel nécessaire :

  • Une prise Jack 3.5mm Mono de préférence mais du stéréo fera l’affaire aussi
  • Un Arduino –  n’importe quel modèle à logique 5V devrait faire l’affaire.
  • Un afficheur LCD
  • Des câbles de connections mâles et femelles
  • Fer à souder et outillages liés
  • Un ordinateur pour programmer l’Arduino

La partie électronique

Souder la prise jack, la pointe est le signal, le reste la masse. (merci à Richard J. Prinz) Privilégiez donc un fil noir pour la masse et un vert pour le signal par exemple. Reliez les broches de l’afficheur et de ses boutons sur l’Arduino. Je vous déconseille de brancher le bouton reset sur la broche reset de l’Arduino sous peine d’effectuer un reset en plein vol par erreur… Vous pouvez aussi prévoir l’alimentation de terrain de l’Arduino. Personnellement, je l’alimente avec la Lipo de mon récepteur FPV par l’intermédiaire d’un régulateur de voltage

14.05.06 - 09935 - Arduino_PPM_T9X

Vous remarquerez que je n’ai pas simplement enfiché l’afficheur sur l’Arduino. La première raison est que la prise Ethernet de ce modèle d’Arduino m’en empêche. La deuxième que certaines broches ne correspondaient pas car réservées à la carte Ethernet.

Le programme

14.05.06 - 09936 - Arduino_PPM_T9X

Il consiste à :

  • Générer un signal PPM grâce à un timer de l’Arduino. Dans mon cas, je voulais contrôler le canal n°5. Il faut cependant envoyer des valeurs arbitraires pour les 4 premiers canaux. On demandera à la radio de les ignorer.
  • Gérer les boutons et leur action. Sur mon LCD, les 5 boutons doivent être gérés sur une même entrée analogique.
  • Afficher un texte pour rendre compte du mode actif.

Voici le code source complet :

// Source d'inspiration pour le signal PPM http://www.rcgroups.com/forums/showthread.php?t%3D1808432&k=2BjihEEf49EEnl2c9cXhDQ%3D%3D%0A&r=3yuNHmLmHt1hrQBr7%2FaeV9KqpNfZSTxLUDQUL57uyxA%3D%0A&m=SkLxmkhQhqEzY%2FvlispUxPuAvUk21SUcjXqzGB5sveo%3D%0A&s=22d39f9f18ccdc0899ce6e7e3fe85015c256e342de2d32f9d2f4448fed710a40
//////////////////////CONFIGURATION///////////////////////////////
#define sigPin 2  //Broche de l'arduino reliée au port écolage
#define chanel_number 8  //set the number of chanels
#define default_servo_value 1500  //set the default servo value
#define PPM_FrLen 22500  //set the PPM frame length in microseconds (1ms = 1000µs)
#define PPM_PulseLen 300  //set the pulse length
#define onState 1  //set polarity of the pulses: 1 is positive, 0 is negative
//////////////////////////////////////////////////////////////////

// Tableau contenant la valeur des différentes voies
int ppm[chanel_number];



// Librairie pour l'écran LCD. Voir http://www.arduino.cc/en/Tutorial/LiquidCrystal&k=2BjihEEf49EEnl2c9cXhDQ%3D%3D%0A&r=3yuNHmLmHt1hrQBr7%2FaeV9KqpNfZSTxLUDQUL57uyxA%3D%0A&m=SkLxmkhQhqEzY%2FvlispUxPuAvUk21SUcjXqzGB5sveo%3D%0A&s=587b781588977e6e878c986d2ea8915bb416cace0afa8a17fb36056dd6a03973
#include 
// Configuration des broches du LCD
LiquidCrystal lcd(8, 9, 3, 5, 6, 7); // ATTENTION, elles correspondent à mon branchement qui n'est pas dans l'ordre des broches entre l'arduino et le LCD, pour vous ce sera probablement lcd(8,9,4,5,6,7); !!!

int button = 0;



// Consantes des valeurs des différents modes
const int STABILIZE = 1000; // < 1230 dans Mission Planner const int ALT_HOLD = 1300; // > 1750 "
const int LOITER = 1400; // 1250
const int RTH = 1550; // 1500
const int AUTO = 1700; // 1400
// Variable contenant la valeur du mode en cours
int modeDeVol_uS=STABILIZE;

// Constantes des boutons
const int BUTTON_SELECT = 1;
const int BUTTON_LEFT = 2;
const int BUTTON_UP = 3;
const int BUTTON_DOWN = 4;
const int BUTTON_RIGHT = 5;

// Constantes des valeur haute et basse de chaque bouton sur l'entrée analogique
const int BUTTON_SELECT_LOW = 700;
const int BUTTON_SELECT_HIGH = 800;
const int BUTTON_LEFT_LOW = 400;
const int BUTTON_LEFT_HIGH = 500;
const int BUTTON_UP_LOW = 100;
const int BUTTON_UP_HIGH = 150;
const int BUTTON_DOWN_LOW = 300;
const int BUTTON_DOWN_HIGH = 350;
const int BUTTON_RIGHT_LOW = 1;
const int BUTTON_RIGHT_HIGH = 99;

 
// Variables gérant l'anti-rebond des boutons. Source : http://www.instructables.com/id/How-to-access-5-buttons-through-1-Arduino-input/step5/Testing-it/&k=2BjihEEf49EEnl2c9cXhDQ%3D%3D%0A&r=3yuNHmLmHt1hrQBr7%2FaeV9KqpNfZSTxLUDQUL57uyxA%3D%0A&m=SkLxmkhQhqEzY%2FvlispUxPuAvUk21SUcjXqzGB5sveo%3D%0A&s=b76be266eab18fb9f2ab45900a5447f8746b125b07910bd94daaf544f3eaac6f  
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers

  
void setup() {
  // Initialise les valeurs par défaut des différentes voies
  for(int i=0; i<chanel_number; i++){
    ppm[i]= default_servo_value;
  }
  
  // Configuration de la broche écolage en sortie
  pinMode(sigPin, OUTPUT);
  digitalWrite(sigPin, !onState);  //set the PPM signal pin to the default state (off)

   // Configuration du timer d'interruption pour générer le signal PPM à interval régulier  
  cli();
  TCCR1A = 0; // set entire TCCR1 register to 0
  TCCR1B = 0;
  
  OCR1A = 100;  // compare match register, change this
  TCCR1B |= (1 << WGM12);  // turn on CTC mode
  TCCR1B |= (1 << CS11);  // 8 prescaler: 0,5 microseconds at 16mhz
  TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
  sei();
  // Définition de la résolution du LCD 
  lcd.begin(16, 2);   // Affiche le mode par défaut
   lcd.print("STABILZE");
    }
 void loop() {
   // Lecture de la valeur des boutons 
  button = analogRead(0);
   // On se positionne sur la deuxième ligne du LCD 
  lcd.setCursor(0, 1); 
  // On y affiche la valeur lue 
  lcd.print(button);   
   // Interprétation de la valeur analogique pour déterminer le bouton    int tmpButtonState = LOW;    if(button>BUTTON_LEFT_LOW && button<BUTTON_LEFT_HIGH){      //Read switch 5      tmpButtonState = BUTTON_LEFT;    }else if(button>BUTTON_RIGHT_LOW && button<BUTTON_RIGHT_HIGH){      //Read switch 4      tmpButtonState = BUTTON_RIGHT;    }else if(button>BUTTON_UP_LOW && button<BUTTON_UP_HIGH){      //Read switch 3      tmpButtonState = BUTTON_UP;    }else if(button>BUTTON_DOWN_LOW && button<BUTTON_DOWN_HIGH){      //Read switch 2      tmpButtonState = BUTTON_DOWN;    }else if(button>BUTTON_SELECT_LOW && button<BUTTON_SELECT_HIGH){      //Read switch 1      tmpButtonState = BUTTON_SELECT;    }else{      //No button is pressed;      tmpButtonState = LOW;    }       // Gestion du rebond      if (tmpButtonState != lastButtonState) {      // reset the debouncing timer      lastDebounceTime = millis();    }     if ((millis() - lastDebounceTime) > debounceDelay) {
     buttonState = tmpButtonState;
   }
   lastButtonState = tmpButtonState;
   
   // Maintenant on effectue les actions correspondantes
   switch(buttonState){
     case BUTTON_LEFT:
     modeDeVol_uS = ALT_HOLD;
     lcd.clear();
     lcd.print("ALT_HOLD - " + String(modeDeVol_uS));
     break;
     case BUTTON_RIGHT:
     modeDeVol_uS = AUTO;
     lcd.clear(); lcd.print("AUTO - " + String(modeDeVol_uS));
     break;
     case BUTTON_UP:
     modeDeVol_uS = LOITER;
     lcd.clear(); lcd.print("LOITER - " + String(modeDeVol_uS));
     break;
     case BUTTON_DOWN:
     modeDeVol_uS = RTH;
     lcd.clear(); lcd.print("RTH - " + String(modeDeVol_uS));
     break;
     case BUTTON_SELECT:
     modeDeVol_uS = STABILIZE;
     lcd.clear(); lcd.print("STABILIZE - " + String(modeDeVol_uS));
     break;
   }
   // On définie la valeur de la voie qui nous intéresse
   // La numérotation commençant à 0. il faut écrire 4 pour la voie 5, ou 5-1 ;-)
   ppm[5-1]=modeDeVol_uS;
}

// Interruption pour générer le signal PPM à interval régulier
// Ne rien modifier sous cette ligne à moins de vraiment maitriser !
ISR(TIMER1_COMPA_vect){
  static boolean state = true;
  TCNT1 = 0;
  if(state) {  //start pulse
    digitalWrite(sigPin, onState);
    OCR1A = PPM_PulseLen * 2;
    state = false;
  }
  else{  //end pulse and calculate when to start the next pulse
    static byte cur_chan_numb;
    static unsigned int calc_rest;
  
    digitalWrite(sigPin, !onState);
    state = true;

    if(cur_chan_numb >= chanel_number){
      cur_chan_numb = 0;
      calc_rest = calc_rest + PPM_PulseLen;// 
      OCR1A = (PPM_FrLen - calc_rest) * 2;
      calc_rest = 0;
    }
    else{
      OCR1A = (ppm[cur_chan_numb] - PPM_PulseLen) * 2;
      calc_rest = calc_rest + ppm[cur_chan_numb];
      cur_chan_numb++;
    }     
  }
}

Paramétrage de la radio

– Activer le mode écolage et bloquer toutes les voies sauf celles que vous voulez commander avec l’Arduino.

14.05.06 - 09937 - Arduino_PPM_T9X

Test

– Dans le menu Display de la radio vous pouvez voir la position des différentes voies. Le graph de la voie 5 doit bouger quand vous actionnez les interrupteurs.

Arduino_PPM_T9X

– Allumez ensuite votre appareil et connectez votre contrôleur de vol à l’ordinateur.

– Dans l’onglet « Mode de vols » vous allez pouvoir choisir le mode de vol correspondant à chaque bouton et donc à ce qui est affiché par l’écran de l’arduino.

Mise en œuvre réelle

– Fixer l’arduino et l’afficheur sur la radio. Par exemple sur un support pour radio. Et alimentez l’arduino. Vous pouvez le brancher sur la batterie de la radio. Par sécurité j’ai préféré l’alimenter avec la batterie du récepteur FPV.

– Allez voler avec. Vous verrez ça fonctionne pour de vrai 🙂 Cependant si un comportement étrange survenait, vous n’avez qu’à maintenir la manette d’écolage en position haute pour que la radio ignore l’Arduino.

Pensez donc à laisser un switch de votre radio d’opérationnel sur la voie 5 pour pouvoir passer en mode manuel et ramener votre appareil !

Conclusion

Ce montage est plutôt encourageant pour réaliser d’autres extensions comme le contrôle de l’appareil photo et de sa nacelle de façon plus ergonomique.

Améliorations à venir :

– Utiliser un afficheur plus visible au soleil. Je vais essayer avec un afficheur 7 segments avec LED bi-color et boutons car j’en ai un sous la main. Mais l’idéal serait un écran à encre électronique

– Ajouter le contrôle de l’appareil photo, de la nacelle…

– Passer à un arduino plus petit et moins cher : Pro Mini Microcontroller Circuit Board for Arduino(5V / 16MHz)

– S’appuyer sur une librairie de génération du signal PPM comme celle de RCLib. Mais elle est vraiment complète par rapport à mon besoin.

Les liens vers dx.com le sont par l’intermédiaire de leur programme d’affiliation. Je fais de nombreux achats sur ce site et en suis pleinement satisfait. Même du SAV. Pensez à acheter dans l’entrepôt européen pour ne pas avoir à vous acquittez des droits de douane et TVA si vous résidez en Europe. Pas de version en langue française par contre.