Histoire de vous montrer une application concrète de l’émetteur/récepteur radio nRF24, je vous partage ici un prototype de voiture télécommandée arduino, à 3 roues. Bien sûr, ce véhicule n’aura pas pour but d’être performant, car il s’agit là d’un projet purement didactique (vous permettant donc d’apprendre l’électronique pas à pas, de manière simple, ludique, et pratique).
Comme d’habitude, je vous mettrai la liste de tous les composants utilisés ici, ainsi que les plans, schémas, et programme arduino en libre téléchargement, en fin d’article (aussi bien pour la partie électronique, que pour le châssis en impression 3d). Ainsi, vous pourrez reproduire cette voiture RC arduino, si le cœur vous en dit ! Par contre, gardez bien à l’esprit qu’il s’agit ici d’un prototype de voiture radiocommandée : il y a donc beaucoup de choses qui pourraient être améliorées ! Le but restant l’apprentissage de l’électronique avant tout ici, encore une fois 😉
Au sujet de cette réalisation : ce projet de voiture télécommandée arduino a deux objectifs. Le 1er est de vous inspirer à créer vous-même vos propres projets, à partir d’un exemple concret de réalisation. Et le 2ème est de vous montrer comment mettre en œuvre des émetteurs récepteurs sans fil 2,4 GHz en pratique, notamment au niveau du code arduino. Bien sûr, libre à vous de reprendre tout ou partie de ce projet à votre guise, et selon vos besoins !
Intro : ce projet de « voiture télécommandée arduino »
En fait, l’idée d’une réalisation de voiture radiocommandée arduino fait suite à vos nombreux messages perso, et commentaires au niveau de l’article tutorial sur le nRF24. Et comme vous le souhaitiez, voici un exemple simple, pratique, et fonctionnel, de communication radio en 2,4 GHz !
Par ailleurs, ce projet me permettra de vous montrer également une mise en pratique concrète du driver de moteurs L298N, au sein d’un projet particulier. Ainsi, vous pourrez voir comment piloter des moteurs à courant continu en PWM, via un Arduino, en toute simplicité.
Enfin, comme j’avais précédemment réalisé une petite alimentation sans fil à base d’accus li-ion 18650, ce sera aussi l’occasion d’en montrer un exemple d’utilisation pratique !
Au final, comme vous l’aurez compris, cette voiture RC arduino comprendra :
- 1 x coupleur d’accus lithium-ion 18650, pour alimenter la partie puissance, ainsi que la partie commande
- 1 x module L298N, pour le pilotage des moteurs
- 1 x module NRF24L01+, pour la partie radio
- Et un arduino, pour orchestrer tout cela !
Bien évidemment, comme vous vous en doutez, il faudra un émetteur radio séparé, pour piloter cette voiture arduino. Pour cela, je me servirai tout simplement de la télécommande radio (à simple joystick), que j’avais réalisé il y a quelques temps. Ainsi, la boucle sera bouclée 😉
Du reste, comme je vous disais au début, ce projet n’a pas pour but d’être meilleur (ou moins cher) que ce que l’on trouve ailleurs, dans le commerce. Non, le but de ce projet est simplement de vous montrer une façon de mettre en œuvre plusieurs modules arduino, afin de créer un ensemble communiquant, et abouti. Et ceci, afin de vous permettre d’apprendre l’électronique de chez vous, tout simplement ! C’est pourquoi cet article se veut plus éducatif, avant toute autre chose !
Bon… trêve de blabla, et commençons par voir le schéma fonctionnel de cette voiture radiocommandée arduino, pour commencer !
Schéma fonctionnel de cette voiture radiocommandée arduino
Le schéma fonctionnel suivant, résume bloc par bloc tout ce que cette voiture télécommandée arduino va faire en « interne », vis-à-vis de l’extérieur. Enfin… de manière simplifiée !
Comme vous pouvez le constater, on retrouve 6 blocs principaux, à savoir :
- Le bloc d’alimentation, qui a pour rôle de fournir de l’énergie aux moteurs, ainsi qu’à la platine arduino
- Le bloc de réception radio, qui a pour mission de capter tous les messages radios émanant de l’émetteur radio
- Le bloc de conversion de niveaux, qui a pour but de transmettre des informations à l’Arduino, au sujet des accus li-ion 18650 (après abaissement des tensions mesurées)
- Le bloc de gestion/pilotage, c’est-à-dire l’arduino en lui-même, qui a pour rôles de :
- surveiller le niveau des accus (afin d’éviter toute décharge trop importante de ces derniers)
- piloter les moteurs électrique (au travers du module L298N)
- et afficher des signaux lumineux au besoin (en cas de batterie faible, ou de signal radio perdu)
- Le bloc de commande de puissance des moteurs, basé sur le L298N, et permettant de piloter directement les moteurs, en fonction des consignes fournies par l’arduino
- Et le bloc d’alertes, qui est simplement constitué de 2 leds (1 rouge pour signaler des accus possiblement trop déchargés, et 1 orange, pour indiquer la perte de signal radio)
Une parenthèse, concernant ce schéma fonctionnel : si je l’ai fait, c’est simplement pour préparer l’étape suivante. D’ailleurs, comme vous pourrez le vérifier, chaque bloc que nous avons vu ici se retrouvera sur le schéma électronique final. Ainsi, ce n’est pas travailler pour rien que de faire un tel travail préparatoire ! Au contraire, je dirais que c’est presque indispensable, lorsqu’on cherche à structurer son travail, pour être plus efficace 😉
Schéma électronique de la platine de commande
Comme évoqué juste avant, le schéma électronique de cette voiture RC arduino découle du schéma fonctionnel vu précédemment. Mais avant d’entrer dans le détail de ce schéma à proprement parler, il y a 2 choses qu’il faut bien comprendre :
- Premièrement, le bloc d’accus assurant l’alimentation de commande et de puissance est un élément à part entière (et comme évoqué un peu plus haut, il a déjà été détaillé, dans un précédent article)
- Deuxièmement, le module L298N assurant le pilotage de puissance des moteurs est également un élément à part entière
Du coup, le schéma présenté ici ne sera en fait que celui de la « platine de commande », intégrant un Arduino Nano et son transmetteur radio nRF24L01+. Cette platine s’alimentera à partir du bloc d’accus li-ion, et commandera le module L298N au besoin. D’ailleurs, voici le schéma complet de cette platine de commande arduino, avec toutes les interconnexions vers l’extérieur :
Comme vous pouvez le constater, on retrouve bien les 6 blocs du schéma fonctionnel, de cette voiture radiocommandée arduino. Ceux-ci sont, pour rappel :
- La partie alim : qui récupère la tension fournie par le pack d’accus li-ion 18650, via un connecteur XT30. Avec, au passage, un interrupteur marche/arrêt pour isoler l’arduino du reste du montage, ainsi qu’une diode de protection contre les inversions de polarité (modèle schottky 1N5817)
- La partie commande : qui est tout simplement constituée d’un Arduino Nano
- La partie signalisation lumineuse : qui est assurée par 2 leds colorées, une rouge et une orange (respectivement pour indiquer l’éventuelle faiblesse des batteries, et la perte éventuelle du signal radio)
- La partie pilotage des moteurs : qui se résume à un connecteur à 6 fils, à destination du module L298N
- La partie surveillance de niveaux d’accus : qui comprend 3 résistances permettant de compléter le système « pont diviseur de tension », initié au niveau du pack d’accus (sera détaillé plus loin)
- Et la partie réception radio : qui est simplement constituée d’un module nRF24L01+ (avec antenne intégrée)
Pour ainsi dire, il n’y a vraiment rien de compliqué dans ce schéma. Il y a très peu de composants utilisés, comme vous pouvez le voir. Toutefois, il y a 2 subtilités à bien comprendre, là aussi :
- La 1ère : les deux LED seront allumées lorsque les sorties de l’arduino seront à l’état bas (0V), et éteintes lorsque les sorties seront à l’état haut (c’est-à-dire quand elles seront à +5V)
- La 2nde : les 3 résistances 10k mises à la masse au niveau du « bloc de surveillance de niveaux d’accus » font suite à 3 résistances 22k mises en série sur ces lignes, au niveau du bloc d’accus (non visibles, sur ce schéma) ; cela peut donc paraître bizarre, mais ces 6 résistances (les 3 ici et les 3 sur l’alim li-ion) forment bien 3 ponts diviseurs de tension, qui permettent d’abaisser la tension des accus, afin que celles-ci puissent être mesurées par l’arduino (pour être dans les limites de la plage de lecture du convertisseur analogique-digital de l’Arduino, plus précisément)
Du reste, comme vous l’aurez compris, toute la « logique de commande » se passe au niveau logiciel. Ce qui permet d’avoir une partie matérielle assez épurée. D’ailleurs, en parlant de la partie logicielle, voyons à présent comment celle-ci s’articule !
Diagramme fonctionnel (processus logiciel)
Le code de programmation arduino de cette voiture radiocommandée va suivre un process bien particulier, comme visible juste après. En effet, il faudra que le programme :
- surveille en permanence le niveau des accus
- vérifie s’il y a ou non des commandes radio reçues
- et pilote les moteurs en conséquence (en envoyant les commandes appropriées, au module L298N)
C’est pourquoi l’ensemble de ces fonctionnalités sera intégré dans une boucle perpétuelle, à répétition cyclique. Le reste tout autour, n’est au final qu’accessoire. D’ailleurs, en parlant de ce diagramme fonctionnel, le voici :
En fait, en « temps normal », tout se passe au niveau de la « colonne centrale ». Sinon :
- si la batterie devient trop faible, alors on bascule sur la colonne de droite, pour mettre la voiture au repos, et arrêter le programme
- et si le signal radio de l’émetteur est « perdu », alors on bascule sur la colonne de gauche, pour mettre temporairement les moteurs à l’arrêt (c’est en fait une sécurité pour que le véhicule ne continue pas sur sa lancée, en cas de défaillance de l’émetteur)
Cela étant dit, vous verrez que le programme est, à peu de choses près, calqué sur ce diagramme fonctionnel. D’ailleurs, voyons-le dès à présent, sans plus attendre !
Programme arduino (code)
Concernant le programme arduino de cette petite voiture télécommandée, vous verrez que cela suit à peu de choses près le diagramme fonctionnel précédent. D’ailleurs, le voici :
/*
______ _ _/// _ _ _
/ _ \ (_) | __\| | | | (_)
| [_| |__ ___ ___ _ ___ _ __ | |__ | | ___ ___| |_ _ __ ___ _ __ _ ___ _ _ ___
| ___/ _ \| __|| __| |/ _ \| '_ \_____| __|| |/ _ \/ _| _| '__/ \| '_ \| |/ \| | | |/ _ \
| | | ( ) |__ ||__ | | ( ) | | | |____| |__ | | __/| (_| |_| | | (_) | | | | | (_) | |_| | __/
\__| \__,_|___||___|_|\___/|_| [_| \____/|_|\___|\____\__\_| \___/|_| |_|_|\__ |\__,_|\___|
| |
\_|
Fichier: prgVoiture3rouesRC
Description: Programme de bord de l'Arduino Nano, faisant tourner le projet de "Voiture Radiocommandée à 3 roues"
(exemple de mise en oeuvre des modules émetteur/récepteur NRF24L01+)
Auteur: Jérôme, Passion-Électronique (https://passionelectronique.fr/)
Création : 29.11.2021
Librairie utilisée : https://github.com/nRF24/RF24
*/
//***************//
// Bibliothèques //
//***************//
#include <SPI.h>
#include <RF24.h>
//**************************************************//
// Définition des entrées/sorties de l'Arduino Nano //
//**************************************************//
#define borneENA_L298N 9 // On associe la borne "ENA" du L298N à la pin D9 de l'arduino
#define borneIN1_L298N 8 // On associe la borne "IN1" du L298N à la pin D8 de l'arduino
#define borneIN2_L298N 7 // On associe la borne "IN2" du L298N à la pin D7 de l'arduino
#define borneIN3_L298N 5 // On associe la borne "IN3" du L298N à la pin D5 de l'arduino
#define borneIN4_L298N 4 // On associe la borne "IN4" du L298N à la pin D4 de l'arduino
#define borneENB_L298N 3 // On associe la borne "ENB" du L298N à la pin D3 de l'arduino
#define pinCE_RF24 10 // On associe la broche "CE" du NRF24L01 à la pin D10 de l'arduino
#define pinCSN_RF24 2 // On associe la broche "CSN" du NRF24L01 à la pin D2 de l'arduino
#define pinVA_PACK_ACCUS_18650 A0 // [Entrée] Pour mesure de tension "nominale 11,1V" du pack d'accus li-ion 18650
#define pinVB_PACK_ACCUS_18650 A1 // [Entrée] Pour mesure de tension "nominale 7,4V" du pack d'accus li-ion 18650
#define pinVC_PACK_ACCUS_18650 A2 // [Entrée] Pour mesure de tension "nominale 3,7V" du pack d'accus li-ion 18650
#define tensionMinimaleAccu 3 // On définit que la tension minimale de chaque accu 18650 qui alimente se projet, ne doit pas être en dessous de 3V
#define pinLed_BatterieFaible A3 // [Sortie] Raccordé à la LED rouge présente sur le PCB (batterie faible), s'allumant quand la sortie est mise à 0
#define pinLed_SignalRadioPerdu A4 // [Sortie] Raccordé à la LED orange présente sur le PCB (signal radio perdu), s'allumant quand la sortie est mise à 0
//*****************************************************//
// Définition de paramètres généraux pour ce programme //
//*****************************************************//
#define tunnelDeCommunication "REA01" // Déclaration d'un "nom de tunnel" (5 caractères) => doit être strictement identique à l'émetteur
#define valeurResistanceDiviseur_serie 22000 // Résistance 1/2 du pont diviseur de tension créé pour mesurer la tension de chaque accu 18650 (côté pack accus)
#define valeurResistanceDiviseur_pullDown 10000 // Résistance 2/2 du pont diviseur de tension créé pour mesurer la tension de chaque accu 18650 (côté de ce montage)
#define tensionReferenceAdcArduino 5 // Tension de référence de l'ADC de l'Arduino Nano (par défaut à 5 volts)
#define vitesseMinimale 55 // Rapport cylique minimal des signaux PWM, pour faire tourner les moteur au minimum de leur vitesse (en pratique, on évitera de trop approcher de la valeur 0)
#define vitesseMaximale 255 // Rapport cylique maximal des signaux PWM, pour faire tourner les moteur au maximum de leur vitesse
//************************//
// Variables du programme //
//************************//
const byte adresse[6] = tunnelDeCommunication; // Mise au format "byte array" du nom du tunnel
int valBrocheVA; // Variable 16 bits où sera stockée la lecture 10 bits (0..1023) de l'ADC en VA
int valBrocheVB; // Variable 16 bits où sera stockée la lecture 10 bits (0..1023) de l'ADC en VB
int valBrocheVC; // Variable 16 bits où sera stockée la lecture 10 bits (0..1023) de l'ADC en VC
float valTensionVA; // Variable de calcul qui donnera la "vraie" valeur de tension de VA, après correction inverse du pont diviseur résistif (11,1V au nominal)
float valTensionVB; // Variable de calcul qui donnera la "vraie" valeur de tension de VB, après correction inverse du pont diviseur résistif ( 7,4V au nominal)
float valTensionVC; // Variable de calcul qui donnera la "vraie" valeur de tension de VC, après correction inverse du pont diviseur résistif ( 3,7V au nominal)
float tensionAccu1; // Variable de calcul qui contiendra la tension de l'accu li-ion n°1
float tensionAccu2; // Variable de calcul qui contiendra la tension de l'accu li-ion n°2
float tensionAccu3; // Variable de calcul qui contiendra la tension de l'accu li-ion n°3
unsigned long heureDernierSignalRecu = 0; // Variable qui contiendra "l'heure" du dernier signal reçu, en provenance de l'émetteur (nota : ce n'est pas réellement l'heure, mais un "compteur de millisecondes écoulées", interne à l'arduino)
boolean bSignalRadioPerdu = false; // Variable qui mémorisera le fait que le signal radio de l'émetteur n'est plus reçu ici, si c'est le cas
RF24 radio(pinCE_RF24, pinCSN_RF24); // Instanciation du NRF24L01
//************************************************************//
// Format des données à recevoir, par ondes radio (structure) //
//************************************************************//
struct DonneesArecevoir {
int valAvancerReculer; // int (2 octets), transportant une valeur comprise entre -255 et +255 (-255 signifie ici reculer à vitesse maximale, et +255, avancer à vitesse maximale)
int valDroiteGauche; // int (2 octets), transportant une valeur comprise entre -255 et +255 (-255 signifie ici tourner à gauche pleinement, et +255, signifie tourner pleinement à droite)
};
DonneesArecevoir donnees;
//*******//
// SETUP //
//*******//
void setup() {
// Configuration des pins de l'Arduino Nano à destination du module L298N, en sorties
pinMode(borneENA_L298N, OUTPUT);
pinMode(borneIN1_L298N, OUTPUT);
pinMode(borneIN2_L298N, OUTPUT);
pinMode(borneIN3_L298N, OUTPUT);
pinMode(borneIN4_L298N, OUTPUT);
pinMode(borneENB_L298N, OUTPUT);
// Configuration des pins de l'Arduino en destination des LEDs, en sorties également
pinMode(pinLed_BatterieFaible, OUTPUT); // Sortie LED rouge "Batterie faible"
pinMode(pinLed_SignalRadioPerdu, OUTPUT); // Sortie LED orange "Signal radio perdu"
// Allumage/extinction des LEDS au démarrage, pour "autotest"
autotestLedsAuDemarrage();
arretMoteurs();
// Démarrage du module NRF24L01+, avec paramétrages de base
radio.begin(); // Initialisation du module nRF24
radio.openReadingPipe(0, adresse); // Ouverture du tunnel en "LECTURE" (avec le "nom" qu'on lui a donné)
radio.setPALevel(RF24_PA_MIN); // Sélection d'un niveau "MINIMAL" d'émission, pour communiquer (car pas besoin ici d'une forte puissance, pour ce projet)
radio.startListening(); // Activation du mode "écoute" pour le nRF24 (signifiant qu'on va recevoir des données, et non en émettre, ici)
}
//**************************//
// Boucle principale : LOOP //
//**************************//
void loop() {
mesurerTensionsAccus(); // Stocke le résultat dans les variables : tensionAccu1, tensionAccu2, et tensionAccu3
// Test : vérification de la tension de chaque accu, par rapport à la valeur minimale qu'on a définit plus haut
if(tensionAccu1 < tensionMinimaleAccu || tensionAccu2 < tensionMinimaleAccu || tensionAccu3 < tensionMinimaleAccu) {
// Si un des accus a une tension trop basse, alors "on arrête tout"
stopperProgramme();
}
else {
// Si les tensions d'accus sont bonnes, alors on continue le programme
if(donneesRecues()) {
heureDernierSignalRecu = millis(); // Mise à jour de "l'heure" du dernier signal reçu
digitalWrite(pinLed_SignalRadioPerdu, HIGH); // Extinction de la LED "signal radio perdu", si allumée
envoiConsignesAuxMoteurs();
} else {
// Si aucune donnée radio n'est reçue, alors on regarde si ça fait plus de 2 secondes (soit 2000 millisecondes)
if((millis() - heureDernierSignalRecu) > 2000) {
// Cela fait plus de 2 seconde qu'aucun signal radio n'a été reçu
digitalWrite(pinLed_SignalRadioPerdu, LOW); // Allumage de la LED "signal radio perdu"
arretMoteurs(); // Arrêt des moteurs, car aucune donnée reçue (émetteur coupé ? trop éloigné ?)
}
}
}
}
//**************************************//
// Fonction : autotestLedsAuDemarrage() //
//**************************************//
void autotestLedsAuDemarrage() {
// Allumage puis extinction des LEDs rouge et orange (activent à l'état bas), et ce, deux fois de suite
for(byte i = 0 ; i < 3 ; i++) {
digitalWrite(pinLed_BatterieFaible, LOW);
digitalWrite(pinLed_SignalRadioPerdu, LOW);
delay(20);
digitalWrite(pinLed_BatterieFaible, HIGH);
digitalWrite(pinLed_SignalRadioPerdu, HIGH);
delay(200);
}
}
//***********************************//
// Fonction : mesurerTensionsAccus() //
//***********************************//
void mesurerTensionsAccus() {
// Lecture des entrées analogiques
valBrocheVA = analogRead(pinVA_PACK_ACCUS_18650); // Valeur comprise entre 0 et 1023 (avec 1023 correspondant à +5V)
valBrocheVB = analogRead(pinVB_PACK_ACCUS_18650); // Valeur comprise entre 0 et 1023 (avec 1023 correspondant à +5V)
valBrocheVC = analogRead(pinVC_PACK_ACCUS_18650); // Valeur comprise entre 0 et 1023 (avec 1023 correspondant à +5V)
// Calcul des tensions réelles, correspondantes à ces entrées (avec calculs inverses, dûs aux ponts diviseurs de tension)
// Les valeurs obtenues seront, au nominal, de : 11,1V pour VA / 7,4V pour VB / 3,7V pour VC
valTensionVA = (float)valBrocheVA * (valeurResistanceDiviseur_serie + valeurResistanceDiviseur_pullDown) / valeurResistanceDiviseur_pullDown * tensionReferenceAdcArduino / 1023;
valTensionVB = (float)valBrocheVB * (valeurResistanceDiviseur_serie + valeurResistanceDiviseur_pullDown) / valeurResistanceDiviseur_pullDown * tensionReferenceAdcArduino / 1023;
valTensionVC = (float)valBrocheVC * (valeurResistanceDiviseur_serie + valeurResistanceDiviseur_pullDown) / valeurResistanceDiviseur_pullDown * tensionReferenceAdcArduino / 1023;
// Calcul des tensions individuelles de chaque accu lithium ion
tensionAccu1 = valTensionVA - valTensionVB; // 11,1 - 7,4 = 3,7V au nominal
tensionAccu2 = valTensionVB - valTensionVC; // 7,4 - 3,7 = 3,7V au nominal
tensionAccu3 = valTensionVC; // 3,7 - 0,0 = 3,7V au nominal
}
//*******************************//
// Fonction : stopperProgramme() //
//*******************************//
void stopperProgramme() {
digitalWrite(pinLed_BatterieFaible, LOW); // On allume la LED rouge ("batterie faible")
digitalWrite(pinLed_SignalRadioPerdu, HIGH); // On éteint la LED orange ("signal radio perdu"), si allumée
arretMoteurs(); // On met les moteurs au repos
radio.powerDown(); // Mise en sommeil du module récepteur nRF24
while(1) {} // Boucle sans fin ("arrêt du programme")
}
//****************************//
// Fonction : donneesRecues() //
//****************************//
boolean donneesRecues() {
// On regarde si des données sont en attente de lecture
if (radio.available()) {
// Si oui, on les lit, et on retourne "VRAI"
radio.read(&donnees, sizeof(donnees));
return true;
} else {
// Sinon, on retourne "FAUX"
return false;
}
}
//***************************//
// Fonction : arretMoteurs() //
//***************************//
void arretMoteurs() {
// Stoppe les signaux PWM de commande
analogWrite(borneENA_L298N, 0);
analogWrite(borneENB_L298N, 0);
// Mise à l'état bas des autres sorties (non indispensable)
digitalWrite(borneIN1_L298N, LOW);
digitalWrite(borneIN2_L298N, LOW);
digitalWrite(borneIN3_L298N, LOW);
digitalWrite(borneIN4_L298N, LOW);
}
//***************************************//
// Fonction : envoiConsignesAuxMoteurs() //
//***************************************//
void envoiConsignesAuxMoteurs() {
// Analyse des données, et définition de valeurs qui vont nous servir
byte vitesse = map(abs(donnees.valAvancerReculer), 0, 255, vitesseMinimale, vitesseMaximale);
boolean bMarcheAvant = donnees.valAvancerReculer > 0 ? true : false;
boolean bMarcheArriere = donnees.valAvancerReculer < 0 ? true : false;
boolean bAuPointMort = donnees.valAvancerReculer == 0 ? true : false;
float coefficienAngleVolant = (1 - abs(donnees.valDroiteGauche) / 255 * 0.7);
boolean bTournerAdroite = donnees.valDroiteGauche > 0 ? true : false;
boolean bTournerAgauche = donnees.valDroiteGauche < 0 ? true : false;
// Cas "MARCHE AVANT"
if (bMarcheAvant) {
// Indication de sens des ponts en H, des L298N
digitalWrite(borneIN1_L298N, HIGH); // L'entrée IN1 doit être au niveau haut
digitalWrite(borneIN2_L298N, LOW); // L'entrée IN2 doit être au niveau bas
digitalWrite(borneIN3_L298N, HIGH); // L'entrée IN3 doit être au niveau haut
digitalWrite(borneIN4_L298N, LOW); // L'entrée IN4 doit être au niveau bas
// Vitesse du moteur de droite (suivant consigne, sauf si besoin de tourner à droite ; là, il faudra le ralentir)
if(bTournerAdroite) {
analogWrite(borneENA_L298N, vitesse * coefficienAngleVolant);
} else {
analogWrite(borneENA_L298N, vitesse);
}
// Vitesse du moteur de gauche (suivant consigne, sauf si besoin de tourner à gauche ; là, il faudra le ralentir)
if(bTournerAgauche) {
analogWrite(borneENB_L298N, vitesse * coefficienAngleVolant);
} else {
analogWrite(borneENB_L298N, vitesse);
}
}
// Cas "MARCHE ARRIERE"
if (bMarcheArriere) {
// Indication de sens des ponts en H, des L298N
digitalWrite(borneIN1_L298N, LOW); // L'entrée IN1 doit être au niveau bas
digitalWrite(borneIN2_L298N, HIGH); // L'entrée IN2 doit être au niveau haut
digitalWrite(borneIN3_L298N, LOW); // L'entrée IN3 doit être au niveau bas
digitalWrite(borneIN4_L298N, HIGH); // L'entrée IN4 doit être au niveau haut
// Vitesse du moteur de droite (suivant consigne, sauf si besoin de tourner à droite ; là, il faudra le ralentir)
if(bTournerAdroite) {
analogWrite(borneENA_L298N, vitesse * coefficienAngleVolant);
} else {
analogWrite(borneENA_L298N, vitesse);
}
// Vitesse du moteur de gauche (suivant consigne, sauf si besoin de tourner à gauche ; là, il faudra le ralentir)
if(bTournerAgauche) {
analogWrite(borneENB_L298N, vitesse * coefficienAngleVolant);
} else {
analogWrite(borneENB_L298N, vitesse);
}
}
// Cas "AU POINT MORT"
if (bAuPointMort) {
arretMoteurs();
}
}
Comme vous avez pu le constater, un maximum de commentaires a été mis au niveau du code de programmation. Ainsi, chaque étape est décrite au possible, pour faciliter la compréhension de l’ensemble.
Mais même s’il n’y a rien de bien compliqué ici, il y a néanmoins 4 points qui vous sembleront peut-être difficile à appréhender au début, en première lecture. Il s’agit de :
- la détection de perte de signal radio, faisant intervenir la fonction « millis() » (dont la valeur est systématiquement comparée à celle stockée lors du précédent passage dans la boucle loop, afin de voir si pas plus de 2 secondes se sont écoulées, depuis la dernière réception radio). Nota : en cas de perte de signal effectif, les moteurs seront coupés ; c’est une sécurité qui permet de stopper le véhicule, si jamais l’émetteur venait à être hors de portée, ou s’il ne pouvait plus émettre, à cause de batteries trop faibles, par exemple.
- la conversion de niveaux de signaux, issus des accus li-ion. En fait, au niveau matériel, les tensions de chaque point de mesure du pack d’accus (les 3,7 volts, 7,4 volts, et 11,1 volts, nominales) sont ramenées à des valeurs comprises entre 0 et 5V, afin que l’arduino puisse les lire. Et donc, au niveau logiciel, il faut faire les calculs inverses, pour retrouver ces tensions, afin de pouvoir en déduire la tension de chaque accus, individuellement.
- la gestion des vitesses de rotation moteurs, afin que les signaux PWM ne démarrent pas à 0 (les moteurs ayant besoin d’une tension minimale pour « démarrer », d’où le « mapping »)
- ainsi que la gestion des modulations de vitesse, en fonction de l’angle de braquage (en effet, pour tourner à droite, on ralentit la vitesse du moteur droit tout en maintenant le moteur gauche à son régime nominal, et vice-versa quand on tourne à gauche).
En cas de difficultés de compréhension, n’hésitez pas à prendre votre temps, tout en analysant bien tout ça « bloc par bloc ». Ainsi, les choses vous paraitront bien moins complexes 😉
Fabrication du prototype de cette voiture RC arduino
Concernant la fabrication de cette voiture télécommandée arduino, cela se passe en plusieurs parties. Car il y a :
- 1 x châssis, imprimé en 3D (avec le fichier STL téléchargeable en fin d’article, si vous souhaitez le reproduire à l’identique)
- 1 x alim lithium-ion de 12V environ (c’est en fait le coupleur d’accus li-ion 3S, que j’avais réalisé il y a quelques temps)
- 1 x module L298N (comme on en trouve couramment, dans le commerce)
- Et 1 x platine arduino, que je vais détailler ci-après
En dehors de ça, il n’y a que du câblage, à proprement parler ! (c’est à dire : des connecteurs M/F XT30, des fils de raccordement pour la partie puissance, et des fils dupont pour les signaux de commande). Au passage, si vous souhaitez plus de détails sur tous les composants et accessoires utilisés ici, vous en trouverez la liste détaillée un peu plus bas, en fin d’article.
Platine de commande Arduino
Concernant la platine Arduino de cette voiture radiocommandée, voici son circuit imprimé (PCB), vu de face :
Il n’y a que peu de composants à souder, mais attention, car il y a 5 résistances CMS implantées sur le circuit imprimé (par soucis de gain de place au niveau du PCB, en fait). Je vous recommande d’ailleurs de souder ces petits composants en premier, afin de ne pas être gêné par la suite. À noter que l’Arduino Nano et le nRF24L01+ figurant sur cette carte sont montés sur support ; mais, bien entendu, rien ne vous empêche de les souder directement, si le coeur vous en dit 😉
Voilà pour cette plaquette !
Du reste, pour soutenir les moteurs électriques ainsi que toutes les cartes électroniques, il faudra un support bien adapté. Ici, je vous propose un châssis rudimentaire, mais fonctionnel, réalisé en PLA, en impression 3d ! Bien sûr, libre à vous de faire de même, ou de prendre un tout autre support (planche de bois, …).
Cela étant dit, voici les étapes d’assemblages de cette voiture télécommandée arduino, avec le châssis spécialement conçu pour faire les essais, de mon côté !
Châssis en impression 3D
Pour commencer, voici le châssis que j’ai réalisé. Il est en fait constitué en un seul bloc, dont voici la vue de dessus, et de dessous :
Vous noterez la présence de trous de fixation pour les cartes électroniques, ainsi que pour les moteurs et la roue centrale.
Entretoises de rehaussement
Afin de rehausser les 3 cartes électroniques qui vont prendre place sur ce châssis, des entretoises M3 de 10mm de haut ont été mises en œuvre. Ainsi, cela donne :
À noter qu’il y a ici, de gauche à droite :
- 10 x entretoises femelle/femelle M3 longueur 10 mm (nylon, noir)
- 10 x vis M3 longueur 6 mm (nylon, noir), qui viennent se visser sous ces entretoises, par-dessous le châssis
- 2 x inserts métalliques M3 (diamètre de vissage), OD 4,2 mm (diamètre extérieur), et longueur 6 mm
- 2 x entretoises mâle/femelle M3 longueur 10 mm (nylon, noir), qui se visseront sur les inserts
Au passage, la pose des inserts métalliques s’est faite à chaud. C’est à dire que je les ai chauffé avec la panne de mon fer à souder, pour les faire pénétrer au travers de la matière PLA du châssis. Ainsi, cette « soudure » permet de bloquer efficacement les inserts dans le châssis, une fois refroidi !
Roue centrale (3ème roue), et supports de moteurs
Ensuite vient le tour de la troisième roue (qui sert d’équilibrage, à la voiture). Celle-ci se place au centre, sur la partie droite du châssis. Elle est fixée par 4 vis métalliques noires (en M4 x 10 mm).
Par ailleurs, les 2 équerres-support de moteur prennent également place sur le châssis, mais à gauche. Chacune de ces équerres est maintenue par 4 vis métalliques M3,5 x 10 mm (vis à « pas large », ici).
Voici ce que cela donne, en images :
Nota : ces équerres de fixation étaient fournies avec les moteurs que j’ai achetés (cf. référence, en fin d’article, si vous souhaitez avoir les mêmes).
Moteurs électriques (avec réducteur de vitesse à engrenages)
On continue avec la fixation des 2 moteurs électriques, qui propulseront cette voiture RC arduino. Ceux-ci viennent se poser à même leurs équerres respectives.
Là encore, rien de bien compliqué, car ces moteurs sont simplement tenus par deux vis chacun.
Roues motrices, de cette voiture
Vient ensuite la fixation des 2 roues motrices, sur l’axe des moteurs fixés précédemment. Là aussi, toute la visserie ainsi que les accessoires étaient fournis avec le moteur.
J’en ai profité pour vous prendre des photos d’un peu tous les côtés, histoire que vous arriviez à bien vous représenter les choses ! Du reste, on en a fini avec cette partie « mécanique ». On arrive enfin à la partie électronique 😉
Cartes électroniques
Il ne reste plus qu’à poser et visser les 3 cartes électroniques (pack d’accus, module L298N, et platine Arduino), sur les entretoises posées en tout début (avec vis nylon M3 pour bloquer le tout).
Cela donne déjà plus de vie à notre véhicule ! En fait, à présent, il ne manque plus que les câbles de raccordement, pour finaliser cette voiture radiocommandée arduino !
Câblage des moteurs
Chaque moteur est relié à la carte de puissance L298N, via 2 fils chacun. Pour ma part, j’ai utilisé du fil de section 1 mm² environ (de couleurs jaune et vert, ici sur les photos).
Au passage, faites bien attention à ne pas vous mélanger les pinceaux, au niveau des fils de chaque moteur. Du reste, quant à la polarité, celle-ci n’a pas vraiment d’importance, puisque ces moteurs sont appelés à fonctionner dans les deux sens. Bien entendu, si toutefois l’un ne tourne pas dans le même sens que l’autre, il faudra alors inverser le branchement d’un des deux, pour que tout se passe bien 😉
Câbles d’alimentation (partie puissance)
Côté alimentation, il n’y a que 2 câbles XT30 à mettre en place :
- Entre le pack d’accus 18650 et le module L298N (pour l’alimentation des moteurs)
- Et entre le pack d’accus 18650 et la platine Arduino (pour l’alimentation de la partie commande)
Bien évidemment, pour ce genre de raccordement, vous pouvez fort bien utiliser des câbles mâle/femelle « tout prêt », afin de ne pas vous embêter ! Pour ma part, j’ai préféré me les fabriquer moi-même, afin qu’ils ne soient pas trop long (pour limiter les pertes en ligne).
Câbles de pilotage (partie commande)
Enfin, les derniers câbles à mettre en place sont :
- 6 fils dupont mâle/femelle, de longueur 20 cm, entre le module L298N et la carte Arduino (pour le pilotage PWM des moteurs)
- Et 3 fils dupont mâle/mâle 20 cm, entre le pack d’accus et la platine Arduino (pour la surveillance du niveau des accus)
Nota : on pourrait certainement faire un câblage plus propre, et plus soigné, mais sinon, ça marche du tonnerre 😉
Vue d’ensemble de la voiture RC arduino
Une fois tous ces câblages effectués, on obtient cela (avec les accus li-ion mis en place, sur la photo de droite) :
À noter que tant que l’Arduino n’est pas programmé, et que la vérification de tous les raccordements et soudures n’a pas été faite, il ne faut pas mettre le fusible de « mise en service », au niveau du pack d’accus lithium-ion. Ceci tant que toutes les vérifications nécessaires, et indispensables au bon fonctionnement, n’ont pas été faites, afin d’éviter toute mésaventure !
Essais, remarques, et améliorations possibles
Une fois les vérifications d’usage effectuées, on peut mettre en place les accus et leur fusible de protection, et mettre l’interrupteur de la platine arduino en position « ON ». Ainsi fait, les petites LEDS rouges (celle située sur le module L298N, et celle intégrée directement sur l’Arduino Nano) doivent s’allumer en rouge.
Mise en service de la voiture
À ce stade, si la télécommande est allumée, le voyant orange de la platine arduino devrait être éteint. Sinon, cela indiquerait qu’il y a un problème de transmission radio, entre la radiocommande et cette voiture.
À noter que si jamais la tension d’un accu venait à être inférieure à 3 volts, alors la led rouge s’allumerait (celle-ci se trouve juste à côté de la led orange). Ceci vous indiquerait que le niveau d’une ou plusieurs batteries n’est pas suffisant, et qu’il faut donc les recharger.
Au passage, si on appuie sur l’interrupteur à poussoir du bloc d’accus 18650, la tension du pack d’accus li-ion s’affiche, comme visible ci-dessous :
Donc si je résume l’allumage des voyants, dans le cas où tout est fonctionnel :
- Le voltmètre du pack d’accus lithium ion affiche la tension de la batterie
- La petite LED rouge du L298N doit être allumée (« sous tension »)
- La petite LED rouge intégrée à l’Arduino Nano doit être allumée (« sous tension »)
- La grosse LED orange de la platine arduino doit être éteinte (« signal radio reçu, de manière continue »)
- Et la grosse LED rouge sur la platine arduino doit également être éteinte (si « pas de batterie faible »)
Essais et remarques
Concernant les essais, tout a parfaitement bien fonctionné ! À part deux petits soucis, … pas méchants, mais pénibles quand même !
Pour commencer, j’ai constaté qu’une roue tournait plus vite que l’autre. En effet, celle de droite tournait plus vite que celle de gauche ! Et clairement, il n’y avait aucune raison à cela ! En fait, après vérifications, je me suis rendu compte que, bien que les moteurs que j’ai reçu avaient bien les mêmes caractéristiques, ceux-ci n’étaient pas de même marque. Du coup, il y avait une légère différence de vitesse de rotation, à tension égale. Ainsi : au lieu d’aller en ligne droite, mon véhicule tournait légèrement vers la gauche ! Bien sûr, j’aurais pu compenser cela dans la programmation. Mais comme il s’agissait là d’un problème d’usage de moteurs non identiques, et non d’un dysfonctionnement matériel, il n’était pas nécessaire de s’en préoccuper plus que ça (car cela ne devrait pas se produire, si vous utilisez deux moteurs strictement identiques).
Par ailleurs, j’ai constaté un autre souci : la vitesse max des moteurs était trop lente, à mon goût. J’étais parti sur des modèles 12V de 77 tours par minute (77 RPM). Mais cela est beaucoup trop lent, au final, selon moi. Qui plus est, la chute de tension induite par le L298N étant d’environ 1,5 volts, la tension arrivant aux moteurs est plutôt de l’ordre de 11 volts, plutôt que 12,6 (quand les accus sont « chargés à bloc »). Du coup, la vitesse de rotation des moteurs est « ralentie ». C’est pourquoi, je pense qu’il aurait mieux valu partir sur des 170 RPM (tr/min), pour plus de « dynamique », au niveau de cette voiture radiocommandée arduino 😉
Améliorations possibles
Au final, les améliorations qu’il serait intéressant de faire sur ce prototype, sont :
- Le remplacement des moteurs 77 RPM par des modèles faisant par exemple 170 RPM (plus ou moins)
- L’intégration d’un facteur de correction différentiel, dans le cas où un moteur tournerait un poil moins vite que l’autre (après tout, cela peut être très utile, en cas de légère dérive à droite ou à gauche !)
Sinon, une dernière remarque, qui n’a rien à voir avec ce prototype : l’émetteur que j’ai utilisé ici, bien que parfaitement fonctionnel, n’était pas si pratique que ça. En effet, celui-ci étant équipé d’un « joystick type PS2 », pour les contrôles haut/bas/droite/gauche, ce n’est pas aussi fin que ceux présent sur une « vraie » radiocommande RC ! Du coup, il faudrait que j’en fasse une version améliorée, en ce sens ! Enfin, … dès que j’aurais du temps de libre 😉
Liens utiles et téléchargements
Pour ceux qui voudraient savoir quels composants et accessoires j’ai utilisé ici, ou ceux qui voudraient simplement reproduire ce projet, voici toutes les sources de cette voiture télécommandée arduino :
- Le schéma électronique, au format PDF (platine arduino)
- Le dossier Gerber, au format ZIP (pour faire fabriquer le PCB à l’identique, si souhaité)
- Le programme arduino de cette voiture radiocommandée, au format ZIP
- Le modèle d’impression 3D, au format STL, du châssis
Concernant les composants et accessoires utilisés au niveau du châssis :
- 1 x ensemble d’entretoises et vis en M3, longueur 10 mm (en nylon, couloir noir)
- 2 x inserts métalliques M3, longueur 6 mm et OD 4,2 mm (diamètre extérieur)
- 8 x vis métalliques noirs, auto-taraudeuses, M3,5 x 10 mm
- 1 x roue pivotante en nylon, 360°
- 2 x moteur-réducteur avec roue, équerre, et accessoires de fixation (modèle utilisé dans ce prototype : 12V 77RPM ; mais je pense que des 170 RPM seraient plus adaptés)
- 1 x pack d’alim lithium ion 3S (à concevoir soi-même, suivant l’article que j’avais fait dessus)
- 1 x module L298N (prêt à câbler)
- 1 x ensemble de connecteurs XT30, mâles et femelles
- 1 x ensemble de fils dupont 20cm (M/M et M/F)
Et enfin, concernant les composants électroniques de la platine Arduino, en elle-même :
- 1 x connecteur XT30 à souder sur PCB (modèle coudé, mâle)
- 1 x micro interrupteur à glissière
- 1 x diode schottky 1N5817, au format DO-41
- 1 x Arduino Nano R3
- 1 x ensemble d’header femelles (pour supporter l’arduino, le nrf24, et les câbles dupont)
- 1 x résistance 560 ohms, format 1206 (cms)
- 1 x résistance 470 ohms, format 1206 (cms)
- 1 x led orange Ø5 mm
- 1 x led rouge Ø5 mm
- 3 x résistances 10k ohms, format 1206 (cms)
- 1 x condensateur 100 µF 25V
- 1 x module nRF24L01+ (avec antenne intégrée, donc)
Voiture RC arduino : conclusion !
Voilà ! Nous avons fait le tour de ce prototype de voiture télécommandée arduino ! Bien sûr, comme évoqué en intro, ce projet n’avait qu’un but « éducatif ». C’est pourquoi, bien que parfaitement fonctionnel, il nécessiterait bon nombre d’améliorations 😉
Du coup, n’hésitez pas à vous inspirer de ce prototype, sans forcément chercher à le reproduire tel quel ! Du reste, j’espère que vous aurez pu découvrir ou apprendre bon nombre de nouvelles choses ici, si vous débutez, ou que cela puisse vous inspirer, pour faire vos propres réalisations !
À bientôt !
Jérôme.
En complément de cette voiture RC arduino : une télécommande radio RC arduino (avec joystick)
(*) Mis à jour le 11/12/2021
J’ai adoré cet article l’ami, bravo pour la générosité du partage merci
De rien, c’est avec plaisir !
Bravo..!! pour ce travail décortiqué et bien documenté, cela prend du temps à réaliser, avec beaucoup de passions.
Je suis tes projets avec beaucoup d’intérêt et merci pour toutes ces infos qui m’aide à réaliser mes montages.
Merci pour ce retour ! Alors oui, ça prend beaucoup de temps ! Mais c’est avec plaisir !!!
Bravos. Je n’ai jamais vu de site aussi cool pour apprendre que ça. J’aime bien la manière dont vous expliquez et votre précision. Et j’aimerais aussi que vous ayez une application qui regroupe tous vos projets qui seront mieux accessibles.
Afin de filtrer au maximum les messages de type "spam" ou "inappropriés", chaque commentaire est soumis à modération, et validé manuellement. Du coup, il se peut que certains commentaires ne soient pas publiés, ou sinon, avec un peu de retard. Par ailleurs, j'ai malheureusement plus de messages à traiter que de temps pour y répondre ; c'est pourquoi je ne pourrais pas répondre à tout le monde. Désolé …