I just received my NodeMCU Motor Shield to go with my NodeMCU v1 ESP12e development board and robot chassis.

So the board has a bunch of screw terminals on it – A+, A-, B+ and B- to connect two motors, and then VM/GND (up to 9v for the microcontroller) and VIN/GND (up to 36v for the motors). However the mostly undocumented feature is that if you jumper the VIN/VM pins near to the power switch, you can supply up to 9v to VIN/GND and it will feed that into the motors and also into the NodeMCU’s 3.3v regulator. I’ve used this configuration with two 18650 Li-Ion batteries that provide about 8v when fully charged (nominal 3.7v each).

Alternatively, but with some caution you can power the motors and the ESP12e via the NodeMCU’s micro USB port.

I had a poke around with a multimeter and found that if you put 8v into the VIN screw terminal and jumper the VIN/VM pins you get:

  • 8v from the VM screw terminal;
  • 8v from the VIN pin on the nodemcu itself;
  • 8v from the two VIN pins on the motor shield;
  • 3.3v from the three 3.3v pins on the modemcu;
  • 3.3v from the 3.3v pin on the motor shield;

The motors seem to pull whatever they need – mine are 6v motors and they’re pulling about 6.25v when full on (1023 PWM) from the A+/B+ screw terminals.

If you power from USB the VIN pins run at about 4.4v and the motors run slower. The power button also does nothing. I think I’ll just use USB for programming rather than power, but you could use a USB power bank I guess, but at least it means you don’t have to unplug the NodeMCU from the motor shield to reprogram it, although it is a bit tight as the USB connector ends up only a few millimeters from the screw terminal blocks.

I initially wrote my own Arduino sketch which is a webserver that runs on the ESP12e and contains forward/backward/right/left/stop buttons.

// include libraries
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

// configure server
ESP8266WebServer server(80);

const char *form = "<center><form action='/'>"
"<button name='dir' type='submit' value='4'>Forward</button><br>"
"<button name='dir' type='submit' value='1'>Left</button> "
"<button name='dir' type='submit' value='2'>Right</button><br>"
"<button name='dir' type='submit' value='3'>Reverse</button><p>"
"<button name='dir' type='submit' value='5'>Stop</button>"
"</form></center>";

void stop(void)
{
    analogWrite(5, 0);
    analogWrite(4, 0);
}

void forward(void)
{
    analogWrite(5, 1023);
    analogWrite(4, 1023);
    digitalWrite(0, HIGH);
    digitalWrite(2, HIGH);
}

void backward(void)
{
    analogWrite(5, 1023);
    analogWrite(4, 1023);
    digitalWrite(0, LOW);
    digitalWrite(2, LOW);
}

void left(void)
{
    analogWrite(5, 1023);
    analogWrite(4, 1023);
    digitalWrite(0, LOW);
    digitalWrite(2, HIGH);
}

void right(void)
{
    analogWrite(5, 1023);
    analogWrite(4, 1023);
    digitalWrite(0, HIGH);
    digitalWrite(2, LOW);
}

void handle_form()
{
    // only move if we submitted the form
    if (server.arg("dir"))
    {
        // get the value of request argument "dir"
        int direction = server.arg("dir").toInt();

        // chose direction
        switch (direction)
        {
            case 1:
                left();
                break;
            case 2:
                right();
                break;
            case 3:
                backward();
                break;
            case 4:
                forward();
                break;
            case 5:
                stop();
                break;
        }

        // move for 300ms, gives chip time to update wifi also
        delay(300);
    }
    
    // in all cases send the response
    server.send(200, "text/html", form);
}

void setup()
{
    // connect to wifi network
    WiFi.begin("essid", "passphrase");

    // static ip, gateway, netmask
    WiFi.config(IPAddress(192,168,1,2), IPAddress(192,168,1,1), IPAddress(255,255,255,0));

    // connect
    while (WiFi.status() != WL_CONNECTED)
    {
        delay(200);
    }
  
    // set up the callback for http server
    server.on("/", handle_form);

    // start the webserver
    server.begin();

    pinMode(5, OUTPUT); // 1,2EN aka D1 pwm left
    pinMode(4, OUTPUT); // 3,4EN aka D2 pwm right
    pinMode(0, OUTPUT); // 1A,2A aka D3
    pinMode(2, OUTPUT); // 3A,4A aka D4
}

void loop()
{
    // check for client connections
    server.handleClient();
}

I also tried the Blynk joystick code with my Android phone. I’m still not happy with either solution though, as I need a way to move in more than one direction at once to give a smooth turning action – for example I can rotate left/right, but can’t drive forward at the same time, so I need to play with timings a bit more. Also I found that PWM at 512 seemed quite slow, so sticking with ultra-fast 1023 for full speed motors!

There’s a bunch of pins broken out on the motor shield – GPIO 0-8, UART, ADC, SPI etc. so you could add a servo or LED’s. Here is another useful post, and here is the pretty useless documentation.