11/30/2022

UZUN MESAFE 8 Kanallı ve Dijital Trimli Uzaktan Kumanda Yapımı. DIY RC | Bölüm-2

100mW NRF24L01 PA LN (E01-ML01DP5) 2.4Ghz modül ve Arduino ile uzun menzilli uzaktan kumanda nasıl yapılır.  Toplam 8 kanallıdır. 6 kanal orantılı çalışır. 2 kanal ise switch ile kontrol edilir ve aç/kapa şeklinde çalışır.
Ayrıca bu uzaktan kumanda devresine 3 kanal için dijital trim ekledim. Aileron (Roll), Elevator (Pitch) ve Rudder (Yaw) kanalları için bu trimler çalışır.
Bu RC devresinin birinci bölümünde temel kurulumu 1 kanal aktif olacak şekilde “BÖLÜM-1” de göstermiştim. Bölüm-2 de ise 7 kanal daha eklenerek 8 kanala tamamladım ve dijital trimleri ekledim.

BÖLÜM-1 de belirttiğim gibi bu verici ve alıcı devrelerinin diğer Arduino uzaktan kumanda devrelerinden en büyük farkı kullandığım E01-ML01DP5 modülleridir. Bu modüller özünde NRF24L01 PA LN ile aynıdır. Ama güçleri daha fazladır. Verici olarak kullanıldığında 100mW (20dBm) gücünde çalışabilir. Teorik olarak 2100 metre menzile sahiptir.  Alıcı olarak kullanıldığında ise yarı güçte çalışmaktadır. Ayrıca metal kasası sayesinde elektriksel gürültüden etkilenmesi azalmıştır. Bu sayede daha kararlı çalışabilmektedir.

8 kanallı uzaktan kumandanın yapımı için bazı opsiyonlar sunuyorum. isteyen sadece 8 kanallı veya 8 kanal + trim özellikli yapabilir. Ayrıca NRF24 modülün direk arduino 5V pininden veya harici güç kaynağından beslendiği opsiyon versiyonları da paylaştım.

Gerekli Malzemeler:

2 x  PS4 Analog Joystick : https://s.click.aliexpress.com/e/_DBSn2AB
2 x Toggle switch: https://s.click.aliexpress.com/e/_DCd5Pzh
2 x 100mW NRF24L01 PA LN (E01-ML01DP5): https://s.click.aliexpress.com/e/_DmEoWQf
2 x Arduino Nano: https://s.click.aliexpress.com/e/_DlhwLS3
2 x NRF24 wireless 3.3v adaptor: https://s.click.aliexpress.com/e/_DlmATh1
2 x 100uF  kondansatör: https://s.click.aliexpress.com/e/_DBJpcn1
4 x Female Header Pin (15 pins): https://s.click.aliexpress.com/e/_DDqmgbh
2 x 10K potansiometre: https://s.click.aliexpress.com/e/_DCV1V11
Universal PCB board: https://s.click.aliexpress.com/e/_DF8xNJ9
AA Pil Kutusu (6xAA Cells) : https://s.click.aliexpress.com/e/_DFMnduf
veya 18650 pil kutusu : https://s.click.aliexpress.com/e/_DERuJnl
5mm LED: https://s.click.aliexpress.com/e/_DB6EXhh
330R Direnç:  https://s.click.aliexpress.com/e/_DFkljF9
Rocker buton (10x15mm): https://s.click.aliexpress.com/e/_DDvMlXd
Tact buton (6x6x7): https://s.click.aliexpress.com/e/_Dm2yUBt
Vidalar: https://s.click.aliexpress.com/e/_DEvN4J9

80W havya: https://s.click.aliexpress.com/e/_DD75tWX

8 Kanal Verici Devresi :
// 8 Channel Transmitter (No Trim) | 8 Kanal Verici (Trim Yok)
// Input pin A5

  #include <SPI.h>
  #include <nRF24L01.h>
  #include <RF24.h>
  const uint64_t pipeOut = 000322;         // NOTE: The same as in the receiver 000322 | Alıcı kodundaki adres ile aynı olmalı
  RF24 radio(9, 10);                       // select CE,CSN pin | CE ve CSN pinlerin seçimi

  struct Signal {
  byte throttle;
  byte pitch;
  byte roll;
  byte yaw;
  byte aux1;
  byte aux2;
  byte aux3;
  byte aux4;
  
};
  Signal data;
  void ResetData() 
{
  data.throttle = 0;
  data.pitch = 127;
  data.roll = 127;
  data.yaw = 127;
  data.aux1 = 0;                       // Signal lost position | Sinyal kesildiğindeki pozisyon
  data.aux2 = 0;
  data.aux3 = 0;
  data.aux4 = 0;
}
  void setup()
{
                                       //Configure the NRF24 module  | NRF24 modül konfigürasyonu
  radio.begin();
  radio.openWritingPipe(pipeOut);
  radio.setAutoAck(false);
  radio.setDataRate(RF24_250KBPS);    // The lowest data rate value for more stable communication  | Daha kararlı iletişim için en düşük veri hızı.
  radio.setPALevel(RF24_PA_MAX);      // Output power is set for maximum |  Çıkış gücü maksimum için ayarlanıyor.
  radio.stopListening();              // Start the radio comunication for Transmitter | Verici için sinyal iletişimini başlatır.
  ResetData();
 
}
                                      // Joystick center and its borders | Joystick merkez ve sınırları
  int Border_Map(int val, int lower, int middle, int upper, bool reverse)
{
  val = constrain(val, lower, upper);
  if ( val < middle )
  val = map(val, lower, middle, 0, 128);
  else
  val = map(val, middle, upper, 128, 255);
  return ( reverse ? 255 - val : val );
}
  void loop()
{
                                     // Control Stick Calibration for channels  |  Her bir kanal için kumanda Kol Kalibrasyonları 

  data.roll = Border_Map( analogRead(A3), 0, 512, 1023, true );        // "true" or "false" for signal direction | "true" veya "false" sinyal yönünü belirler
  data.pitch = Border_Map( analogRead(A2), 0, 512, 1023, true );      
  data.throttle = Border_Map( analogRead(A1),570, 800, 1023, false );  // For Single side ESC | Tek yönlü ESC için
  // data.throttle = Border_Map( analogRead(A1),0, 512, 1023, false ); // For Bidirectional ESC | Çift yönlü ESC için  
  data.yaw = Border_Map( analogRead(A0), 0, 512, 1023, true );        
  data.aux1 = Border_Map( analogRead(A4), 0, 512, 1023, true );        // "true" or "false" for change signal direction | "true" veya "false" sinyal yönünü değiştirir.
  data.aux2 = Border_Map( analogRead(A5), 0, 512, 1023, true );        // "true" or "false" for change signal direction | "true" veya "false" sinyal yönünü değiştirir.
  data.aux3 = digitalRead(7);
  data.aux4 = digitalRead(8);

  radio.write(&data, sizeof(Signal));  
}

NOT: “true” ve “false” ibareleri servonun yönünü belirler. Eğer “true” yerine “false” yazarsak sinyal yönü değişir ve servo diğer tarafa hareket eder. Yani “reverse” komutu işlevini görür.

 

8 KANAL,  TRIMLİ VERİCİ Devresi:

8 KANAL, TRIMLI VERİCİ KODU:

// 8 Channel Transmitter & Trims | 8 Kanal Verici ve Trimler

  #include <SPI.h>
  #include <nRF24L01.h>
  #include <RF24.h>
  #include <EEPROM.h>
    
  const uint64_t pipeOut = 000322;        // NOTE: The same as in the receiver 000322 | Alıcı kodundaki adres ile aynı olmalı
  RF24 radio(9, 10);                      // Select CE,CSN pin | CE ve CSN pinlerin seçimi
  
 #define trimbut_1 1                      // Trim button 1 / Pin D1
 #define trimbut_2 2                      // Trim button 2 / Pin D2
 #define trimbut_3 3                      // Trim button 3 / Pin D3
 #define trimbut_4 4                      // Trim button 4 / Pin D4
 #define trimbut_5 5                      // Trim button 5 / Pin D5
 #define trimbut_6 6                      // Trim button 6 / Pin D6
 
 int tvalue1 = EEPROM.read(1) * 4;        // Reading trim values from Eprom  |  Trim değerlerinin Epromdan okunması
 int tvalue2 = EEPROM.read(3) * 4;        
 int tvalue3 = EEPROM.read(5) * 4;        

  struct Signal {
  byte throttle;
  byte pitch;
  byte roll;
  byte yaw;
  byte aux1;
  byte aux2;
  byte aux3;
  byte aux4;  
};

  Signal data;
  void ResetData() 
{
  data.throttle = 512;                      // Signal lost position | Sinyal kesildiğindeki pozisyon
  data.pitch = 127;
  data.roll = 127;
  data.yaw = 127;
  data.aux1 = 0;                         
  data.aux2 = 0;
  data.aux3 = 0;
  data.aux4 = 0;
}
  void setup()
{
                                         // Configure the NRF24 module  | NRF24 modül konfigürasyonu
  radio.begin();
  radio.openWritingPipe(pipeOut);
  radio.setAutoAck(false);
  radio.setDataRate(RF24_250KBPS);       // The lowest data rate value for more stable communication  | Daha kararlı iletişim için en düşük veri hızı.
  radio.setPALevel(RF24_PA_MAX);         // Output power is set for maximum |  Çıkış gücü maksimum için ayarlanıyor.
  radio.stopListening();                 // Start the radio comunication for Transmitter | Verici için sinyal iletişimini başlatır.
  ResetData();
 
  pinMode(trimbut_1, INPUT_PULLUP); 
  pinMode(trimbut_2, INPUT_PULLUP);
  pinMode(trimbut_3, INPUT_PULLUP); 
  pinMode(trimbut_4, INPUT_PULLUP);
  pinMode(trimbut_5, INPUT_PULLUP); 
  pinMode(trimbut_6, INPUT_PULLUP);

  tvalue1= EEPROM.read(1) * 4;
  tvalue2= EEPROM.read(3) * 4;
  tvalue3= EEPROM.read(5) * 4;
}

// Joystick center and its borders | Joystick merkez ve sınırları
  int Border_Map(int val, int lower, int middle, int upper, bool reverse)
{
  val = constrain(val, lower, upper);
  if ( val < middle )
  val = map(val, lower, middle, 0, 128);
  else
  val = map(val, middle, upper, 128, 255);
  return ( reverse ? 255 - val : val );
}
  void loop()
{

// Trims and Limiting trim values  |  Trimler ve Trim değerlerini sınırlandırma

  if(digitalRead(trimbut_1)==LOW and tvalue1 < 630) {
    tvalue1=tvalue1+15;
    EEPROM.write(1,tvalue1/4); 
    delay (130);
  }   
  if(digitalRead(trimbut_2)==LOW and tvalue1 > 280){
    tvalue1=tvalue1-15;
    EEPROM.write(1,tvalue1/4);
    delay (130);
  }
 
  if(digitalRead(trimbut_3)==LOW and tvalue2 < 630) {
    tvalue2=tvalue2+15;
    EEPROM.write(3,tvalue2/4);
    delay (130);
  }   
  if(digitalRead(trimbut_4)==LOW and tvalue2 > 280){
    tvalue2=tvalue2-15;
    EEPROM.write(3,tvalue2/4);
    delay (130);
  }  
    
    if(digitalRead(trimbut_5)==LOW and tvalue3 < 630) {
     tvalue3=tvalue3+15;
     EEPROM.write(5,tvalue3/4);
     delay (130);
  }   
  if(digitalRead(trimbut_6)==LOW and tvalue3 > 280){
    tvalue3=tvalue3-15;
    EEPROM.write(5,tvalue3/4);
    delay (130);
  }
  
// Control Stick Calibration for channels  |  Her bir kanal için kumanda Kol Kalibrasyonları 

  data.roll = Border_Map( analogRead(A3), 0, tvalue1, 1023, true );       // "true" or "false" for signal direction | "true" veya "false" sinyal yönünü belirler
  data.pitch = Border_Map( analogRead(A2), 0, tvalue2, 1023, true );            
  data.throttle = Border_Map( analogRead(A1),570, 800, 1023, false );    // For Single side ESC | Tek yönlü ESC için
//data.throttle = Border_Map( analogRead(A1),0, 512, 1023, false );      // For Bidirectional ESC | Çift yönlü ESC için
  data.yaw = Border_Map( analogRead(A0), 0, tvalue3, 1023, true );              
  data.aux1 = Border_Map( analogRead(A4), 0, 512, 1023, true );                 
  data.aux2 = Border_Map( analogRead(A5), 0, 512, 1023, true );                 
  data.aux3 = digitalRead(7);
  data.aux4 = digitalRead(8);
  radio.write(&data, sizeof(Signal)); 
}

Not:
– Gaz kontrolü için kullandığım PS4 joystikleri yaylı olduğundan kolu bırakınca merkeze döner. Bu durum tek yönlü ESC ler için uygun değildir. Bu yüzden Gaz kanalını kontrol eden (3.kanal) kol merkezde iken minumum konumda duruyormuş gibi ayarlanmalıdır. “data.throttle” satırındaki ilk iki değer “570, 800” bunu sağlar. Çift yönlü ESC ler için ise (Araba ve tekne esc leri gibi) diğer kanallarda olduğu gibi “0, 512” değerleri kullanılır.
– roll, pitch ve yaw satırlarında ise ilk değer “tvalue” isimli değişkendir. Trim butonlarından gelen değeri bu değişken saklar. Bu kısım kanalın merkez konumunu değiştirir.
Trim değerleri eproma kaydedilir.

8 KANAL ALICI DEVRESİ:

 

8 KANALLI ALICI KODU:

//  8 Channel Receiver | 8 Kanal Alıcı

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

int ch_width_1 = 0;
int ch_width_2 = 0;
int ch_width_3 = 0;
int ch_width_4 = 0;
int ch_width_5 = 0;
int ch_width_6 = 0;
int ch_width_7 = 0;
int ch_width_8 = 0;

Servo ch1;
Servo ch2;
Servo ch3;
Servo ch4;
Servo ch5;
Servo ch6;
Servo ch7;
Servo ch8;

struct Signal {

byte throttle;
byte pitch;  
byte roll;
byte yaw;
byte aux1;
byte aux2;
byte aux3;
byte aux4;     
};

Signal data;

const uint64_t pipeIn = 000322;
RF24 radio(9, 10); 

void ResetData()
{

data.throttle = 0;
data.roll = 127;
data.pitch = 127;
data.yaw = 127;
data.aux1 = 0;                                              // Define the inicial value of each data input. | Veri girişlerinin başlangıç değerleri
data.aux2 = 0;
data.aux3 = 0;
data.aux4 = 0;                                                     
}

void setup()
{
                                                           // Set the pins for each PWM signal | Her bir PWM sinyal için pinler belirleniyor.
  ch1.attach(0);
  ch2.attach(2);
  ch3.attach(3);
  ch4.attach(4);
  ch5.attach(5);
  ch6.attach(6);
  ch7.attach(7);
  ch8.attach(8);
                                                           
  ResetData();                                             // Configure the NRF24 module  | NRF24 Modül konfigürasyonu
  radio.begin();
  radio.openReadingPipe(1,pipeIn);
  radio.setAutoAck(false);
  radio.setDataRate(RF24_250KBPS);                          // The lowest data rate value for more stable communication  | Daha kararlı iletişim için en düşük veri hızı.
  radio.setPALevel(RF24_PA_MAX);                            // Output power is set for maximum |  Çıkış gücü maksimum için ayarlanıyor.
  radio.startListening();                                   // Start the radio comunication for receiver | Alıcı için sinyal iletişimini başlatır.

}

unsigned long lastRecvTime = 0;

void recvData()
{
while ( radio.available() ) {
radio.read(&data, sizeof(Signal));
lastRecvTime = millis();                                    // Receive the data | Data alınıyor
}
}

void loop()
{
recvData();
unsigned long now = millis();
if ( now - lastRecvTime > 1000 ) {
ResetData();                                                // Signal lost.. Reset data | Sinyal kayıpsa data resetleniyor
}

ch_width_1 = map(data.roll, 0, 255, 1000, 2000);
ch_width_2 = map(data.pitch, 0, 255, 1000, 2000); 
ch_width_3 = map(data.throttle, 0, 255, 1000, 2000); 
ch_width_4 = map(data.yaw, 0, 255, 1000, 2000); 
ch_width_5 = map(data.aux1, 0, 255, 1000, 2000); 
ch_width_6 = map(data.aux2, 0, 255, 1000, 2000); 
ch_width_7 = map(data.aux3, 0, 1, 1000, 2000); 
ch_width_8 = map(data.aux4, 0, 1, 1000, 2000); 


ch1.writeMicroseconds(ch_width_1);                          // Write the PWM signal | PWM sinyaller çıkışlara gönderiliyor
ch2.writeMicroseconds(ch_width_2);
ch3.writeMicroseconds(ch_width_3);
ch4.writeMicroseconds(ch_width_4);
ch5.writeMicroseconds(ch_width_5);
ch6.writeMicroseconds(ch_width_6);                          
ch7.writeMicroseconds(ch_width_7);
ch8.writeMicroseconds(ch_width_8);


}

Not: Alıcı kodu içerisinde yer alan map komutundaki “1000” ve “2000” değerleri servonun maksimum hareket sınırlarını belirler. 1000 ve 2000 değerleri ile 120° lik servo hareketi elde edilir. Örneğin bu değerleri 800 ve 2300 ile değiştirirseniz servo toplam 180° hareket edebilir.  İhtiyacınıza göre bu değerleri değiştirebilirsiniz. (Min 800, maks 2300 olabilir)

İSTEĞE BAĞLI EKLER:
Alıcı devresini 3S – 6S LiPo lie kullanmak isterseniz bir voltaj düşürücü (Regulator) devresi eklemek gerekecektir. Çünkü Arduino nano direk olarak maksimum 10V ile çalışabilir.
Aşağıda 9V voltaj regülatör devresi ile onun alıcı devresine eklenmiş halini gösteren şema mevcuttur.

 

NOT: Arduinonun 5V pini için maksimum sürekli akım desteği 20mA (Anlık 40mA) dir. NRF modül ise videoda gösterdiğim gibi yaklaşık 12.32 mA çekiyor. Bu yüzden harici bir güç kaynağı eklemedim. Ama E01-ML01DP5 NRF24 modülü için teknik özelliklerini araştıdığımda Alıcı olarak kullanıldığında maksimum 20mA, verici olarak kullanıldığında ise maksimum 130mA değerleri verilmiş. Fakat NRF24 ün bu versiyonu için teknik özellikleri gösteren resmi üretici sitesi veya bir datasheet bulamadım. Bundan dolayı kendi ölçtüğüm akım değerini dikkate aldım ve harici bir güç kaynağı kullanmadım.

Yinede harici güç kaynağı tercih edenler için aşağıda ilgili devre şemalarını paylaştım.

5V Voltaj Düşürücü Regülatör ve Birlikte kullanıldığı Alıcı Devre Şeması:


Regulatorler için gerekli malzemeler:

1uF  Elektrolit kondansatör: https://s.click.aliexpress.com/e/_DDVm071
10uF Elektrolit kondansatör: https://s.click.aliexpress.com/e/_Ddfia2R
100nF Seramik kondansatör: https://s.click.aliexpress.com/e/_Dd496aB
7805 5V Regulator IC: https://s.click.aliexpress.com/e/_DDvYt5v
7809 9V Regulator IC: https://s.click.aliexpress.com/e/_DlXmEG7

Digital Multimetre AC DC A830L : https://s.click.aliexpress.com/e/_DmjzgOJ
Profesyonel Digital Multimetre Tester: https://s.click.aliexpress.com/e/_DmtkrmJ