Manufaktur industri
Industri Internet of Things | bahan industri | Pemeliharaan dan Perbaikan Peralatan | Pemrograman industri |
home  MfgRobots >> Manufaktur industri >  >> Manufacturing Technology >> Proses manufaktur

Pemancar RC Arduino DIY

Dalam tutorial kita akan belajar cara membuat pemancar RC Arduino DIY. Sangat sering saya membutuhkan kontrol nirkabel untuk proyek yang saya buat, oleh karena itu saya membuat pengontrol radio multifungsi ini yang dapat digunakan untuk hampir semua hal.

Anda dapat menonton video berikut atau membaca tutorial tertulis di bawah ini.

Ringkasan

Sekarang saya dapat mengontrol proyek Arduino secara nirkabel hanya dengan beberapa penyesuaian kecil di sisi penerima. Pemancar ini juga dapat digunakan sebagai pemancar RC komersial untuk mengendalikan mainan RC, mobil, drone, dan sebagainya. Untuk tujuan itu, ia hanya membutuhkan penerima Arduino sederhana yang kemudian menghasilkan sinyal yang sesuai untuk mengendalikan perangkat RC komersial tersebut.

Saya akan menjelaskan cara kerja semuanya dalam video ini melalui beberapa contoh mengendalikan mobil robot Arduino, mengendalikan Robot Semut Arduino dari video saya sebelumnya dan mengendalikan motor DC brushless menggunakan ESC dan beberapa motor servo.

Komunikasi radio pengontrol ini didasarkan pada modul transceiver NRF24L01 yang jika digunakan dengan antena yang diperkuat dapat memiliki jangkauan stabil hingga 700 meter di ruang terbuka. Ini memiliki 14 saluran, 6 di antaranya adalah input analog dan 8 input digital.

Ini memiliki dua joystick, dua potensiometer, dua sakelar sakelar, enam tombol, dan tambahan unit pengukur internal yang terdiri dari akselerometer dan giroskop yang juga dapat digunakan untuk mengontrol berbagai hal hanya dengan menggerakkan atau memiringkan pengontrol.

Diagram Sirkuit Pemancar RC Arduino

Untuk memulainya, mari kita lihat diagram sirkuitnya. Otak dari pengontrol RC ini adalah Arduino Pro Mini yang ditenagai menggunakan 2 baterai LiPo yang menghasilkan sekitar 7,4 volt. Kita bisa menghubungkannya langsung ke pin RAW Pro Mini yang memiliki pengatur tegangan yang menurunkan tegangan menjadi 5V. Perhatikan bahwa ada dua versi Arduino Pro Mini, seperti yang saya miliki yang beroperasi pada 5V dan yang lainnya beroperasi pada 3.3V.

Di sisi lain, modul NRF24L01 sangat membutuhkan 3.3V dan disarankan untuk berasal dari sumber khusus. Oleh karena itu kita perlu menggunakan regulator tegangan 3.3V yang terhubung ke baterai dan mengubah 7.4V menjadi 3.3V. Juga kita perlu menggunakan kapasitor decoupling tepat di sebelah modul untuk menjaga tegangan lebih stabil, sehingga komunikasi radio juga akan lebih stabil. Modul NRF24L01 berkomunikasi dengan Arduino menggunakan protokol SPI, sedangkan modul akselerometer dan gyro MPU6050 menggunakan protokol I2C.

Anda bisa mendapatkan komponen yang diperlukan untuk Tutorial Arduino ini dari link di bawah ini:

  • Modul Pemancar NRF24L01……….. 
  • NRF24L01 + PA + LNA ……………………….
  • Potensiometer ……………………………….. 
  • Motor Servo …………………………… 
  • Toggle Switch …………………………….….. 
  • Joystick ………………………………………….. – Joystick ini dilengkapi dengan papan breakout sehingga Anda harus melepaskan Joystick dari dalamnya
  • Joystick tanpa papan breakout ………… Ebay
  • Arduino Pro Mini…………………………….. – Anda memerlukan versi PCB V2 atau V3 untuk papan ini
  • Arduino Pro Mini seperti yang saya gunakan….. – PCB V1
  • Pengatur tegangan HT7333 3.3v ……………. Dari toko elektronik lokal – PCB V1 &PCB V2
  • Pengatur tegangan AMS1117 3.3v …………… Amazon / Bagus / AliExpress – PCB V3

Desain PCB

Saya akhirnya menggunakan semua pin analog dan digital dari Arduino Pro Mini. Jadi sekarang jika saya mencoba menghubungkan semuanya bersama-sama menggunakan kabel lompat, itu akan sangat berantakan. Oleh karena itu saya merancang PCB khusus menggunakan perangkat lunak desain sirkuit online gratis EasyEDA.

Di sini saya mempertimbangkan ergonomis pengontrol dan mendesainnya agar mudah dipegang oleh dua tangan, sementara semua kontrol berada dalam jangkauan jari. Saya membuat tepinya bulat dan menambahkan beberapa lubang 3mm sehingga saya bisa memasang PCB ke sesuatu nanti. Saya menempatkan pin untuk memprogram Arduino Pro Mini di sisi atas pengontrol sehingga dapat dengan mudah diakses jika kita ingin memprogram ulang Arduino. Kita juga dapat melihat di sini bahwa saya menggunakan pin RX dan TX dari Arduino untuk tombol joystick. Namun kedua baris ini perlu diputuskan dari apa pun saat kami mengunggah sketsa ke Arduino. Oleh karena itu, mereka diinterupsi dengan dua pin yang kemudian dapat dihubungkan dengan mudah menggunakan tutup jumper sederhana.

Harap diperhatikan: Pastikan Anda memiliki versi Arduino Pro Mini yang tepat untuk membuat mach PCB atau memodifikasi desain PCB sesuai dengan itu. Berikut foto perbandingan antara tiga versi yang berbeda, tergantung pada Arduino Anda dan regulator tegangan.

Berikut tautan ke file proyek desain PCB ini. Ini akan membuka tiga versi berbeda di tab terpisah, sehingga Anda dapat memilih salah satu yang Anda butuhkan.

Jadi, setelah saya menyelesaikan desain, saya membuat file Gerber yang diperlukan untuk membuat PCB.

File Gerber:

Kemudian saya memesan PCB dari JLCPCB yang juga menjadi sponsor video ini.

Di sini kita cukup drag dan drop file Gerber dan setelah diunggah, kita dapat meninjau PCB kita di penampil Gerber. Jika semuanya baik-baik saja maka kita dapat melanjutkan dan memilih properti yang kita inginkan untuk PCB kita. Kali ini saya memilih warna PCB menjadi hitam. Dan hanya itu, sekarang kami dapat memesan PCB kami dengan harga yang wajar. Perhatikan bahwa jika ini adalah pesanan pertama Anda dari JLCPCB, Anda bisa mendapatkan hingga 10 PCB hanya dengan $2.

Dan ini dia. Saya sangat suka bagaimana PCB ini ternyata dalam warna hitam ini. Kualitas PCB sangat bagus, dan semuanya sama persis dengan desainnya.

Merakit PCB

Ok sekarang kita bisa melanjutkan dengan merakit PCB. Saya mulai dengan menyolder pin header dari Arduino Pro Mini. Cara mudah dan baik untuk melakukannya adalah dengan meletakkannya di atas papan tempat memotong roti agar tetap kokoh di tempatnya saat menyolder.

Pro Mini juga memiliki pin di bagian samping, tetapi perhatikan bahwa lokasi pin ini mungkin berbeda, tergantung pada produsennya.

Untuk model tertentu yang saya miliki, saya membutuhkan 5 pin untuk setiap sisi, sementara satu pin GND dibiarkan kosong karena saya menggunakan area di bawah pada PCB untuk menjalankan beberapa jejak. Saya menyolder Arduino Pro Mini langsung ke PCB dan memotong panjang kepala eksekutif. Tepat di sebelahnya terdapat modul akselerometer dan giroskop MPU6050.

Kemudian saya menyolder regulator tegangan 3.3V dengan kapasitor di sebelahnya, dan kapasitor lain di dekat modul NRF24L01. Modul ini memiliki tiga versi berbeda dan kita dapat menggunakannya di sini.

Saya melanjutkan dengan pin untuk memprogram Arduino, pin RX dan TX, pin catu daya, dan sakelar daya.

Selanjutnya untuk menyolder potensiometer ke PCB saya harus memperpanjang pinnya menggunakan beberapa pin header.

Kita dapat mencatat di sini bahwa saya sebelumnya memotong panjang kenop sehingga saya dapat memasukkan beberapa tutup dengan benar ke atasnya. Namun, kami akan menyolder potensiometer ke PCB nanti.

Kemudian saya memasukkan dan menyolder kedua sakelar sakelar dan dua joystick di tempatnya.

Akhirnya yang tersisa adalah menyolder empat tombol tekan. Namun mereka tidak memiliki ketinggian yang tepat, jadi sekali lagi saya menggunakan header pin untuk sedikit memperpanjang pin.

Dan itu saja, PCB kami sekarang sudah siap sehingga kami dapat melanjutkan dengan membuat penutupnya. Karena saya suka tampilan PCB dan saya ingin terlihat, saya memutuskan untuk menggunakan akrilik transparan untuk sampulnya.

Di sini saya memiliki akrilik transparan centang 4 mm yang saat ini memiliki lapisan pelindung dan tampak berwarna biru. Ide untuk penutupnya adalah membuat dua pelat dengan bentuk PCB dan mengamankan salah satunya di sisi atas dan yang lainnya di sisi bawah PCB.

Jadi saya menandai bentuk PCB dan menggunakan gergaji tangan logam saya memotong akrilik sesuai dengan itu.

Kemudian menggunakan serak sederhana, saya menyempurnakan bentuk akrilik. Kedua pelatnya terlihat bagus dan sangat cocok dengan PCB.

Selanjutnya saya menandai lokasi di mana saya perlu membuat bukaan agar komponen dapat lewat. Menggunakan bor 3mm saya pertama kali membuat 4 lubang untuk mengamankan pelat ke PCB. Untuk lubang ini saya juga membuat counter sink agar bautnya bisa dipasang flash dengan platnya.

Untuk bukaan sakelar toggle dan potensiometer saya menggunakan bor 6mm, dan untuk bukaan joystick saya menggunakan bit Forstner 25mm. Sekali lagi, menggunakan serak, saya menyempurnakan semua bukaan.

Sebelum memasang penutup, perlu diperhatikan bahwa saya menyolder pin header untuk catu daya secara terbalik sehingga dapat dijangkau dari sisi belakang tempat baterai akan ditempatkan.

Ok sekarang kita bisa mulai dengan merakit covernya. Saya mulai dengan mengupas foil pelindung dari akrilik yang harus saya akui cukup memuaskan karena akrilik sekarang sudah sangat bersih. Jadi pertama-tama saya mengamankan dua potensiometer di pelat atas, memasukkan baut pemasangan 3mm dan menempatkan cincin jarak 11mm di tempatnya.

Kemudian saya dengan hati-hati menggabungkan dan mengamankan pelat atas dan PCB menggunakan beberapa baut. Pada titik ini saya akhirnya menyolder potensiometer ke PCB karena sebelumnya saya tidak tahu persis di ketinggian berapa mereka akan ditempatkan.

Selanjutnya pada pelat belakang saya pasang dudukan baterai menggunakan 2 baut. Saya menyelesaikan perakitan penutup dengan mengencangkan pelat belakang ke sisi belakang PCB menggunakan empat baut pemasangan.

Terakhir, kita dapat memasang saluran baterai ke pin catu daya, memasukkan dan mengencangkan kenop pada potensiometer, memasukkan kenop joystick dan memasang antena ke modul NRF24l01. Dan hanya itu, kita akhirnya selesai dengan pemancar Arduino RC DIY.

Yang tersisa sekarang adalah memprogram Arduino. Untuk memprogram papan Pro Mini, kami memerlukan antarmuka UART USB ke serial yang dapat dihubungkan ke header program yang terletak di sisi atas pengontrol kami.

Kemudian di menu alat Arduino IDE kita perlu memilih papan Arduino Pro atau Pro Mini, pilih versi prosesor yang tepat, pilih port dan pilih metode pemrograman ke “USBasp”.

Jadi sekarang kami dapat mengunggah kode ke Arduino.

Kode Pemancar RC berbasis Arduino DIY

Mari kita jelaskan cara kerja kode pemancar. Jadi pertama-tama kita perlu menyertakan pustaka SPI dan RF24 untuk komunikasi nirkabel, dan pustaka I2C untuk modul akselerometer. Kemudian kita perlu mendefinisikan input digital, beberapa variabel yang diperlukan untuk program di bawah ini, mendefinisikan objek radio dan alamat komunikasi.

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

Kemudian kita perlu mendefinisikan struktur di mana kita akan menyimpan 14 nilai input dari controller. Ukuran maksimum struktur ini bisa 32 byte karena itulah batas buffer NRF24L01 atau jumlah data yang dapat dikirim modul sekaligus.

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

Di bagian setup kita perlu menginisialisasi modul MPU6050 dan kita juga dapat menghitung kesalahan IMU yang merupakan nilai yang nantinya digunakan saat menghitung sudut yang benar dari modul.

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)

Anda dapat menemukan detail lebih lanjut bagaimana akselerometer dan gyro MEMS bekerja di sini. Tutorial khusus untuk MPU6050 akan segera hadir.

Kemudian kita perlu menginisialisasi komunikasi radio, mengaktifkan resistor pull-up internal Arduino untuk semua input digital dan menetapkan nilai default awal untuk semua variabel.

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

Di bagian loop, mulailah dengan membaca semua input analog, petakan nilainya dari 0 hingga 1023 menjadi nilai byte dari 0 hingga 255 karena kita telah mendefinisikan variabel dalam struktur kita sebagai byte. Setiap input disimpan dalam variabel data tertentu dari struktur.

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

Kami hanya perlu mencatat bahwa karena kami menggunakan resistor pull-up, pembacaan pin digital adalah 0 saat tombol ditekan.

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

Jadi, dengan menggunakan fungsi radio.write() kita cukup mengirimkan nilai dari 14 saluran ke penerima.

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

Jika sakelar sakelar 1 diaktifkan, maka kami menggunakan data akselerometer dan gyro sebagai kontrolnya.

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

Jadi, alih-alih nilai joystick 1 X dan Y, kami menggunakan nilai sudut yang kami peroleh dari IMU, yang sebelumnya kami ubah dari nilai dari -90 hingga +90 derajat menjadi nilai byte dari 0 hingga 255 dengan tepat.

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

Jadi begitulah kode pemancar, yang terpenting adalah mendefinisikan komunikasi radio dan mengirimkan data ke penerima.

Berikut kode Arduino lengkap untuk Pemancar RC Arduino DIY ini:

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

Kode Penerima

Sekarang mari kita lihat bagaimana kita dapat menerima data ini. Berikut adalah skema penerima Arduino dan NRF24L01 sederhana. Tentu saja Anda dapat menggunakan papan Arduino lainnya.

Dan inilah kode penerima sederhana di mana kami akan menerima data dan hanya mencetaknya di monitor serial sehingga kami tahu bahwa komunikasi berfungsi dengan baik. Sekali lagi kita perlu menyertakan perpustakaan RF24 dan mendefinisikan objek dan struktur dengan cara yang sama seperti pada kode pemancar. Di bagian penyiapan saat mendefinisikan komunikasi radio, kita perlu menggunakan pengaturan yang sama dengan pemancar dan mengatur modul sebagai penerima menggunakan fungsi 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)

In the main loop using the available() function we check whether there is an incoming data. If true we simply read the data and store it into the variables of the structure. Now we can print the data on the serial monitor to check whether the transmission work properly. Also using the millis() function and an if statement we check whether we keep receiving data, or if we don’t receive data for a period longer than 1 second, then we reset variables to their default values. We use this to prevent unwanted behavior, for example if a drone has a throttle up and we lose connection it can keep flying away unless we reset the values.

So that’s it. Now we can implement this method of receiving the data for any Arduino project. For example here the code for controlling the Arduino robot car from one of my previous videos.

As an update to this project, I made a dedicated Arduino based RC Receiver. Again, it’s based on the Arduino Pro mini board and it has several ready to use servos and ESCs connections, placed on a compact PCB.

Arduino Robot Car Wireless Control using RC Transmitter

Arduino Code:

Here we need to define the libraries, the structure and the radio communication as explained earlier. Then in the main loop we just need read the incoming data and use any of it for whatever we want. 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. I hope you enjoyed this video and learned something new. Feel free to ask any question in the comments section below and check my Arduino Projects Collection.


Proses manufaktur

  1. Kazoo
  2. DIY LUMAZOID Arduino Music Visualizer
  3. Membuat Mesin Tulis Pekerjaan Rumah DIY di Rumah
  4. Voltmeter DIY Menggunakan Arduino dan Smartphone
  5. Arduino + ESP Weather Box
  6. Skateboard Realitas Virtual DIY
  7. DIY Arduino RADIONICS Treatment MMachine
  8. Simulator Balap Gerak 2D DIY
  9. Ide DIY dengan RFID
  10. VMC CNC 3-Sumbu DIY