DRV8833 Motor trouble Inquiry

Hello,

I hope everyone is doing well. I am working on a robot using the DRV8833 to power two motors. For some reason, the left motor will sometimes move slower than the right motor. We use a PID system to make the bot move straight, but the inconsistency poses problems (Sometimes, it will go straight, and other times it does not). Below is the schematic:

Hardware

  • Parts:
    • Waveshare esp32 zero, driving the motor driver.
    • Polulu DRV8833 motor driver, powered by a boost regulator from 3.7V to 6V.
    • U3V40F9 voltage step-up regulator
    • step up is powered by 1 3.7 850 mah battery.

Software

Driving the Motor

static char Rcurrentdirection = '\0';
static void actualMoveRightMotor(uint8_t rightPWM, char direction) {
  if(direction == 'N') { //moving forward relative to front of robot
    if(Rcurrentdirection != direction){
      digitalWrite(BIN1_RIGHTMOT, LOW);
      digitalWrite(BIN2_RIGHTMOT, HIGH);
      Rcurrentdirection = direction;
    }
    analogWrite(BIN2_RIGHTMOT, rightPWM);
  } else {
    if(Rcurrentdirection != direction){
      digitalWrite(BIN1_RIGHTMOT, HIGH);
      digitalWrite(BIN2_RIGHTMOT, LOW);
      Rcurrentdirection = direction;
    }
    analogWrite(BIN1_RIGHTMOT, rightPWM);
  }
}

To move the motor forward/backward, we specify the direction. I also have a condition that if the current motor direction is different from the previous motor direction, do the digital writes to change the direction of the motor driver. The logic is similar for the left motor.

PID Control

  • We are using the Adafruit bno055 IMU to ensure the bot goes straight. We know this approach works correctly, as we have used this approach on previous bots. It moves the bot at the Angle specified.
#define DIA 32
#define PI 3.1415926535897932384626433832795

double maxSpeed = 175;
double minSpeed = 100;

void straight(char direction, int distance)
{
    // ratio for the Angle PID
    double AKp = 1.0; /* Angle proportion scale constant */
    double AKd = 0.0;
    // ratios for the Encoder PID 
    double LEKp = 1; /* Left encoder proportion scale constant */
    double LEKd = 0.0;
    double REKp = 1; /* Right encoder proportion scale constant */
    double REKd = 0.0;

    //Angle variables
    double AngleError = 0.0;
    double PreviousAngleError = 0.0;
    double currentAngle = angle();
    double targetDirection = 0.0;
    switch (direction)
    {
    case 'N':
        targetDirection = 0;
        break;
    case 'S':
        targetDirection = 180;
        break;
    case 'E':
        targetDirection = 90;
        break;
    case 'W':
        targetDirection = 270;
        break;
    }

    // encoder values
    double numTicks = (102 * distance) / (DIA * PI); // Num ticks that we need to travel
    double EncoderLeftError = numTicks;
    double EncoderRightError = numTicks;

    // clear the encoder count
    encLeft.clearCount();
    encRight.clearCount();

    // final motor speeds
    double LeftMotorSpeed = 0.0;
    double RightMotorSpeed = 0.0;

    // time values (for derivative)
    unsigned long PreviousTime = millis();
    unsigned long CurrentTime = millis();
    
    /* stall detection variables */

    // Variables for destination check
    bool isAtDestination = false;
    const double encoderTolerance = 5.0;      // Consider arrived if within this many ticks
    
    double basespeed = 135;
    while (1)
    {
        AngleError = targetDirection - Angle (); //Angle () gets the Angle the bot is at. 
        //normalize the angle error
        while (AngleError > 180) AngleError -= 360;
        while (AngleError <= -180) AngleError += 360;

        // Calculate encoder errors
        EncoderLeftError = numTicks - getLeftEncoder();
        EncoderRightError = numTicks + getRightEncoder();

        //constrain the max encoder error to the base speed.
        EncoderLeftError = constrain(EncoderLeftError, 0, basespeed);
        EncoderRightError = constrain(EncoderRightError, 0, basespeed);
        /* Calculate the motor speeds based on the error*/

        LeftMotorSpeed = (LEKp * EncoderLeftError) + (AKp * AngleError);
        RightMotorSpeed = (REKp * EncoderRightError) - (AKp * AngleError);
        LeftMotorSpeed = constrain(LeftMotorSpeed, 0, maxSpeed);
        RightMotorSpeed = constrain(RightMotorSpeed, 0, maxSpeed);

        /* Stalling logic (not relevant here) */

        // Apply motor speeds
        moveLeftMotor(LeftMotorSpeed);
        moveRightMotor(RightMotorSpeed);
        
        // Update time for next iteration
        PreviousTime = CurrentTime;
        CurrentTime = millis();
    }
    
    // Stop motors
    moveLeftMotor(0);
    moveRightMotor(0);
    delay(100);
    // turnTo(direction);
}
  • I know there is a lot to this question, but I look forward to a response.

TDLR: We are experiencing inconsistencies with the motor speeds. What are some potential causes and remedies for this? If there are any questions, I’d love to clarify anything. Thanks for the help, cheers!

Hello.

One good first step would be to try to determine if the problem is hardware related (i.e. uneven load on the motor, something rubbing or creating additional friction, tire slipping) or if it is software related. You might try having your program print out some debugging information to see if the commanded duty cycle for the left motor is actually lower than expected sometimes.

If it is software related, I noticed that you are currently only using a proportional term for both the encoder and IMU feedback. So, you might need to do some additional tuning of that and try introducing a derivative and/or integral term. Also, if you haven’t done so already, it might be better to get the encoder and IMU controllers working separately from each other before trying to combine them.

Brandon