Today, lets build an Transmitter to control DIY RC projects using easy to obtain off the shelves parts and Arduino Micro as brains.
Table of Contents
What is RC Transmitter?
RC is basically short form of referring Remote Control. It is often used where there are application of a remote or a transmitter and a receiver to receive the control signals.
What is a Transmitter ?
Transmitter is basically an electronic device which produces radio waves with an antenna with the purpose of signal transmission up to a radio receiver to receive at particular frequency.
What is Arduino Micro ?
Arduino Micro is a microcontroller board based on the ATmega32u4, developed in conjunction with Adafruit. It has 20 digital input/output pins of which 7 can be used as PWM outputs and 12 as analog inputs, a 16 MHz crystal oscillator, a micro USB connection, an ICSP header, and a reset button.
Some of the key features of Arduino Micro-
- ATmega32u4
- 2.5kB RAM
- Supported input voltage 4–12V DC
- 1× UART, 1× I2C controllers, 1x SPI, 7× PWM channels
Hardware Requirements of this Project –
- Arduino Micro
- nrf24L01+PA+LNA with adapter board
- SSD 1306 Display (0.96 inch)
- SSD 1306 Display (0.91 inch)
- MPU6050
- Toggle Switches
- Rocker Switch
- Slide potentiometer
- 10k potentiometer and Knob
- Joystick module
- Prototype board
- Male and Female headers
- Jumper Wires
- 9V Battery and Battery cap
- 3D printed housing
Software Requirements of this Project –
Circuit Diagram and Hardware Interfacing –
Circuit Diagram –
Hardware Interfacing –
Arduino Micro
Arduino Micro |
NRF24L01 |
11 |
CE |
12 |
CSN |
SCK |
SCK |
MISO |
MISO |
MOSI |
MOSI |
Arduino Micro |
MPU6050 |
2 |
SDA |
3 |
SCL |
Arduino Micro |
SSD 1306 Disp 1 |
2 |
SDA |
3 |
SCL |
Arduino Micro |
SSD 1306 Disp 2 |
2 |
SDA |
3 |
SCL |
Arduino Micro |
Toggle Switches |
5 |
SW 1 UP |
6 |
SW 1 DOWN |
7 |
SW 2 UP |
8 |
SW 2 DOWN |
Arduino Micro |
Joystick |
A0 |
JS X |
A1 |
JS Y |
4 |
JS Switch |
Arduino Micro |
Potentiometers |
A2 |
Pot 1 Output |
A5 |
Slide Pot Output |
Coding –
Though, I’ve fitted this remote with manual and gyro options for controlling. But is up to the coding on how to utilize the available resources and plan on which functions to do what.
#include <SPI.h>
#include <Wire.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <Adafruit_GFX.h>
#include <Adafruit_MPU6050.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_Sensor.h>
Adafruit_SSD1306 disp1(-1);
Adafruit_SSD1306 disp2(-1);
Adafruit_MPU6050 mpu;
RF24 radio(11, 12); // CE, CSN
const byte addresses[][6] = {"00001", "00002"};
struct pack{
int spot=0, x=0, y=0, jsw=1, trim=0;
};
struct drone{
int batt;
};
pack data;
drone stat;
void setup() {
Serial.begin(9600);
//Wire.setClock(400000);
pinMode(5, INPUT_PULLUP); //SW 1 L
pinMode(6, INPUT_PULLUP); //SW 1 H
pinMode(7, INPUT_PULLUP); //SW 2 L
pinMode(8, INPUT_PULLUP); //SW 2 H
pinMode(A0, INPUT); //JY X
pinMode(A1, INPUT); //JY Y
pinMode(4, INPUT_PULLUP); //JY SW
pinMode(A2, INPUT); //POT OUT
pinMode(A5, INPUT); //SPOT OUT
radio.begin();
radio.setRetries(15, 15);
radio.openWritingPipe(addresses[1]); // 00002
radio.openReadingPipe(1, addresses[0]); // 00001
radio.setPALevel(RF24_PA_MIN);
if (!disp1.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Large Display Check & Initialize
Serial.println("Failed to initialize Large Display");
for(;;);
}
if (!disp2.begin(SSD1306_SWITCHCAPVCC, 0x3D)) { // Small Display Check & Initialize
Serial.println("Failed to initialize Small Display");
for(;;);
}
if (! mpu.begin()) { // MPU 6050 Check & Initialize
Serial.println("Failed to initialize MPU6050 chip");
for(;;);
}
mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
mpu.setGyroRange(MPU6050_RANGE_500_DEG);
mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);
disp1.clearDisplay(); //Clear Initial Buffers
disp2.clearDisplay();
disp1.setTextSize(1);
disp1.setTextColor(WHITE);
disp1.setCursor(42, 0);
disp1.println("Booting");
disp1.display();
disp2.display();
delay(2000);
if(analogRead(A5) >= 5){
while(analogRead(A5) >= 2){
disp1.clearDisplay();
disp1.setTextColor(WHITE);
disp1.setCursor(35, 0);
disp1.println("! Warning !");
disp1.setCursor(15, 20);
disp1.println("Throttle not Zero");
disp1.display();
delay(50);
}
}
}
sensors_event_t a, g, temp; // Gyro Variables
int flag = 0; // To zero out gyro
float x_cor= 0, y_cor= 0; // Correction Values
void loop(){
if(digitalRead(5) == digitalRead(6)){
calc_0();
delay(25);
radio.stopListening();
radio.write(&data, sizeof(data));
// delay(25);
// radio.startListening();
// if (radio.available()) {
// while (radio.available()){
// radio.read(&stat, sizeof(stat));
// }
// }
selector_screen();
flag=0;
}
else if(digitalRead(5) == 0){
calc_1();
delay(25);
radio.stopListening();
radio.write(&data, sizeof(data));
// delay(25);
// radio.startListening();
// if (radio.available()) {
// while (radio.available()){
// radio.read(&stat, sizeof(stat));
// }
// }
//serial_debug();
screen_1();
flag=0;
}
else if(digitalRead(6) == 0){
while (flag == 0 && digitalRead(6) == 0){
zero_out();
}
if(flag == 1){
mpu.getEvent(&a, &g, &temp);
calc_2();
delay(25);
radio.stopListening();
radio.write(&data, sizeof(data));
// delay(25);
// radio.startListening();
// if (radio.available()) {
// while (radio.available()){
// radio.read(&stat, sizeof(stat));
// }
// }
serial_debug();
screen_2();
}
}
}
void selector_screen(){
disp1.clearDisplay();
disp1.setTextSize(1);
disp1.setTextColor(WHITE);
disp1.setCursor(10, 0);
disp1.println("Select Mode");
disp1.setCursor(10, 10);
disp1.println("Up for Manual");
disp1.setCursor(10, 20);
disp1.println("Down for Gyro");
disp1.display();
disp2.clearDisplay();
disp2.setTextSize(2);
disp2.setTextColor(WHITE);
disp2.setCursor(5, 0);
disp2.cp437(true);
disp2.write(24);
disp2.display();
}
void screen_1(){
disp1.clearDisplay();
disp1.setTextSize(1);
disp1.setTextColor(WHITE);
disp1.setCursor(32, 0);
disp1.println("Manual Mode");
disp1.display();
disp2.clearDisplay();
disp2.display();
}
void screen_2(){
disp1.clearDisplay();
disp1.setTextSize(1);
disp1.setTextColor(WHITE);
disp1.setCursor(40, 0);
disp1.println("Gyro Mode");
disp1.display();
disp2.clearDisplay();
disp2.setTextSize(1);
disp2.setTextColor(WHITE);
disp2.setCursor(5, 0);
disp2.println("X = ");
disp2.setCursor(25, 0);
disp2.println(a.acceleration.x + x_cor);
disp2.setCursor(5, 10);
disp2.println("Y = ");
disp2.setCursor(25, 10);
disp2.println(a.acceleration.y + y_cor);
disp2.display();
}
void zero_out(){
disp1.clearDisplay();
disp1.setTextSize(1);
disp1.setTextColor(WHITE);
disp1.setCursor(40, 0);
disp1.println("Gyro Mode");
disp1.setCursor(5, 20);
disp1.println("Press JSW when ready");
disp1.display();
mpu.getEvent(&a, &g, &temp);
x_cor = 0 - a.acceleration.x;
y_cor = 0 - a.acceleration.y;
if(digitalRead(4) == 0){
flag=1;
}
}
void calc_0(){
data.spot = 0;
data.x = analogRead(A0);
data.y = analogRead(A1);
data.jsw = digitalRead(4);
data.trim = analogRead(A2);
}
void calc_1(){
data.spot = analogRead(A5);
data.x = analogRead(A0);
data.y = analogRead(A1);
data.jsw = digitalRead(4);
data.trim = analogRead(A2);
}
void calc_2(){
data.spot = analogRead(A5);
if(a.acceleration.x + x_cor >= -5 && a.acceleration.x + x_cor <= 5){
data.y = map(a.acceleration.x + x_cor, -5, 5, 800, 200);
}
else if(a.acceleration.x + x_cor < -5){
data.y = 800;
}
else if(a.acceleration.x + x_cor > 5){
data.y = 200;
}
if(a.acceleration.y + y_cor >= -8 && a.acceleration.y + y_cor <= 8){
data.x = map(a.acceleration.y + y_cor, -8, 8, 1023, 0);
}
else if(a.acceleration.y + y_cor < -8){
data.x = 1023;
}
else if(a.acceleration.y + y_cor > 8){
data.x = 0;
}
data.jsw = digitalRead(4);
data.trim = analogRead(A2);
}
void serial_debug(){
Serial.print(data.spot);
Serial.print(" ");
Serial.print(data.x);
Serial.print(" ");
Serial.print(data.y);
Serial.print(" ");
Serial.print(data.jsw);
Serial.print(" ");
Serial.print(data.trim);
Serial.print(" ");
Serial.print(stat.batt);
Serial.println(" ");
}
Working of Project –
The working of this project is pretty simple. Upon connecting all the components as per the circuit diagram and upload the the above code. The remote should start working.
And after the remote is turned on, wait for few seconds. Till the other side also pairs up and follows commands given from the remote.
The above code which is given, has been developed for a RC car. However the above code can modified to control a RC Plane, or a quadcopter or anything. Imagination is the limit.
If there’s no major error till this point. Then congratulation, you’ve successfully made a Remote for your upcoming RC projects. And the remote will cover most of the basic needs of any similar RC project.
Â
– For more such Arduino and Raspberry Pi Pico based projects,
check out our Arduino Playlist and Raspberry Pi Pico Playlist
– And for other more interesting projects, check our main YouTube Channel