Introduction: Wifi PPM (no App Needed)
I wanted to control my diy micro indoor quadrocopter with my smart phone but I couldn't find a good solution for this. I had a few ESP8266 wifi modules laying around so I decided to make my own one.
The program starts a wifi access point with a HTML 5 website to control the PPM signal. The PPM signal is generated by interrupt.
Thanks to HTML5 you can control your RC device with any smart phone without any app.
You can also connect to the website with a PC and use a joystick for controlling. At the moment this works only in Firefox.
In this inscrutable I will explain how to set up the ESP8266 and how to configure the receiver in Betaflight.
Step 1: Parts List
Let's start with the parts list. You just need a few components:
- ESP8266: Any module should work. I use the ESP 12-F module: http://www.watterott.com/de/ESP8266-ESP-12F-WiFi/W...
- a 3,3V USB to Serial converter for uploading the scetch the first time. (After the first upload you can use the OTA update). Use Something like this: https://www.banggood.com/de/RobotDyn-USB-Serial-A...
- a 3,3V voltage regulator: The ESP8266 needs 3,3V. Any voltage above 3,6V will kill the device. It can also drop about 200mA peak current. If you don´t have a strong enough 3,3V supply at your RC model you need an additional voltage regulator. I use this step down regulator with a 3,9K Ohm resistor: http://www.produktinfo.conrad.com/datenblaetter/15...
- a PC with Arduino IDE: https://www.arduino.cc/en/Main/Software
- ESP8266 support for Arduino IDE. Follow these instructions: https://learn.sparkfun.com/tutorials/esp8266-thing...
- Websocket library for Arduino: https://github.com/Links2004/arduinoWebSockets
- Maybe a 3,3V/5V level shifter if your PPM decoder doesn´t support 3,3V inputs. For most quadcopter flight controllers you don´t need this.
- The WifiPPM scetch: Download file below or https://goo.gl/Qj5Gwb
- A smart phone or a PC with a joystick and Firefox
Step 2: Set Up the Electronics and Upload the Program
The first thing to do is to set the power connections to the ESP8266. You can see the wiring in the picture. Make the following connections:
RST, EN and VCC to 3,3V
GPIO15 and GND to GND
Put a small capacitor between VCC and GND (about 100 nF)
TXD to RXD of your USB2Serial device
RXD to TXD of your USB2Serial device
Put GPIO0 to GND while powerup to enter the flash mode.
After you have installed the Arduino IDE, the ESP8266 support and the websocket library open the sketch. Hold GIO0 to GND while powering up the ESP8266 to enter the flash mode. Now you can upload the sketch.
After you have uploaded the sketch, the controller will reset. You should find a WIFI Access Point named WifiPPM. If this is OK you can power down the chip and disconnect the TXD, RXD and GPIO0 wires. In the future you can update the program over OTA. To do so connect to the Access Point and go to "192.168.1.4/update" in your web browser.
Step 3: Website
Now you can connect GPIO5 to the PPM input of your flight controller or whatever you use to decode the PPM signal.
After powering up the module you can connect to the Access Point "WifiPPM". There is no password. Open the address 192.168.4.1 in your browser.
You will see the site of the first picture. On a touch device you can control the sticks with your touch screen.
If you open the site with a PC you must use Firefox. As soon as you connect a joystick, the site will change to the one you can see at the second picture. You can control the sticks with your joystick.
In the next step I will explain how to set up Betaflight, because I use it. If you use some other controller you have to go on yourself from now on.
Step 4: Setting Up Betaflight
I use the WifiPPM controller for my quadcopter with Betaflight. I explain now how to set it up.
- Connect your flight controller to the PC
- open Betaflight
- connect to the flight controller
- go to Receiver tab
- type RTAE1234 into the channel map field
- change the "Stick Low Threshold" to 1020, the "Stick Center" to 1500 and the "Stick High Threshold" to 1980
- save the changes
- open the wifiPPM website with your mobile phone and test if the adjustment is OK
Thats it. You are done. Now you can fly with your mobile phone without any additional app.

Participated in the
Remote Control Contest 2017
97 Comments
2 years ago
hello i'm using mpu6050, an Arudino and aN esp8266 nodemcu. Uploading the code onto the esp8266 is fine, however when i access the ip address through wifi_ppm on my phone, the joysticks don't move and the drone is stationary. how should the pins be conencted between the Arduino and Nodemcu.
LIPO 3S 11.1V
this is my current pin connection
ARDUINO UNO ------ MPU 6050
SDA SDA
SCL SCL
UNO------------------- MOTORS
D11 M3
D10 M1
D9 M2
D3 M4
UNO ESP8266 NODEMCU
3.3V VIN
GND GND
TX D1 D1
Reply 1 year ago
hi did u get it to work?
Question 1 year ago on Introduction
hy, i am trying to make a blynk controlled quadcopter via internet, i have set up the same variables as yours and put the same ppm output code as yours, but i cant get it to work, can you help me with sending the ppm variables output from your ppm output code but change the ppm variables according to blynk's data, i am not very good at programming by the way, if you help me with where i went wrong and what i should do, it would be very helpful
here is the code
#define BLYNK_PRINT Serial
/* Fill-in your Template ID (only if using Blynk.Cloud) */
//#define BLYNK_TEMPLATE_ID "YourTemplateID"
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <Hash.h>
#include "MSP.h"
#include <SPI.h>
#define CPU_MHZ 80
#define CHANNEL_NUMBER 8 //set the number of chanels
#define CHANNEL_DEFAULT_VALUE 1100 //set the default servo value
#define FRAME_LENGTH 22500 //set the PPM frame length in microseconds (1ms = 1000µs)
#define PULSE_LENGTH 300 //set the pulse length
#define onState 0 //set polarity of the pulses: 1 is positive, 0 is negative
#define sigPin 5 //set PPM signal output pin on the arduino
#define DEBUGPIN 4
volatile unsigned long next;
volatile unsigned int ppm_running=1;
volatile unsigned long OCR1A;
unsigned int alivecount=0;
MSP msp;
int ppm[CHANNEL_NUMBER];
// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
char auth[] = " q3jtIQhMAddZROHQDihkQhZbs3DhFtpr";
// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "Pakistan";
char pass[] = "12345679";
int throttle_blynk;
int yaw_blynk;
int pitch_blynk;
int roll_blynk;
int AUX1_blynk;
int AUX2_blynk ;
//
void inline ppmISR(void){
static boolean state = true;
if (state) { //start pulse
digitalWrite(sigPin, 1);
next = next + (PULSE_LENGTH * CPU_MHZ);
state = false;
alivecount++;
}
else{ //end pulse and calculate when to start the next pulse
static byte cur_chan_numb;
static unsigned int calc_rest;
digitalWrite(sigPin, 0);
state = true;
if(cur_chan_numb >= CHANNEL_NUMBER){
cur_chan_numb = 0;
calc_rest = calc_rest + PULSE_LENGTH;//
next = next + ((FRAME_LENGTH - calc_rest) * CPU_MHZ);
calc_rest = 0;
digitalWrite(DEBUGPIN, !digitalRead(DEBUGPIN));
}
else{
next = next + ((ppm[cur_chan_numb] - PULSE_LENGTH) * CPU_MHZ);
calc_rest = calc_rest + ppm[cur_chan_numb];
cur_chan_numb++;
}
}
timer0_write(next);
}
void handleRoot() {
if(ppm_running==0)
{
noInterrupts();
timer0_isr_init();
timer0_attachInterrupt(ppmISR);
next=ESP.getCycleCount()+1000;
timer0_write(next);
for(int i=0; i<CHANNEL_NUMBER; i++){
ppm[i]= CHANNEL_DEFAULT_VALUE;
}
ppm_running=1;
interrupts(); }
}
void setPPMValuesFromData()
{
ppm[0] = throttle_blynk ;
ppm[1] = yaw_blynk ;
ppm[2] = pitch_blynk ;
ppm[3] = roll_blynk ;
ppm[4] = AUX1_blynk ;
ppm[5] = AUX2_blynk ;
}
void setupPPM() {
pinMode(sigPin,OUTPUT);
digitalWrite(sigPin, !onState); //set the PPM signal pin to the default state (off)
pinMode(DEBUGPIN,OUTPUT);
digitalWrite(DEBUGPIN, !onState);
}
void setup()
{
ppm[0]=1100; ppm[1]=1500; ppm[2]=1500; ppm[3]=1500;
ppm[4]=1100; ppm[5]=1100; ppm[6]=1100; ppm[7]=1100;
setupPPM();
// Debug console
Serial.begin(115200);
Blynk.begin(auth, ssid, pass);
/* noInterrupts();
timer0_isr_init();
timer0_attachInterrupt(ppmISR);
next=ESP.getCycleCount()+1000;
timer0_write(next);
for(int i=0; i<CHANNEL_NUMBER; i++){
ppm[i]= CHANNEL_DEFAULT_VALUE;
}
interrupts();
Serial.begin(115200);
msp.begin(Serial);
*/
}
BLYNK_WRITE(V0)
{
Serial.println(param.asInt());
yaw_blynk = param.asInt();
ppm[1]=param.asInt();
}
BLYNK_WRITE(V1)
{
Serial.println(param.asInt());
throttle_blynk = param.asInt();
ppm[0]=param.asInt();
}
void loop()
{
Blynk.run();
setPPMValuesFromData();
if(alivecount>1000){
for(int i=0; i<4;i++){
ppm[i]=900;
}
for(int i=4; i<8;i++){
ppm[i]=1100;
}
}
ppmISR();
yield();
/*
static boolean state = true;
if (state) { //start pulse
digitalWrite(sigPin, 1);
next = next + (PULSE_LENGTH * CPU_MHZ);
state = false;
alivecount++;
}
else{ //end pulse and calculate when to start the next pulse
static byte cur_chan_numb;
static unsigned int calc_rest;
digitalWrite(sigPin, 0);
state = true;
if(cur_chan_numb >= CHANNEL_NUMBER){
cur_chan_numb = 0;
calc_rest = calc_rest + PULSE_LENGTH;//
next = next + ((FRAME_LENGTH - calc_rest) * CPU_MHZ);
calc_rest = 0;
digitalWrite(DEBUGPIN, !digitalRead(DEBUGPIN));
}
else{
next = next + ((ppm[cur_chan_numb] - PULSE_LENGTH) * CPU_MHZ);
calc_rest = calc_rest + ppm[cur_chan_numb];
cur_chan_numb++;
}
}
*/
static boolean state = true;
;
if ( state ) {
//end pulse
digitalWrite(sigPin,0);
OCR1A = PULSE_LENGTH * CPU_MHZ;
state = false;
}
else {
//start pulse
static byte cur_chan_numb;
static unsigned int calc_rest;
digitalWrite(sigPin,1);
state = true;
if(cur_chan_numb >= CHANNEL_NUMBER) {
cur_chan_numb = 0;
calc_rest += PULSE_LENGTH;
OCR1A = (FRAME_LENGTH - calc_rest) * CPU_MHZ;
calc_rest = 0;
}
else {
OCR1A = (ppm[cur_chan_numb] - PULSE_LENGTH) * CPU_MHZ;
calc_rest += ppm[cur_chan_numb];
cur_chan_numb++;
}
}
}
2 years ago
Controlling is difficult for me can someone comment me or show me how to drive drone using this wifi controller
4 years ago
Hello Andi,
I am trying to build an arduino quadcopter using arduino nano flashed with multiwii firmware with mpu6050 connected and esp8266 nodemcu as reciever with ppm signal. I have followed you article wifi ppm (No app needed) and connected the gpio 5 of esp to the pin D2 of the arduino nano and also uncommented the following lines in multiwii config.h file.
#define QUADX
#define NANOWII
#define SERIAL_SUM_PPM ROLL,PITCH,THROTTLE,YAW,AUX1,AUX2,AUX3,AUX4,8,9,10,11
But I am not getting any results, motors are not rotating also the changes are showing in multiwii config gui. I feel the esp is not communicating with arduino. But I have checked the signal at esp gpio pin 5 I am getting the signals i am not getting where i am missing. Kindly help me with this.
Thank You
Reply 4 years ago
Hello,
can you connect to the Access Point of WIFIPPM? Is the website working? If yes, do you have an oscilloscope? Then you can check the signals at GPIO5. If you don't have an oscilloscope you can measure the frequency on GPIO4 and GPIO5. If the signal is OK, it is some problem of the MultiWii controller or software, but I never used it myself, so I can't help you with that. Which voltage is the Arduino working with? Maybe the 3,3 Volt output level of the ESP is too low for the Arduino.
Reply 4 years ago
Hello,
Thank you for your response, yes i have connected to the access point in my mobile and site is working also i have checked the signal at GPIO5, signal is also fine but when i gave the signal to the arduino pin D2 am not getting the results in terms of motor rotation. Does arduino nano flased with multiwii code accepts the ppm in and processes the signal or do i need to use extra hardware or need to change in multiwii code.
If i need to uncomment some lines in multiwii code can you please guide me which are those. I am using quad-x with esp8266 nodemcu with the wifi ppm code flased in esp.
Has anyone flyied the quad using arduino nano with esp using wifi ppm and multiwii code. can you please give me some idea about it.
Does your wifi ppm code provided above works with multiwii code?
Thank You
Reply 4 years ago
Are you sure the timings are alright. Is the #define CPU_MHZ in your WifiPPM sketch similar to the adjustment of your esp8266 nodemcu? You can set/check the clock speed in "Tools->CPU Frequency" in Arduino IDE.
If you have defined only 80MHz in WifiPPM and your controller is running on 160 MHz your signals would have double speed and it would not work. The same the other way around.
Reply 4 years ago
Hey finally got it working, thank for your support. But I am facing another issue in esp8266, at start i have uploaded the wifippm code in esp and it is showing the access point, but every time when i remove the power and power it again or if I reset it, it is not showing me the access point. Every time I am uploading the code. Can you suggest me on this what will be the issue.
Reply 2 years ago
Hello Nazzz i also made it but the motors are not running i used arduino multiwii is there any thing you fixed thanks.
Reply 3 years ago
please help when i am moving the joystic in mozilla firefox there is nothing happening in multwii gui. how can i fix it . please help
Reply 4 years ago
That sounds like you did not disconnect the programming pin (GPIO0) from ground before restarting the chip.
Reply 4 years ago
Yes i have not disconnected programming pin (GPIO0) from ground before restarting the chip. Now i have removed it is working fine.
But wifi access point is not stable it is getting restarted again and again. Can you tell me what will be the reason for getting restarted.
Reply 4 years ago
That usually happens if you your power source is too small. You need 3,3 Volt with at least 200mA, better more.
Reply 4 years ago
I am giving common power constant 5v from BEC to the esp arduino and mpu6050.
Do i need to give 3.3v only to the esp or 5v will do better?
Reply 4 years ago
The ESP chip runs with 3,3V. So there must be some voltage regulator at the arduino board.
Can you try a stable 3,3V power supply directly to the chip? Maybe that's better.
Is your 5V power supply strong/stable enough?
A capacitor at your power supply could also help.
There are many esp8266 forums. And many other people have this problem. Google is your friend :)
Reply 4 years ago
Thank you Andi for your support it really helps me alot, and i have used separate 3.3v for esp now its working fine.
Reply 4 years ago
Hey Andi,
I was setting up new esp quadcopter so i have used wifippm code provided in your post, but now I am getting the controls different means on right hand side am getting thorttle and yaw, and on left hand side am getting roll and pitch. But when initially i had used your code i was getting the correct controls that is on right side roll and pitch, and o left side throttle and yaw without any changes in the code.
But now I am getting it opposite, kindly help me with this.
Thank You
Reply 4 years ago
Which flight controller software are you useing? You need to adjust the
channel mappings. In Betaflight/Cleanflight they are in the Receiver
Tab. The mappings need to be adjusted to RTAE1234. There should be some
channel mapping setting in any other flight controller, too.
You can
also change the channel mappings in the index.html.c. To do this change
the last two parameters of "drawstick(...)" function to the desired
channels everytime when it's called.
The function call of drawstick is: drawstick(context, x, y, ppm0, ppm1);
context: the canvas context to which you want to draw
x and y: the positions of the stick
ppm0 and ppm1: ppm channels.
Reply 4 years ago
Thank you for your reply, am using multiwii config for the calibration. But before when i had used wifippm code i did not do any changes in the code for channel setting, by default it had come correct. But now it is not coming same as before.
What shall I change in this function to make it to work in mode 2,
function draw_stick(context,x,y,ppm0,ppm1)
{
context.clearRect(0, 0, context.canvas.width, context.canvas.height);
context.beginPath();
context.arc(x,y,window.innerWidth/100*2,0,2*Math.PI);
if(wsconnect)
context.fillStyle = 'green';
else
context.fillStyle = 'red';
context.fill();
context.lineWidth = 5;
context.strokeStyle = '#003300';
context.stroke();
ppm[ppm0] = parseInt(1000+((1000/context.canvas.width)*x))
ppm[ppm1] = parseInt(2000-((1000/context.canvas.height)*y))
}
There were any updates in wifippm code from last 15 days??