Industriële fabricage
Industrieel internet der dingen | Industriële materialen | Onderhoud en reparatie van apparatuur | Industriële programmering |
home  MfgRobots >> Industriële fabricage >  >> Manufacturing Technology >> Productieproces

DIY Arduino RC-zender

In de tutorial leren we hoe we een DIY Arduino RC-zender kunnen bouwen. Ik heb heel vaak draadloze bediening nodig voor de projecten die ik maak, dus daarom heb ik deze multifunctionele radiocontroller gebouwd die voor vrijwel alles kan worden gebruikt.

Je kunt de volgende video bekijken of de schriftelijke tutorial hieronder lezen.

Overzicht

Nu kan ik elk Arduino-project draadloos besturen met slechts enkele kleine aanpassingen aan de ontvangerzijde. Deze zender kan ook worden gebruikt als elke commerciële RC-zender voor het besturen van RC-speelgoed, auto's, drones enzovoort. Voor dat doel heeft het alleen een eenvoudige Arduino-ontvanger nodig die vervolgens de juiste signalen genereert voor het besturen van die commerciële RC-apparaten.

Ik zal in deze video uitleggen hoe alles werkt aan de hand van enkele voorbeelden van het besturen van een Arduino-robotauto, het besturen van de Arduino Ant Robot uit mijn vorige video en het besturen van een borstelloze gelijkstroommotor met behulp van een ESC en enkele servomotoren.

De radiocommunicatie van deze controller is gebaseerd op de NRF24L01-zendontvangermodule die, indien gebruikt met een versterkte antenne, een stabiel bereik tot 700 meter in open ruimte kan hebben. Het beschikt over 14 kanalen, waarvan 6 analoge ingangen en 8 digitale ingangen.

Het heeft twee joysticks, twee potentiometers, twee tuimelschakelaars, zes knoppen en bovendien een interne meeteenheid bestaande uit een versnellingsmeter en een gyroscoop die ook kan worden gebruikt om dingen te regelen door gewoon te bewegen of de controller te kantelen.

Arduino RC-zender schakelschema

Laten we om te beginnen eens kijken naar het schakelschema. Het brein van deze RC-controller is een Arduino Pro Mini die wordt aangedreven door 2 LiPo-batterijen die ongeveer 7,4 volt produceren. We kunnen ze rechtstreeks aansluiten op de RAW-pin van de Pro Mini die een spanningsregelaar heeft die de spanning verlaagde naar 5V. Merk op dat er twee versies van de Arduino Pro Mini zijn, zoals de versie die ik heb die werkt op 5V en de andere op 3,3V.

Aan de andere kant heeft de NRF24L01-module strikt 3,3 V nodig en het wordt aanbevolen om van een speciale bron te komen. Daarom moeten we een 3.3V spanningsregelaar gebruiken die is aangesloten op de batterijen en de 7.4V omzetten naar 3.3V. Ook moeten we een ontkoppelcondensator direct naast de module gebruiken om de spanning stabieler te houden, dus ook de radiocommunicatie zal stabieler zijn. De NRF24L01-module communiceert met de Arduino via het SPI-protocol, terwijl de MPU6050-versnellingsmeter en gyromodule het I2C-protocol gebruiken.

U kunt de benodigde componenten voor deze Arduino-zelfstudie verkrijgen via de onderstaande links:

  • NRF24L01 Zendontvangermodule………….. 
  • NRF24L01 + PA + LNA …………………….
  • Potentiometer …………………………….. 
  • Servomotor ………………………………… 
  • Toggle-schakelaar ………………………….….. 
  • Joystick ……………………………………….. – deze Joystick wordt geleverd met een breakout-bord, dus je zult de Joystick ervan moeten desolderen
  • Joystick zonder breakout-bord ………… Ebay
  • Arduino Pro Mini……………………………….. – Je hebt PCB V2- of V3-versie nodig voor deze boards
  • Arduino Pro Mini zoals degene die ik gebruikte….. – PCB V1
  • HT7333 3.3v spanningsregelaar ……………. Van lokale elektronische winkel - PCB V1 &PCB V2
  • AMS1117 3.3v spanningsregelaar …………… Amazon / Banggoood / AliExpress – PCB V3

PCB-ontwerp

Uiteindelijk heb ik alle analoge en digitale pinnen van de Arduino Pro Mini gebruikt. Dus als ik nu alles probeer aan te sluiten met behulp van springdraden, wordt het nogal een puinhoop. Daarom heb ik een aangepaste PCB ontworpen met behulp van de gratis EasyEDA-software voor online circuitontwerp.

Hier heb ik rekening gehouden met de ergonomie van de controller en heb ik deze ontworpen om gemakkelijk met twee handen vast te houden, terwijl alle bedieningselementen zich binnen het bereik van de vingers bevinden. Ik heb de randen rond gemaakt en wat gaten van 3 mm toegevoegd, zodat ik de print later ergens op kan monteren. Ik heb de pinnen voor het programmeren van de Arduino Pro Mini aan de bovenzijde van de controller geplaatst, zodat ze gemakkelijk toegankelijk zijn voor het geval we de Arduino opnieuw willen programmeren. We kunnen hier ook opmerken dat ik de RX- en TX-pinnen van de Arduino heb gebruikt voor de joystickknoppen. Deze twee lijnen moeten echter van alles worden losgekoppeld terwijl we de schets naar de Arduino uploaden. Daarom worden ze onderbroken met twee pinnen die vervolgens gemakkelijk kunnen worden aangesloten met behulp van eenvoudige jumperdoppen.

Let op: Zorg ervoor dat je de juiste Arduino Pro Mini-versie hebt om de printplaat aan te passen of wijzig het printontwerp overeenkomstig. Hier is een vergelijkingsfoto tussen de drie verschillende versies, afhankelijk van je Arduino en de spanningsregelaar.

Hier is een link naar de projectbestanden van dit PCB-ontwerp. Deze openen de drie verschillende versies in aparte tabbladen, zodat je degene kunt kiezen die je nodig hebt.

Dus toen ik klaar was met het ontwerp, genereerde ik het Gerber-bestand dat nodig was voor het maken van de PCB.

Gerber-bestand:

Toen bestelde ik de PCB bij JLCPCB, die ook de sponsor van deze video zijn.

Hier kunnen we eenvoudig het Gerber-bestand slepen en neerzetten en eenmaal geüpload, kunnen we onze PCB bekijken in de Gerber-viewer. Als alles in orde is, kunnen we doorgaan en de eigenschappen selecteren die we voor onze PCB willen. Deze keer koos ik voor de kleur van de printplaat zwart. En dat was het, nu kunnen we onze PCB gewoon voor een redelijke prijs bestellen. Houd er rekening mee dat als het uw eerste bestelling bij JLCPCB is, u tot 10 PCB's kunt krijgen voor slechts $ 2.

En hier is het. Ik ben er echt dol op hoe deze PCB in deze zwarte kleur is uitgekomen. De kwaliteit van de print is geweldig, en alles is precies hetzelfde als in het ontwerp.

Montage van de print

Ok nu kunnen we verder met het monteren van de printplaat. Ik begon met het solderen van de pin-headers van de Arduino Pro Mini. Een gemakkelijke en goede manier om dat te doen, is door ze op een breadboard te plaatsen, zodat ze tijdens het solderen stevig op hun plaats blijven.

De Pro Mini heeft ook pinnen aan de zijkanten, maar houd er rekening mee dat de locatie van deze pinnen kan variëren, afhankelijk van de fabrikant.

Voor het specifieke model dat ik heb, heb ik 5 pinnen nodig voor elke kant, terwijl ik een GND-pin leeg laat omdat ik het gebied eronder op de PCB heb gebruikt voor het uitvoeren van enkele sporen. Ik soldeerde de Arduino Pro Mini rechtstreeks op de printplaat en sneed de execs lengte van de headers. Direct ernaast bevindt zich de MPU6050 accelerometer en gyroscoopmodule.

Daarna soldeerde ik de 3.3V spanningsregelaar met een condensator ernaast, en een andere condensator bij de NRF24L01-module. Deze module heeft drie verschillende versies en we kunnen ze hier allemaal gebruiken.

Ik ging verder met de pinnen voor het programmeren van de Arduino, de RX- en TX-pinnen, de voedingspinnen en de aan / uit-schakelaar.

Vervolgens moest ik voor het solderen van de potentiometers aan de PCB hun pinnen verlengen met behulp van enkele pin-headers.

We kunnen hier opmerken dat ik eerder de lengte van de knoppen heb afgesneden, zodat ik er enkele doppen goed op kan passen. We zullen de potentiometers echter iets later op de print solderen.

Daarna heb ik de twee tuimelschakelaars en de twee joysticks op hun plaats gestoken en gesoldeerd.

Wat nu nog rest is het solderen van de vier drukknoppen. Ze hebben echter niet de juiste hoogte, dus ik heb opnieuw pin-headers gebruikt om hun pinnen een beetje uit te breiden.

En that's it, onze print is nu klaar dus we kunnen verder met het maken van de hoes ervoor. Omdat ik het leuk vind hoe de print eruitziet en ik zichtbaar wil zijn, heb ik besloten om transparant acryl te gebruiken voor de kap.

Hier heb ik 4 mm tick transparant acryl die momenteel een beschermende folie heeft en blauw lijkt te zijn. Het idee voor het deksel is om twee platen te maken met de vorm van de printplaat en de ene aan de bovenzijde en de andere aan de onderzijde van de printplaat vast te zetten.

Dus ik markeerde de PCB-vorm en met behulp van een metalen handzaag sneed ik het acryl overeenkomstig.

Vervolgens heb ik met een eenvoudige rasp de vorm van het acryl verfijnd. De twee platen kwamen er geweldig uit en ze passen perfect bij de PCB.

Vervolgens heb ik de locaties gemarkeerd waar ik openingen moet maken waar de componenten doorheen kunnen gaan. Met een boor van 3 mm heb ik eerst de 4 gaten gemaakt om de platen op de print te bevestigen. Voor deze gaten heb ik ook gootstenen gemaakt zodat de bouten flitser met de platen kunnen worden geplaatst.

Voor de openingen voor de tuimelschakelaars en de potentiometers heb ik een boor van 6 mm gebruikt en voor de openingen van de joystick heb ik een Forstner-bit van 25 mm gebruikt. Nogmaals, met een rasp heb ik alle openingen verfijnd.

Voordat ik de kap monteerde, even een opmerking dat ik de pin-header voor de voeding ondersteboven heb gesoldeerd, zodat deze kan worden bereikt vanaf de achterkant waar de batterij zich zal bevinden.

Ok nu kunnen we beginnen met het monteren van de hoes. Ik begon met het afpellen van de beschermfolie van het acryl wat, moet ik toegeven, best bevredigend was omdat het acryl nu zo schoon was. Dus eerst heb ik de twee potentiometers op de bovenplaat vastgezet, de 3 mm bevestigingsbouten geplaatst en de 11 mm afstandsringen op hun plaats geplaatst.

Daarna heb ik de bovenplaat en de print voorzichtig samengevoegd en met enkele bouten vastgezet. Op dit punt heb ik eindelijk de potmeters op de print gesoldeerd omdat ik eerder niet precies wist op welke hoogte ze zullen worden geplaatst.

Vervolgens heb ik op de achterplaat de batterijhouder met 2 bouten bevestigd. Ik heb de montage van de kap voltooid door de achterplaat aan de achterkant van de printplaat te bevestigen met behulp van de vier montagebouten.

Ten slotte kunnen we de batterijlijnen aan de voedingspinnen bevestigen, de knoppen op de potentiometers plaatsen en vastzetten, de joystickknoppen plaatsen en de antenne op de NRF24l01-module bevestigen. En dat is het, we zijn eindelijk klaar met de DIY Arduino RC-zender.

Wat nu nog rest is het programmeren van de Arduino. Voor het programmeren van een Pro Mini-bord hebben we een USB-naar-serieel UART-interface nodig die kan worden aangesloten op de programmeerkop aan de bovenzijde van onze controller.

Vervolgens moeten we in het menu Arduino IDE-tools het Arduino Pro- of Pro Mini-bord selecteren, de juiste versie van de processor selecteren, de poort selecteren en de programmeermethode "USBasp" selecteren.

En dus kunnen we nu de code uploaden naar de Arduino.

DIY Arduino-gebaseerde RC-zendercode

Laten we uitleggen hoe de zendercode werkt. Dus eerst moeten we de SPI- en RF24-bibliotheek opnemen voor de draadloze communicatie en de I2C-bibliotheek voor de accelerometermodule. Vervolgens moeten we de digitale ingangen definiëren, enkele variabelen die nodig zijn voor het onderstaande programma, het radio-object en het communicatie-adres definiëren.

#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)

Vervolgens moeten we een structuur definiëren waarin we de 14 invoerwaarden van de controller zullen opslaan. De maximale grootte van deze structuur kan 32 bytes zijn, omdat dat de NRF24L01-bufferlimiet is of de hoeveelheid gegevens die de module in één keer kan verzenden.

/ 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)

In het setup-gedeelte moeten we de MPU6050-module initialiseren en we kunnen ook de IMU-fout berekenen, een waarde die later wordt gebruikt bij het berekenen van de juiste hoeken van de 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)

U kunt hier meer details vinden over hoe MEMS-versnellingsmeter en gyro werken. Er komt binnenkort een speciale tutorial voor de MPU6050.

Vervolgens moeten we de radiocommunicatie initialiseren, de interne pull-upweerstanden van Arduino voor alle digitale ingangen activeren en de initiële standaardwaarden voor alle variabelen instellen.

// 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)

In de lussectie begint u met het lezen van alle analoge ingangen, zet u hun waarden van 0 tot 1023 in bytewaarden van 0 tot 255, omdat we de variabelen in onze structuur al als bytes hebben gedefinieerd. Elke invoer wordt opgeslagen in de specifieke gegevensvariabele uit de structuur.

// 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)

We moeten alleen opmerken dat, omdat we de pull-up-weerstanden gebruiken, de digitale pinnen 0 zijn wanneer de knoppen worden ingedrukt.

// 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)

Dus met de functie radio.write() sturen we eenvoudig de waarden van alle 14 kanalen naar de ontvanger.

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

Als de tuimelschakelaar 1 is ingeschakeld, gebruiken we in plaats daarvan de accelerometer- en gyrogegevens voor de besturing.

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

Dus in plaats van de joystick 1 X- en Y-waarden gebruiken we de hoekwaarden die we krijgen van de IMU, die we eerder converteerden van waarden van -90 tot +90 graden in bytewaarden van 0 tot 255.

// 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)

Dus dat is hoe de zendercode, de belangrijkste dingen waren het definiëren van de radiocommunicatie en het verzenden van de gegevens naar de ontvanger.

Hier is de volledige Arduino-code voor deze DIY Arduino RC-zender:

/*
        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)

Ontvangercode

Laten we nu eens kijken hoe we deze gegevens kunnen ontvangen. Hier is een eenvoudig Arduino- en NRF24L01-ontvangerschema. Je kunt natuurlijk elk ander Arduino-bord gebruiken.

En hier is een eenvoudige ontvangercode waar we de gegevens zullen ontvangen en deze eenvoudig op de seriële monitor zullen afdrukken, zodat we weten dat de communicatie goed werkt. Nogmaals, we moeten de RF24-bibliotheek opnemen en de objecten en de structuur op dezelfde manier definiëren als in de zendercode. In het setup-gedeelte bij het definiëren van de radiocommunicatie moeten we dezelfde instellingen gebruiken als de zender en de module als ontvanger instellen met behulp van de radio.startListening()-functie.

/*
    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)

In de hoofdlus controleren we met behulp van de functie available() of er binnenkomende gegevens zijn. Als het waar is, lezen we gewoon de gegevens en slaan deze op in de variabelen van de structuur. Nu kunnen we de gegevens op de seriële monitor afdrukken om te controleren of de overdracht goed werkt. Ook met behulp van de millis()-functie en een if-statement controleren we of we gegevens blijven ontvangen, of dat we gedurende een periode van langer dan 1 seconde geen gegevens ontvangen, dan zetten we variabelen terug naar hun standaardwaarden. We gebruiken dit om ongewenst gedrag te voorkomen, bijvoorbeeld als een drone gas geeft en we de verbinding verliezen, kan deze blijven wegvliegen tenzij we de waarden resetten.

Dus dat is het. Nu kunnen we deze methode voor het ontvangen van de gegevens voor elk Arduino-project implementeren. Hier bijvoorbeeld de code voor het besturen van de Arduino-robotauto uit een van mijn vorige video's.

Als een update van dit project heb ik een speciale op Arduino gebaseerde RC-ontvanger gemaakt. Nogmaals, het is gebaseerd op het Arduino Pro mini-bord en het heeft verschillende kant-en-klare servo's en ESC's-aansluitingen, geplaatst op een compacte PCB.

Arduino Robot Car Wireless Control met RC-zender

Arduino-code:

Hier moeten we de bibliotheken, de structuur en de radiocommunicatie definiëren zoals eerder uitgelegd. Dan hoeven we in de hoofdlus alleen de binnenkomende gegevens te lezen en deze te gebruiken voor wat we maar willen. In dit geval gebruik ik de joystick 1-waarden voor het besturen van de auto.

Arduino Ant Robot / Hexapod -besturing met Arduino RC-zender

Arduino-code:

Op exact dezelfde manier heb ik de Arduino Ant Robot uit mijn vorige video draadloos bestuurd met deze Arduino RC Transmitter. We hoeven alleen de gegevens te lezen en op basis daarvan de juiste functies uit te voeren, zoals vooruit, links, rechts, bijten, aanvallen enzovoort.

ESC- en servobesturing met RC-zender

Laten we tot slot eens kijken hoe deze zender kan worden gebruikt voor het aansturen van commerciële RC-apparaten.

Meestal moeten we voor deze apparaten hun servo's of borstelloze motoren aansturen. Dus na ontvangst van de gegevens van de zender, gebruiken we voor het besturen van de servo gewoon de Arduino Servo-bibliotheek en gebruiken we waarden van 0 tot 180 graden. Voor het besturen van een borstelloze motor met behulp van ESC, kunnen we opnieuw de servobibliotheek gebruiken voor het genereren van het 50 Hz PWM-signaal dat wordt gebruikt voor het besturen van de ESC. Door de duty cycle te variëren van 1000 tot 2000 microseconden regelen we het toerental van de motor van nul tot maximaal. Meer over het besturen van borstelloze motoren met ESC in mijn volgende tutorial.

Houd er rekening mee dat we het standaard RC-ontvangersysteem eigenlijk niet kunnen binden met dit NRF24L01 2.4GHz-systeem. In plaats daarvan moeten we onze eigen ontvanger aanpassen of maken, bestaande uit een Arduino en NRF24L01-module. Van daaruit kunnen we dan de juiste PWM- of PPM-signalen genereren voor het besturen van het RC-apparaat.

/*
    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. I hope you enjoyed this video and learned something new. Stel gerust een vraag in de opmerkingen hieronder en bekijk mijn Arduino Projects-collectie.


Productieproces

  1. Kazoo
  2. DIY LUMAZOID Arduino Music Visualiser
  3. Maak thuis een zelfgemaakte schrijfmachine voor huiswerk
  4. DIY voltmeter met Arduino en smartphone
  5. Arduino + ESP-weerbox
  6. DIY Virtual Reality Skateboard
  7. DIY Arduino RADIONICS-behandelingsmachine
  8. DIY 2D Motion Racing Simulator
  9. DIY-idee met RFID
  10. DIY 3-assige CNC VMC
  11. DIY Arduino + GY-906 Infraroodthermometer