Control DC motor with DRV8871 on ESP32

I'm new to Arduino programming so I apologize because I know this question is extremely basic for most.

I have a DC motor that I want to control with a DRV8871 and my ESP32, this tutorial explains how to do it: Usage | Adafruit DRV8871 Brushed DC Motor Driver Breakout | Adafruit Learning System

But, I get the error "ESP32 error: 'analogWrite' was not declared in this scope" (apparently it only gives an error with ESP32).

I found this tutorial: 14 DC motor with ESP32 by using DRV8871 Driver - YouTube
It explains how to do it, it works fine, but I have a couple of problems and questions:

  1. That code turns on the LED, and for me it is not necessary to turn it on.
  2. My DC motor has a gearbox and at first it doesn't move (it does start) because the speed is small, how can I change the speed?
  3. That code uses pins 21 and 2, is it possible to use others? For example, 22/23... and 19/21 for my other DC motor.
int Motor = 21;
int Direction = 2;
boolean direction  = true;

void setup() {
  //Serial.begin(115200);
  //Serial.println("DRV8871 test");
  pinMode(Direction, OUTPUT);
  ledcAttachPin(Motor,0);  // assign the speed control PWM pin to a channel
  
  // initialize channel 0-15, resolution 1-16 bit, frequency limit depend on resolution
  ledcSetup(0,4000,8);  // channel- 0, frequency- 4000, Resolution bit- 8
 
}

void loop() {
  digitalWrite(Direction, direction);
  for(int i=0; i<=255; i++) {
   ledcWrite(0,i);
   delay(15);
  }
  direction = !direction;  // switch direction
}

I just compiled the sketch from the Adafruit page for an ESP32 (DOIT ESP32 DEVKIT V1) and it compiled without any errors or warnings. What model ESP32 did you select?

1 Like

Thanks, I'm going to try it.

But how to specify the speed? That is, 255 or 100. One that is exact and immediate, that is, that does not start from 0 to 255, but immediately 255.

Take out:

  // ramp up forward
  digitalWrite(MOTOR_IN1, LOW);
  for (int i = 0; i < 255; i++)
  {
    analogWrite(MOTOR_IN2, i);
    delay(10);
  }

and replace it with:

  // forward
  digitalWrite(MOTOR_IN1, LOW);
  analogWrite(MOTOR_IN2, 255); // or digitalWrite(MOTOR_IN2, HIGH);
1 Like

I hope it's not too much to ask, but can you explain to me what that loop does?

Increase one by 1 the value of i or what?

How do I change the direction?

for (int i = 0; i < 255; i++)
means:

    int i = 0;
    while (i < 255)
    {
      {
        // Do the stuff inside the 'for' loop body
      }
      i++; // works like i = i + 1;
    }

Basically, execute the body of the loop with 'i' having values from 0 to 254.

1 Like

I understand, thank you very much.

How do I change the direction?
It occurs to me that it is as follows, am I right?

  // forward
  digitalWrite(MOTOR_IN1, HIGH);
  analogWrite(MOTOR_IN2, 255); // or digitalWrite(MOTOR_IN2, HIGH);

Close but (EDIT to add: "typically,") the motor moves when the two pins are different. If you change IN1 to HIGH that means that the motor will move in reverse when IN2 is LOW. Now '255' means stopped and '0' means full speed. An easy way to make it more understandable is:

  speed = 255;
  // Forwrd
  digitalWrite(MOTOR_IN1, LOW);
  analogWrite(MOTOR_IN2, speed);

  // Reverse
  digitalWrite(MOTOR_IN1, HIGH);
  analogWrite(MOTOR_IN2, 255 - speed);

That way speed = 0 is stopped and speed = 255 is full speed.

1 Like

I use ESP32 Dev Module, I get the error that I told you before:

Is there a solution where I just use : analogWrite ?

I tried with:

  // Forwrd
  digitalWrite(MOTOR_IN1, LOW);
  digitalWrite(MOTOR_IN2, 255);
  
  delay(1000);
  
  // Reverse
  digitalWrite(MOTOR_IN1, HIGH);
  digitalWrite(MOTOR_IN2, 0);

But it only moves in one direction without stopping.

Originally, ESP32 codes didn´t accept analogWrite(). ledcWrite() should be used instead, in order to use PWM control.

But, according to @UKHeliBob in #8 answer at this post --> Control 12DCv Moter Using L298n and esp-32 - #8 by UKHeliBob

analogWrite has just been implemented for ESP32 if you have the latest version of the board installed. Take a look there!

Probably @johnwasser already has the latest version and you don´t. :wink:

1 Like

I honestly don't understand this because I don't 100% understand what LEDC is. Can you clarify?

I'm reading about this library, I think it's the solution: GitHub - erropix/ESP32_AnalogWrite: Provides an analogWrite polyfill for ESP32 using the LEDC functions
This use LEDC. But I don't know how it works.

ledcWrite() is the function used to write PWM in ESP32s. analogWrite() wouldn´t work. Take a look at the code you´ve posted at first: it uses the following sequence:

ledcAttachPin(Motor,0); // to attach PWM channel 0 to pin 21
ledcSetup(0,4000,8);  // configures channel 0 with 4000 Hz frequency and 8 bit resolution (that means 2^8 values --> min=0, max=255)
ledcWrite(0,i); // writes a PWM value between 0 and 255 to channel 0

To solve your problem you can do one of the following things:

  1. Learn how to use PWM in ESP32 "old fashioned way" like above; OR

  2. On the Arduino IDE, update ESP32 board version to 2.0.2. This way, it will accept analogWrite(). Adafruit and @johnwasser ´s code will then work for you; OR

  3. install and use the library that you´ve mentioned in #11, which probably just converts analogWrite() format to ledcWrite() format.

Number (3) will need you to learn how to use the library anyway. So, if you have some time and patience, it´s better going to (1). But if you want faster result, (2) looks better.

1 Like

I already achieved it with the library that I mentioned before. But I have a question.

To turn left I use:

digitalWrite(MOTOR_IN1, LOW);
analogWrite(MOTOR_IN2, 255);

To turn right I use:

digitalWrite (MOTOR_IN1, LOW);
analogWrite (MOTOR_IN2, 0);

1- Why should I put 0 in one and 255 in another? As I said, it already works, this is a simple curiosity question.

2- If I want it to go slower, in case 1 I reduce the number and in case 2 I increase the number?

1 Like

To be honest, I don´t know why it´s working... If IN1 is LOW and IN2 is 0, the motor should stop, not turn right.

If you´re using this to turn left:

Then, you should be using this to turn right:

analogWrite(MOTOR_IN1, 255);
digitalWrite(MOTOR_IN2, LOW);

To go slower you can use any number that is less than 255. In theory, 128 would give you 50% of the speed.

1 Like

johnwasser said it before, but didn't say why.

It's like I said, in one case I increase the value so that the speed decreases, and in the other case I increase the value so that the speed decreases, but why? The logic is that 255 is always the highest speed, as with l298n.

The main statement of @johnwasser declaration is this one:

That means when IN1 is HIGH and IN2 is LOW, motor rotates to one side. When IN1 is LOW and IN2 is HIGH, motor rotates to the other side. If you want to control speed, then you change the HIGH side for an analogWrite() with the value that you want.

The rest of his statement was related to this:

In this case, both channels are HIGH at the same time and the motor will stop. Changing 255 for 0 would move the motor full speed (EDIT: because de other side is already HIGH).

In this case I would like to take a look in your code that is working. Would you mind to share it?

1 Like

I have an unusual problem.

My motor works fine when I control it via serial monitor, but not when I control it via BLE. When I do it via BLE it only works in one direction, via serial monitor it works in both directions.

I opened a new question because it is a different topic, you can see it here: Motor works via serial monitor, but not via BLE - ESP32

Please help. I don't have the slightest idea why this problem occurs.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.