Stepper Motor Rover + HomeBrew Lidar

Thought it may be of interest to document a rover platform using Stepper Motors as drive linked to an ESP32 sporting a Web gui to control movement and display Sensor data.

It will map with LIDAR, the LIDAR will be a home brew system ....still on order....

Its still early stages, however at least the mechanics and Gui are functional.

This consists of a 3D printed chassis (back-end still in blender) holding two stepper motors ,
Its controlled with an ESP32 with A4988 Stepper motor drivers.

.... as this is the 5th stepper motor I have used, each time printing complete new wheels ... had that eureka moment to just make an oversized hole at centre of wheel and make insert adaptors for the various steppershaft diameters ... bingo-bongo print time goes from 2 hours down to 5 mins/wheel.

As breadboard is not the best solution the circuit has been migrated to perf board :-

and wiring loom worked out neater than anticipated :-

Present Code.... to get it up and working :-

#include <WiFi.h>

const char* ssid         = "My";
const char* password = "RobotLab";
int num=4;
int stepper=15;
int sliderint=0;
int gridx=0; int gridy=0;
int nemaA,nemaB;

WiFiServer server(80);

void setup()
 pinMode(16, OUTPUT);      pinMode(17, OUTPUT);      pinMode(18, OUTPUT);    pinMode(19, OUTPUT);   

    // We start by connecting to a WiFi network
    Serial.println();    Serial.print("Connecting to ");    Serial.println(ssid);    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) {  delay(100);   Serial.print("."); }
    Serial.println("");    Serial.println("WiFi connected");    Serial.println("IP address: ");    Serial.println(WiFi.localIP());    

void loop(){
  String currentLine = "";   
  String slidera = "blahblahblah";  sliderint=250;  // random string content probably not needed...

 WiFiClient client = server.available();   // listen for incoming clients
  if (client) {                             // if you get a client
   // Serial.println("new client");           // print a message out the serial port
               // make a String to hold incoming data from the client
    while (client.connected()) {            // loop while the client's connected
      if (client.available()) {             // if there's bytes to read from the client,
        digitalWrite(13, HIGH);
        char c =;             // read a byte, then
       // Serial.write(c);                    // print it out the serial monitor
        if (c == '\n') {                    // if the byte is a newline character
          if (currentLine.length() == 0) {
            client.println("<!DOCTYPE html>");
            client.print("<html><head><style>div { width: 250px; height: 250px; border: 1px solid black;}</style></head>");          
            client.print("<body><div onmousedown='showCoords(event)' ></div><p id='demo'></p>");
            client.print("<script>function showCoords(event) {");
            client.print("var x = event.clientX;");
            client.print("var y = event.clientY*250;");
            client.print("var coor =  x +  y;");   
            client.print("document.getElementById('demo').innerHTML = location.href= coor+'end';}</script> ");
            // break out of the while loop:
          } else {  currentLine = "";   }
        } else if (c != '\r') { currentLine += c;  }


         if (currentLine.startsWith("GET") && currentLine.endsWith("end")) { slidera[0]=currentLine[5];slidera[1]=currentLine[6];slidera[2]=currentLine[7];slidera[3]=currentLine[8];slidera[4]=currentLine[9];slidera[5]=0;sliderint=slidera.toInt();Serial.print(currentLine );Serial.print(">");Serial.print(sliderint);gridy=sliderint/250;gridx=sliderint-(gridy*250);Serial.print(" x>");Serial.print(gridx);Serial.print(" y>");Serial.println(gridy);}
    // close the connection:
   if (millis()-nemaA >=(250-gridx)/10)    { MOTOR_A()    ; nemaA=millis();     }
   if (millis()-nemaB >=(250-gridy)/10)    { MOTOR_B()    ; nemaB=millis();      }
void MOTOR_A()
{  if (gridx>150) {digitalWrite(16, LOW) ;  digitalWrite(19, HIGH); delayMicroseconds(1000);digitalWrite(19,LOW ); delayMicroseconds(1000);  }  
   if (gridx<150) {digitalWrite(16, HIGH);  digitalWrite(19, HIGH); delayMicroseconds(1000);digitalWrite(19,LOW ); delayMicroseconds(1000);  }  
void MOTOR_B()
{  if (gridy>150) {digitalWrite(16, LOW) ;  digitalWrite(18, HIGH); delayMicroseconds(1000);digitalWrite(18,LOW ); delayMicroseconds(1000);  }  
   if (gridy<150) {digitalWrite(16, HIGH);  digitalWrite(18, HIGH); delayMicroseconds(1000);digitalWrite(18,LOW ); delayMicroseconds(1000);  }  

The highlighted regions in above code enables the placing and extraction of variables between Web Gui and ESP32 (its the key part to the project, which is the reason for sharing this info to make it simple/easier for other).

The ESP32 spits out a local IP Address .... (in my case
All you need to do then is use a browser window pointed to this address and the Rover can be controlled by clicking the mouse pointer in the box.
The xy coords give direction and speed. works great.

The end idea is to display a graphic in the box with more intuitive GUI and use a second box to display the LIDAR data.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
GroG's picture

Great Design Gareth ! The

Great Design Gareth !

The size, and the proliferation of little stepper motors makes a nice compact little floor rover.

Perfect for a ESP32 brain plug.  Excited to see this develop.
I'm still thinking about the MRL to ESPx / MRLComm link ... even got the parts for it - just keep getting distracted by Squirrels :)