Andrey Ovcharov

Professional Software Engineer and hobbyist Hardware enthusiast

Andrey Ovcharov

Can ESP01 be used as a receiver for the drone?

Recently I was exploring the differences between IBUS and SBUS protocols used in remote controls. The IBUS protocol appears to be a very simple half-duplex UART operating on speed 115200 baud. Packets of a fixed size, simple checksum calculation… Wait a second. What if we take the dirt-cheap ESP01 module, program it as the receiver and operate it with the smartphone? In just half an hour the minimal prototype was built.

The ESP01 module connected to the flight controller
The ESP01 module connected to the flight controller

I’ve found an old Betaflight-compatible flight controller F4 Noxe V1 in one of the boxes on my shelf. The ESP01 module was programmed with a simple sketch - every second all the channels take random values in range from 1000 to 2000 and the data packet is sent to the flight controller. The module was connected to the controller and…

Random values from ESP01 receiver

The magic happened! The Receiver tab in the Betaflight Configurator shows random values for all 14 channels changing every second. Yes, this small, cheap and lightweight module can be programmed as a receiver for the remote-controlled model!

However, now I have more open questions than half an hour ago. I think the performance of the WebServer is not enough and some UDP socket server should be used. How it will work with the real drone with all the electric noises from the motors and other components? What is the operating range for this setup indoors and outdoors? The ESP07 module with the external antenna could be a solution here. Some transmitter application for the smartphone should be written as well…

I don’t think this setup can provide enough performance for racing and freestyle, but what about indoor flights for beginners? Might be an interesting project to build.

For ones who are interested and wants to repeat this setup - the Arduino sketch for the ESP01 receiver prototype looks as follows:

#include <Arduino.h>

#include <SoftwareSerial.h>

#include <RecurringTask.h>

SoftwareSerial SerialIBUS(0, 2); // RX, TX

typedef struct
{
    uint8_t header1;
    uint8_t header2;
    uint16_t channels[14];
    uint16_t checksum;
} IBUS_Packet;

IBUS_Packet packet = {};

uint16_t calc_checksum(IBUS_Packet &p)
{
    uint16_t checksum = 0xFFFF;
    checksum -= p.header1;
    checksum -= p.header2;

    for (int i = 0; i < 14; i++)
    {
        checksum -= p.channels[i] & 0xFF;
        checksum -= (p.channels[i] >> 8) & 0xFF;
    }

    return checksum;
}

void send_packet(IBUS_Packet &p)
{
    SerialIBUS.write((uint8_t *)&p, sizeof(IBUS_Packet));
}

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

    SerialIBUS.begin(115200);

    packet.header1 = 0x20;
    packet.header2 = 0x40;

    for (int i = 0; i < 14; i++)
    {
        packet.channels[i] = 0x5dc;
    }

    packet.checksum = calc_checksum(packet);
}

void loop()
{
    RecurringTask::interval(1000, []() {
        for (int i = 0; i < 14; i++)
        {
            packet.channels[i] = 1000 + random(1000);
        }
        packet.checksum = calc_checksum(packet);
    });

    send_packet(packet);

    delay(10);
}

References