Learning by doing. ESP32 based WiFi Controlled Car.

Reproducing the Project

  1. Gather the required parts as mentioned below
  2. Follow the Fritzing diagram for the wiring(exact GPIO can be infered from Main.py code)
  3. Make your Boot.py to suit your Wifi SSID or AP modes
  4. Connect to your WiFi in case of AP client mode Boot.py OR Connect to your ESP32 based AP, if Boot.py contains AP mode
  5. Open browser and point to the ESP32 IP, to get remote control as webpage
  6. Drive away!

Parts list

  • ESP32 board
  • L298N Motor Driver
  • 2 x 18650 + Battery holder
  • 4 x 3V-12V DC BO motor
  • Chassis for mounting everything
  • Mini project bread board
  • Soldering iron

Fritzing Diagram

Project Diagram

Wiring

Remove the Jumper from ENA1+ENA2 and ENB1+ENB2

LEFT SIDE MOTORS

  • ENA1 –> GPIO 4
  • IN1 –> GPIO 2
  • IN2 –> GPIO 15

RIGHT SIDE MOTORS

  • ENA1 –> GPIO 13
  • IN3 –> GPIO 14
  • IN4 –> GPIO 12

MicroPython Code

Borrowed from many places

Main.py

import machine
import time

class engines:
    def __init__(self, machine):
        self.machine = machine
        
        # Left side DC Motor Control
        self.ena1_gpio = 4
        self.in1_gpio = 2
        self.in2_gpio = 15

        # Right side DC Motor Control
        self.enb1_gpio = 13
        self.in3_gpio = 14
        self.in4_gpio = 12

        # Set the duty for PWM
        #self.full_pwm_duty = 500
        #self.half_pwm_duty = 200
                
        # Control INx pins for forward or backward
        #self.in1 = machine.Pin(self.in1_gpio, machine.Pin.OUT, value=0)
        #self.in2 = machine.Pin(self.in2_gpio, machine.Pin.OUT, value=1)
        #self.in3 = machine.Pin(self.in3_gpio, machine.Pin.OUT, value=0)
        #self.in4 = machine.Pin(self.in4_gpio, machine.Pin.OUT, value=1)
        print("init")

    def forward(self, duty=600):
        self.stop()
        # Right side DC Motor Speed Control and direction
        ena1=machine.PWM(self.machine.Pin(self.ena1_gpio),freq=100,duty=duty)
        enb1=machine.PWM(self.machine.Pin(self.enb1_gpio),freq=100,duty=duty)
        # Control INx pins for forward
        self.in1 = machine.Pin(self.in1_gpio, machine.Pin.OUT, value=0)
        self.in2 = machine.Pin(self.in2_gpio, machine.Pin.OUT, value=1)
        self.in3 = machine.Pin(self.in3_gpio, machine.Pin.OUT, value=0)
        self.in4 = machine.Pin(self.in4_gpio, machine.Pin.OUT, value=1)
        print("forward")

    def forward_left(self):
        self.stop()
        # Right side DC Motor Speed Control and direction
        ena1=machine.PWM(self.machine.Pin(self.ena1_gpio), freq=100, duty=300)
        enb1=machine.PWM(machine.Pin(self.enb1_gpio), freq=100, duty=600)
        # Control INx pins for forward
        self.in1 = machine.Pin(self.in1_gpio, machine.Pin.OUT, value=0)
        self.in2 = machine.Pin(self.in2_gpio, machine.Pin.OUT, value=1)
        self.in3 = machine.Pin(self.in3_gpio, machine.Pin.OUT, value=0)
        self.in4 = machine.Pin(self.in4_gpio, machine.Pin.OUT, value=1)
        print("forward_left")

    def forward_right(self):
        self.stop()
        # Right side DC Motor Speed Control and direction
        ena1=machine.PWM(self.machine.Pin(self.ena1_gpio),freq=100,duty=600)
        enb1=machine.PWM(self.machine.Pin(self.enb1_gpio),freq=100,duty=300)
        # Control INx pins for forward
        self.in1 = machine.Pin(self.in1_gpio, machine.Pin.OUT, value=0)
        self.in2 = machine.Pin(self.in2_gpio, machine.Pin.OUT, value=1)
        self.in3 = machine.Pin(self.in3_gpio, machine.Pin.OUT, value=0)
        self.in4 = machine.Pin(self.in4_gpio, machine.Pin.OUT, value=1)
        print("forward_right")

    def reverse(self, duty=600):
        self.stop()
        # Right side DC Motor Speed Control and direction
        ena1=machine.PWM(self.machine.Pin(self.ena1_gpio),freq=100,duty=duty)
        enb1=machine.PWM(self.machine.Pin(self.enb1_gpio),freq=100,duty=duty)
        # Control INx pins for backward
        self.in1 = machine.Pin(self.in1_gpio, machine.Pin.OUT, value=1)
        self.in2 = machine.Pin(self.in2_gpio, machine.Pin.OUT, value=0)
        self.in3 = machine.Pin(self.in3_gpio, machine.Pin.OUT, value=1)
        self.in4 = machine.Pin(self.in4_gpio, machine.Pin.OUT, value=0)
        print("reverse")

    def reverse_left(self):
        self.stop()
        # Right side DC Motor Speed Control and direction
        ena1=machine.PWM(self.machine.Pin(self.ena1_gpio), freq=100, duty=600)
        enb1=machine.PWM(self.machine.Pin(self.enb1_gpio), freq=100, duty=300)
        # Control INx pins for backward
        self.in1 = machine.Pin(self.in1_gpio, machine.Pin.OUT, value=1)
        self.in2 = machine.Pin(self.in2_gpio, machine.Pin.OUT, value=0)
        self.in3 = machine.Pin(self.in3_gpio, machine.Pin.OUT, value=1)
        self.in4 = machine.Pin(self.in4_gpio, machine.Pin.OUT, value=0)
        print("reverse_left")
        
    def reverse_right(self):
        self.stop()
        # Right side DC Motor Speed Control and direction
        ena1=machine.PWM(self.machine.Pin(self.ena1_gpio),freq=100,duty=600)
        enb1=machine.PWM(self.machine.Pin(self.enb1_gpio),freq=100,duty=300)
        # Control INx pins for backward
        self.in1 = machine.Pin(self.in1_gpio, machine.Pin.OUT, value=1)
        self.in2 = machine.Pin(self.in2_gpio, machine.Pin.OUT, value=0)
        self.in3 = machine.Pin(self.in3_gpio, machine.Pin.OUT, value=1)
        self.in4 = machine.Pin(self.in4_gpio, machine.Pin.OUT, value=0)
        print("reverse_right")
        
    def stop(self):
        machine.PWM(self.machine.Pin(self.ena1_gpio),freq=0,duty=0)
        machine.PWM(self.machine.Pin(self.enb1_gpio),freq=0,duty=0)
        self.in1 = machine.Pin(self.in1_gpio, machine.Pin.OUT, value=0)
        self.in2 = machine.Pin(self.in2_gpio, machine.Pin.OUT, value=0)
        self.in3 = machine.Pin(self.in3_gpio, machine.Pin.OUT, value=0)
        self.in4 = machine.Pin(self.in4_gpio, machine.Pin.OUT, value=0)
        print("stop")

E=engines(machine)
try:
    import usocket as socket
except:
    import socket

CONTENT = b"""\
HTTP/1.0 200 OK
Hello #%d
"""

CONTENT = b"""\
<!DOCTYPE html>
<html lang="en">
<meta charset="UTF-8">
<title>:: SERVO WEB CONTROL ::</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<style type="text/css" media="screen">
  .rcdiv {
    border: 3px outset red;
    background-color: lightblue;
    text-align: center;
  }
  .container {
    margin: 10px auto;
    max-width: 600px;
    text-align: center;
  }
  .rctable {
    margin-left: auto;
    margin-right: auto;
    border: 1;
  }
  .rcbtn {
    border: 2px solid black;
    background-color: white;
    color: black;
    padding: 14px 28px;
    font-size: 16px;
    cursor: pointer;
    border-color: #2196F3;
    color: dodgerblue
    background: #2196F3;
    color: white;
  }
  h1 {
    margin: 30px 0;
    font-size: 4em;
    line-height: 1;
    letter-spacing: -1px;
  }
</style>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js" type="text/javascript" charset="utf-8"></script>

<script type="text/javascript">
var DEVICE_URL = 'http://%s'
function iotAction(action){
    var requestURL = DEVICE_URL + "/?action="+action
    $.get (requestURL)
}
</script>

<body>
  <div class="container">
    <h2>CAR WIFI REMOTE</h2>

    <table class="rctable">
      <tbody>
        <tr><!-- First row -->
          <td><button class="rcbtn" name='btnForwardLeft' style="width:100px;height:160px" ontouchstart="iotAction('forward_left')" ontouchend="iotAction('stop')"/></td>
          <td><button class="rcbtn" name='btnForward' style="width:100px;height:160px" ontouchstart="iotAction('forward')" ontouchend="iotAction('stop')"/></td>
          <td><button class="rcbtn" name='btnForwardRight' style="width:100px;height:160px" ontouchstart="iotAction('forward_right')" ontouchend="iotAction('stop')"/></td>
        </tr>
        <tr><!-- Second row -->
          <td><button class="rcbtn" name='btnReverseLeft' style="width:100px;height:160px" ontouchstart="iotAction('reverse_left')" ontouchend="iotAction('stop')"/></td>
          <td><button class="rcbtn" name='btnReverse' style="width:100px;height:160px" ontouchstart="iotAction('reverse')" ontouchend="iotAction('stop')"/></td>
          <td><button class="rcbtn" name='btnReverseRight' style="width:100px;height:160px" ontouchstart="iotAction('reverse_right')" ontouchend="iotAction('stop')"/></td>
        </tr>
      </tbody>
    </table>

  </div>
</body>
</html>
"""

def main(E,micropython_optimize=False):
    s = socket.socket()
#    ai = socket.getaddrinfo("192.168.0.159", 80)
    ai = socket.getaddrinfo("192.168.0.219", 80)
    addr = ai[0][-1]
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.bind(addr)
    s.listen(5)
    while True:
        res = s.accept()
        client_sock=res[0]
        if not micropython_optimize:
            client_stream = client_sock.makefile("rwb")
        else:
            client_stream = client_sock
        req = client_stream.readline()
        get = req.split()[1].decode('utf-8')
        if get == '/?action=forward_left':
            E.forward_left()
        elif get == '/?action=forward':
            E.forward()
        elif get == '/?action=forward_right':
            E.forward_right()
        elif get == '/?action=reverse_left':
            E.reverse_left()
        elif get == '/?action=reverse':
            E.reverse()
        elif get == '/?action=reverse_right':
            E.reverse_right()
        elif get == '/?action=stop':
            E.stop()
        else:
            pass

        while True:
            h = client_stream.readline()
            if h == b"" or h == b"\r\n":
                break

        client_stream.write(CONTENT % station.ifconfig()[0])
        client_stream.close()
        if not micropython_optimize:
            client_sock.close()

main(E)