Construire un émetteur RC Arduino multifonctionnel : guide DIY étape par étape
Présentation
Dans ce tutoriel, nous allons apprendre à construire un émetteur radio DIY basé sur Arduino. J'ai souvent besoin de contrôle sans fil pour mes projets, c'est pourquoi j'ai conçu ce contrôleur radio multifonctionnel utilisable pour pratiquement toutes les applications.
Vous pouvez regarder la vidéo ci-dessous ou suivre le tutoriel écrit.
Vue d'ensemble
Cet émetteur permet de contrôler sans fil n'importe quel projet Arduino avec de légères modifications côté récepteur. Il peut également remplacer n'importe quel émetteur RC commercial pour piloter des voitures, drones, etc. Il suffit d'un récepteur Arduino simple qui génère les signaux appropriés pour ces dispositifs.
Je montrerai le fonctionnement à travers plusieurs exemples : contrôle d'un robot voiture Arduino, du robot fourmi Arduino (voir tutoriel précédent) et d'un moteur brushless via ESC et servomoteurs.

La communication radio repose sur le module transceiver NRF24L01 qui, avec une antenne amplifiée, offre une portée stable jusqu'à 700 mètres en espace ouvert. L'émetteur dispose de 14 canaux : 6 entrées analogiques et 8 entrées numériques.

Il comprend deux joysticks, deux potentiomètres, deux interrupteurs à bascule, six boutons poussoirs et une unité de mesure inertielle (IMU) intégrée avec accéléromètre et gyroscope, permettant le contrôle par mouvement ou inclinaison.
Schéma de câblage de l'émetteur RC Arduino
Le cœur du contrôleur est un Arduino Pro Mini alimenté par deux batteries LiPo (environ 7,4 V) connectées directement à la broche RAW, qui possède un régulateur de tension abaissant à 5 V. Attention : il existe deux versions du Pro Mini (5 V et 3,3 V).

Le module NRF24L01 nécessite impérativement du 3,3 V depuis une source dédiée. Nous utilisons donc un régulateur 3,3 V (HT7333 ou AMS1117) connecté aux batteries, avec un condensateur de découplage près du module pour stabiliser la tension et améliorer la fiabilité radio. La communication NRF24L01 utilise le protocole SPI, tandis que le module MPU6050 (accéléromètre/gyroscope) utilise I2C.
Composants nécessaires
- Module transceiver NRF24L01
- NRF24L01 + PA + LNA (version amplifiée)
- Potentiomètres
- Servomoteurs
- Interrupteurs à bascule
- Joysticks (avec carte de débrochage - à dessouder) / Joysticks sans carte de débrochage (eBay)
- Arduino Pro Mini – Version PCB V2 ou V3
- Arduino Pro Mini (version utilisée) – PCB V1
- Régulateur 3,3 V HT7333 (boutique locale) – PCB V1 & V2
- Régulateur 3,3 V AMS1117 – Amazon / Banggood / AliExpress – PCB V3
Conception du PCB
Tous les broches analogiques et numériques du Pro Mini étant utilisées, le câblage avec fils volants serait chaotique. J'ai donc conçu un PCB personnalisé avec EasyEDA (logiciel gratuit en ligne).

Le design tient compte de l'ergonomie pour une prise en main à deux mains, tous les contrôles étant accessibles aux doigts. Bords arrondis, trous de fixation de 3 mm, broches de programmation accessibles sur le dessus. Les broches RX/TX (utilisées pour les boutons des joysticks) sont interrompues par des cavaliers à retirer lors du téléversement.
Important : Vérifiez que votre version d'Arduino Pro Mini correspond au PCB ou modifiez le design en conséquence. Photo comparative des trois versions selon votre Arduino et régulateur :

Lien vers les fichiers du projet PCB (trois versions dans des onglets séparés).
Une fois le design finalisé, j'ai généré les fichiers Gerber pour la fabrication.

Commande chez JLCPCB (sponsor) : glisser-déposer le fichier Gerber, vérification dans le visualiseur, choix des options (couleur noire), prix raisonnable (jusqu'à 10 PCB pour 2 $ pour une première commande).


Assemblage du PCB
Soudure des connecteurs de l'Arduino Pro Mini (astuce : les placer sur une breadboard pour les maintenir). Les broches latérales varient selon le fabricant ; pour mon modèle, 5 broches par côté en laissant un GND libre (zone utilisée pour des pistes).


Module MPU6050 à côté. Régulateur 3,3 V avec condensateur, second condensateur près du NRF24L01 (toutes versions compatibles).


Broches de programmation, RX/TX, alimentation, interrupteur d'alimentation. Potentiomètres : rallongement des broches avec connecteurs. Découpe préalable des boutons de potentiomètres pour y adapter des capuchons. Soudure finale des potentiomètres après assemblage du boîtier (hauteur précise).

Interrupteurs à bascule et joysticks insérés et soudés.

Quatre boutons poussoirs : rallongement des broches avec connecteurs. PCB terminé.
Fabrication du boîtier en acrylique transparent
Pour laisser le PCB visible, j'ai utilisé de l'acrylique transparent 4 mm (film protecteur bleu). Deux plaques de la forme du PCB, fixées dessus et dessous.



Découpe à la scie à métaux, finition à la râpe. Les deux plaques correspondent parfaitement au PCB.

Marquage et perçage : 4 trous de 3 mm pour fixation (avec fraisage pour têtes de vis affleurantes), 6 mm pour interrupteurs et potentiomètres, forêt Forstner 25 mm pour joysticks. Finition à la râpe.


Note : connecteur d'alimentation soudé côté verso pour accès depuis l'arrière (emplacement batterie).

Assemblage final
Retrait du film protecteur (très satisfaisant). Fixation des potentiomètres sur plaque supérieure, insertion des boulons de 3 mm et entretoises de 11 mm.

Assemblage plaque supérieure + PCB, puis soudure définitive des potentiomètres (hauteur maintenant connue).

Plaque arrière : fixation du support de batterie (2 boulons), puis fixation sur l'arrière du PCB (4 boulons).

Connexion batterie, mise en place des capuchons potentiomètres, boutons joysticks, antenne NRF24L01. Émetteur terminé !

Programmation de l'Arduino
Pour programmer le Pro Mini : interface USB-série UART sur l'en-tête de programmation (côté supérieur).

Dans l'IDE Arduino : Outils → Carte "Arduino Pro or Pro Mini", processeur adapté, port série, programmateur "USBasp".

Code de l'émetteur RC Arduino
Structure du code
Bibliothèques : SPI.h, nRF24L01.h, RF24.h (radio), Wire.h (I2C pour MPU6050). Définition des entrées numériques, variables, objet radio, adresse de communication.
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <Wire.h>
// Entrées numériques
#define jB1 1 // Bouton joystick 1
#define jB2 0 // Bouton joystick 2
#define t1 7 // Interrupteur bascule 1
#define t2 4 // Interrupteur bascule 2
#define b1 8 // Bouton 1
#define b2 9 // Bouton 2
#define b3 2 // Bouton 3
#define b4 3 // Bouton 4
const int MPU = 0x68; // Adresse I2C MPU6050
// Variables pour accéléromètre/gyroscope
float AccX, AccY, AccZ;
float GyroX, GyroY, GyroZ;
float accAngleX, accAngleY, gyroAngleX, gyroAngleY;
float angleX, angleY;
float AccErrorX, AccErrorY, GyroErrorX, GyroErrorY;
float elapsedTime, currentTime, previousTime;
int c = 0;
RF24 radio(5, 6); // NRF24L01 (CE, CSN)
const byte address[6] = "00001"; // Adresse
Structure de données (max 32 octets - limite buffer NRF24L01)
struct Data_Package {
byte j1PotX; byte j1PotY; byte j1Button;
byte j2PotX; byte j2PotY; byte j2Button;
byte pot1; byte pot2;
byte tSwitch1; byte tSwitch2;
byte button1; byte button2; byte button3; byte button4;
};
Data_Package data;
Initialisation MPU6050
void initialize_MPU6050() {
Wire.begin();
Wire.beginTransmission(MPU);
Wire.write(0x6B); Wire.write(0x00); // Reset
Wire.endTransmission(true);
// Config accéléromètre (±8g)
Wire.beginTransmission(MPU);
Wire.write(0x1C); Wire.write(0x10);
Wire.endTransmission(true);
// Config gyroscope (1000 dps)
Wire.beginTransmission(MPU);
Wire.write(0x1B); Wire.write(0x10);
Wire.endTransmission(true);
}
Setup : radio, pull-ups, valeurs par défaut
void setup() {
Serial.begin(9600);
initialize_MPU6050();
// calculate_IMU_error(); // Décommenter pour calibration
radio.begin();
radio.openWritingPipe(address);
radio.setAutoAck(false);
radio.setDataRate(RF24_250KBPS);
radio.setPALevel(RF24_PA_LOW);
// Pull-ups internes pour entrées numériques
pinMode(jB1, INPUT_PULLUP); pinMode(jB2, INPUT_PULLUP);
pinMode(t1, INPUT_PULLUP); pinMode(t2, INPUT_PULLUP);
pinMode(b1, INPUT_PULLUP); pinMode(b2, INPUT_PULLUP);
pinMode(b3, INPUT_PULLUP); pinMode(b4, INPUT_PULLUP);
// Valeurs par défaut (127 = centre joystick, 1 = non pressé)
data.j1PotX = 127; data.j1PotY = 127;
data.j2PotX = 127; data.j2PotY = 127;
data.j1Button = 1; data.j2Button = 1;
data.pot1 = 1; data.pot2 = 1;
data.tSwitch1 = 1; data.tSwitch2 = 1;
data.button1 = 1; data.button2 = 1;
data.button3 = 1; data.button4 = 1;
}
Boucle principale : lecture entrées, envoi radio
void loop() {
// Lectures analogiques → 0-255 (1 octet)
data.j1PotX = map(analogRead(A1), 0, 1023, 0, 255);
data.j1PotY = map(analogRead(A0), 0, 1023, 0, 255);
data.j2PotX = map(analogRead(A2), 0, 1023, 0, 255);
data.j2PotY = map(analogRead(A3), 0, 1023, 0, 255);
data.pot1 = map(analogRead(A7), 0, 1023, 0, 255);
data.pot2 = map(analogRead(A6), 0, 1023, 0, 255);
// Lectures numériques (0 = pressé car pull-up)
data.j1Button = digitalRead(jB1);
data.j2Button = digitalRead(jB2);
data.tSwitch2 = digitalRead(t2);
data.button1 = digitalRead(b1);
data.button2 = digitalRead(b2);
data.button3 = digitalRead(b3);
data.button4 = digitalRead(b4);
// Mode IMU si interrupteur 1 activé (LOW)
if (digitalRead(t1) == 0) {
read_IMU(); // Remplace joystick 1 par angles IMU
}
// Envoi structure complète
radio.write(&data, sizeof(Data_Package));
}
Fonction read_IMU() : angles → valeurs joystick
void read_IMU() {
// Lecture accéléromètre
Wire.beginTransmission(MPU);
Wire.write(0x3B); Wire.endTransmission(false);
Wire.requestFrom(MPU, 6, true);
AccX = (Wire.read() << 8 | Wire.read()) / 4096.0;
AccY = (Wire.read() << 8 | Wire.read()) / 4096.0;
AccZ = (Wire.read() << 8 | Wire.read()) / 4096.0;
// Angles accéléromètre (avec correction erreur)
accAngleX = (atan(AccY / sqrt(pow(AccX,2) + pow(AccZ,2))) * 180 / PI) + 1.15;
accAngleY = (atan(-1 * AccX / sqrt(pow(AccY,2) + pow(AccZ,2))) * 180 / PI) - 0.52;
// Lecture gyroscope
currentTime = millis();
elapsedTime = (currentTime - previousTime) / 1000.0;
previousTime = currentTime;
Wire.beginTransmission(MPU);
Wire.write(0x43); Wire.endTransmission(false);
Wire.requestFrom(MPU, 4, true);
GyroX = (Wire.read() << 8 | Wire.read()) / 32.8 + 1.85;
GyroY = (Wire.read() << 8 | Wire.read()) / 32.8 - 0.15;
// Filtre complémentaire
gyroAngleX = GyroX * elapsedTime;
gyroAngleY = GyroY * elapsedTime;
angleX = 0.98 * (angleX + gyroAngleX) + 0.02 * accAngleX;
angleY = 0.98 * (angleY + gyroAngleY) + 0.02 * accAngleY;
// Mapping -90°/+90° → 0-255 (inversé pour X)
data.j1PotX = map(angleX, -90, 90, 255, 0);
data.j1PotY = map(angleY, -90, 90, 0, 255);
}
Le code complet avec fonction calculate_IMU_error() pour calibration est disponible ici.
Code récepteur
Schéma récepteur simple (Arduino + NRF24L01). Code de test affichant les données reçues sur le moniteur série.

/* Code récepteur basique */
#include <SPI.h> #include <nRF24L01.h> #include <RF24.h>
RF24 radio(10, 9); const byte address[6] = "00001";
unsigned long lastReceiveTime = 0, currentTime = 0;
struct Data_Package { /* même structure que l'émetteur */ };
Data_Package data;
void setup() {
Serial.begin(9600);
radio.begin(); radio.openReadingPipe(0, address);
radio.setAutoAck(false); radio.setDataRate(RF24_250KBPS);
radio.setPALevel(RF24_PA_LOW); radio.startListening();
resetData();
}
void loop() {
if (radio.available()) {
radio.read(&data, sizeof(Data_Package));
lastReceiveTime = millis();
}
currentTime = millis();
if (currentTime - lastReceiveTime > 1000) resetData(); // Perte liaison
// Affichage série
Serial.print("j1PotX: "); Serial.print(data.j1PotX);
Serial.print("; j1PotY: "); Serial.print(data.j1PotY);
Serial.print("; button1: "); Serial.print(data.button1);
Serial.print("; j2PotX: "); Serial.println(data.j2PotX);
}
void resetData() { /* valeurs par défaut identiques à l'émetteur */ }
La fonction resetData() évite les comportements dangereux en cas de perte de liaison (ex: drone qui continue de monter).
Exemples d'applications
Contrôle sans fil robot voiture Arduino

Utilisation des valeurs joystick 1 pour le pilotage. Code complet disponible.
Contrôle robot fourmi / hexapode Arduino

Lecture des données et exécution des fonctions appropriées (avancer, tourner, mordre, attaquer...).
Contrôle ESC et servomoteurs (dispositifs RC commerciaux)

Important : Impossible de lier un récepteur RC standard avec ce système NRF24L01 2,4 GHz. Il faut créer son propre récepteur (Arduino + NRF24L01) qui génère les signaux PWM/PPM adaptés.

/* Récepteur pour contrôle ESC et Servos */
#include <SPI.h> #include <nRF24L01.h> #include <RF24.h> #include <Servo.h>
// ... même structure Data_Package ...
Servo esc, servo1, servo2;
void setup() {
// ... init radio identique ...
esc.attach(9); servo1.attach(3); servo2.attach(4);
}
void loop() {
// Vérification liaison + resetData() si timeout
// Lecture radio si disponible
// Contrôle servos (0-180°)
servo1Value = map(data.j2PotX, 0, 255, 0, 180);
servo2Value = map(data.j2PotY, 0, 255, 0, 180);
servo1.write(servo1Value); servo2.write(servo2Value);
// Contrôle ESC (1000-2000 µs)
escValue = map(data.pot1, 0, 255, 1000, 2000);
esc.writeMicroseconds(escValue);
}
J'espère que ce tutoriel vous a plu et appris quelque chose. N'hésitez pas à poser vos questions en commentaires et à consulter ma collection de projets Arduino.
Processus de fabrication
- Le Kazoo : Du Mirliton Ancestral au Jouet Plastique Moderne — Histoire, Fabrication et Avenir
- Construisez votre propre LUMAZOID : Visualiseur musical DIY Arduino
- Construire sa propre machine à écrire les devoirs à la maison (Traceur à stylo)
- Construire un Voltmètre Intelligent avec Arduino et Smartphone – Projet DIY Facile
- Station Météo Compacte : Arduino Nano & ESP8266 avec Capteur BMP280 et Affichage OLED/Nokia LCD
- Construisez un skateboard VR DIY avec Arduino, Google Cardboard et Bluetooth
- Dispositif de Traitement Radionique EMR DIY avec Arduino Nano
- Simulateur de Course 2 Axes DIY : Arduino Nano & Servos SG90
- Construire une serrure de porte RFID portable avec Arduino – Guide étape par étape