MicroPython: ESP32/ESP8266 Control a DC Motor with the L298N Driver

In this guide, you’ll learn how to control a DC Motor with the ESP32 and ESP8266 NodeMCU boards programmed with MicroPython. You’ll learn how to make it go forward, backward, stop, and control its speed by creating your own MicroPython module. We’ll use the L298N motor driver, but other similar motor drivers should also be compatible.

MicroPython ESP32 ESP8266 NodeMCU Control a DC Motor with the L298N Driver

We have a similar tutorial using Arduino IDE: ESP32 with DC Motor and L298N Motor Driver – Control Speed and Direction.

Table of Contents

This tutorial covers the following topics:

Prerequisites

Before proceeding with this tutorial, make sure you check the following prerequisites

MicroPython Firmware

micorpython logo

To follow this tutorial you need MicroPython firmware installed in your ESP32 or ESP8266 boards. You also need an IDE to write and upload the code to your board. We suggest using Thonny IDE or uPyCraft IDE:

If you like to program using VS Code, there’s also an option: MicroPython: Program ESP32/ESP8266 using VS Code and Pymakr

Learn more about MicroPython: MicroPython Programming with ESP32 and ESP8266

Parts Required

To complete this tutorial you need the following parts:

Control DC Motor ESP32 - Parts required

You can use the preceding links or go directly to MakerAdvisor.com/tools to find all the parts for your projects at the best price!

Introducing the L298N Motor Driver

There are several ways to control a DC motor. The method we’ll use here is suitable for most hobbyist motors, that require 6V or 12V to operate.

We’re going to use the L298N motor driver that can handle up to 3A at 35V. Additionally, it allows us to drive two DC motors simultaneously, which is perfect for building a robot.

The L298N motor driver is shown in the following figure:

298N Motor Driver

L298N Motor Driver pinout

Let’s take a look at the L298N motor driver pinout and see how it works.

L298N Motor Driver pinout

The motor driver has a two-terminal block on each side for each motor. OUT1 and OUT2 at the left and OUT3 and OUT4 at the right.

  • OUT1: DC motor A + terminal
  • OUT2: DC motor A – terminal
  • OUT3: DC motor B + terminal
  • OUT4: DC motor B – terminal

At the bottom, you have a three-terminal block with +12V, GND, and +5V. The +12V terminal block is used to power up the motors. The +5V terminal is used to power up the L298N chip. However, if the jumper is in place, the chip is powered using the motor’s power supply and you don’t need to supply 5V through the +5V terminal.

Important: despite the +12V terminal name, you can supply any voltage between 5V and 35V (but 6V to 12V is the recommended range).

Note: if you supply more than 12V, you need to remove the jumper and supply 5V to the +5V terminal.

In this tutorial, we’ll be using 4 AA 1.5V batteries that combined output approximately 6V, but you can use any other suitable power supply. For example, you can use a bench power supply to test this tutorial.

In summary:

  • +12V: The +12V terminal is where you should connect the motor’s power supply
  • GND: power supply GND
  • +5V: provide 5V if jumper is removed. Acts as a 5V output if jumper is in place
  • Jumper: jumper in place – uses the motor power supply to power up the chip. Jumper removed: you need to provide 5V to the +5V terminal. If you supply more than 12V, you should remove the jumper

At the bottom right you have four input pins and two enable terminals. The input pins are used to control the direction of your DC motors, and the enable pins are used to control the speed of each motor.

  • IN1: Input 1 for Motor A
  • IN2: Input 2 for Motor A
  • IN3: Input 1 for Motor B
  • IN4: Input 2 for Motor B
  • EN1: Enable pin for Motor A
  • EN2: Enable pin for Motor B

There are jumper caps on the enable pins by default. You need to remove those jumper caps to control the speed of your motors. Otherwise, they will either be stopped or spinning at the maximum speed.

Control DC motors with the L298N Motor Driver

Now that you’re familiar with the L298N Motor Driver, let’s see how to use it to control your DC motors.

Enable pins

The enable pins are like an ON and OFF switch for your motors. For example:

  • If you send a HIGH signal to the enable 1 pin, motor A is ready to be controlled and at the maximum speed;
  • If you send a LOW signal to the enable 1 pin, motor A turns off;
  • If you send a PWM signal, you can control the speed of the motor. The motor speed is proportional to the duty cycle. However, note that for small duty cycles, the motors might not spin, and make a continuous buzz sound.
SIGNAL ON THE ENABLE PINMOTOR STATE
HIGHMotor enabled
LOWMotor not enabled
PWMMotor enabled: speed proportional to the duty cycle

Input pins

The input pins control the direction the motors are spinning. Input 1 and input 2 control motor A, and input 3 and 4 control motor B.

  • If you apply LOW to input1 and HIGH to input 2, the motor will spin forward;
  • If you apply power the other way around: HIGH to input 1 and LOW to input 2, the motor will rotate backwards. Motor B can be controlled using the same method but applying HIGH or LOW to input 3 and input 4.

For example, for motor A, this is the logic:

DirectionInput 1Input 2Enable 1
Forward011
Backwards101
Stop000

Controlling 2 DC Motors – ideal to build a robot

If you want to build a robot car using 2 DC motors, these should be rotating in specific directions to make the robot go left, right, forward, or backward.

For example, if you want your robot to move forward, both motors should be rotating forward. To make it go backward, both should be rotating backward.

To turn the robot in one direction, you need to spin the opposite motor faster. For example, to make the robot turn right, enable the motor at the left, and disable the motor at the right. The following table shows the input pins’ state combinations for the robot directions.

DIRECTIONINPUT 1INPUT 2INPUT 3INPUT 4
Forward0101
Backward1010
Right0100
Left0001
Stop0000

Control DC Motor with ESP32 or ESP8266 – Speed and Direction

Now that you know how to control a DC motor with the L298N motor driver, let’s build a simple example to control the speed and direction of one DC motor.

Wiring a DC Motor to the ESP32 (L298N Motor Driver)

The motor we’ll control is connected to the motor A output pins, so we need to wire the ENABLEA, INPUT1, and INPUT2 pins of the motor driver to the ESP32. Follow the next schematic diagram to wire the DC motor and the L298N motor driver to the ESP32.

ESP32 wiring DC Motor L298N driver circuit diagram
LN298N Motor DriverInput 1Input 2EnableGND
ESP32GPIO 12GPIO 14GPIO 13GND

We’re using the GPIOs on the previous table to connect to the motor driver. You can use any other suitable GPIOs as long as you modify the code accordingly. Learn more about the ESP32 GPIOs: ESP32 Pinout Reference Guide.

Wiring a DC Motor to the ESP8266 NodeMCU (L298N Motor Driver)

The motor we’ll control is connected to the motor A output pins, so we need to wire the ENABLEA, INPUT1, and INPUT2 pins of the motor driver to the ESP8266. Follow the next schematic diagram to wire the DC motor and the L298N motor driver to the ESP8266.

ESP8266 NodeMCU DC Motor with L298N Wiring driver circuit diagram
LN298N Motor DriverInput 1Input 2EnableGND
ESP32GPIO 12 (D6)GPIO 14 (D5)GPIO 13 (D7)GND

We’re using the GPIOs on the previous table to connect to the motor driver. You can use any other suitable GPIOs as long as you modify the code accordingly. Learn more about the ESP8266 GPIOs: ESP8266 Pinout Reference: Which GPIO pins should you use?

Powering the LN298N Motor Driver

The DC motor requires a big jump in current to move, so the motors should be powered using an external power source from the ESP32. As an example, we’re using 4AA batteries, but you can use any other suitable power supply. In this configuration, you can use a power supply with 6V to 12V.

The switch between the battery holder and the motor driver is optional, but it is very handy to cut and apply power. This way you don’t need to constantly connect and then disconnect the wires to save power.

We recommend soldering a 0.1uF ceramic capacitor to the positive and negative terminals of the DC motor, as shown in the diagram to help smooth out any voltage spikes. (Note: the motors also work without the capacitor.)

Creating a MicroPython Module to Control a DC Motor

Writing the code to control the DC motor is not difficult, but it requires some repetitive commands. It would be nice to have a module (library) that would allow us to control the motor speed and direction with a single command.

With that in mind, we’ll create a simple Python module with the basic commands to initialize a motor and control its speed and direction.

Creating the dcmotor Module

Before writing the code for this module, it’s important to write down its functionalities:

  • The library will be called dcmotor.py, and it will have a single class called DCMotor with several methods.
  • We should be able to initialize the motor using input pin 1, input pin 2, and the enable pin as follows:
motor1 = DCMotor(Pin1, Pin2, enable)

Pin1 and Pin2 should be initialized as output pins, and the enable should be initialized as a PWM pin.

  • To move the motor forward, we want to use a method called forward() on the DCMotor object that accepts the speed as a parameter. For example:
motor1.forward(speed)

The speed should be an integer number between 0 and 100, in which 0 corresponds to the motor stopped and 100 to maximum speed.

  • Similarly, to make the motor go backwards:
motor1.backwards(speed)
  • It is also handy to have a command to make the motor stop, as follows:
motor1.stop() 

Importing the dcmotor.py Module

Create a new file called dcmotor.py and copy the following code into that file.

# Created by https://RandomNerdTutorials.com/micropython-esp32-esp8266-dc-motor-l298n/
#This file includes a class to control DC motors

class DCMotor:
  #the min_duty and max_duty are defined for 15000Hz frequency
  #you can pass as arguments
  def __init__(self, pin1, pin2, enable_pin, min_duty=750, max_duty=1023):
    self.pin1 = pin1
    self.pin2= pin2
    self.enable_pin = enable_pin
    self.min_duty = min_duty
    self.max_duty = max_duty
  
  #speed value can be between 0 and 100
  def forward(self, speed):
    self.speed = speed
    self.enable_pin.duty(self.duty_cycle(self.speed))
    self.pin1.value(1)
    self.pin2.value(0)

  def backwards(self, speed):
    self.speed = speed
    self.enable_pin.duty(self.duty_cycle(self.speed))
    self.pin1.value(0)
    self.pin2.value(1)

  def stop(self):
    self.enable_pin.duty(0)
    self.pin1.value(0)
    self.pin2.value(0)
        
  def duty_cycle(self, speed):
    if self.speed <= 0 or self.speed > 100:
      duty_cycle = 0
    else:
      duty_cycle = int (self.min_duty + (self.max_duty - self.min_duty)*((self.speed - 1)/(100-1)))
    return duty_cycle

View raw code

Upload that file to your ESP32 or ESP8266 board with the following name: dcmotor.py.

If you’re using Thonny IDE, you can follow the next steps:

1) Copy the code provided to a new file on Thonny IDE.

2) Upload the code to your board. If you’re using Thonny IDE, go to File > Save as… and then select MicroPython device.

Thonny IDE Save to MicroPython Device

3) Save your file as dcmotor.py. There should be a file called boot.py. That file is created by default when you burn MicroPython firmware.

Save Script to MicroPython device ESP32 ESP8266

4) Finally, click OK to proceed. The dcmotor.py module should have been uploaded successfully to your board.

How the dcmotor Module Works

The dcmotor module contains a single class called DCMotor.

class DCMotor:

We use the constructor method (__init__) to initiate the data as soon as an object of the DCMotor class is instantiated.

def __init__(self, pin1, pin2, enable_pin, min_duty=750, max_duty=1023):
  self.pin1 = pin1
  self.pin2= pin2
  self.enable_pin = enable_pin
  self.min_duty = min_duty
  self.max_duty = max_duty

A DCMotor object accepts as parameters:

  • pin1: GPIO (output) that connects to L298N input 1 pin.
  • pin2: GPIO (output) that connects to L298N input 2 pin.
  • enable_pin: GPIO (PWM pin) that connects to L298N enable 1 pin.
  • min_duty: minimum duty cycle to make the motor move. This parameter is optional, and it’s set to 750 by default. You may need to change this parameter depending on the frequency required to control your DC motor.
  • max_duty: maximum duty cycle to make the motor move. This parameter is set to 1023 by default.

Then, create several methods to control the DC motor: forward(), backwards(), and stop().

The forward() and backwards() methods make the motor spin forward and backwards, respectively. The stop() method stops the motor.

The forward() and backwards() methods accept the speed as a parameter. The speed should be an integer number between 0 and 100.

Let’s take a closer look at the forward() method:

def forward(self, speed):
  self.speed = speed
  self.enable_pin.duty(self.duty_cycle(self.speed))
  self.pin1.value(1)
  self.pin2.value(0)

To make the motor move forward, set pin1 to 1 and pin2 to 0. The enable pin’s duty cycle is set to the corresponding speed. The speed is an integer number between 0 and 100, but the duty cycle should be a number between the max_duty and min_duty. So, we have another method at the end of the code, called duty_cycle() that calculates the corresponding duty cycle value based on the speed.

def duty_cycle(self, speed):
  if self.speed <= 0 or self.speed > 100:
    duty_cycle = 0
  else:
    duty_cycle = int (self.min_duty + (self.max_duty - self.min_duty)*((self.speed - 1)/(100-1)))
  return duty_cycle

The backwards() method works similarly, but pin1 is set to 0, and pin2 is set to 1.

def backwards(self, speed):
  self.speed = speed
  self.enable_pin.duty(self.duty_cycle(self.speed))
  self.pin1.value(0)
  self.pin2.value(1)

Controlling the DC Motor

Now that we understand how the dcmotor.py module works and that we’ve already imported it to your ESP32 or ESP8266 board, we can create a new script to control the DC motor using the library functionalities.

The following code demonstrates how to use the library’s functionalities to control the DC motor. The code is compatible with both the ESP32 and ESP8266 boards.

# Complete project details at https://RandomNerdTutorials.com/micropython-esp32-esp8266-dc-motor-l298n/

from dcmotor import DCMotor
from machine import Pin, PWM
from time import sleep

frequency = 15000

pin1 = Pin(12, Pin.OUT)
pin2 = Pin(14, Pin.OUT)
enable = PWM(Pin(13), frequency)

dc_motor = DCMotor(pin1, pin2, enable)
#Set min duty cycle (350) and max duty cycle (1023)
#dc_motor = DCMotor(pin1, pin2, enable, 350, 1023)

dc_motor.forward(50)
sleep(2)
dc_motor.stop()
sleep(3)
dc_motor.backwards(100)
sleep(2)
dc_motor.forward(5)
sleep(5)
dc_motor.stop()

View raw code

Importing libraries

To use the library’s functionalities, you need to import the library into your code. We import the DCMotor class from the dcmotor library we’ve created previously.

from dcmotor import DCMotor

You also need to import the Pin and PWM classes to control the GPIOs and the sleep() method.

from machine import Pin, PWM
from time import sleep

Setting the frequency

Set the PWM signal frequency to 15000 Hz. You can choose other frequency values. Note that for lower frequency values, the motor may not spin and make a weird beep sound.

frequency = 15000

Initializing GPIOs

We create three variables that refer to the motor driver’s pin1, pin2, and enable pins. These are connected to GPIO 12, 14, and 13, respectively. pin1 and pin2 are output pins, and the enable is a PWM pin.

pin1 = Pin(12, Pin.OUT)
pin2 = Pin(14, Pin.OUT)
enable = PWM(Pin(13), frequency)

Then, initialize a DCMotor object with the pin1, pin2, and enable defined earlier:

dc_motor = DCMotor(pin1, pin2, enable)

Note: you may need to pass the min_duty and max_duty parameters depending on the motor and board you’re using. For example:

dc_motor = DCMotor(pin1, pin2, enable, 350, 1023)

Now you have a DCMotor object called dc_motor. You can use the methods to control the motor. Make the motor move forward at 50% speed:

dc_motor.forward(50)

Stop the motor:

dc_motor.stop()

Move the motor backwards at maximum speed:

dc_motor.backwards(100)

Move the motor forward at 5% speed:

dc_motor.forward(5)

Demonstration

Run the previous code on your ESP32 or ESP8266 board. The motor will move forward at 50% speed, backward at 100% speed, and then forward again at 5% speed. You can experiment with the methods and pass different speeds as an argument to see how your DC motor behaves.

Mini DC Motor Spinning

Wrapping Up

In this tutorial, you’ve learned how to control a DC motor using the L298N motor driver with the ESP32 or ESP8266 programmed with MicroPython. We’ve created a Python module with methods to easily control the motor: the dcmotor.py library.

Now, you can use this library in your projects to create DCMotor objects and use the library methods to control the motor: forward(), backwards() and stop().

If you prefer programming using Arduino IDE, take a look at the following tutorial instead:

If you want to learn more about MicroPython with the ESP32 and ESP8266 boards, check out:



Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »
Learn how to build a home automation system and we’ll cover the following main subjects: Node-RED, Node-RED Dashboard, Raspberry Pi, ESP32, ESP8266, MQTT, and InfluxDB database DOWNLOAD »

Recommended Resources

Build a Home Automation System from Scratch » With Raspberry Pi, ESP8266, Arduino, and Node-RED.

Home Automation using ESP8266 eBook and video course » Build IoT and home automation projects.

Arduino Step-by-Step Projects » Build 25 Arduino projects with our course, even with no prior experience!

What to Read Next…


Enjoyed this project? Stay updated by subscribing our newsletter!

Leave a Comment

Download Our Free eBooks and Resources

Get instant access to our FREE eBooks, Resources, and Exclusive Electronics Projects by entering your email address below.