Fabrication industrielle
Internet des objets industriel | Matériaux industriels | Entretien et réparation d'équipement | Programmation industrielle |
home  MfgRobots >> Fabrication industrielle >  >> Manufacturing Technology >> Processus de fabrication

Émetteur RC Arduino bricolage

Dans le didacticiel, nous apprendrons comment construire un émetteur DIY Arduino RC. Très souvent, j'ai besoin d'un contrôle sans fil pour les projets que je réalise, c'est pourquoi j'ai construit ce contrôleur radio multifonctionnel qui peut être utilisé pour à peu près tout.

Vous pouvez regarder la vidéo suivante ou lire le didacticiel écrit ci-dessous.

Aperçu

Maintenant, je peux contrôler sans fil n'importe quel projet Arduino avec juste quelques petits ajustements du côté du récepteur. Cet émetteur peut également être utilisé comme n'importe quel émetteur RC commercial pour contrôler les jouets RC, les voitures, les drones, etc. Pour cela, il suffit d'un simple récepteur Arduino qui génère ensuite les signaux appropriés pour contrôler ces appareils RC commerciaux.

J'expliquerai comment tout fonctionne dans cette vidéo à travers quelques exemples de contrôle d'une voiture robot Arduino, de contrôle du robot Arduino Ant de ma vidéo précédente et de contrôle d'un moteur CC sans balais à l'aide d'un ESC et de certains servomoteurs.

La communication radio de ce contrôleur est basée sur le module émetteur-récepteur NRF24L01 qui, s'il est utilisé avec une antenne amplifiée, peut avoir une portée stable allant jusqu'à 700 mètres en espace ouvert. Il dispose de 14 canaux, dont 6 entrées analogiques et 8 entrées numériques.

Il dispose de deux joysticks, de deux potentiomètres, de deux interrupteurs à bascule, de six boutons et d'une unité de mesure interne composée d'un accéléromètre et d'un gyroscope qui peut également être utilisé pour contrôler des choses simplement en déplaçant ou en inclinant le contrôleur.

Schéma du circuit de l'émetteur Arduino RC

Pour commencer, regardons le schéma du circuit. Le cerveau de ce contrôleur RC est un Arduino Pro Mini alimenté par 2 batteries LiPo produisant environ 7,4 volts. Nous pouvons les connecter directement à la broche RAW du Pro Mini qui dispose d'un régulateur de tension qui réduit la tension à 5V. Notez qu'il existe deux versions de l'Arduino Pro Mini, comme celle que j'ai qui fonctionne à 5V et l'autre fonctionne à 3,3V.

En revanche, le module NRF24L01 a strictement besoin de 3.3V et il est recommandé de provenir d'une source dédiée. Par conséquent, nous devons utiliser un régulateur de tension de 3,3 V qui est connecté aux batteries et convertir le 7,4 V en 3,3 V. Nous devons également utiliser un condensateur de découplage juste à côté du module afin de maintenir la tension plus stable, ainsi la communication radio sera également plus stable. Le module NRF24L01 communique avec l'Arduino en utilisant le protocole SPI, tandis que le module accéléromètre et gyroscope MPU6050 utilise le protocole I2C.

Vous pouvez obtenir les composants nécessaires pour ce didacticiel Arduino à partir des liens ci-dessous :

  • Module émetteur-récepteur NRF24L01……….. 
  • NRF24L01 + PA + LNA …………………….
  • Potentiomètre ……………………………….. 
  • Servomoteur …………………………………… 
  • Interrupteur à bascule …………………………….….. 
  • Joystick ………………………………………… .. - ce Joystick est livré avec une carte de dérivation, vous devrez donc dessouder le Joystick à partir de celui-ci
  • Joystick sans carte de dérivation ………… Ebay
  • Arduino Pro Mini…………………………….. – Vous avez besoin de la version PCB V2 ou V3 pour ces cartes
  • Arduino Pro Mini comme celui que j'ai utilisé….. – PCB V1
  • Régulateur de tension HT7333 3.3v ……………. Du magasin d'électronique local - PCB V1 &PCB V2
  • Régulateur de tension 3,3 v AMS1117 …………… Amazon / Banggoood /AliExpress – PCB V3

Conception de circuits imprimés

En fait, j'ai fini par utiliser toutes les broches analogiques et numériques de l'Arduino Pro Mini. Alors maintenant, si j'essaie de tout connecter ensemble à l'aide de câbles de saut, ce sera tout un gâchis. J'ai donc conçu un circuit imprimé personnalisé à l'aide du logiciel de conception de circuits en ligne gratuit EasyEDA.

Ici, j'ai pris en considération l'ergonomie du contrôleur et l'ai conçu pour qu'il soit facilement tenu à deux mains, tandis que toutes les commandes sont à portée des doigts. J'ai arrondi les bords et ajouté des trous de 3 mm pour pouvoir monter le PCB sur quelque chose plus tard. J'ai placé les broches de programmation de l'Arduino Pro Mini sur le dessus du contrôleur afin qu'elles soient facilement accessibles au cas où nous voudrions reprogrammer l'Arduino. On peut aussi remarquer ici que j'ai utilisé les broches RX et TX de l'Arduino pour les boutons du joystick. Cependant, ces deux lignes doivent être déconnectées de tout pendant que nous téléchargeons l'esquisse sur l'Arduino. Ils sont donc interrompus par deux broches qui peuvent ensuite être facilement connectées à l'aide de simples capuchons de cavalier.

Veuillez noter : Assurez-vous d'avoir la bonne version d'Arduino Pro Mini pour usiner le PCB ou modifier la conception du PCB en fonction de celle-ci. Voici une photo de comparaison entre les trois versions différentes, en fonction de votre Arduino et du régulateur de tension.

Voici un lien vers les fichiers de projet de cette conception de PCB. Celles-ci ouvrent les trois versions différentes dans des onglets séparés, afin que vous puissiez choisir celle dont vous avez besoin.

Donc une fois la conception terminée, j'ai généré le fichier Gerber nécessaire à la fabrication du PCB.

Fichier Gerber :

Ensuite, j'ai commandé le PCB à JLCPCB qui est également le sponsor de cette vidéo.

Ici, nous pouvons simplement faire glisser et déposer le fichier Gerber et une fois téléchargé, nous pouvons revoir notre PCB dans la visionneuse Gerber. Si tout va bien, nous pouvons continuer et sélectionner les propriétés que nous voulons pour notre PCB. Cette fois, j'ai choisi la couleur du PCB pour qu'elle soit noire. Et voilà, maintenant nous pouvons simplement commander notre PCB à un prix raisonnable. Notez que s'il s'agit de votre première commande auprès de JLCPCB, vous pouvez obtenir jusqu'à 10 PCB pour seulement 2 $.

Et le voici. J'aime vraiment la façon dont ce PCB s'est avéré dans cette couleur noire. La qualité du PCB est excellente et tout est exactement comme dans la conception.

Assemblage du PCB

Ok maintenant nous pouvons passer à l'assemblage du PCB. J'ai commencé par souder les en-têtes de broches de l'Arduino Pro Mini. Un moyen facile et efficace de le faire est de les placer sur une planche à pain et ainsi ils resteront fermement en place pendant la soudure.

Le Pro Mini a également des broches sur les côtés, mais notez que l'emplacement de ces broches peut varier selon le fabricant.

Pour le modèle particulier que j'ai, j'ai besoin de 5 broches de chaque côté, tout en laissant une broche GND vide car j'ai utilisé sa zone en dessous sur le PCB pour exécuter des traces. J'ai soudé l'Arduino Pro Mini directement sur le PCB et coupé la longueur execs des en-têtes. Juste à côté se trouve le module accéléromètre et gyroscope MPU6050.

Ensuite, j'ai soudé le régulateur de tension 3,3 V avec un condensateur à côté et un autre condensateur près du module NRF24L01. Ce module a trois versions différentes et nous pouvons utiliser n'importe laquelle d'entre elles ici.

J'ai continué avec les broches de programmation de l'Arduino, les broches RX et TX, les broches d'alimentation et l'interrupteur d'alimentation.

Ensuite, pour souder les potentiomètres au circuit imprimé, j'ai dû étendre leurs broches à l'aide de connecteurs à broches.

On peut noter ici que j'ai préalablement coupé la longueur des potards afin de pouvoir y emboîter correctement quelques capuchons. Cependant, nous souderons les potentiomètres au PCB un peu plus tard.

Ensuite, j'ai inséré et soudé les deux interrupteurs à bascule et les deux joysticks en place.

Reste enfin à souder les quatre boutons poussoirs. Cependant, ils n'ont pas la bonne hauteur, donc encore une fois, j'ai utilisé des en-têtes de broches pour étendre un peu leurs broches.

Et voilà, notre PCB est maintenant prêt, nous pouvons donc continuer à fabriquer sa couverture. Parce que j'aime l'apparence du PCB et que je veux être visible, j'ai décidé d'utiliser de l'acrylique transparent pour le couvercle.

Ici, j'ai de l'acrylique transparent de 4 mm qui a actuellement une feuille de protection et qui semble être bleu. L'idée pour le couvercle est de faire deux plaques avec la forme du PCB et de fixer l'une d'elles sur le dessus et l'autre sur le dessous du PCB.

J'ai donc marqué la forme du circuit imprimé et à l'aide d'une scie à main en métal, j'ai coupé l'acrylique en fonction de celle-ci.

Ensuite, à l'aide d'une simple râpe, j'ai affiné la forme de l'acrylique. Les deux plaques sont bien sorties et elles correspondent parfaitement au PCB.

Ensuite, j'ai marqué les endroits où je dois faire des ouvertures pour le passage des composants. À l'aide d'une perceuse de 3 mm, j'ai d'abord fait les 4 trous pour fixer les plaques au PCB. Pour ces trous, j'ai également fait des contre-éviers afin que les boulons puissent être placés en flash avec les plaques.

Pour les ouvertures des interrupteurs à bascule et des potentiomètres, j'ai utilisé une perceuse de 6 mm, et pour les ouvertures du joystick, j'ai utilisé une mèche Forstner de 25 mm. Encore une fois, à l'aide d'une râpe, j'ai affiné toutes les ouvertures.

Avant d'assembler le couvercle, juste une petite note que j'ai en fait soudé l'en-tête de broche pour l'alimentation à l'envers afin qu'il puisse être atteint par l'arrière où la batterie sera située.

Ok maintenant nous pouvons commencer par assembler le couvercle. J'ai commencé par décoller le film protecteur de l'acrylique, ce qui, je dois l'admettre, était assez satisfaisant car l'acrylique était si propre maintenant. J'ai donc d'abord fixé les deux potentiomètres sur la plaque supérieure, inséré les boulons de montage de 3 mm et placé les anneaux de distance de 11 mm en place.

Ensuite, j'ai soigneusement fusionné et fixé la plaque supérieure et le PCB à l'aide de boulons. À ce stade, j'ai finalement soudé les potentiomètres au PCB car auparavant, je ne savais pas exactement à quelle hauteur ils seraient placés.

Ensuite, sur la plaque arrière, j'ai fixé le support de batterie à l'aide de 2 boulons. J'ai terminé l'assemblage du couvercle en fixant la plaque arrière à l'arrière du circuit imprimé à l'aide des quatre boulons de montage.

Enfin, nous pouvons attacher les lignes de la batterie aux broches d'alimentation, insérer et fixer les boutons sur les potentiomètres, insérer les boutons des joysticks et attacher l'antenne au module NRF24l01. Et voilà, nous en avons enfin fini avec l'émetteur DIY Arduino RC.

Il ne reste plus qu'à programmer l'Arduino. Pour programmer une carte Pro Mini, nous avons besoin d'une interface USB vers UART série qui peut être connectée à l'en-tête de programmation situé sur le dessus de notre contrôleur.

Ensuite, dans le menu des outils Arduino IDE, nous devons sélectionner la carte Arduino Pro ou Pro Mini, sélectionner la version appropriée du processeur, sélectionner le port et sélectionner la méthode de programmation sur "USBasp".

Et maintenant, nous sommes en mesure de télécharger le code sur l'Arduino.

Code d'émetteur RC basé sur Arduino DIY

Expliquons comment fonctionne le code émetteur. Nous devons donc d'abord inclure la bibliothèque SPI et RF24 pour la communication sans fil, et la bibliothèque I2C pour le module accéléromètre. Ensuite, nous devons définir les entrées numériques, certaines variables nécessaires au programme ci-dessous, définir l'objet radio et l'adresse de communication.

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <Wire.h>


// Define the digital inputs
#define jB1 1  // Joystick button 1
#define jB2 0  // Joystick button 2
#define t1 7   // Toggle switch 1
#define t2 4   // Toggle switch 1
#define b1 8   // Button 1
#define b2 9   // Button 2
#define b3 2   // Button 3
#define b4 3   // Button 4

const int MPU = 0x68; // MPU6050 I2C address
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"; // AddressCode language: Arduino (arduino)

Ensuite, nous devons définir une structure dans laquelle nous stockerons les 14 valeurs d'entrée du contrôleur. La taille maximale de cette structure peut être de 32 octets, car il s'agit de la limite de mémoire tampon NRF24L01 ou de la quantité de données que le module peut envoyer en même temps.

/ Max size of this struct is 32 bytes - NRF24L01 buffer limit
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; //Create a variable with the above structureCode language: Arduino (arduino)

Dans la section de configuration, nous devons initialiser le module MPU6050 et nous pouvons également calculer l'erreur IMU qui est une valeur qui est ensuite utilisée lors du calcul des angles corrects du module.

void initialize_MPU6050() {
  Wire.begin();                      // Initialize comunication
  Wire.beginTransmission(MPU);       // Start communication with MPU6050 // MPU=0x68
  Wire.write(0x6B);                  // Talk to the register 6B
  Wire.write(0x00);                  // Make reset - place a 0 into the 6B register
  Wire.endTransmission(true);        //end the transmission
  // Configure Accelerometer
  Wire.beginTransmission(MPU);
  Wire.write(0x1C);                  //Talk to the ACCEL_CONFIG register
  Wire.write(0x10);                  //Set the register bits as 00010000 (+/- 8g full scale range)
  Wire.endTransmission(true);
  // Configure Gyro
  Wire.beginTransmission(MPU);
  Wire.write(0x1B);                   // Talk to the GYRO_CONFIG register (1B hex)
  Wire.write(0x10);                   // Set the register bits as 00010000 (1000dps full scale)
  Wire.endTransmission(true);
}Code language: Arduino (arduino)

Vous pouvez trouver plus de détails sur le fonctionnement de l'accéléromètre et du gyroscope MEMS ici. Un tutoriel dédié au MPU6050 sera bientôt disponible.

Ensuite, nous devons initialiser la communication radio, activer les résistances pull-up internes Arduino pour toutes les entrées numériques et définir les valeurs initiales par défaut pour toutes les variables.

// Define the radio communication
  radio.begin();
  radio.openWritingPipe(address);
  radio.setAutoAck(false);
  radio.setDataRate(RF24_250KBPS);
  radio.setPALevel(RF24_PA_LOW);
  
  // Activate the Arduino internal pull-up resistors
  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);Code language: Arduino (arduino)

Dans la section de boucle, commencez par lire toutes les entrées analogiques, mappez leurs valeurs de 0 à 1023 en valeurs d'octets de 0 à 255 car nous avons déjà défini les variables dans notre structure en tant qu'octets. Chaque entrée est stockée dans la variable de données particulière de la structure.

// Read all analog inputs and map them to one Byte value
  data.j1PotX = map(analogRead(A1), 0, 1023, 0, 255); // Convert the analog read value from 0 to 1023 into a BYTE value from 0 to 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);Code language: Arduino (arduino)

Nous devons juste noter que parce que nous utilisons les résistances pull-up, les lectures des broches numériques sont à 0 lorsque les boutons sont enfoncés.

// Read all digital inputs
  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);Code language: Arduino (arduino)

Donc, en utilisant la fonction radio.write(), nous envoyons simplement les valeurs des 14 canaux au récepteur.

// Send the whole data from the structure to the receiver
  radio.write(&data, sizeof(Data_Package));Code language: Arduino (arduino)

Dans le cas où l'interrupteur à bascule 1 est activé, nous utilisons les données de l'accéléromètre et du gyroscope à la place pour le contrôle.

if (digitalRead(t1) == 0) {
    read_IMU();    // Use MPU6050 instead of Joystick 1 for controling left, right, forward and backward movements
  }Code language: Arduino (arduino)

Ainsi, au lieu des valeurs X et Y du joystick 1, nous utilisons les valeurs d'angle que nous obtenons de l'IMU, que nous avons précédemment converties de valeurs de -90 à +90 degrés en valeurs d'octets de 0 à 255 de manière appropriée.

// Map the angle values from -90deg to +90 deg into values from 0 to 255, like the values we are getting from the Joystick
  data.j1PotX = map(angleX, -90, +90, 255, 0);
  data.j1PotY = map(angleY, -90, +90, 0, 255);Code language: Arduino (arduino)

Voilà donc comment le code de l'émetteur, les choses les plus importantes étaient de définir la communication radio et d'envoyer les données au récepteur.

Voici le code Arduino complet pour cet émetteur DIY Arduino RC :

/*
        DIY Arduino based RC Transmitter
  by Dejan Nedelkovski, www.HowToMechatronics.com
  Library: TMRh20/RF24, https://github.com/tmrh20/RF24/
*/

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <Wire.h>


// Define the digital inputs
#define jB1 1  // Joystick button 1
#define jB2 0  // Joystick button 2
#define t1 7   // Toggle switch 1
#define t2 4   // Toggle switch 1
#define b1 8   // Button 1
#define b2 9   // Button 2
#define b3 2   // Button 3
#define b4 3   // Button 4

const int MPU = 0x68; // MPU6050 I2C address
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"; // Address

// Max size of this struct is 32 bytes - NRF24L01 buffer limit
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; //Create a variable with the above structure

void setup() {
  Serial.begin(9600);
  
  // Initialize interface to the MPU6050
  initialize_MPU6050();

  // Call this function if you need to get the IMU error values for your module
  //calculate_IMU_error();
  
  // Define the radio communication
  radio.begin();
  radio.openWritingPipe(address);
  radio.setAutoAck(false);
  radio.setDataRate(RF24_250KBPS);
  radio.setPALevel(RF24_PA_LOW);
  
  // Activate the Arduino internal pull-up resistors
  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);
  
  // Set initial default values
  data.j1PotX = 127; // Values from 0 to 255. When Joystick is in resting position, the value is in the middle, or 127. We actually map the pot value from 0 to 1023 to 0 to 255 because that's one BYTE value
  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;
}
void loop() {
  // Read all analog inputs and map them to one Byte value
  data.j1PotX = map(analogRead(A1), 0, 1023, 0, 255); // Convert the analog read value from 0 to 1023 into a BYTE value from 0 to 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);
  // Read all digital inputs
  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);
  // If toggle switch 1 is switched on
  if (digitalRead(t1) == 0) {
    read_IMU();    // Use MPU6050 instead of Joystick 1 for controling left, right, forward and backward movements
  }
  // Send the whole data from the structure to the receiver
  radio.write(&data, sizeof(Data_Package));
}

void initialize_MPU6050() {
  Wire.begin();                      // Initialize comunication
  Wire.beginTransmission(MPU);       // Start communication with MPU6050 // MPU=0x68
  Wire.write(0x6B);                  // Talk to the register 6B
  Wire.write(0x00);                  // Make reset - place a 0 into the 6B register
  Wire.endTransmission(true);        //end the transmission
  // Configure Accelerometer
  Wire.beginTransmission(MPU);
  Wire.write(0x1C);                  //Talk to the ACCEL_CONFIG register
  Wire.write(0x10);                  //Set the register bits as 00010000 (+/- 8g full scale range)
  Wire.endTransmission(true);
  // Configure Gyro
  Wire.beginTransmission(MPU);
  Wire.write(0x1B);                   // Talk to the GYRO_CONFIG register (1B hex)
  Wire.write(0x10);                   // Set the register bits as 00010000 (1000dps full scale)
  Wire.endTransmission(true);
}

void calculate_IMU_error() {
  // We can call this funtion in the setup section to calculate the accelerometer and gury data error. From here we will get the error values used in the above equations printed on the Serial Monitor.
  // Note that we should place the IMU flat in order to get the proper values, so that we then can the correct values
  // Read accelerometer values 200 times
  while (c < 200) {
    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 ;
    // Sum all readings
    AccErrorX = AccErrorX + ((atan((AccY) / sqrt(pow((AccX), 2) + pow((AccZ), 2))) * 180 / PI));
    AccErrorY = AccErrorY + ((atan(-1 * (AccX) / sqrt(pow((AccY), 2) + pow((AccZ), 2))) * 180 / PI));
    c++;
  }
  //Divide the sum by 200 to get the error value
  AccErrorX = AccErrorX / 200;
  AccErrorY = AccErrorY / 200;
  c = 0;
  // Read gyro values 200 times
  while (c < 200) {
    Wire.beginTransmission(MPU);
    Wire.write(0x43);
    Wire.endTransmission(false);
    Wire.requestFrom(MPU, 4, true);
    GyroX = Wire.read() << 8 | Wire.read();
    GyroY = Wire.read() << 8 | Wire.read();
    // Sum all readings
    GyroErrorX = GyroErrorX + (GyroX / 32.8);
    GyroErrorY = GyroErrorY + (GyroY / 32.8);
    c++;
  }
  //Divide the sum by 200 to get the error value
  GyroErrorX = GyroErrorX / 200;
  GyroErrorY = GyroErrorY / 200;
  // Print the error values on the Serial Monitor
  Serial.print("AccErrorX: ");
  Serial.println(AccErrorX);
  Serial.print("AccErrorY: ");
  Serial.println(AccErrorY);
  Serial.print("GyroErrorX: ");
  Serial.println(GyroErrorX);
  Serial.print("GyroErrorY: ");
  Serial.println(GyroErrorY);
}

void read_IMU() {
  // === Read acceleromter data === //
  Wire.beginTransmission(MPU);
  Wire.write(0x3B); // Start with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU, 6, true); // Read 6 registers total, each axis value is stored in 2 registers
  //For a range of +-8g, we need to divide the raw values by 4096, according to the datasheet
  AccX = (Wire.read() << 8 | Wire.read()) / 4096.0; // X-axis value
  AccY = (Wire.read() << 8 | Wire.read()) / 4096.0; // Y-axis value
  AccZ = (Wire.read() << 8 | Wire.read()) / 4096.0; // Z-axis value

  // Calculating angle values using
  accAngleX = (atan(AccY / sqrt(pow(AccX, 2) + pow(AccZ, 2))) * 180 / PI) + 1.15; // AccErrorX ~(-1.15) See the calculate_IMU_error()custom function for more details
  accAngleY = (atan(-1 * AccX / sqrt(pow(AccY, 2) + pow(AccZ, 2))) * 180 / PI) - 0.52; // AccErrorX ~(0.5)

  // === Read gyro data === //
  previousTime = currentTime;        // Previous time is stored before the actual time read
  currentTime = millis();            // Current time actual time read
  elapsedTime = (currentTime - previousTime) / 1000;   // Divide by 1000 to get seconds
  Wire.beginTransmission(MPU);
  Wire.write(0x43); // Gyro data first register address 0x43
  Wire.endTransmission(false);
  Wire.requestFrom(MPU, 4, true); // Read 4 registers total, each axis value is stored in 2 registers
  GyroX = (Wire.read() << 8 | Wire.read()) / 32.8; // For a 1000dps range we have to divide first the raw value by 32.8, according to the datasheet
  GyroY = (Wire.read() << 8 | Wire.read()) / 32.8;
  GyroX = GyroX + 1.85; //// GyroErrorX ~(-1.85)
  GyroY = GyroY - 0.15; // GyroErrorY ~(0.15)
  // Currently the raw values are in degrees per seconds, deg/s, so we need to multiply by sendonds (s) to get the angle in degrees
  gyroAngleX = GyroX * elapsedTime;
  gyroAngleY = GyroY * elapsedTime;

  // Complementary filter - combine acceleromter and gyro angle values
  angleX = 0.98 * (angleX + gyroAngleX) + 0.02 * accAngleX;
  angleY = 0.98 * (angleY + gyroAngleY) + 0.02 * accAngleY;
  // Map the angle values from -90deg to +90 deg into values from 0 to 255, like the values we are getting from the Joystick
  data.j1PotX = map(angleX, -90, +90, 255, 0);
  data.j1PotY = map(angleY, -90, +90, 0, 255);
}Code language: Arduino (arduino)

Code du destinataire

Voyons maintenant comment nous pouvons recevoir ces données. Voici un schéma de récepteur Arduino et NRF24L01 simple. Bien sûr, vous pouvez utiliser n'importe quelle autre carte Arduino.

Et voici un code récepteur simple où nous recevrons les données et les imprimerons simplement sur le moniteur série afin que nous sachions que la communication fonctionne correctement. Encore une fois, nous devons inclure la bibliothèque RF24 et définir les objets et la structure de la même manière que dans le code de l'émetteur. Dans la section de configuration lors de la définition de la communication radio, nous devons utiliser les mêmes paramètres que l'émetteur et définir le module comme récepteur à l'aide de la fonction radio.startListening().

/*
    DIY Arduino based RC Transmitter Project
              == Receiver Code ==

  by Dejan Nedelkovski, www.HowToMechatronics.com
  Library: TMRh20/RF24, https://github.com/tmrh20/RF24/
*/
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
RF24 radio(10, 9);   // nRF24L01 (CE, CSN)
const byte address[6] = "00001";

unsigned long lastReceiveTime = 0;
unsigned long currentTime = 0;

// Max size of this struct is 32 bytes - NRF24L01 buffer limit
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; //Create a variable with the above structure

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(); //  Set the module as receiver
  resetData();
}
void loop() {
  // Check whether there is data to be received
  if (radio.available()) {
    radio.read(&data, sizeof(Data_Package)); // Read the whole data and store it into the 'data' structure
    lastReceiveTime = millis(); // At this moment we have received the data
  }
  // Check whether we keep receving data, or we have a connection between the two modules
  currentTime = millis();
  if ( currentTime - lastReceiveTime > 1000 ) { // If current time is more then 1 second since we have recived the last data, that means we have lost connection
    resetData(); // If connection is lost, reset the data. It prevents unwanted behavior, for example if a drone has a throttle up and we lose connection, it can keep flying unless we reset the values
  }
  // Print the data in the Serial Monitor
  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() {
  // Reset the values when there is no radio connection - Set initial default values
  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;
}Code language: Arduino (arduino)

Dans la boucle principale utilisant la fonction available() nous vérifions s'il y a des données entrantes. Si vrai, nous lisons simplement les données et les stockons dans les variables de la structure. Nous pouvons maintenant imprimer les données sur le moniteur série pour vérifier si la transmission fonctionne correctement. En utilisant également la fonction millis() et une instruction if, nous vérifions si nous continuons à recevoir des données, ou si nous ne recevons pas de données pendant une période supérieure à 1 seconde, nous réinitialisons les variables à leurs valeurs par défaut. Nous l'utilisons pour éviter les comportements indésirables, par exemple si un drone a une manette des gaz et que nous perdons la connexion, il peut continuer à voler à moins que nous ne réinitialisions les valeurs.

Alors c'est tout. Nous pouvons maintenant implémenter cette méthode de réception des données pour n'importe quel projet Arduino. Par exemple ici le code pour contrôler la voiture robot Arduino d'une de mes vidéos précédentes.

En tant que mise à jour de ce projet, j'ai créé un récepteur RC dédié basé sur Arduino. Encore une fois, il est basé sur la mini carte Arduino Pro et il dispose de plusieurs connexions servos et ESC prêtes à l'emploi, placées sur un PCB compact.

Contrôle sans fil Arduino Robot Car avec émetteur RC

Code Arduino :

Ici, nous devons définir les bibliothèques, la structure et la communication radio comme expliqué précédemment. Ensuite, dans la boucle principale, nous avons juste besoin de lire les données entrantes et de les utiliser pour tout ce que nous voulons. In this case I use the joystick 1 values for driving the car.

Arduino Ant Robot / Hexapod  control using Arduino RC Transmitter

Arduino Code:

In the exact same way I made the Arduino Ant Robot from my previous video to be wirelessly controlled using this Arduino RC Transmitter. We just need to read the data, and according to it execute the appropriate functions, like moving forward, left, right, bite, attack and so on.

ESC and Servo Control using RC Transmitter

Lastly, let’s take a look how can this transmitter be used for controlling commercial RC devices.

Usually for these devices we need to control their servos or brushless motors. So after receiving the data from the transmitter, for controlling servo we simply use the Arduino Servo library and use values from 0 to 180 degrees. For controlling brushless motor using ESC, we can again use the servo library for generating the 50Hz PWM signal used for controlling the ESC. By varying the duty cycle from 1000 to 2000 microseconds we control the RPM of the motor from zero to maximum. However, more on controlling brushless motors using ESC in my next tutorial.

Please note that we actually cannot bind the standard RC receiver system with this NRF24L01 2.4GHz system. Instead, we need to modify or create our own receiver consisting of an Arduino and NRF24L01 Module. From there we can than generate the appropriate PWM or PPM signals for controlling the RC device.

/*
    DIY Arduino based RC Transmitter Project
   == Receiver Code - ESC and Servo Control ==

  by Dejan Nedelkovski, www.HowToMechatronics.com
  Library: TMRh20/RF24, https://github.com/tmrh20/RF24/
*/
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <Servo.h>

RF24 radio(10, 9);   // nRF24L01 (CE, CSN)
const byte address[6] = "00001";

unsigned long lastReceiveTime = 0;
unsigned long currentTime = 0;

Servo esc;  // create servo object to control the ESC
Servo servo1;
Servo servo2;
int escValue, servo1Value, servo2Value;

// Max size of this struct is 32 bytes - NRF24L01 buffer limit
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; //Create a variable with the above structure

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(); //  Set the module as receiver
  resetData();
  esc.attach(9);
  servo1.attach(3);
  servo2.attach(4);
}
void loop() {
  // Check whether we keep receving data, or we have a connection between the two modules
  currentTime = millis();
  if ( currentTime - lastReceiveTime > 1000 ) { // If current time is more then 1 second since we have recived the last data, that means we have lost connection
    resetData(); // If connection is lost, reset the data. It prevents unwanted behavior, for example if a drone jas a throttle up, if we lose connection it can keep flying away if we dont reset the function
  }
  // Check whether there is data to be received
  if (radio.available()) {
    radio.read(&data, sizeof(Data_Package)); // Read the whole data and store it into the 'data' structure
    lastReceiveTime = millis(); // At this moment we have received the data
  }
  // Controlling servos
  servo1Value = map(data.j2PotX, 0, 255, 0, 180);
  servo2Value = map(data.j2PotY, 0, 255, 0, 180);
  servo1.write(servo1Value);
  servo2.write(servo2Value);
  // Controlling brushless motor with ESC
  escValue = map(data.pot1, 0, 255, 1000, 2000); // Map the receiving value form 0 to 255 to 0 1000 to 2000, values used for controlling ESCs
  esc.writeMicroseconds(escValue); // Send the PWM control singal to the ESC
}

void resetData() {
  // Reset the values when there is no radio connection - Set initial default values
  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;
}Code language: Arduino (arduino)

So that’s it. J'espère que cette vidéo vous a plu et que vous avez appris quelque chose de nouveau. N'hésitez pas à poser des questions dans la section des commentaires ci-dessous et à consulter ma collection de projets Arduino.


Processus de fabrication

  1. Kazoo
  2. Visualiseur de musique Arduino DIY LUMAZOID
  3. Fabriquer une machine à écrire pour les devoirs à la maison
  4. Voltmètre DIY utilisant Arduino et Smartphone
  5. Boîte météo Arduino + ESP
  6. Planche à roulettes en réalité virtuelle DIY
  7. Traitement DIY Arduino RADIONICS MMachine
  8. Simulateur DIY 2D Motion Racing
  9. Idée de bricolage avec RFID