nRF24L01+ la programmation simplifiée !

Bonjour :wink:

Dans ce présent sujet je vais vous expliquer comment programmer facilement un émetteur/récepteur 2.4Ghz avec le composant nRF24L01+. Ces exemples fonctionnent avec MODULE℠, le système que j'ai développé qui est une alternative à Arduino™, et l'ATmega328P, voir ici pour télécharger et comprendre ce projet:
MODULE℠ l'alternative à Arduino™ pour l'ATmega328P
Comprendre ce qu'est MODULE℠

Cet article a pour but de vous montrer l'ergonomie de programmation avec la classe Nrf24l01p.h, et surtout la simplicité de programmation par rapport aux bibliothèques tierces.


Une radiocommande R/C avec Nrf24l01p.h et le composant nRF24L01+ :wink:

Nrf24l01p.h permet de transmettre de manière bi-directionnelle des informations (sur 32 bits quelles qu'elles soient) sur la bande fréquence des 2.4Ghz. Cette classe utilise le composant nRF24L01+ qui communique en SPI avec le microcontrôlleur.

Exemple d'émetteur:

#include "../module/Nrf24l01p.h"

int main()
{
 Nrf24l01p myChannel = Nrf24l01p (1);
 unsigned long increment = 0;
 
 Nrf24l01p::start (11, 1524003746, true);
 
 while (true)
 {
 myChannel.transmit (increment);
 increment++;
 }
 
 return 0;
}

Dans cet exemple, un objet myChannel de type Nrf24l01p est déclaré, en paramètre est indiqué le canal 1 sur lequel communiquer les informations. À la ligne suivante une variable de type unsigned long (32 bits non signés) est déclarée avec une valeur de 0, elle va servir à incrémenter un nombre entier.

Puis, le composant nRF24L01+ est démarré en appelant la fonction statique start prenant plusieurs paramètres:

  • Le 1er paramètre 11 est le numéro du port de l'automate sur lequel est connectée la broche SS (slave select) du composant nRF24L01+.

Ce paramètre est utile lorsque vous souhaitez connecter en SPI différents composants en série ou en parallèle avec le microcontrôleur.

  • Le 2ème paramètre 1524003746 correspond à la clé unique qui permet de sécuriser la communication entre deux nRF24L01+.

C'est à vous de choisir cette clé unique, plus le nombre est complexe et plus la communication sera sécurisée et protégée contre les parasites.

  • Le 3ème paramètre true indique d'émettre à la puissance maximale. Une valeur sur false serait la puissance minimale, ce qui peut être suffisant en communication courte distance (par exemple en intérieur).

Puis dans la boucle while, la fonction transmit de l'objet myChannel est utilisée pour transmettre une information 32 bits à un autre nRF24L01+. Dans ce cas c'est la valeur de la variable increment qui est transmise, variable dont la valeur est incrémentée à la ligne suivante.

Ce petit bout de programme est simple, mais il permet déjà d'assurer une communication 2.4Ghz efficace et sécurisée entre deux nRF24L01+.

Envoyer la valeur d'une variable qui s'incrémente au cours du temps peut servir à programmer simplement une fonction "fail-safe" sur la partie récepteur du montage. En effet, si la valeur reçue ne s'incrémente plus pendant un certain temps (1 seconde par exemple), il peut être alors intéressant de déclencher une mise au neutre des servo-moteurs, une coupure de la motorisation d'un aéronef, une procédure de vol automatisée par gyroscope, etc...

Exemple de récepteur:

#include "../module/Nrf24l01p.h"

int main()
{
 Nrf24l01p myChannel = Nrf24l01p (1);
 unsigned long increment = 0;
 
 Nrf24l01p::start (11, 1524003746, true);
 
 while (true)
 {
 myChannel.receive();
 
 //myChannel.value est la valeur reçue:
 increment = myChannel.value;
 }
 
 return 0;
}

Dans cet exemple le seul changement notable est l'appel de la fonction receive de l'objet myChannel afin de recevoir les informations émises, en l'occurrence ici la valeur de la variable incrémentée dans le montage coté émetteur.


Exemple d’un système R/C 5 voies: :wink:

Dans l’exemple suivant, 4 potentiomètres (2 par manche) sont connectés aux ports 15, 16, 17, et 18 de l’automate. Ce sont des GPIO connectées au convertisseur analogique/numérique du microcontrôlleur. Un interrupteur est également connecté au port 1 de l’automate, ce qui va servir d’interrupteur de coupure moteur dans ce cas précis.

Les 4 potentiomètres et l’interrupteur servent d’interface utilisateur entre l’homme et la machine.

5 objets de type Nrf24l01p (correspondants aux 5 voies) servent à transmettre les valeurs brutes des 4 potentiomètres et de l’interrupteur (respectivement des valeurs allants de 0 à 1023 pour les potentiomètres et 0 ou 1 pour l’interrupteur).

L’émetteur:

#include "../module/AnalogRead.h"
#include "../module/GpioRead.h"
#include "../module/Nrf24l01p.h"

int main()
{
 AnalogRead stickThrottle = AnalogRead (15);
 AnalogRead stickPitch = AnalogRead (16);
 AnalogRead stickRoll = AnalogRead (17);
 AnalogRead stickYaw = AnalogRead (18);
 GpioRead buttonHold = GpioRead (1, true, 20);
 Nrf24l01p channelThrottle = Nrf24l01p (1);
 Nrf24l01p channelPitch = Nrf24l01p (2);
 Nrf24l01p channelRoll = Nrf24l01p (3);
 Nrf24l01p channelYaw = Nrf24l01p (4);
 Nrf24l01p channelHold = Nrf24l01p (5);
 
 Nrf24l01p::start (11, 1524003746, true);
 
 while (true)
 {
 stickThrottle.read();
 stickPitch.read();
 stickRoll.read();
 stickYaw.read();
 buttonHold.read();
 
 channelThrottle.transmit (stickThrottle.value);
 channelPitch.transmit (stickPitch.value);
 channelRoll.transmit (stickRoll.value);
 channelYaw.transmit (stickYaw.value);
 channelHold.transmit (buttonHold.continuous);
 }
 
 return 0;
}

L’exemple suivant est la partie récepteur du montage. 5 objets de type PwmWrite sont utilisés pour générer des signaux PWM ce qui permet de faire fonctionner 4 servo-moteurs:

  • Le 1er pour les gaz (throttle).
  • Le 2ème pour l’axe de tangage (pitch).
  • Le 3ème pour l’axe de rouli (roll).
  • Le 4ème pour l’axe de lacet (yaw).

Une fois reçues avec les fonctions receive, les valeurs brutes sont transformées à l’aide de la classe Math.h (qui permet de créer entre autre des courbes) en valeurs adaptées PWM (modulation de la largeur d’impulsion en microsecondes) afin de les envoyer aux servo-moteurs par les ports 1, 2, 3, et 4 de l’automate.

Le récepteur:

#include "../module/Nrf24l01p.h"
#include "../module/PwmWrite.h"
#include "../module/Math.h"

int main()
{
 Nrf24l01p channelThrottle = Nrf24l01p (1);
 Nrf24l01p channelPitch = Nrf24l01p (2);
 Nrf24l01p channelRoll = Nrf24l01p (3);
 Nrf24l01p channelYaw = Nrf24l01p (4);
 Nrf24l01p channelHold = Nrf24l01p (5);
 PwmWrite servoThrottle = PwmWrite (1, 1000, 1000, 2000);
 PwmWrite servoPitch = PwmWrite (2, 1500, 1000, 2000);
 PwmWrite servoRoll = PwmWrite (3, 1500, 1000, 2000);
 PwmWrite servoYaw = PwmWrite (4, 1500, 1000, 2000);
 
 Nrf24l01p::start (11, 1524003746, true);
 PwmWrite::start (50);
 
 while (true)
 {
 channelThrottle.receive();
 channelPitch.receive();
 channelRoll.receive();
 channelYaw.receive();
 channelHold.receive();
 
 if (channelHold.value == true)
 {
 servoThrottle.moveHold();
 }
 else
 {
 servoThrottle.us (Math::curve (0, channelThrottle.value, 1023, 1000, 2000, 0));
 servoPitch.us (Math::curve (0, channelPitch.value, 1023, 1000, 2000, 0));
 servoRoll.us (Math::curve (0, channelRoll.value, 1023, 1000, 2000, 0));
 servoYaw.us (Math::curve (0, channelYaw.value, 1023, 1000, 2000, 0));
 }
 }
 
 return 0;
}

La 5ème voie (hold) permet la coupure des gaz quel que soit la position du manche de gaz, c’est une des sécurités fondamentales notamment en aéromodélisme.

Libre à vous d’explorer les possibilités de MODULE℠ afin d’utiliser et de modifier ces exemples pour vos applications !

En l’occurrence je pense au retour air/sol de la pression atmosphérique et de la température à l’aide du baromètre BMP180 et de la classe Bmp180.h, de l’utilisation des gyroscopes MPU6050 et BNO055 à l’aide des classes Mpu6050.h et Bno055.h, de l’ajout de trims à l’émetteur, d’un écran de contrôle, d’une alarme batterie faible, d’une temporisation, de réglages divers (exponentiel, double débattements), etc…

N’hésitez pas si vous avez des questions :wink:

Vous pouvez retrouver cet article ici:
Une radiocommande R/C avec Nrf24l01p.h