Uniostar
Published © GPL3+

Arduino 8 Channel RC Controller with 5km+ Range, Expo & Trim

Ever wanted to make an anything RC on a budget? This tutorial walks you through how to make a simple, low cost RC controller with Arduino.

IntermediateWork in progress4 hours671
Arduino 8 Channel RC Controller with 5km+ Range, Expo & Trim

Things used in this project

Story

Read more

Schematics

Transmitter Schematic

Receiver Schematic

Code

Transmitter Code

Arduino
Upload to Transmitter
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

RF24 radio(7, 8); // CE, CSN

const byte address[6] = "77777";

#define buttonPin 6

struct package 
{
  int x1 = 0; // aileron
  int y1 = 0; // elevator

  int x2 = 0; // rudder
  int y2 = 0; // thrust

  char b1 = '0'; // eject
};

struct package data;

void setup() 
{
  Serial.begin(9600);

  radio.begin();
  radio.openWritingPipe(address);
  radio.setPALevel(RF24_PA_MIN);
  radio.setDataRate(RF24_250KBPS);
  radio.setAutoAck(false);
  radio.stopListening();

  pinMode(buttonPin, INPUT_PULLUP);
}

void loop() 
{
  data.x1 = map(analogRead(A1), 0, 1023, 0, 180);
  data.y1 = map(analogRead(A0), 0, 1023, 0, 180);
  data.x2 = map(analogRead(A3), 0, 1023, 180, 0);
  data.y2 = map(analogRead(A2), 0, 1023, 180, 0);
  data.b1 = digitalRead(buttonPin) ? '1' : '0';
  
  radio.write(&data, sizeof(data));
}

Receiver Code

Arduino
Upload to receiver.
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <Servo.h>

RF24 radio(7, 8); // CE, CSN
const byte address[6] = "77777";

struct package 
{
  int x1 = 0; // aileron
  int y1 = 0; // elevator

  int x2 = 0; // rudder
  int y2 = 0; // thrust

  char b1 = '0'; // eject
};

struct package data;

// Servo objects
Servo motor;
Servo rudder;
Servo aileron1;
Servo aileron2;
Servo elevator;

// Trim values (adjust as needed)
int trimElevator = 0;
int trimRudder = 0;
int trimAileron1 = 0;
int trimAileron2 = 0;

void setup() 
{
  Serial.begin(9600);

  elevator.attach(3);
  aileron1.attach(5);
  aileron2.attach(6);
  rudder.attach(10);
  motor.attach(9, 1000, 2000);

  // Initialize control surfaces to trimmed neutral
  elevator.write(constrain(90 + trimElevator, 0, 180));
  aileron1.write(constrain(90 + trimAileron1, 0, 180));
  aileron2.write(constrain(90 + trimAileron2, 0, 180));
  rudder.write(constrain(90 + trimRudder, 0, 180));

  radio.begin();
  radio.openReadingPipe(0, address);
  radio.setPALevel(RF24_PA_MIN);
  radio.setDataRate(RF24_250KBPS);
  radio.setAutoAck(false);
  radio.startListening();
}

void loop() 
{
  if (radio.available()) 
  {
    radio.read(&data, sizeof(data));

    // Thrust control
    data.y2 = constrain(data.y2, 90, 180);
    motor.write(map(data.y2, 90, 180, 0, 90));

    // Control surfaces with trim applied
    rudder.write(constrain(data.x2 + trimRudder, 0, 180));
    aileron1.write(constrain(data.x1 + trimAileron1, 0, 180));
    aileron2.write(constrain(data.x1 + trimAileron2, 0, 180));
    elevator.write(constrain(data.y1 + trimElevator, 0, 180));

    // Debug info
    Serial.print("x1: "); Serial.print(data.x1);
    Serial.print(" y1: "); Serial.print(data.y1);
    Serial.print(" x2: "); Serial.print(data.x2);
    Serial.print(" y2: "); Serial.print(data.y2);
    Serial.print(" button: "); Serial.println(data.b1);
  }
}

Credits

Uniostar
10 projects • 8 followers
Electrical Engineering Undergrad Student specialized in low-level programming, IoT projects, and microcontroller electronics.

Comments