Sunday, 26 February 2023

ESP32 with DC Motor and L298N Motor Driver – Control Speed and Direction

https://randomnerdtutorials.com/esp32-dc-motor-l298n-motor-driver-control-speed-direction/

ESP32 with DC Motor and L298N Motor Driver – Control Speed and Direction

This tutorial shows how to control the direction and speed of a DC motor using an ESP32 and the L298N Motor Driver. First, we’ll take a quick look on how the L298N motor driver works. Then, we’ll show you an example on how to control the speed and direction of a DC motor using the ESP32 with Arduino IDE and the L298N motor driver.

Note: there are many ways to control a DC motor. We’ll be using the L298N motor driver. This tutorial is also compatible with similar motor driver modules.

To better understand with this tutorial, you may want to take a look at the following posts:

Parts Required

To complete this tutorial you need the following parts:

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 many 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 to build a robot.

The L298N motor driver is shown in the following figure:

L298N Motor Driver pinout

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

The motor driver has a two terminal block in 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 +12VGND, 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.

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

It’s important to note that despite the +12V terminal name, with the setup we’ll use here (with the jumper in place) you can supply any voltage between 6V and 12V. In this tutorial will 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 your 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 motors 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.

Control DC motors with the L298N

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 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.

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 backwards.

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

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

Recommended reading: Build Robot Car Chassis Kit for ESP32, ESP8266, Arduino, etc…

Control DC Motor with ESP32 – 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.

Schematic

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.


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.)

Preparing the Arduino IDE

There’s an add-on for the Arduino IDE allows you to program the ESP32 using the Arduino IDE and its programming language. Follow one of the next tutorials to prepare your Arduino IDE to work with the ESP32, if you haven’t already.

After making sure you have the ESP32 add-on installed, you can continue this tutorial.

Uploading code

The following code controls the speed and direction of the DC motor. This code is not useful in the real world, this is just a simple example to better understand how to control the speed and direction of a DC motor with the ESP32.

/*********
  Rui Santos
  Complete project details at https://randomnerdtutorials.com  
*********/

// Motor A
int motor1Pin1 = 27; 
int motor1Pin2 = 26; 
int enable1Pin = 14; 

// Setting PWM properties
const int freq = 30000;
const int pwmChannel = 0;
const int resolution = 8;
int dutyCycle = 200;

void setup() {
  // sets the pins as outputs:
  pinMode(motor1Pin1, OUTPUT);
  pinMode(motor1Pin2, OUTPUT);
  pinMode(enable1Pin, OUTPUT);
  
  // configure LED PWM functionalitites
  ledcSetup(pwmChannel, freq, resolution);
  
  // attach the channel to the GPIO to be controlled
  ledcAttachPin(enable1Pin, pwmChannel);

  Serial.begin(115200);

  // testing
  Serial.print("Testing DC Motor...");
}

void loop() {
  // Move the DC motor forward at maximum speed
  Serial.println("Moving Forward");
  digitalWrite(motor1Pin1, LOW);
  digitalWrite(motor1Pin2, HIGH); 
  delay(2000);

  // Stop the DC motor
  Serial.println("Motor stopped");
  digitalWrite(motor1Pin1, LOW);
  digitalWrite(motor1Pin2, LOW);
  delay(1000);

  // Move DC motor backwards at maximum speed
  Serial.println("Moving Backwards");
  digitalWrite(motor1Pin1, HIGH);
  digitalWrite(motor1Pin2, LOW); 
  delay(2000);

  // Stop the DC motor
  Serial.println("Motor stopped");
  digitalWrite(motor1Pin1, LOW);
  digitalWrite(motor1Pin2, LOW);
  delay(1000);

  // Move DC motor forward with increasing speed
  digitalWrite(motor1Pin1, HIGH);
  digitalWrite(motor1Pin2, LOW);
  while (dutyCycle <= 255){
    ledcWrite(pwmChannel, dutyCycle);   
    Serial.print("Forward with duty cycle: ");
    Serial.println(dutyCycle);
    dutyCycle = dutyCycle + 5;
    delay(500);
  }
  dutyCycle = 200;
}

View raw code

Upload the code to your ESP32. Make sure you have the right board and COM port selected. Let’s take a look on how the code works.

Declaring motor pins

First, you define the GPIOs the motor pins are connected to. In this case, Input 1 for motor A is connected to GPIO 27, the Input 2 to GPIO 26, and the Enable pin to GPIO 14.

int motor1Pin1 = 27; 
int motor1Pin2 = 26; 
int enable1Pin = 14;

Setting the PWM  properties to control the speed

As we’ve seen previously, you can control the DC motor speed by applying a PWM signal to the enable pin of the L298N motor driver. The speed will be proportional to the duty cycle. To use PWM with the ESP32, you need to set the PWM signal properties first.

const int freq = 30000;
const int pwmChannel = 0;
const int resolution = 8;
int dutyCycle = 200;

In this case, we’re generating a signal of 30000 Hz on channel 0 with a 8-bit resolution. We start with a duty cycle of 200 (you can set a duty cycle value from 0 to 255).

For the frequency we’re using, when you apply duty cycles smaller than 200, the motor won’t move and will make a weird buzz sound. So, that’s why we set a duty cycle of 200 at the start.

Note: the PWM properties we’re defining here are just an example. The motor works fine with other frequencies.

setup()

In the setup(), you start by setting the motor pins as outputs.

pinMode(motor1Pin1, OUTPUT);
pinMode(motor1Pin2, OUTPUT);
pinMode(enable1Pin, OUTPUT);

You need to configure a PWM signal with the properties you’ve defined earlier by using the ledcSetup() function that accepts as arguments, the pwmChannel, the frequency, and the resolution, as follows:

ledcSetup(pwmChannel, freq, resolution);

Next, you need to choose the GPIO you’ll get the signal from. For that use the ledcAttachPin() function that accepts as arguments the GPIO where you want to get the signal, and the channel that is generating the signal. In this example, we’ll get the signal in the enable1Pin GPIO, that corresponds to GPIO 14. The channel that generates the signal is the pwmChannel, that corresponds to channel 0.

ledcAttachPin(enable1Pin, pwmChannel);

Moving the DC motor forward

In the loop() is where the motor moves. The code is well comment on what each part of the code does. To move the motor forward, you set input 1 pin to LOW and input 2 pint to HIGH. In this example, the motor speeds forward for 2 seconds (2000 milliseconds).

// Move the DC motor forward at maximum speed
Serial.println("Moving Forward");
digitalWrite(motor1Pin1, LOW);
digitalWrite(motor1Pin2, HIGH); 
delay(2000);

Moving the DC motor backwards

To move the DC motor backwards you apply power to the motor input pins the other way around. HIGH to input 1 and LOW to input 2.

// Move DC motor backwards at maximum speed
Serial.println("Moving Backwards");
digitalWrite(motor1Pin1, HIGH);
digitalWrite(motor1Pin2, LOW); 
delay(2000);

Stop the DC motor

To make the DC motor stop, you can either set the enable pin to LOW, or set both input 1 and input 2 pins to LOW. In this example we’re setting both input pins to LOW.

// Stop the DC motor
Serial.println("Motor stopped");
digitalWrite(motor1Pin1, LOW);
digitalWrite(motor1Pin2, LOW);
delay(1000);

Controlling the DC motor speed

To control the DC motor speed, we need to change the PWM signal duty cycle. For that you use the ledcWrite() function that accepts as arguments the PWM channel that is generating the signal (not the output GPIO) and the duty cycle, as follows.

ledcWrite(pwmChannel, dutyCycle);

In our example, we have a while loop that increases the duty cycle by 5 in every loop.

// Move DC motor forward with increasing speed
digitalWrite(motor1Pin1, HIGH);
digitalWrite(motor1Pin2, LOW);
while (dutyCycle <= 255){
  ledcWrite(pwmChannel, dutyCycle);
  Serial.print("Forward with duty cycle: ");
  Serial.println(dutyCycle);
  dutyCycle = dutyCycle + 5;
  delay(500);
}

When the while condition is no longer true, we set the duty cycle to 200 again.

dutyCycle = 200;

Watch the Video Demonstration

Watch the next video to see the project in action:

Wrapping Up

In this tutorial we’ve shown you how to control the direction and speed of a DC motor using an ESP32 and the L298N motor driver. In summary:

  • To control the direction the DC motor is spinning you use the input 1 and input 2 pins;
  • Apply LOW to input 1 and HIGH to input 2 to spin the motor forward. Apply power the other way around to make it spin backwards;
  • To control the speed of the DC motor, you use a PWM signal on the enable pin. The speed of the DC motor is proportional to the duty cycle.

We hope you’ve found this tutorial useful.

This is an excerpt from our course: Learn ESP32 with Arduino IDE. If you like ESP32 and you want to learn more about it, we recommend enrolling in Learn ESP32 with Arduino IDE course.

You might also like reading:

Thanks for reading.



Build Web Server projects with the ESP32 and ESP8266 boards to control outputs and monitor sensors remotely. Learn HTML, CSS, JavaScript and client-server communication protocols 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!

46 thoughts on “ESP32 with DC Motor and L298N Motor Driver – Control Speed and Direction”

    • Hi Alan.
      Yes, you can use two PWM channels. For example, one controls one motor, and the other channel the other motor.
      Or you can use the same PWM channel for both motors if you want them to have a similar behavior.

      Reply
      • this is my program to control two motors, i use L293D motor driver, but the motor couldn’t spin in the same time. the first motor spin and stop, then the second motor start and not stop, please help me how to spin motor in the same time. im sorry for my bad english.

        {
        digitalWrite(leftForward,HIGH);
        digitalWrite(leftBackward,LOW);
        digitalWrite(rightForward,HIGH);
        digitalWrite(rightBackward,LOW);
        while (dutyCycle <= 255){
        ledcWrite(ledChannel1, dutyCycle);
        ledcWrite(ledChannel2, dutyCycle);
        dutyCycle = dutyCycle + 5;
        delay(500);
        }
        dutyCycle = 100;
        }

        Reply
        • Hi Evan.
          Change one of the motors red wire with the black wire, when connecting to L293D motor driver.
          For example, connect motor A red wire to OUT2 and the black wire to OUT1, and see what you get.
          I hope this helps.
          Regards
          Sara ðŸ™‚

          Reply
    • Hello Surya,
      You can set the bit resolution in your sketch in that line:

      const int resolution = 8;

      I recommend trying different frequencies and read the datasheet for your particular motor to find the best frequency. With these types of motors we usually use a frequency between 2000-40000 Hz
      I hope this helps. Regards,
      Rui

      Reply
  1. Hi, I can’t figure out how to PWM modulate speed on 2 channels. Whatever I tried, only one channel changes speed.

    I’m copying samples of my sketch below, knowing that I’m only asking if according to you this should work and, if not, why. It’s kinda frustrating to be back to square one with ESP32! lol

    Thanks in advance.

    Here is the code I’m using:

    [code]
    // Setting PWM properties
    const int freq = 40000;
    const int pwmChannelL = 0;
    const int pwmChannelR = 1;
    const int resolution = 8;

    (…)

    // configure LED PWM functionalitites
    ledcSetup(pwmChannelL, freq, resolution);
    ledcSetup(pwmChannelR, freq, resolution);

    // attach the channel to the GPIO to be controlled
    ledcAttachPin(ENABLE_LEFT, pwmChannelL);
    ledcAttachPin(ENABLE_RIGHT, pwmChannelR);

    (…)

    int dutcycl = SLOW; // sartpoint
    if (SpeedReqST > reqSpeed) { // if ST requested a speed greater than the last one registered by fwd() or here
    while (dutcycl <= SpeedReqST) {
    ledcWrite(pwmChannelL, dutcycl);
    ledcWrite(pwmChannelR, dutcycl);
    // Serial.print("Forward with duty cycle: ");
    // Serial.println(dutcycl);
    dutcycl += 1;
    delay(100);
    }
    }
    else if (SpeedReqST = SpeedReqST) {
    ledcWrite(pwmChannelL, dutcycl);
    ledcWrite(pwmChannelR, dutcycl);
    // Serial.print(“Forward with duty cycle: “);
    // Serial.println(dutcycl);
    dutcycl -= 1;
    delay(100);
    }
    }
    // update last value
    reqSpeed = SpeedReqST;

    [/code]

    Reply
    • Hi.
      Which GPIOs are you using to control the motors? Make sure you are not using “Input only GPIOs”.
      If you want both motors to have the same behavior, you can attach both enable pins to the same channel. Then, you just need to control one channel and both motors will work similarly.
      Regards,
      Sara ðŸ™‚

      Reply
      • Thank you for your answer! Actually it was a problem with my encoders management code, which was systematically reducing pwm on one channel, continuously… pure coding mistake, in a library I had forgotten to correct… :p

        Thanks again Sara.

        Reply
  2. many many thanks fpr the great tutorial – would love to see a port to mycropython . d o you thnk taht this is possible

    love to hear from you
    greetings

    Reply
    • Hi Martin.
      What do you mean by “port to micropython”?
      We’re working on a tutorial for the L298N with ESP8266 and ESP32 with MicroPython.
      It is not published yet, but it will be published soon.
      Regards,
      Sara

      Reply
  3. Hi which pin of esp32 can be connected to motor driver if we use two motor (Motor A&B)? I tried to connect many pin of esp32 for two motor but doesn’t work.how to code PWM
    to control two motor?

    Reply
  4. Hi Sara,
    I tried with this modified code below but only my left motor works . There is no movement in my right motor. Is that any problem in my code? Can help?

    // Motor A
    int LM1 = 27;
    int LM2 = 26;
    int ENA = 14;

    //Motor B
    int RM1 = 33;
    int RM2 = 25;
    int ENB= 32;

    // Setting PWM properties
    const int freq = 30000;
    const int pwmChannelLM = 0;
    const int pwmChannelRM = 1;
    const int resolution = 8;
    int dutyCycle = 200;

    void setup() {
    // sets the pins as outputs:
    pinMode(LM1, OUTPUT);
    pinMode(LM2, OUTPUT);
    pinMode(ENA, OUTPUT);
    pinMode(RM1, OUTPUT);
    pinMode(RM2, OUTPUT);
    pinMode(ENB, OUTPUT);

    // configure LED PWM functionalitites
    ledcSetup(pwmChannelLM, freq, resolution);
    ledcSetup(pwmChannelRM, freq, resolution);

    // attach the channel to the GPIO to be controlled
    ledcAttachPin(ENA, pwmChannelLM);
    ledcAttachPin(ENB, pwmChannelRM);

    Serial.begin(115200);

    // testing
    Serial.print(“Testing DC Motor…”);
    }

    void loop() {
    // Move the DC motor forward at maximum speed
    Serial.println(“Moving Forward”);
    digitalWrite(LM1, LOW);
    digitalWrite(LM2, HIGH);
    digitalWrite(RM1, LOW);
    digitalWrite(RM2, HIGH);

    delay(2000);

    // Stop the DC motor
    Serial.println(“Motor stopped”);
    digitalWrite(LM1, LOW);
    digitalWrite(LM2, LOW);
    digitalWrite(RM1, LOW);
    digitalWrite(RM2, LOW);
    delay(1000);

    // Move DC motor backwards at maximum speed
    Serial.println(“Moving Backwards”);
    digitalWrite(LM1, HIGH);
    digitalWrite(LM2, LOW);
    digitalWrite(RM1, HIGH);
    digitalWrite(RM2, LOW);
    delay(2000);

    // Stop the DC motor
    Serial.println(“Motor stopped”);
    digitalWrite(LM1, LOW);
    digitalWrite(LM2, LOW);
    digitalWrite(RM1, LOW);
    digitalWrite(RM2, LOW);
    delay(1000);

    // Move DC motor forward with increasing speed
    digitalWrite(LM1, HIGH);
    digitalWrite(LM2, LOW);
    digitalWrite(RM1, HIGH);
    digitalWrite(RM2, LOW);
    while (dutyCycle <= 255){
    ledcWrite(pwmChannelLM, dutyCycle);
    ledcWrite(pwmChannelRM, dutyCycle);
    Serial.print("Forward with duty cycle: ");
    Serial.println(dutyCycle);
    dutyCycle = dutyCycle + 5;
    delay(500);
    }
    dutyCycle = 200;
    }

    Reply
    • Dear Tray,
      I used your code on other pins of the ESP32.
      Needless to say, it worked and thanks to you my project has movement.
      I searched earth and land for a code that did this.
      I also edited it having two dutyCycles (CycleA and B) to have each motor work at a different speed.
      Thank you so much.

      Reply
  5. Hola intente mesclar el proyecto de los leds por servidor wiffi y el este y que mi carro no andaba y crei que era porque el codigo no tiene el PWM y este si pero me arroja error-
    CODIGO:
    #include

    const char* ssid = “CowBoy”;
    const char* password = “GATOSxGATOS”;

    WiFiServer server(80);

    String header;


    }

    Reply
  6. ssue: unable to flash micropython to esp 32: open serial error, please try again. hope to connect internet and try again.

    pretty new to micropython – want to flash micropython to esp 32 ( resp 8266) board.

    Quote

    getting this errors all the time.

    open serial error, please try again.
    hope to connect internet and try again.
    current version only open py txt json ini file.
    hope to connect internet and try again.
    hope to connect internet and try again.

    any idea;

    many thanks for any and all help in advance.

    Reply
  7. Hi! thank you for your tutorial
    Quote: “For the frequency we’re using, when you apply duty cycles smaller than 200, the motor won’t move and will make a weird buzz sound”
    How can this be avoided? because if the resolution allows values beteween 0 and 255, by starting at 200 we lose 78% of the values and the motor is much less controllable!!

    Thank you

    Reply
  8. Hello,

    I am having some trouble getting my motors to spin with my ESP32 and the L298N. I believe I have narrowed down the problem to the voltage that the ESP32 is supplying to the L298N’s input pins.

    Using a multimeter, I am reading an expected 3.2v when I use digitalWrite() to the ESP32’s output pin. However, when it’s attached to the motor’s input pin on the L298N, nothing happens. When I supply 5v to the input pin, the motor moves.

    From the L298N’s datasheet, I see that the input voltage is from -0.3 – 7v. Would you know why my ESP32’s 3.2 is failing to drive the motor?

    Thank you!

    Reply
  9. Hey guys, the L298N is ancient, dont use it.
    Why? it’s literally back from 1980s.
    – it needs 3 GPIOs for one motor, wtf?! (wtf= what for?)
    – it uses old transistors, loosing a lot of energy (draining your batteries and reducing max voltage significantly)
    – it puts that energy into heat (needing to be cooled)
    – so it has a big heatsink (making that board giantic overall)
    I dropped dead when i received those monsters, they are bigger than my ESP board.
    I reccomend the adarfruit drv8871: can handle more Amperes, less hot, much smaller, needs 2 wires per motor, still cheap. Done.

    Reply
  10. I checked L298 spec sheet, that its nominal input voltage is 5V, but esp32 out put is only 3.3V. That means for 12V power supply we provide 10V something to motors?

    Reply
  11. Hello,
    I’m trying to follow this tutorial, I did everything step-by-step, cabling everything as shown and using the same exact code.
    There are 2 differences in my experiment, I’m using a 7.4V battery to power the L298N and I’m using a different motor. My motor is one of those 6V yellow motors used by robot car kits.
    My problem is that it only rotates only if motor1Pin1 is set to LOW and motor1Pin2 is set to HIGH (forward direction), not if they are set opposite (backward).
    I’ve connected the L298N to Arduino and the motor can rotate forward and backward.
    What problem could I have with this tutorial?

    Reply
  12. Hello,
    I’m trying to use the tutorial sketch with an H brigde L193D.
    One thing seems odd.
    At startup, the Forward, Stopped and Backward sequences do not work. They execute only after running the Forward increase sequence. After that the sketch runs normally. Do you have any idea what the problem could be.
    Thanks for your help.

    Reply
  13. Hello,
    I don’t find much information about the frequency setting
    “const int freq = XXX”
    I see examples that put 40Khz and other 1Khz for very similar DC motors. Yet something will change ..
    Doing some tests with the classic yellow motors for arduino I noticed that by putting a lower frequency (700 hz) the dutycicle also works at values below 100 (with 8bit = 0/255) but using 2 motors it seems to me that are more evident some speed differences between motors, while at high frequencies the motors run at equal speed.
    Anyone have similar experiences?
    Are there any reference parameters to choose the right frequency for different actuators?

    Reply
  14. One of the shortfalls of using the L298N board is that it doesn’t use the sense pins on the L298N chip. One needs to use the bare L298N chip in order to access them. The purpose of those pins is to measure the current drawn by each motor through a shunt resistor. If you connect the hot side of that resistor to an analog input of the ESP32, you can verify that the motor is consuming the correct amount of current. No current could mean that te motor is not spinning for some reason (like a bad connection or broken motor coil), too much current would mean that the motor can’t cope with the load or is even stalling.
    The only limitation is that the voltage drop across the shunt resistor must not exceed 2V (I assume that he voltage drop is at the expense of Vgs to drive the lower leg of the H-bridge).

    Reply
  15. You’re using a way too high frequency. I tell you why. Moving my experimental robot driven by two geared 12V/0,58A DC motors from an Uno to an ESP32, I had to change the PWM-part of my code and I set the PWM-frequency at 10 kHz. This resulted in motors that would hardly move if the duty cycle was reduced to about 50% and didn’t move at all for lower duty cycles. Since the default PWM frequency of an Uno is 490 Hz, I lowered it to this value. After that my motors were driving as I was used to.

    Choosing a very high frequency reduces the transferred energy to the motor immense. A normal DC motor is, seen from the electronical point of view, a slow device. Compare it with a potter’s wheel of which you control the speed by giving it a firm kick once a while. Imagine the ineffectiveness to softly kick it ten times a second.

    I believe it’s reasonless to choose a PWM frequency higher than about 1000 Hz for any motor whatsoever.

    Reply
  16. Hey Rui and Sara,

    Thanks so much for this tutorial! BTW, I just used the code with an ESP32-S3 DevKitC-1 board, and the only changes required were the motor pin numbers. Unless I’m missing something, pins 26 and 27 aren’t exposed on this board. I used 12 and 13 instead, and the code worked like a charm.

    Steve

    Reply

Leave a Comment

 

 

Close ad


GPS for Arduino

https://youtu.be/09sNLmoJ3HI

Arduino Neural Network Robot

https://youtu.be/97R3TcUh5eI

Sunday, 1 December 2019

4WD Arduino Car Project

This is an excellent project which demonstrates how to control a 4WD Arduino Car.

However this car cannot spin but it is easy to modify the code to allow it to spin instead of just turning left and right.
 
This Arduino car has a better turning radius than cars that have steering wheels because it can spin.
If the left wheels are run forward and the right wheels are run reversed, the car will spin.

It allows the car to manoeuvre in tight spaces, but when spinning it cannot move forward at the same time.

To left or right while moving forward, just move the left wheels at a different speed from that of the right wheels.

It means that there is no need to use 4 speed controllers. Only 2 speed controllers are required. One speed controller for the left and another for the right wheels.

If we can control the speed of 3 wheels independently, we can spin the car around one wheel. I do not see much advantage out of it. 

Building a 4WD Autonomous Car with Arduino

In this tutorial you will learn to make a 4WD robotic car with built-in obstacle avoidance. This project involves building a 4WD car with an ultrasonic sensor that can detect nearby objects and change its direction to avoid these objects. The ultrasonic sensor will be attached to a servo motor which is constantly scanning left and right looking for objects in its way.
4WD autonomous robotic car
4WD autonomous robotic car
You can extend this project by adding more sensors such as ultrasonic sensor to the rear so that the car doesn’t reverse into objects, speed detection sensors to determine speed, line following sensors, and LED brake lights. You could even add light sensors and LEDs to turn headlights on in low-light conditions or a Bluetooth connection to control the car through a mobile app.

Parts required

Here is what you will need:
  • 1x Arduino Uno board
  • 1x 4WD Robotic Car kit (4 wheels, 4 motors, chassis, AA battery enclosure, screws)
  • 6x AA batteries
  • 1x 9V battery
  • 1x 9V battery power cable barrel jack connector
  • 1x L298N Motor Module
  • 1x Arduino Sensor Shield v5.0
  • 1x HC-SR04 Ultrasonic Sensor
  • 1x Servo motor (any small servo motor will do but if you don’t have one you can leave it out)
  • Assorted colour wires:
    • 4x female-to-female wires for Ultrasonic Sensor
    • 8x female-to-female wires for the Motor Module to Sensor Shield
    • 8x bare-ended wires to go from the four motors to the Motor Module
    • 2x bare-ended wires to go from the Motor Module to Sensor Shield
    • 3x wires for the servo motor with female end attaching to Sensor Shield (should already be included with the servo motor)
    • 2x bare-ended wires to go from AA Battery enclosure to the motor Module (should already be included with the battery enclosure)
  • Arduino IDE software – free at http://www.arduino.cc
  • 1x USB cable (A male plug to B male plug)
  • A computer to program with
Note: Make sure you get a range of different colours for the wires (eg. red for voltage, black for ground, etc.). Some items such as the battery enclosure, motors and servo motor may come with wires so you may not need to purchase these separately. Some motor modules or sensor shields may use different pins (eg. male or female or just bare-ended wires).
Below are images of the main components you need (apart from the wiring and batteries) – the different robot parts, shields, modules and sensors.
Click for larger image
Click for larger image

Assembling the robotic car

The first thing to do is to assemble all the car chassis parts and attach the motors to the wheels. This is explained in detail in the video below.
Video Player
00:00
15:59

Wiring it up

Now that the chassis is assembled and the wheels and motors are attached, you will need to wire up all of the components. You can watch the video below or scroll down for the step-by-step instructions and wiring diagram.
Video Player
00:00
18:38
  1. Connect the red wire (voltage) from the battery enclosure to VCC on the L298N Motor Module.
  2. Connect the black wire (ground) from the battery enclosure to GND on the Motor Module.
  3. Connect the red wire from Motor A1 (rear left) and the red wire from Motor A2 (front left) to OUT1 on the Motor Module (both wires can be twisted together and will go into OUT1 – the wiring diagram further down this page shows how to do this).
  4. Connect the black wire from Motor A1 (rear left) and the black wire from Motor A2 (front left) to OUT2 on the Motor Module.
  5. Connect the red wire from Motor B1 (rear right) and the red wire from Motor B2 (front right) to OUT3 on the Motor Module.
  6. Connect the black wire from Motor B1 (rear right) and the black wire from Motor B2 (front right) to OUT4 on the Motor Module.
  7. Connect a female-to-female end wire from ENA (Engine A) on the Motor Module to signal pin 1 on the Sensor Shield (the #2 pin in the S row. There are three rows – S stands for Signal, V for Voltage and G for Ground).
  8. Connect a female-to-female end wire from 5V (next to ENA) on the Motor Module to voltage pin 1 on the Sensor Shield (it doesn’t really matter which pin for voltage as long as it is in the V row).
  9. Connect a female-to-female end wire from IN1 on the Motor Module to signal pin 2 on the Sensor Shield.
  10. Connect a female-to-female end wire from IN2 on the Motor Module to signal pin 3 on the Sensor Shield.
  11. Connect a female-to-female end wire from IN3 on the Motor Module to signal pin 4 on the Sensor Shield.
  12. Connect a female-to-female end wire from IN4 on the Motor Module to signal pin 5 on the Sensor Shield.
  13. Connect a female-to-female end wire from 5V (next to ENB) on the Motor Module to voltage pin 6 on the Sensor Shield (it doesn’t really matter which pin for voltage as long as it is in the V row).
  14. Connect a female-to-female end wire from ENB (Engine B) on the Motor Module to signal pin 6 on the Sensor Shield.
  15. Connect the signal wire from the servo motor to signal (S) pin 7 on the Sensor Shield, the voltage wire from the servo motor to the voltage (V) pin 7 on the Sensor Shield, and the ground wire from the servo motor to the GND (G) pin 7 on the Sensor Shield.
  16. Attach the Ultrasonic Sensor to the servo motor and then attach the servo motor to the front of the car so that it can scan left and right looking for objects in its path.
    You can use sticky tape, blu-tack, glue or a 3D printed/laser cut mount or whatever you like to attach everything, as long as everything is firmly mounted.
  17. Use female-to-female end plugs to connect the Ultrasonic sensor to the Sensor Shield. Firstly, attach the TRIG pin from the Ultrasonic sensor to signal (S) pin 8 on the Sensor Shield. Attach the ECHO pin from the ultrasonic sensor to signal (S) pin 9 on the Sensor Shield. Attach the VCC pin from the Ultrasonic Sensor to the voltage (V) pin 10 on the Sensor Shield. Lastly, attach the GND pin from the Ultrasonic Sensor to the GND (G) pin 11 on the Sensor Shield.
  18. Now attach the Sensor Shield on top of the Arduino Uno board making sure to not bend any pins. Connect a 9V Battery Barrel Jack Connector to a 9V battery and then plug this in to the Arduino’s barrel jack (see diagram below).
  19. That’s it! Now all you need is batteries and the code!
Please note: There are several variations of the sensors and modules and several different ways to wire this up. For example, you can add a charging component to charge batteries and you can also add different switches. There may be other better methods to use, but I have gone for the simplest way I know of to set this up.

Wiring diagram

Click for larger image
Click for larger image

Writing the code

Here is the code to get your robot moving. The code is written in C language and is written in the Arduino IDE software. The code for a robot with a servo motor and the code for a robot without a servo motor is shown below. If you don’t have an ultrasonic sensor and just want to use Bluetooth control via a phone app, then you can just extract the parts of the code that you need and then add the Bluetooth code.

Code to use with a servo motor

  1. // Setup the servo motor
  2. #include <Servo.h>
  3. Servo myservo;
  4. int servposnum = 0;
  5. int servpos = 0;

  6. // Setup Motor A (front and rear) pins
  7. int enableA = 1;
  8. int pinA1 = 3;
  9. int pinA2 = 2;

  10. // Setup Motor B (front and rear) pins
  11. int enableB = 6;
  12. int pinB1 = 5;
  13. int pinB2 = 4;

  14. // Setup Ultrasonic Sensor pins
  15. #define trigPin 8
  16. #define echoPin 9


  17. void setup() {
  18. // The setup code goes here and runs once only
  19. // Configure the pin modes for each drive motor
  20. pinMode (enableA, OUTPUT);
  21. pinMode (pinA1, OUTPUT);
  22. pinMode (pinA2, OUTPUT);

  23. pinMode (enableB, OUTPUT);
  24. pinMode (pinB1, OUTPUT);
  25. pinMode (pinB2, OUTPUT);

  26. // Configure the pin modes for the Ultrasonic Sensor
  27. pinMode(trigPin, OUTPUT);
  28. pinMode(echoPin, INPUT);

  29. // Turn pin into servo driver. Calls pinMode. Returns 0 on failure.
  30. myservo.attach(7);
  31. }

  32. void loop() {
  33. // Main code goes here and will run repeatedly:

  34. car(); // function keeps moving car forward while distance > 15cm
  35. avoid(); // function makes car go back, turn slightly right to move forward in new direction
  36. }

  37. // Create motor functions
  38. void motorAforward() {
  39. digitalWrite (pinA1, HIGH);
  40. digitalWrite (pinA2, LOW);
  41. }
  42. void motorBforward() {
  43. digitalWrite (pinB1, LOW);
  44. digitalWrite (pinB2, HIGH);
  45. }
  46. void motorAbackward() {
  47. digitalWrite (pinA1, LOW);
  48. digitalWrite (pinA2, HIGH);
  49. }
  50. void motorBbackward() {
  51. digitalWrite (pinB1, HIGH);
  52. digitalWrite (pinB2, LOW);
  53. }
  54. void motorAstop() {
  55. digitalWrite (pinA1, HIGH);
  56. digitalWrite (pinA2, HIGH);
  57. }
  58. void motorBstop() {
  59. digitalWrite (pinB1, HIGH);
  60. digitalWrite (pinB2, HIGH);
  61. }
  62. void motorAcoast() {
  63. digitalWrite (pinA1, LOW);
  64. digitalWrite (pinA2, LOW);
  65. }
  66. void motorBcoast() {
  67. digitalWrite (pinB1, LOW);
  68. digitalWrite (pinB2, LOW);
  69. }
  70. void motorAon() {
  71. digitalWrite (enableA, HIGH);
  72. }
  73. void motorBon() {
  74. digitalWrite (enableB, HIGH);
  75. }
  76. void motorAoff() {
  77. digitalWrite (enableA, LOW);
  78. }
  79. void motorBoff() {
  80. digitalWrite (enableB, LOW);
  81. }

  82. // Setup movement functions
  83. void forward (int duration) {
  84. motorAforward();
  85. motorBforward();
  86. delay (duration);
  87. }
  88. void backward (int duration) {
  89. motorAbackward();
  90. motorBbackward();
  91. delay (duration);
  92. }
  93. void right (int duration) {
  94. motorAbackward();
  95. motorBforward();
  96. delay (duration);
  97. }
  98. void left (int duration) {
  99. motorAforward();
  100. motorBbackward();
  101. delay (duration);
  102. }
  103. void coast (int duration) {
  104. motorAcoast();
  105. motorBcoast();
  106. delay (duration);
  107. }
  108. void breakRobot (int duration) {
  109. motorAstop();
  110. motorBstop();
  111. delay (duration);
  112. }
  113. void disableMotors() {
  114. motorAoff();
  115. motorBoff();
  116. }
  117. void enableMotors() {
  118. motorAon();
  119. motorBon();
  120. }

  121. // Setup Ultrasonic Sensor distance measuring
  122. int distance() {
  123. int duration, distance;
  124. digitalWrite(trigPin, HIGH);
  125. delayMicroseconds(1000);
  126. digitalWrite(trigPin, LOW);
  127. duration = pulseIn(echoPin, HIGH);
  128. distance = (duration/2) / 29.1;
  129. return distance;
  130. }

  131. // Setup the main car function
  132. void car() {
  133. int distance_0;
  134. distance_0 = distance();
  135. // Keep moving forward in a straight line while distance of objects > 15cm
  136. while(distance_0 > 15)
  137. {
  138. // Keep moving servo motor back and forth to scan surroundings
  139. // This allows the ultrasonic sensor to see more to its left and right
  140. if(servposnum == 0)
  141. {
  142. myservo.writeMicroseconds (1900);
  143. servposnum = 1;
  144. delay(100);
  145. }
  146. else if(servposnum == 1)
  147. {
  148. myservo.writeMicroseconds (2200);
  149. servposnum = 2;
  150. delay(100);
  151. }
  152. else if(servposnum == 2)
  153. {
  154. myservo.writeMicroseconds (1900);
  155. servposnum = 3;
  156. delay(100);
  157. }
  158. else if(servposnum == 3)
  159. {
  160. myservo.writeMicroseconds (1600);
  161. servposnum = 1;
  162. delay(100);
  163. }
  164. motorAon();
  165. motorBon();
  166. forward(1);
  167. distance_0 = distance();
  168. }
  169. breakRobot(0);

  170. }
  171. void avoid()
  172. {
  173. // Go back and turn slightly right to move car in new direction if object detected < 15cm away
  174. backward(500);
  175. right(360);
  176. }

Code to use without a servo motor

  1. // Setup Motor A (front and rear) pins
  2. int enableA = 1;
  3. int pinA1 = 3;
  4. int pinA2 = 2;

  5. // Setup Motor B (front and rear) pins
  6. int enableB = 6;
  7. int pinB1 = 5;
  8. int pinB2 = 4;

  9. // Setup Ultrasonic Sensor pins
  10. #define trigPin 8
  11. #define echoPin 9

  12. void setup() {
  13. // The setup code goes here and runs once only
  14. // Configure the pin modes for each drive motor
  15. pinMode (enableA, OUTPUT);
  16. pinMode (pinA1, OUTPUT);
  17. pinMode (pinA2, OUTPUT);

  18. pinMode (enableB, OUTPUT);
  19. pinMode (pinB1, OUTPUT);
  20. pinMode (pinB2, OUTPUT);

  21. // Configure the pin modes for the Ultrasonic Sensor
  22. pinMode(trigPin, OUTPUT);
  23. pinMode(echoPin, INPUT);
  24. }

  25. void loop() {
  26. // Main code goes here and will run repeatedly:
  27. car(); // function keeps moving car forward while distance of objects in front are > 15cm away
  28. avoid(); // function makes car go back, turn slightly right to move forward in new direction
  29. }

  30. // Create motor functions
  31. void motorAforward() {
  32. digitalWrite (pinA1, HIGH);
  33. digitalWrite (pinA2, LOW);
  34. }
  35. void motorBforward() {
  36. digitalWrite (pinB1, LOW);
  37. digitalWrite (pinB2, HIGH);
  38. }
  39. void motorAbackward() {
  40. digitalWrite (pinA1, LOW);
  41. digitalWrite (pinA2, HIGH);
  42. }
  43. void motorBbackward() {
  44. digitalWrite (pinB1, HIGH);
  45. digitalWrite (pinB2, LOW);
  46. }
  47. void motorAstop() {
  48. digitalWrite (pinA1, HIGH);
  49. digitalWrite (pinA2, HIGH);
  50. }
  51. void motorBstop() {
  52. digitalWrite (pinB1, HIGH);
  53. digitalWrite (pinB2, HIGH);
  54. }
  55. void motorAcoast() {
  56. digitalWrite (pinA1, LOW);
  57. digitalWrite (pinA2, LOW);
  58. }
  59. void motorBcoast() {
  60. digitalWrite (pinB1, LOW);
  61. digitalWrite (pinB2, LOW);
  62. }
  63. void motorAon() {
  64. digitalWrite (enableA, HIGH);
  65. }
  66. void motorBon() {
  67. digitalWrite (enableB, HIGH);
  68. }
  69. void motorAoff() {
  70. digitalWrite (enableA, LOW);
  71. }
  72. void motorBoff() {
  73. digitalWrite (enableB, LOW);
  74. }

  75. // Setup movement functions
  76. void forward (int duration) {
  77. motorAforward();
  78. motorBforward();
  79. delay (duration);
  80. }
  81. void backward (int duration) {
  82. motorAbackward();
  83. motorBbackward();
  84. delay (duration);
  85. }
  86. void right (int duration) {
  87. motorAbackward();
  88. motorBforward();
  89. delay (duration);
  90. }
  91. void left (int duration) {
  92. motorAforward();
  93. motorBbackward();
  94. delay (duration);
  95. }
  96. void coast (int duration) {
  97. motorAcoast();
  98. motorBcoast();
  99. delay (duration);
  100. }
  101. void breakRobot (int duration) {
  102. motorAstop();
  103. motorBstop();
  104. delay (duration);
  105. }
  106. void disableMotors() {
  107. motorAoff();
  108. motorBoff();
  109. }
  110. void enableMotors() {
  111. motorAon();
  112. motorBon();
  113. }

  114. // Setup Ultrasonic Sensor distance measuring
  115. int distance() {
  116. int duration, distance;
  117. digitalWrite(trigPin, HIGH);
  118. delayMicroseconds(1000);
  119. digitalWrite(trigPin, LOW);
  120. duration = pulseIn(echoPin, HIGH);
  121. distance = (duration/2) / 29.1;
  122. return distance;
  123. }

  124. // Setup the main car function
  125. void car() {
  126. int distance_0;
  127. distance_0 = distance();
  128. // Keep moving forward in a straight line while distance of objects in front > 15cm away
  129. while(distance_0 > 15)
  130. {
  131. motorAon();
  132. motorBon();
  133. forward(1);
  134. distance_0 = distance();
  135. }
  136. breakRobot(0);

  137. }

  138. // Go back and turn slightly right to move car in new direction
  139. // This function only runs if an obstacle within 15cm is detected
  140. void avoid()
  141. {
  142. backward(500);
  143. right(360);
  144. }

Finishing up

Once you have the code you will need to verify it and then upload it to your Arduino Uno board. Make sure you have either the Arduino disconnected from the Sensor Shield or all batteries disconnected when uploading the code to prevent any errors while uploading. Make sure to also arrange the different components carefully in the chassis to prevent any short circuits.
And that’s it! There is so much more that can be done with this project. Try extending your project by adding the following features:
  • Line following
  • Low-light activated headlights (using light sensors and LEDs)
  • Brake lights
  • Speed measuring
  • Bluetooth/mobile app control
  • More ultrasonic sensors to avoid reversing into objects or falling off edges
The video below shows a demo of the 4WD autonomous car using an Arduino and the ultrasonic sensor attache to a servo motor. Six AA batteries power the motors while the Arduino board is powered using a separate 9V battery.
Video Player
00:00
00:21

More photos