Introduction: WiFi Voice Controlled Robot With NodeMCU

About: Engineer, writer and forever student. Passionate to share knowledge of electronics with focus on IoT and robotics.

On my last tutorial, Voice Activated Control With Android and NodeMCU we explored how to develop our own App on an Android smartphone to control locally (using buttons or voice) smart home devices. But How about starting from there and instead home devices we control motors? And still better, how about having those motors driving a differential robot? That is exactly what we will develop here, a WiFi Voice Controlled Robot using as a controller, our old bud NodeMCU!

The above block diagram shows what will be done in general and the movie below shows the final project working:

Please consider that one of my motors was with very little torque. Spite the result seems a little bit rare, the robot is working properly. As soon I change the motor I will update the video. Sorry about that and thanks.

    Step 1: Bill of Material (BoM)

    All values are referencial in USD
    1. NodeMCU ESP8266-12E ($8.79)
    2. 400-point Experiment Breadboard Breadboard ($ 4.97)
    3. H-Bridge L293D ($2.17)
    4. Motor Robot Car Chassis Kit ($13.00)
    5. Male-Female Dupont Cables ($1.00)
    6. Portable Charger 5VDC 3000mAh Power Bank ($10.00)
    7. External 9VDC Battery

    ..... and of course, any Android Smartphone or Tablet!

    Step 2: The H-Bridge L293D

    In order to drive the motors we will use the L293D a Quadruple Half-H Drivers H-Bridge.

    According its Datasheet, The L293 and L293D devices are quadruple high-current half-H drivers. The L293 is designed to provide bidirectional drive currents of up to 1 A at voltages from 4.5 V to 36 V. The L293D is designed to provide bidirectional drive currents of up to 600-mA at voltages from 4.5 V to 36 V. Both devices are solenoids, DC and bipolar stepping motors, as well as supply applications.

    We will use the IC directly with the NodeMCU, not using a shield, that is also common.

    Our Robot has two wheels, that are driven by 2 DC motors:

    • LEFT Motor
    • RIGHT Motor

    We will connect the motors to our H-Bridge as shown at above diagram. The NodeMCU will have 6 GPIOs that will command those motors.

    int rightMotor2 = 13;   // D7 - right Motor -
    int rightMotor1 = 15;   // D8 - right Motor +
    int leftMotor2 = 0;     // D3 - left Motor - 
    int leftMotor1 = 2;     // D4 - left Motor +
    int eneLeftMotor = 12;  // D6 - enable Motor Left
    int eneRightMotor = 14; // D5 - enable Motor Right
    

    For example, to drive LEFT motor FORWARD you must put:

    • HIGH at pin D4 (left Motor +) and
    • LOW at pin D3 (left Motor -)

    For the RIGHT Motor you must do the opposite:

    • HIGH at pin D8 (right Motor +) and
    • LOW at pin D7 (left Motor -)

    Due the way that my motors are assembly and the robot moves, the above combination will drive both motors in the same direction pushing the Robot forward.

    Look the above diagram that define how the robot will move. This is important for proper definition of your variables.

    To control the H-Bridge properly, you must also working with the enable pins. The above combination that will drive robot forward will only work if the enable pins (eneLeftMotor and eneRightMotor) are both in HIGH. You can connect those L293D pins (1 and 9) directly to +VCC and forget them. I do not like it, because for a full stop, those pins are better to be in LOW. Also, associating the enable pins to a NodeMCU PWM digital outputs will allow you to control motor speed (using digital values as HIGH and LOW, will set the speed to MAX and ZERO, respectively).

    So, for creating a function to drive our robot forward, we should pu together a code like this:

    void forwardMotor(void)   
    {
      digitalWrite(eneLeftMotor,HIGH);
      digitalWrite(eneRightMotor,HIGH);
        
      digitalWrite(leftMotor1,HIGH);
      digitalWrite(leftMotor2,LOW);
      digitalWrite(rightMotor1,HIGH);
      digitalWrite(rightMotor2,LOW);
    }
    

    Step 3: Moving the Robot Around

    In the previous step we learned how we can move the robot forward, let's think now how to move it around.

    We will define 5 possible commands:

    1. STOP
    2. Turn to LEFT
    3. Turn to RIGHT
    4. REVERSE
    5. FORWARD

    The first command "STOP" is simple to accomplish. All H-Bridge inputs must be LOW, this way the motors will not be moving:

    void stopMotor(void)   
    {
      digitalWrite(eneLeftMotor,LOW);
      digitalWrite(eneRightMotor,LOW);
    
      digitalWrite(leftMotor1,LOW);
      digitalWrite(leftMotor2,LOW);
      digitalWrite(rightMotor1,LOW);
      digitalWrite(rightMotor2,LOW);
    }
    

    The same way let's think about turn the robot to one direction, let's say LEFT. Consider that the robot is going Forward, if we want to turn to left, we can have two situations:

    1. Stop LEFT motor and keep RIGHT going FW
    2. Reverse LEFT Motor and keep RIGHT going FW

    At first situation, the robot will do an arc trajectory to the left. On the second, the robot will turn in its axy to the left. We will implement the second one.

    void leftMotor(void)   
    {
      digitalWrite(eneLeftMotor,HIGH);
      digitalWrite(eneRightMotor,HIGH); 
      
      digitalWrite(leftMotor1,LOW);
      digitalWrite(leftMotor2,HIGH);
      digitalWrite(rightMotor1,HIGH);
      digitalWrite(rightMotor2,LOW);
    }
    

    The remain commands follow the same logic. The above table resume the 5 commands.

    Step 4: Completing the HW

    Follow the above diagram and complete the Robot HW.

    You can make simple tests to see you your code are OK.

    It's good for simplify tests, to introduce a "Button" for starting your robot. We will install it at NodeMCU port D0 as shown at diagram.

    You can use the below program for testing your robot movements:

    // Set Motor Control Pins
    int rightMotor2 = 13;    // D7 - right Motor -
    int rightMotor1 = 15;    // D8 - right Motor +
    int leftMotor2 = 0;    // D3 - left Motor - 
    int leftMotor1 = 2;    // D4 - left Motor +
    int eneLeftMotor = 12;  // D6 - enable Mortor Left
    int eneRightMotor = 14; // D5 - enable Mortor Right
    
    int buttonPin = 16; // D0
    
    void setup()
    {
      Serial.begin(115200);
    
      pinMode(buttonPin, INPUT_PULLUP);
      pinMode(eneLeftMotor, OUTPUT); 
      pinMode(eneRightMotor, OUTPUT); 
      pinMode(leftMotor1, OUTPUT); 
      pinMode(leftMotor2, OUTPUT);  
      pinMode(rightMotor1, OUTPUT);  
      pinMode(rightMotor2, OUTPUT);  
    
      digitalWrite(eneLeftMotor,LOW);
      digitalWrite(eneRightMotor,LOW);
      digitalWrite(leftMotor1,LOW);
      digitalWrite(leftMotor2,LOW);
      digitalWrite(rightMotor1,LOW);
      digitalWrite(rightMotor2,LOW);
          
      while (digitalRead(buttonPin))  // Wait for button to be pressed to move on 
      {  
      }
    }
    
    void loop()
    {
      forwardMotor();
      delay (5000);
      stopMotor();
      delay (200);
      leftMotor();
      delay (3000);
      stopMotor();
      delay (200);
      forwardMotor();
      delay (5000);
      stopMotor();
      delay (200);
      rightMotor();
      delay (3000);
      stopMotor();
      delay (200);
      reverseMotor();
      delay (5000);
      stopMotor();
      delay (200);
    } 
    
    /* command motor forward */
    void forwardMotor(void)   
    {
      digitalWrite(eneLeftMotor,HIGH);
      digitalWrite(eneRightMotor,HIGH);
        
      digitalWrite(leftMotor1,HIGH);
      digitalWrite(leftMotor2,LOW);
      digitalWrite(rightMotor1,HIGH);
      digitalWrite(rightMotor2,LOW);
    }
    
    /* command motor backward */
    void reverseMotor(void)   
    {
      digitalWrite(eneLeftMotor,HIGH);
      digitalWrite(eneRightMotor,HIGH);
      
      digitalWrite(leftMotor1,LOW);
      digitalWrite(leftMotor2,HIGH);
      digitalWrite(rightMotor1,LOW);
      digitalWrite(rightMotor2,HIGH);
    }
    
    /* command motor turn left */
    void leftMotor(void)   
    {
      digitalWrite(eneLeftMotor,HIGH);
      digitalWrite(eneRightMotor,HIGH); 
      
      digitalWrite(leftMotor1,LOW);
      digitalWrite(leftMotor2,HIGH);
      digitalWrite(rightMotor1,HIGH);
      digitalWrite(rightMotor2,LOW);
    }
    
    /* command motor turn right */
    void rightMotor(void)   
    {
      digitalWrite(eneLeftMotor,HIGH);
      digitalWrite(eneRightMotor,HIGH);
      
      digitalWrite(leftMotor1,HIGH);
      digitalWrite(leftMotor2,LOW);
      digitalWrite(rightMotor1,LOW);
      digitalWrite(rightMotor2,HIGH);
    }
    
    /* command motor stop */
    void stopMotor(void)   
    {
      digitalWrite(eneLeftMotor,LOW);
      digitalWrite(eneRightMotor,LOW);
    
      digitalWrite(leftMotor1,LOW);
      digitalWrite(leftMotor2,LOW);
      digitalWrite(rightMotor1,LOW);
      digitalWrite(rightMotor2,LOW);
    }
    

    When you press the button, the robot will start doing the movements defined on loop(). it will continuous until you press "Reset" on NodeMCU. Pressing the button, the cycle repeats.

    The code can be download from my GitHub:

    WiFi_Robot_NodeMCU_Android_Voice_Motor_tests

    Step 5: Assembling the Robot Body

    1. Take the Kit (Chassis, 2 Wheels, 2 DC Motors, 1 coaster
    2. Take out the Chassis cover (or leave it)
    3. Solder 2 10 cm wires (Red and Black) at each motor
    4. Fixed the motors at chassis
    5. Assembly the coaster
    6. Joint the motor wires to electronics (L293D)
    7. Fix the 9V battery on the chassis
    8. Fix the 5V battery under the chassis

    Step 6: Connecting the NodeMCU to Local WiFi

    Let's connect the NodeMCU to our local WiFi and check its IP address. For that, let's use the below small program:

    #include <ESP8266WiFi.h>
    WiFiClient client;
    WiFiServer server(80);
    const char* ssid = "YOUR SSID";
    const char* password = "YOUR PASSWORD";
    
    void setup() 
    {
      Serial.begin(115200);
      connectWiFi();
      server.begin();
    }
    
    void loop() 
    {
    }
    
    /* connecting WiFi */
    void connectWiFi()
    {
      Serial.println("Connecting to WIFI");
      WiFi.begin(ssid, password);
      while ((!(WiFi.status() == WL_CONNECTED)))
      {
        delay(300);
        Serial.print("..");
      }
      Serial.println("");
      Serial.println("WiFi connected");
      Serial.println("NodeMCU Local IP is : ");
      Serial.print((WiFi.localIP()));
    }
    

    On the Serial monitor you can see its IP Address. Take note of it. We will need it to connect the Android App.

    The code can be download from my GitHub:

    NodeMCU_Connection_Test_EXT

    Step 7: Completing the Code

    To move our Robot, we need to receive commands from the Android device. for that a command variable will be defined:

    String  command ="";

    So, for example, If the Android App send as a command: "forward", the robot must move forward:

    if (command == "forward")
    {
      forwardMotor();
    }

    The same must be done for all possible commands received.

    Download the complete code: WiFi_Robot_NodeMCU_Android_Voice_EXT from my GitHub.

    Change the dummy wifi credentials, with your own:

    const char* ssid = "YOUR SSID";
    const char* password = "YOUR PASSWORD";
    

    Upload the code to your NodeMCU and that's it! You can check on Serial Monitor if the program is running, but, noting more. Let the program run for testing of your app on next step.

    Step 8: The Android App: "Designer Tab"

    We will use the MIT App Inventor to develop our Android App.

    Main Components on Screen 1 (see above photo):

    • User Interface:
      • Input of IP Address
        • TextBox named "IP_Address"
      • 5 Command Buttons:
        • forward
        • reverse
        • right
        • left
        • stop
      • Voice Input Button
        • Voice_Input
    • Non Visible Components:
      • Web1
      • SpeachRecognizer1
      • TextToSpeach1
    • Other:
      • Text Box:
        • Speach_To_Text
      • Label:
        • Comm_Status

    Step 9: The Android App: Buttons

    We must at Blocks tabs, create 5 Buttons. All of them will follow the structure of the one shown at the photo.

    This button block is called when the Forward Button ("UP") is pressed:

    • When forward.Click

    For example, when you click on Button forward, 3 actions will be performed:

    • A command will be send on the format: http:/ip_address*/forward
    • An "echo" on the same format is expected
    • A sound "message" will be read by the App: in the case: "forward"

    * The IP_Address will be the one that you enter on Screen 1. The default is 10.1.0.3, so the real message would be: http:/10.0.1.3/forward

    You can use any message you want, or even took this block out. It is optional for the project.

    Step 10: The Android App: Voice Recognition

    The above blocks show the voice recognition code for our App.

    Note that, for any voice command entered, the result will be a lower case command. This will facilitate the voice recognition decoding on NodeMCU.

    For example, if you want to move your robot forward, a word or sentence must be sent to be exactly recognized by NodeMCU code. I will send a command in Portuguese (my language), but you must send it on your own language (the one that is set-up on your Android device), and change the NodeMCU code properly. At bellow example, The code would recognize any one of the words: "forward", "frente" or ä frente"

    if (command == "forward" || command == "frente" || command == "a frente")  
    {
      forwardMotor();
    }
    

    So, when I say "forward", the App will send for example: http:/10.0.1.10/forward and the NodeMCU will take what is received after the "/", that is a command "forward". As we saw above, with this command, the function forwardMotor() will be called.

    Step 11: The Android App: Error Manipulation

    If an error occur, for example when you say a voice command not recognized by the NodeMCU, the above block will write the error details on the last line (Comm_Status) of the App as shown at above photo.

    Step 12: Final Test

    You can create your App step by step as shown on the previous steps or upload my complete project (.aia) at MIT App Inventor modifying it for your needs. Also If you do not have experience on developing Android apps, you can execute the .apk file directly on your Android device.

    Both, the .aia and .apk files can be downloaded from my GitHub:

    WiFi_Voice_Robot_Ctrl_V2.aia

    WiFi_Voice_Robot_Ctrl_V2.apk

    Below video show some motor tests with the App:

    Step 13: Conclusion

    As always, I hope this project can help others find their way in the exciting world of electronics, robotics and IoT!

    Please visit my GitHub for updated files:

    WiFi-Voice-Controlled-Robot

    For more projects, please visit my blog: MJRoBot.org

    Saludos from the south of the world!

    See you at my next instructable!

    Thank you

    Marcelo