Close

Software Part 1: WiFi Control

A project log for ESP32 Mini-Bot

A small proof-of-concept ESP32 Bot

matthew-james-bellafaireMatthew James Bellafaire 02/21/2019 at 21:250 Comments

Before this project I had limited experience with the ESP32 and for the most part I followed this tutorial to get the project up and running in the beginning and modified from it. That tutorial got me started, however, since the software for this project is probably the most likely reused part of it, there were not a lot of compromises and I had a few goals: 

So lets start with the web page the ESP32 serves every time a user connects: 

<html><head><meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<script src = "https://cdn.jsdelivr.net/gh/jeromeetienne/virtualjoystick.js/virtualjoystick.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<style>
body {overflow    : hidden;background-color: #BBB;}
#container {width: 100%;height: 100%;overflow: hidden;padding:0;margin:0;-webkit-user-select:none;-moz-user-select:none;}
</style><title> ESP32 Bot Control Site </title></head><body>
<div id="container"><h1>ESP32 Bot Control</h1></div><div id="info"><span id="result"></span></div> <script>
console.log("touchscreen is", VirtualJoystick.touchScreenAvailable() ? "available" : "not available");
var joystick    = new VirtualJoystick({
container    : document.getElementById('container'),
mouseSupport    : true,
limitStickTravel : true,
stickRadius : 100
});
            
joystick.addEventListener('touchStart', function(){
console.log('down')
})
joystick.addEventListener('touchEnd', function(){
console.log('up')
})
$.ajaxSetup({timeout:50});
setInterval(function(){
var message = "/?M/?X"+Math.round(joystick.deltaX())+"/X/?Y"+Math.round(joystick.deltaY())+"/Y/M";$.get(message);var outputEl    = document.getElementById('result');}, 50);
</script></body></html>
 

which looks like: 

I can't embed the web-page directly into this log, but the full HTML file is posted on the main page of this project. 

The blue circles you see in the image above are actually a joystick. I didn't create this joystick, the credit for that goes to jeromeetienne on github. The virtualjoystick.js github page can be found here

Now, as I said in the first log this project write up is for someone who wants to do something similar to this project. The web interface specifically took the majority of the time I spent on this project and I really want someone else who does this to have an easier time. there are two very important parts in this website that make the whole thing work as intended, first loading the javascript externally:

<script src = "https://cdn.jsdelivr.net/gh/jeromeetienne/virtualjoystick.js/virtualjoystick.js"></script>

Notice the script tag is pulling the .js file from somewhere that's not the ESP32, github will not let you load a file directly with one of their raw URL's, additionally the javascript file is too big to be sent by the ESP32 (it can do it but you're adding 40ms to the transmission time). The solution to this is to use jsdelivr.com to offer up the JavaScript file to any computer that loads the web-page. This offloads the burden from the ESP32 to the device connected to it. 

second sending the information to the ESP32:

$.ajaxSetup({timeout:50});
setInterval(
function(){
var message = "/?M/?X"+Math.round(joystick.deltaX())+"/X/?Y"+Math.round(joystick.deltaY())+"/Y/M";
$.get(message);}
, 50);

(which is all on the same line in the code posted above)

The bottom part of the code simply composes a string with the x and y coordinates of the joystick, formats it, then requests it as a URL from the ESP32 every 50ms. The ESP32 receives this then processes it, for the longest time this code would not work because the ESP32 would become backlogged with requests. The longer it spent running, the more behind it was with the requests. Eventually the bot was impossible to control, this issue was resolved by adding the line:

$.ajaxSetup({timeout:50});

Which allowed the request to time out and therefore prevented the ESP32 from becoming back-logged, if it misses a request for whatever reason with this code it will just be ignored and the next one will be executed. As a result the controls generally feel responsive and all and all work as intended. 

Feel free to use this code and the ESP32 code however you want. I couldn't find any examples online that gave me both the joystick and the ESP32 code simply.

So now the ESP32 can send a website with a joystick and the website sends data back, we still have to process the data. The ESP32's code was written using the Arduino IDE with the ESP32 library, for everything not relating to the direct control of the motors here is the code that processes the request: 

void loop() {
  client = server.available();
  if (client) {
    String currentLine = "";
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        header += c;

        if (c == '\n') {
          if (currentLine.length() == 0) {
            printWebsite();

            if (header.indexOf("GET /?M") >= 0) {
              valueString = header.substring(header.indexOf("/?X") + 3, header.indexOf("/X"));
              rx = valueString.toInt();

              valueString = header.substring(header.indexOf("/?Y") + 3, header.indexOf("/Y"));
              ry = valueString.toInt() * -1 ; //the joystick considers down to be positive so we adjust that here

            }
            client.println();
            setMotorsXY(rx, ry);

            break;
          } else {
            currentLine = "";
          }
        } else if (c != '\r') {  
          currentLine += c;      
        }
      }
    }
    // Clear the header variable
    header = "";
    // Close the connection
    client.stop();
  }
}

the website sends its GET request every 50ms using a string that looks like:

/?M/?X***/X/?Y***/Y/M

There's actually much more data than that sent, but this is what actually gets used by the ESP32, the asterisks represent the values the website read from the joystick. the program checks for the string "GET /?M", once found the code chops out the X and Y values and converts them to integers:

              valueString = header.substring(header.indexOf("/?X") + 3, header.indexOf("/X"));
              rx = valueString.toInt();

              valueString = header.substring(header.indexOf("/?Y") + 3, header.indexOf("/Y"));
              ry = valueString.toInt() * -1 ; //the joystick considers down to be positive so we adjust that here

once the program has two values X and Y all of the difficult parts of this code are done, they are then passed into the set motor function which is covered in the next log (Because this one is already way too long).  

Discussions