esp8266/Nodemcu wifi based helicopter control using webserver and laptop Keyboard





 Code

#include <ESP8266WiFi.h>

#include <ESP8266WebServer.h>


const char* ssid     = "YOUR_SSID";

const char* password = "YOUR_PASSWORD";


ESP8266WebServer server(80);


// motor control pins

const int motorThrottle    = D1;  // vertical lift

const int motorForwardBack = D2;  // forward/backward

const int motorLeftRight   = D3;  // left/right


// throttle ramp globals

int   throttleValue   = 0;

bool  isRamping       = false;

int   rampStartValue  = 0;

int   rampTargetValue = 0;

int   rampDuration    = 0;

unsigned long rampStartTime = 0;


// movement globals

int movementFB = 0;

int movementLR = 0;

int speedValue = 0;


void setup() {

  Serial.begin(115200);

  WiFi.begin(ssid, password);

  pinMode(motorThrottle,    OUTPUT);

  pinMode(motorForwardBack, OUTPUT);

  pinMode(motorLeftRight,   OUTPUT);

  analogWriteFreq(1000);


  while (WiFi.status() != WL_CONNECTED) {

    delay(500);

    Serial.print(".");

  }

  Serial.println();

  Serial.print("IP: "); Serial.println(WiFi.localIP());


  server.on("/",        HTTP_GET,  handleWebpage);

  server.on("/command", HTTP_GET,  handleCommand);

  server.begin();

}


void loop() {

  handleRamping();

  server.handleClient();

}


// smoothly step throttle from rampStartValue → rampTargetValue over rampDuration ms

void handleRamping() {

  if (!isRamping) return;

  float t = float(millis() - rampStartTime) / rampDuration;

  if (t >= 1.0) {

    throttleValue = rampTargetValue;

    analogWrite(motorThrottle, throttleValue);

    isRamping = false;

  } else {

    int v = rampStartValue + (rampTargetValue - rampStartValue) * t;

    analogWrite(motorThrottle, v);

  }

}


void startRamp(int target, int duration) {

  rampStartValue  = throttleValue;

  rampTargetValue = target;

  rampDuration    = duration;

  rampStartTime   = millis();

  isRamping       = true;

  // throttleValue will be updated in handleRamping()

}


// web‑page

void handleWebpage() {

  String html = R"rawliteral(

<!DOCTYPE html><html><head>

  <title>Helicopter Control</title>

  <meta name="viewport" content="width=device-width, initial-scale=1.0">

  <style>

    body{background:#111;color:#fff;font-family:Arial;text-align:center;padding:20px}

    button{background:#00aaff;color:#fff;border:none;padding:15px;margin:5px;border-radius:8px;cursor:pointer}

    button:hover{background:#007acc}

    .grid{display:grid;grid-template-columns:80px 80px 80px;gap:10px;justify-content:center;margin-bottom:20px}

    input[type=range]{width:300px;margin:10px}

  </style>

</head><body>

  <h1>Helicopter Control</h1>

  <h2>Direction</h2>

  <div class="grid">

    <div></div><button onclick="cmd('move',0,-30)">↑</button><div></div>

    <button onclick="cmd('move',-30,0)">←</button><div></div><button onclick="cmd('move',30,0)">→</button>

    <div></div><button onclick="cmd('move',0,30)">↓</button><div></div>

  </div>

  <h2>Throttle</h2>

  <button onclick="cmd('throttle',30)">↑ Throttle</button>

  <button onclick="cmd('throttle',-30)">↓ Throttle</button>

  <h2>Speed</h2>

  <input type="range" min="0" max="100" id="speed" oninput="fetch(`/command?type=speed&value=${this.value}`)">

  <h2>Actions</h2>

  <button onclick="fetch('/command?type=takeoff')">Takeoff</button>

  <button onclick="fetch('/command?type=land')">Land</button>

  <button onclick="fetch('/command?type=stop')">Stop</button>

  <script>

    function cmd(t,x,y=0){ fetch(`/command?type=${t}&x=${x}&y=${y}`) }

    document.addEventListener('keydown',e=>{

      if(e.key=='ArrowUp')    cmd('move',0,-30);

      if(e.key=='ArrowDown')  cmd('move',0,30);

      if(e.key=='ArrowLeft')  cmd('move',-30,0);

      if(e.key=='ArrowRight') cmd('move',30,0);

      if(e.key=='w'||e.key=='W') cmd('throttle',30);

      if(e.key=='s'||e.key=='S') cmd('throttle',-30);

      if(e.key=='k'||e.key=='K') fetch('/command?type=takeoff');

      if(e.key=='l'||e.key=='L') fetch('/command?type=land');

    });

  </script>

</body></html>

)rawliteral";

  server.send(200, "text/html", html);

}


// handle incoming commands

void handleCommand() {

  String type = server.arg("type");

  if (type=="throttle") {

    throttleValue = constrain(throttleValue + server.arg("x").toInt(), 0, 1023);

    analogWrite(motorThrottle, throttleValue);

  }

  else if (type=="move") {

    movementFB = server.arg("y").toInt();

    movementLR = server.arg("x").toInt();

    analogWrite(motorForwardBack, map(movementFB,-50,50,0,1023));

    analogWrite(motorLeftRight,   map(movementLR,-50,50,0,1023));

  }

  else if (type=="speed") {

    speedValue = server.arg("value").toInt();

    // you could scale other outputs by speedValue here

  }

  else if (type=="takeoff") {

    startRamp(800, 2000);  // ramp up to 800/1023 in 2 s

  }

  else if (type=="land") {

    startRamp(0, 3000);    // ramp down to 0 in 3 s

  }

  else if (type=="stop") {

    throttleValue = 0;

    analogWrite(motorThrottle,0);

    analogWrite(motorForwardBack,0);

    analogWrite(motorLeftRight,0);

    isRamping = false;

  }

  server.send(200, "text/plain", "OK");

}


1. Overall Power & Ground

  • Motor supply (e.g. 7.4 V Li‑Po) → both L298N “VCC”

  • L298N GNDNodeMCU GNDBattery GND (common ground)

  • NodeMCU VIN (or 5 V USB) → L298N “5 V” logic supply (only if your board doesn’t onboard 5 V regulator—otherwise leave 5 V jumper in place)


2. NodeMCU → L298N Driver #1 (Main Blades)

L298N PinConnect to NodeMCUDrives Motor…
ENA+5 V (jumper ON)enable channel A
IN1D1 (GPIO 5)Blade 1 direction A
IN2D2 (GPIO 4)Blade 1 direction B
IN3D3 (GPIO 0)Blade 2 direction A
IN4D4 (GPIO 2)Blade 2 direction B
OUT1/OUT2→ Motor 1 leadsMain blade motor 1
OUT3/OUT4→ Motor 2 leadsMain blade motor 2

3. NodeMCU → L298N Driver #2 (Tail)

L298N PinConnect to NodeMCUDrives Motor…
ENB+5 V (jumper ON)enable channel B
IN1D5 (GPIO 14)Tail direction A
IN2D6 (GPIO 12)Tail direction B
OUT1/OUT2→ Tail motor leadsTail rotor motor

 

Physically hook up & program the NodeMCU

  1. Power & USB

    • Plug a Micro‑USB cable from the NodeMCU into your PC. This powers the board and gives you a serial port for uploading.

    • If Windows doesn’t see it, install the CP210x/CH340 USB‑serial driver (depending on your clone).

  2. In Arduino IDE

    • Select Tools → Board → “NodeMCU 1.0 (ESP-12E Module)”

    • Select the COM port that appeared when you plugged in.

    • Click Upload.

    • When it’s done, open the Serial Monitor at 115200 baud.

  3. Read the IP

    • In the Serial Monitor you’ll see something like:

      makefil
      …. IP: 192.168.1.42
    • That is the address your PC will use to control the helicopter.


2. Put your PC on the same Wi‑Fi

‑ Your PC (or laptop) must be connected to the same SSID (e.g. “YOUR_SSID”) that the NodeMCU joined.


3. Open the web interface in your browser

  1. In Chrome/Firefox on your PC, type the ESP’s IP into the address bar:

    http://192.168.1.42
  2. The control page will load.


4. Control with mouse or keyboard

Click any of the on‑screen buttons to move, throttle, take‑off (“Takeoff”) or land (“Land”).
‑ Or give the page keyboard focus (click once in the gray area) and use:

KeyAction
Arrow UpMove forward
Arrow DownMove backward
Arrow LeftMove left
Arrow RightMove right
W or wThrottle up (increase lift)
S or sThrottle down (decrease lift)
K or kTakeoff (smooth ramp up)
L or lLand (smooth ramp down)
SpaceStop all motors immediately


Circuit wiring summary

NodeMCU PinL298N IN pinMotor function
D1 (GPIO5)IN1 & IN2Throttle (vertical)
D2 (GPIO4)IN3 & IN4Forward / Backward
D3 (GPIO0)IN5 & IN6Left / Right
GNDGNDCommon ground
VIN or 5V5VLogic power (if needed)
  • All GNDs (NodeMCU, motor‑driver, battery) must be tied together.

  • Motor supply (e.g. 7.4 V LiPo) goes to the L298N motor‑power input.

With this sketch and wiring, you get a web‑page you can open in any browser on your LAN. Click buttons or press:

  • Arrow keys for movement

  • W / S for throttle up/down

  • K for take‑off ramp

  • L for landing ramp

Post a Comment

1 Comments