esp8266/NodeMCU Robot WORKING! untethered!

I have been building and testing out a few robots recently and want to share the great success.

I toss together a robot chassis based off 2 motors and a little motor controller and a nodeMCU/esp8266 board and a led.

once I got it to work and after the recent update the robot is running around the house controlled by my daughter who is “LOVING THIS!!!” with a nexus7 tablet

I had posted on twitter before about it being tethered to the laptop via USB but now its full roaming wifi robot

https://instagram.com/p/2zOtB4iC7P/

looking forward to more updates and more widgets from kickstarter!

4 Likes

I am also planning to do something like this.
So which esp8266 version doe you used? There are so many versions :hushed: I. Control my robot. With a arduino, the esp8266 is going to provide the internet connection

@katzworld

wow, glad you did it! Blynk team will appreciate a lot if you could also post small video showing how your setup works.

I am not big on write ups but… will work on the video but for now I will post up how I did it.

I used a NodeMCU devboard because it seemed to have more gpio then what I needed and was what I had on hand. I have worked with the esp8266 chipset before and familiar with its Power problems 3v strict. I uploaded the esp8266 standalone with the “KEY” wifi and password changed using the arduino IDE 1.6.1 with the esp8266 toolset

Onto the robot chasis its a basic “UGLY” style hack up … I used 2 motors and wheels from a Radio Shack Make It robotics Gear Motor Kit #2770174. its a 3 wheel caster style chassis with a trailing 3rd wheel. The Motor control is done with a Dual H-bridge L9110s, tossed all together on 2 bread boards. The motors are powered with 4"AA" in a sled, the MCU is powered with a similiar setup but with a on and off switch inline.

The Blynk app was loaded on the nexus tablet and the setup was prettty straight forward from there. I tied the L9110s 4 input for motor control to the corresponding output on the MCU using the pinout map https://raw.githubusercontent.com/nodemcu/nodemcu-devkit/daf9c016989ab1f1dda6cb00a3f8f2aa59c7688c/Documents/NODEMCU-DEVKIT-INSTRUCTION-EN.png there are set on digital pins. once that is complete you can test out the robot moves when the correct “motor” is triggered … toss in a few LED for good measure and poof instant happy daughter for driving around the house tickled to death that its not tethered to the laptop

hope this helps, any questions feel free to ask I will attempt to answer what I know




KaT

1 Like

I’m just wondering, can we use blynk directly with ESP8266 without arduino. Because when ESP has on chip controller why not take advantage of it.

I am using the arduino IDE only to upload the code… the esp8266/nodemcu is running standalone

Video is here sorry for the camera phone but it works

and more driving

4 Likes

Cool, thanks for sharing!

I am using a similar 2 wheel setup with caster wheel in front. I am able to control mine using virtual pins, and the following code. My steering is terrible though. Any feedback would be greatly appreciated.

/**************************************************************
 * Blynk is a platform with iOS and Android apps to control
 * Arduino, Raspberry Pi and the likes over the Internet.
 * You can easily build graphic interfaces for all your
 * projects by simply dragging and dropping widgets.
 *
 *   Downloads, docs, tutorials: http://www.blynk.cc
 *   Blynk community:            http://community.blynk.cc
 *   Social networks:            http://www.fb.com/blynkapp
 *                               http://twitter.com/blynk_app
 *
 * Blynk library is licensed under MIT license
 * This example code is in public domain.
 *
 **************************************************************
 * This example runs directly on ESP8266 chip.
 *
 * You need to install this for ESP8266 development:
 *   https://github.com/esp8266/Arduino
 * 
 * Please be sure to select hte right ESP8266 module
 * in the Tools -> Board menu!
 *
 * Change WiFi ssid, pass, and Blynk auth token to run :)
 *
 **************************************************************/

#define BLYNK_PRINT Serial    // Comment this out to disable prints and save space
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>

// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
char auth[] = "authenticationkey";

//Standard PWM DC control
int E1 = 5;     //M1 Speed Control D1 Motor A
int E2 = 4;     //M2 Speed Control D2 Motor B
int M1 = 0;    //M1 Direction Control D3 Motor A
int M2 = 2;    //M2  Direction Control D4 Motor B



/* --GPIO Define
2     function initGPIO()
3     --1,2EN     D1 GPIO5
4     --3,4EN     D2 GPIO4
5     --1A  ~2A   D3 GPIO0
6     --3A  ~4A   D4 GPIO2
*/  

void setup()
{
   pinMode(5, OUTPUT);//power to motor
   pinMode(4, OUTPUT);//power to motor
   pinMode(0, OUTPUT);//Reverse Motor Direction
   pinMode(2, OUTPUT);//Reverse Motor Direction
   
  Serial.begin(9600);
  Blynk.begin(auth, "wifi", "password");
}
// This function will be called every time
// when App writes value to Virtual Pin 1



  BLYNK_WRITE(V1) {
  int x = param[0].asInt();
  int y = param[1].asInt();

  // Do something with x and y
  Serial.print("X = ");
  Serial.print(x);
  Serial.print("; Y = ");
  Serial.println(y);



   if (y > 30){
  analogWrite (E1,-y);      //PWM Speed Control 4
  digitalWrite(M1,LOW);    
  analogWrite (E2,-y+abs(x/2));    //5
  digitalWrite(M2,HIGH);
  }

   else if (y < -30){
  analogWrite (E1,y+abs(x/2));      //PWM Speed Control 4
  digitalWrite(M1,HIGH);    
  analogWrite (E2,y);    //5
  digitalWrite(M2,LOW);
  }

/*  if (y > 30 && x < -30){
  analogWrite (E1,1-(y+abs(x)));      //PWM Speed Control
  digitalWrite(M1,LOW);    
  analogWrite (E2,1-(y-abs(x)));    
  digitalWrite(M2,HIGH);
  }

   if (y > 30 && x > 30){
   analogWrite (E1,1-(y-abs(x)));      //PWM Speed Control
  digitalWrite(M1,LOW);    
  analogWrite (E2,1-y+abs(x));    
  digitalWrite(M2,HIGH);
  }*/
 
 /* else if (x < -30 && y > 0){
 // analogWrite (E1,1+(y-abs(x)));      //PWM Speed Control
 analogWrite (E1,-y-abs(x));
  digitalWrite(M1,LOW);    
  analogWrite (E2,-y+abs(x));   
  digitalWrite(M2,HIGH);
  }

  else if (x > 30 && y > 0){
  analogWrite  (E1,-y+abs(x));       //PWM Speed Control
  digitalWrite(M1,LOW);    
  analogWrite (E2,-y-abs(x));   
  digitalWrite(M2,HIGH);
  }*/

   
   else {
   analogWrite (E1,0);
   analogWrite (E2,0);
  }
}
  

void loop()
{
  Blynk.run();

}

I think you need to think about debouncing your steering. The direct control is probably what gives it a bad temper. Maybe even calculate an average of some steering motions. A bit like I’ve done with my LDR project. I take a couple readings, average it out and then decide how light or dark it is. It may be something to help you too. I’d love to build a robot but I don’t currently have the parts for it (nor the time).

Thanks for the feedback. I was hoping to decrease the speed one wheel with respect to the distance moved in the X Direction. I can show you a code I used for Romeo BLE to make this work. They have a different set of libraries that hide some of the magic functions that I was able to call to make the abs() formula work.

I feel you on the time though. I will look through the LDR project when I have a chance. I have found that I learn a lot when I have the discipline to just sit down and research what has already been done lol. Thanks.

A quick view for the abs() function also gave me the little insight that you should do the math outside your abs() function and not in it, more like so:

int valueY = x/2
analogWrite (E1,y+abs(valueY));

Not sure why, but they say it on the forum, so there must be some truth in there, lol. You may also be interested in using the map() function. It can map an input range from one range to another:

int valueX = param.asInt();
int valueY = map(valueX, 0, 1023, 0, 255);

This wil translate the incoming range of 0 - 1023 from the valueX var to a range of 0 - 255, the Arduino will do the math for you. It may be of help for you. It also works for back and forth:

maps(valueX, 1023, 0, 0, 255);

That way you can easily reverse a given range of numbers. I use it to control my Lego trains because that Infrared protocol has silly numbers which go from 0 - 7 for speed and for reverse speed from 16 - 9 (slow to fast).

Thanks a lot. I’m very new to programming so this is very helpful to me. I have been reading up on the map function and I’ve been wondering what cool things I could do with it besides scaling signals for the motor speed. In this case, it sounds like you are suggesting I could map the x variable to the y variable to make the steering proportional which does sound logical. The key to differential steering is that the difference in the speed of the motors is proportional to how far left or right you move the joystick so that the car drifts smoothly left to right while still being able to drive forward or backward. Also, now that I have had sleep, I realize how bad my math was on that absolute value. I was trying to slow it down 50%, so maybe (E1,y+abs(valueY)/2)?

So what you are saying is that if Motor1 moves at speedY and Motor2 moves at speedX and you need to stir left or right, the motor speed of one motor has to be proportional to the speed of another? If I make a really silly table out of that of 5 speeds, would I end up with something like this? :

Motor1 | Motor2
1 | 1 > going straight ahead
2 | 1 > beginning a turn
3 | 1 > still turning
4 | 2 > turning faster
5 | 2 > still turning faster

etc. ?

I haven’t used the Joystick Widget yet, I used a slider for my Lego trains, but I guess I just as well could use the Joystick. It would even make more sense I guess.

I do apologize for my lack of clearness lol. What I mean is that the DIFFERENCE in speed is proportional to the horizontal control on the analog joystick. As you move the joystick left or right, one wheel spins slower causing the car to turn left or right. I have it working a robot I made with the Romeo BLE board, but it uses a different library with a lot of stuff that I’m worried may complicate things or conflict with Im trying to do with blynk and the motor control on the ESP8266. I may just add blynk to that code and try to upload it to ESP8266 and just start throwing out what doesn’t belong. I will upload that code later. Its just more tedious because much of the functions are defined in their libraries so its not as easy to follow along as the blynk libraries.

The table you made is pretty accurate as far as the end result.

This is what I used for Romeo BLE board and the GoBLE App. It uses blue tooth BLE. There are some library files that have to be loaded for it to work and I’m really not sure what could be stripped and applied to the Blynk and ESP8266 Stand Alone setup.

/*********************************************************************
 * DFMobile GoBLE_APP
 *********************************************************************
 * This example is aimed to control DFMobile basic motion by APP GoBle
 * Created 2015-3-12
 * By Gavin
 * 
 * Button ID:
 * SWITCH_UP      -- 1
 * SWITCH_RIGHT   -- 2
 * SWITCH_DOWN    -- 3
 * SWITCH_LEFT    -- 4
 * SWITCH_SELECT  -- 5
 * SWITCH_START   -- 6
 ********************************************************************/
#include "DFMobile.h"
DFMobile Robot (4,5,7,6);
#include "Metro.h"
// Speed is modified by mapping vlaue of GamePad Stick
int LeftWheelSpeed;
int RightWheelSpeed;

//GoBle configuration library, help user to identify control button and stick on Gamepad
#include "GoBLE.h"
int joystickX, joystickY;
int buttonState[6];

int ledPin = 13;

void setup (){
  Robot.Direction (LOW,HIGH);// (left direction,right direction); 
  pinMode(ledPin,OUTPUT);
  Goble.begin();
  Serial.begin(115200);
}

void loop (){
  if(Goble.available()){
    joystickX = Goble.readJoystickX();  
    joystickY = Goble.readJoystickY();
//    Serial.print("joystickX: ");
//    Serial.print(joystickX);
//    Serial.print("joystickY: ");
//    Serial.println(joystickX);

    buttonState[SWITCH_UP]     = Goble.readSwitchUp();
    buttonState[SWITCH_LEFT]   = Goble.readSwitchLeft();
    buttonState[SWITCH_RIGHT]  = Goble.readSwitchRight();
    buttonState[SWITCH_DOWN]   = Goble.readSwitchDown();
    

    //enable to map the value from (1~255) to (-255~255)
    int SpeedX=2*joystickY-256; //Changed X to Y because joystick is mapped wrong. SpeedX will now correspond to the horizontal joystick movement.
    int SpeedY=2*joystickX-256; //Changed Y to X because joystick is mapped wrong. SpeedY will now correspond to the vertical joystick movement.
    Serial.print("Speed: ");
    Serial.print(SpeedX);
    Serial.print("  ");
    Serial.println(SpeedY);
    /* Code assumes M1 is Left Motor and M2 is Right Motor, but right now I have the Left Motor wired to M2 and Right Motor to M1. */

  if (SpeedX<-50){           //when joystick X is moved left this code causes the robot to rotate left
      //LeftWheelSpeed=SpeedX-80;                 
     // RightWheelSpeed=-SpeedX-80;
      LeftWheelSpeed = (SpeedY+abs(SpeedX))*3/4;               
      RightWheelSpeed = (SpeedY-abs(SpeedX))*3/4 ;   //added absolute value to make sure value returns to 0 eitherway
      Robot.Speed (LeftWheelSpeed,RightWheelSpeed);
    }  
  
    else if (SpeedX>50){           //when joystick X is right this code causes the robot to rotate right
      //LeftWheelSpeed=SpeedX-80;                 
     // RightWheelSpeed=-SpeedX-80;
      LeftWheelSpeed = (SpeedY-abs(SpeedX))*3/4;               //added absolute value to make sure value returns to 0 eitherway
      RightWheelSpeed = (SpeedY+abs(SpeedX))*3/4;
      Robot.Speed (LeftWheelSpeed,RightWheelSpeed);
    }
  
    else if (SpeedY>50 || SpeedY<-50){           
      LeftWheelSpeed=SpeedY*3/4;               //when joystick Y is moved up or down
      RightWheelSpeed=SpeedY*3/4;
      Robot.Speed(LeftWheelSpeed,RightWheelSpeed);
    }
    else if (SpeedX==0 && SpeedY==0){ //When joystick is in neutral position
      Robot.Speed(0,0);
    }
    else if (SpeedY>50 && buttonState[2] == PRESSED){           
      LeftWheelSpeed=SpeedY;               //when joystick Y is Right
      RightWheelSpeed=SpeedY;
      Robot.Speed(LeftWheelSpeed,RightWheelSpeed);
       }
     else if (buttonState[3] == PRESSED || SpeedY<-50){           
      LeftWheelSpeed=SpeedY;               //when joystick Y is moved Left
      RightWheelSpeed=SpeedY;
      Robot.Speed(LeftWheelSpeed,RightWheelSpeed);
  }
       else if (SpeedY>50 && buttonState[5] == PRESSED){           
      LeftWheelSpeed=0;               //when joystick Y is Right
      RightWheelSpeed=SpeedY;
      Robot.Speed(LeftWheelSpeed,RightWheelSpeed);
      }
     else if (buttonState[6] == PRESSED || SpeedY<-50){           
      LeftWheelSpeed=SpeedY;               //when joystick Y is moved Left
      RightWheelSpeed=0;
      Robot.Speed(LeftWheelSpeed,RightWheelSpeed);
       }
    
    if (buttonState[1] == PRESSED){
        digitalWrite(ledPin,HIGH);  
    }
    if (buttonState[1] == RELEASED){
        digitalWrite(ledPin,LOW);//makes pin go low
    }
  }
}

Cool, I see where you are going (left, right and forward, LOL).

I’ll think about that for a bit, but it should be quite doable with an ESP or Arduino. I think the logic is sound, but I have to think about it for a bit.

What would happen if you just do a simple reverse mapping? Something along the lines of this:

BLYNK_WRITE(V0)
{
  // Start or stop Robot button (simple push button, switch or push at your leisure)
  int StartStop = param.asInt();
  if(StartStop == 1)  // Starting
  {
    analogWrite(E1, 30);
    analogeWrite(E2, 30);
  }
  else // Stopping
  {
    analogWrite(M1, 0);
    analogWrite(M2, 0);
  }
}

BLYNK_WRITE(V1)
{
  // param[x|y] goes from 0 - 255, center of joystick is 127, you probably could use a slider here too, maybe even easier?
  int speedX = param[0].asInt();
  int speedY = param[1].asInt();

  // Turning left would map out from 0 - 127
  // Turning right would map out fro 128 - 255
  // Somewhere in the middle you have to go straight, 20 or so?
  // so left would be from 0 - 107, right 138 - 255

  // Map left/right values of joystick to left/right turning variables
  int speedForM1 = map(speedX, 0, 255, 0, 107);
  int speedForM2 = map(speedY, 0, 255, 138, 255);

  // Fyi, constrain() makes sure values don't go above/below specified values
  int correctedSpeedForM1 = constrain(speedX, 30, 255);
  int correctedSpeedForM2 = constrain(speedY, 30, 255);

  // Motor should be minimum of 30 + the amount to maximum of 255)
  analogWrite(M1, correctedSpeedForM1);
  analogWrite(M2, correctedSpeedForM2);
}

This is written up in about 10 minutes all form the top of my head, but you may be able to see the logic in this. This way the Robot will always have a minimum speed of 30, if you fancy this up you could set the minimum speed with a slider for better control. The map() X and Y are probably correct, but I’m not sure.

1 Like

This strategy looks amazing. I’m going to get back in the lab after work tomorrow and play around with this idea some. I will followup with results. Thank you for your awesomeness!

I was thinking you could use UP-DOWN parts to vary the robot in speed to instead of pushing a button and having it go one speed. That way you can set limits too. May be nice if you don’t want kids moving your Bot at full speed, lol.

2 Likes