Hey guys, this is a tutorial on how to make a transmitter that we can use to control RC plane, drone and other RC models using Arduino. Below you will find a diagram for the RC transmitter and the receiver circuit and also the coding for each of them.

Before uploading the code, make sure you have the NRF24 library important in your project. If you don’t have the NRF24 library, go to Arduino IDE and go sketch > include library > manage libraries.

On the search bar, type RF24 and scroll down to the one it says “RF24 by TMRh20” and click on install. This should install the necessary library to use the NRF module. Wait for the installation to complete before uploading the code.
The schematic diagram for the Transmitter
Now let's talk a bit of what we have in this circuit. I am using an Arduino nano (328p) to control the transmitter as it is relatively small in size to fit the transmitter. For this project, I am using the NRF24l01 with a power amplifier that has an external antenna for wireless communication. Note that this might not be the best way for wireless communication as the range is often affected by interferences. However, with the amplified version of the NRF24, you can get a decent range of around 800 m to even 1.2 Km. It is, however, easier to use this module. You do have alternatives such as LoRa,  RF module of 433Mhz, Bluetooth module or even wifi.


I am also using spring return joystick which is also available in Arduino pack. If you are planning to make a drone or RC plane with it, you might want to choose one which is not spring return for the throttle. If you do not have one, you can map only the upper half of the joystick for the throttle else the motor will always remain on. I have also added two digital switches which can be used to turn on or off a led or to switch from angle mode to horizontal mode for the drone. I have also added a potentiometer for analog signals. Now, this is a beginner project, it lacks more features that a commercial transmitter would have. So it can be powered from a 9 V battery and you can use the regulated voltage, 5 V or 3.3 V where needed. Note that in other posts, I have made some changes in this schematic. This one uses the 3.3 V from the Arduino to power the NRF24l01 which is the required voltage for the NRF module. However, as the 3.3 V can supply a maximum of 150mA, it would not be good to use it with the power amplified version of the Arduino. This will often create lost a connection between the transmitter and the receiver. To solve this problem, I have added a buck converter to regulate the 9 V, to 3.3 V which was able to deliver the required current to the NRF. We could also use a linear voltage regulator but it would be very inefficient for our purpose.

Receiver Schematics

For the receiver, you connect the Arduino same as we did earlier for the transmitter, I have added 3 different types of output for you to understand how it works. The first one is the led, which is controlled to be either on or off through the transmitter. This is a digital output. The second thing is the servo, and the third one is a speed control dc motor. To control the speed of a DC motor, you must switch on and of the input of the motor at a very fast rate. The amount of time the switch is on and off determines the average voltage. The higher the average voltage, the higher is the speed of the motor. This is normally achieved by sending a PWM signal to the drain of MOSFETs or IGBTs, which will turn on and off the circuit at a very high frequency. 

If you want to make a drone with this transmitter and receiver, check it HERE.

Transmitter code

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

const uint64_t pipeOut = 0xE7E7F0F0E1LL; //Remember to keep this exactly the same for the receiver code also

RF24 radio(9, 10);

struct MyData {
  byte throttle;
  byte yaw;
  byte pitch;
  byte roll;
  byte AUX1;
  byte AUX2;
};

MyData data;

void resetData() 
{

  data.throttle = 0;
  data.yaw = 127;
  data.pitch = 127;
  data.roll = 127;
  data.AUX1 = 0;
  data.AUX2 = 0;
}

void setup()
{

  radio.begin();
  radio.setAutoAck(false);
  radio.setDataRate(RF24_250KBPS);
  radio.openWritingPipe(pipeOut);
  resetData();
}

int mapJoystickValues(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()
{
  data.throttle = mapJoystickValues( analogRead(A0), 13, 524, 1015, true );
  data.yaw      = mapJoystickValues( analogRead(A1),  1, 505, 1020, true );
  data.pitch    = mapJoystickValues( analogRead(A2), 12, 544, 1021, true );
  data.roll     = mapJoystickValues( analogRead(A3), 34, 522, 1020, true );
  data.AUX1     = digitalRead(4); //The 2 toggle switches
  data.AUX2     = digitalRead(5);

  radio.write(&data, sizeof(MyData));
}
****************************************************************************
I’ll make some important points in the code that you should take into consideration.

First of all is this line: “const uint64_t pipeOut = 0xE7E7F0F0E1LL; “

This part of the code is the address of the transmitter. It is very important to make it the same as the receiver for it to be detected. I recommend copy and paste the exact thing to the receiver code which you will find below.

The second thing is this: “RF24 radio (9, 10);”

This line of code defines the pin that we have selected from the Arduino that we are going to connect to the NRF24L01 CE and CSN input. In the above circuit diagram, you can see I connected the CE and CSN of the NRF to pin 9 and 10 of the Arduino respectively. So, I define it as above.

Now this part:

int mapJoystickValues(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 );
}

This part is a function that is telling to map the values of the joystick to the PWM signal. You should check the values of the lower, middle and upper position of your joystick and enter the values according to it. Use analogRead( The analog pin your joystick is connected to), and then use Serial.println to print the values in the serial monitor.

Here you should add the values you got from the above test.

void loop()
{

  data.throttle = mapJoystickValues( analogRead(A0), 13, 524, 1015, true );
  data.yaw      = mapJoystickValues( analogRead(A1),  1, 505, 1020, true );
  data.pitch    = mapJoystickValues( analogRead(A2), 12, 544, 1021, true );
  data.roll     = mapJoystickValues( analogRead(A3), 34, 522, 1020, true );
  data.AUX1     = digitalRead(4); //The 2 toggle switches
  data.AUX2     = digitalRead(5);

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

This will calibrate the joystick for you.

Receiver code

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

const uint64_t pipeIn = 0xE7E7F0F0E1LL; 

RF24 radio(9, 10); CE and CSN pin 
Servo myServo;

struct MyData {
byte throttle;
byte yaw;
byte pitch;
byte roll;
byte Trim;
byte AUX1;
byte AUX2;
};

MyData data;

void resetData()
{

data.throttle = 0;
data.yaw = 127;
data.pitch = 127;
data.roll = 127;
data.Trim = 0;
data.AUX1 = 0;
data.AUX2 = 0;

}

void setup()
{
Serial.begin(9600); //Set the speed to 9600 bauds if you want.

resetData();
radio.begin();
radio.setAutoAck(false);
radio.setDataRate(RF24_250KBPS);

radio.openReadingPipe(1,pipeIn);
radio.startListening();

pinMode(2,OUTPUT);
pinMode(3,OUTPUT);
myServo.attach(4);
pinMode(5,OUTPUT);

}

/**************************************************/

unsigned long lastRecvTime = 0;

void recvData()
{
while ( radio.available() ) {
radio.read(&data, sizeof(MyData));
lastRecvTime = millis(); //here we receive the data
}
}

/**************************************************/

void loop()
{
recvData();
unsigned long now = millis();

if ( now - lastRecvTime > 1000 ) {

resetData();
}

digitalWrite(2,data.AUX1);
digitalWrite(3,data.AUX2);

int val = map(data.throttle,128,255,0,255);

int val1 = map(data.roll,0,255,0,180);

myServo.write(val1);

if(val > 0){
analogWrite(5,val);
}else{

  analogWrite(5,0);
}

Serial.print("Throttle: "); Serial.print(data.throttle);  Serial.print("    ");
Serial.print("Yaw: ");      Serial.print(data.yaw);       Serial.print("    ");
Serial.print("Pitch: ");    Serial.print(data.pitch);     Serial.print("    ");
Serial.print("Roll: ");     Serial.print(data.roll);      Serial.print("    ");
Serial.print("Trim: ");     Serial.print(data.Trim);      Serial.print("    ");
Serial.print("Aux1: ");     Serial.print(data.AUX1);      Serial.print("    ");
Serial.print("Aux2: ");     Serial.print(data.AUX2);      Serial.print("\n");

}

So that’s the receiver code that you can use to test if the receiver is working. If you do not own an oscilloscope, you can open the serial monitor and see if the receiver is getting the data sent by the transmitter.


Watch also the video for this tutorial on YouTube here:


NEXT >>