Problems driving 4 motors with L298N and Arduino Mega

Hello everyone,
I have built a (mechanum wheel) car with 4 yellow DC-Motors. The problem i have is, that if i want to drive the motors, they wont spin everytime. Here are some scenarios where it works and where it doenst work:
-all 4 motors forward or backward: works
-the right two forward and the left two backward and vice versa: works
-the top right one and the left bottom one foward: no motor spins
-the top left one and the bottom right one forward: only the top left one spins

You can see which motors i mean when looking at the wiring diagram:

It has to do something with the electrical wiring, as the code runs the motors the same in every scenario, it just tells them to spin or not to spin.

Heres how the car is built up, the motor drivers sit under the Arduino Mega:

I would appreciate it if anyone could help me to solve this issue, Thanks!

Hi, @guter123
Welcome to the forum.

It sounds like your 9V batteries are not able to power ALL your vehicle.
Those batteries are designed for much lower current loads than your car.

If you lift the car off the ground and let the motors run with no load, what result do you get?

Do you have a DMM? Digital MultiMeter?

Thanks... Tom... :grinning: :+1: :coffee: :australia:

@TomGeorge As I said, if I run all 4 motors simultaneously, it works as expected. Only in some special scenarios, the motors won't spin. And if I lift the car, the result is the same.
And yes, I have a multimeter :slight_smile:
And the 9V batteries are rechargeable and are able to deliver more current than the normal ones

Hi,
Post your code, using code tags.
To add code please click this link;

Did you build this from a kit?

Thanks.. Tom... :grinning: :+1: :coffee: :australia:

This should be the relevant code:
Car.cpp:

#include <Car.h>

Car::Car() : 
    ultrasonicSensorFront_(ULTRASONIC_FRONT_TRIG, ULTRASONIC_FRONT_ECHO, ULTRASONIC_MAX_DISTANCE),
    ultrasonicSensorBack_(ULTRASONIC_BACK_TRIG, ULTRASONIC_BACK_ECHO, ULTRASONIC_MAX_DISTANCE),
    ultrasonicSensorLeft_(ULTRASONIC_LEFT_TRIG, ULTRASONIC_LEFT_ECHO, ULTRASONIC_MAX_DISTANCE),
    ultrasonicSensorRight_(ULTRASONIC_RIGHT_TRIG, ULTRASONIC_RIGHT_ECHO, ULTRASONIC_MAX_DISTANCE),
    camera_()
{
    initMotors();
    stopAllMotors();
    speed = 255;
    Serial.println("Car initialized");
}

void Car::initMotors(){
    pinMode(MOTOR_A_EN, OUTPUT);
    pinMode(MOTOR_A_IN1, OUTPUT);
    pinMode(MOTOR_A_IN2, OUTPUT);
    pinMode(MOTOR_B_EN, OUTPUT);
    pinMode(MOTOR_B_IN1, OUTPUT);
    pinMode(MOTOR_B_IN2, OUTPUT);
    pinMode(MOTOR_C_EN, OUTPUT);
    pinMode(MOTOR_C_IN1, OUTPUT);
    pinMode(MOTOR_C_IN2, OUTPUT);
    pinMode(MOTOR_D_EN, OUTPUT);
    pinMode(MOTOR_D_IN1, OUTPUT);
    pinMode(MOTOR_D_IN2, OUTPUT);
}

void Car::driveMotor(Motor motor, MotorDirection direction){
    bool in1 = LOW;
    bool in2 = LOW;
    
    if(direction == FORWARD) {
        in1 = HIGH;
        in2 = LOW;
    } else if (direction == REVERSE) {
        in1 = LOW;
        in2 = HIGH;
    }   //if none of the if-statements triggered, the direction is 
        //STOP and both pins are set to LOW as they were initialized

    if(direction == STOP) {
        speed = 0;
    }

    switch(motor){
        case MOTOR_A:
            analogWrite(MOTOR_A_EN, speed);
            if(in1 == HIGH) {   //prevents both pins from being HIGH by first writing the LOW Pin
                digitalWrite(MOTOR_A_IN2, in2);
            }

            digitalWrite(MOTOR_A_IN1, in1);
            digitalWrite(MOTOR_A_IN2, in2);
        break;

        case MOTOR_B:
            if(in1 == HIGH) {
                digitalWrite(MOTOR_B_IN2, in2);
            }

            analogWrite(MOTOR_B_EN, speed);
            digitalWrite(MOTOR_B_IN1, in1);
            digitalWrite(MOTOR_B_IN2, in2);
        break;

        case MOTOR_C:
            if(in1 == HIGH) {
                digitalWrite(MOTOR_C_IN2, in2);
            }

            analogWrite(MOTOR_C_EN, speed);
            digitalWrite(MOTOR_C_IN1, in1);
            digitalWrite(MOTOR_C_IN2, in2);
        break;

        case MOTOR_D:
            if(in1 == HIGH) {
                digitalWrite(MOTOR_D_IN2, in2);
            }
            
            analogWrite(MOTOR_D_EN, speed);
            digitalWrite(MOTOR_D_IN1, in1);
            digitalWrite(MOTOR_D_IN2, in2);
        break;
    }
}

void Car::updateMotorDirections(Joystick joystick1, Joystick joystick2){
    Position joy1X = joystick1.getPositionX();
    Position joy1Y = joystick1.getPositionY();
    Position joy2X = joystick2.getPositionX();
    Position joy2Y = joystick2.getPositionY();

    MotorDirection directionAandD = FORWARD;    //automatically handles state if joy2Y is TOP and joy2X is MIDDLE
    MotorDirection directionBandC = FORWARD;

    bool areAllJoysticksInMiddle = true;

    if(joystick2.hasPositionChanged()) {
        areAllJoysticksInMiddle = false;

        switch(joy2Y) {
            case TOP: {
                if(joy2X == LEFT) {
                    directionAandD = STOP;
                } else if(joy2X == RIGHT) {
                    directionBandC = STOP;
                }
                driveMotor(MOTOR_A, directionAandD);
                driveMotor(MOTOR_B, directionBandC);
                driveMotor(MOTOR_C, directionBandC);
                driveMotor(MOTOR_D, directionAandD);
            } break;

            case MIDDLE: {
                MotorDirection directionAandC = REVERSE;    //automatically handles state if joy2X is LEFT
                MotorDirection directionBandD = FORWARD;
                if(joy2X == RIGHT) {
                    directionAandC = FORWARD;
                    directionBandD = REVERSE;
                }
                driveMotor(MOTOR_A, directionAandC);
                driveMotor(MOTOR_B, directionBandD);
                driveMotor(MOTOR_C, directionAandC);
                driveMotor(MOTOR_D, directionBandD);
            } break;       

            case BOTTOM: {
                directionAandD = REVERSE;    //automatically handles state if joy2X is MIDDLE
                directionBandC = REVERSE;
                if(joy2X == LEFT) {
                    directionBandC = STOP;
                } else if(joy2X == RIGHT) {
                    directionAandD = STOP;
                }
                driveMotor(MOTOR_A, directionAandD);
                driveMotor(MOTOR_B, directionBandC);
                driveMotor(MOTOR_C, directionBandC);
                driveMotor(MOTOR_D, directionAandD);
            } break;

            case RIGHT: //fallthrough
            case LEFT:
                Serial.println("ERROR: Joystick´s y-axis has a value from the x-axis");
                break;
        }
    } else if(joystick1.hasPositionChanged()){
        areAllJoysticksInMiddle = false;

        if(joy1Y == MIDDLE) {
            directionAandD = REVERSE;    //automatically handles state if joy1X is LEFT
            directionBandC = FORWARD;
            if(joy1X == RIGHT) {
                directionAandD = FORWARD;
                directionBandC = REVERSE;
            }
            driveMotor(MOTOR_A, directionAandD);
            driveMotor(MOTOR_B, directionBandC);
            driveMotor(MOTOR_C, directionBandC);
            driveMotor(MOTOR_D, directionAandD);
        } 
    }

    if(joy1Y == TOP && joy1X == MIDDLE) {
        camera_.moveLeft();
    } else if(joy1Y == BOTTOM && joy1X == MIDDLE) {
        camera_.moveRight();
    }

    if(communicator_.joystick1_.isButtonDown()) {
        camera_.returnToCenter();
    }

    if(joystick1.isInPosition(MIDDLE, MIDDLE) && joystick2.isInPosition(MIDDLE, MIDDLE) && !areAllJoysticksInMiddle) {
        stopAllMotors();
        areAllJoysticksInMiddle = true;
    }
}

void Car::stopAllMotors(){
    driveMotor(MOTOR_A, STOP);
    driveMotor(MOTOR_B, STOP);
    driveMotor(MOTOR_C, STOP);
    driveMotor(MOTOR_D, STOP);
    Serial.println("All motors stopped");
}

void Car::update(){
    uint8_t* data = communicator_.getReceivedData();

    communicator_.joystick1_.setPositionX(Joystick::getPositionByValue(X_Axis, *data));
    communicator_.joystick1_.setPositionY(Joystick::getPositionByValue(Y_Axis, *(data + 1)));
    communicator_.joystick1_.setButtonDown(*(data + 2));
    communicator_.joystick2_.setPositionX(Joystick::getPositionByValue(X_Axis, *(data + 3)));
    communicator_.joystick2_.setPositionY(Joystick::getPositionByValue(Y_Axis, *(data + 4)));
    communicator_.joystick2_.setButtonDown(*(data + 5));
    speed = map(*(data + 6), 0, 255, 100, 255);

    camera_.setSpeed(*(data + 6));

    if(communicator_.getSaveStopTimer() + CONNECTION_LOST_WARNING > millis()) {     //check if the remote responded in the last 500 milliseconds
        updateMotorDirections(communicator_.joystick1_, communicator_.joystick2_);
    } else {
        stopAllMotors();
        Serial.println("NO DATA AVAILABLE");
    }

    sendSensorData();
}

Car.h:

#include <Arduino.h>
#include <Communicator.h>
#include <DHT11Sensor.h>
#include <UltrasonicSensor.h>
#include <Camera.h>

#define MOTOR_A_EN 12
#define MOTOR_A_IN1 22
#define MOTOR_A_IN2 23

#define MOTOR_B_EN 11
#define MOTOR_B_IN1 25                        //A  B
#define MOTOR_B_IN2 24                        //
                                              //C  D
#define MOTOR_C_EN 9
#define MOTOR_C_IN1 27
#define MOTOR_C_IN2 26

#define MOTOR_D_EN 10
#define MOTOR_D_IN1 28
#define MOTOR_D_IN2 29


#define ULTRASONIC_FRONT_TRIG 38
#define ULTRASONIC_FRONT_ECHO 39
#define ULTRASONIC_BACK_TRIG 42  
#define ULTRASONIC_BACK_ECHO 43
#define ULTRASONIC_LEFT_TRIG 44
#define ULTRASONIC_LEFT_ECHO 45
#define ULTRASONIC_RIGHT_TRIG 40
#define ULTRASONIC_RIGHT_ECHO 41

#define ULTRASONIC_MAX_DISTANCE 100

enum Motor {
    MOTOR_A,
    MOTOR_B,
    MOTOR_C,
    MOTOR_D
};

enum MotorDirection {
    FORWARD,
    REVERSE,
    STOP
};

class Car {
    public:
        Communicator communicator_;
        UltrasonicSensor ultrasonicSensorFront_;
        UltrasonicSensor ultrasonicSensorBack_;
        UltrasonicSensor ultrasonicSensorLeft_;
        UltrasonicSensor ultrasonicSensorRight_;
        DHT11Sensor dht11Sensor_;
        Camera camera_;
        
        Car();
        void stopAllMotors();
        void update();

        private:
            int speed;
            void updateMotorDirections(Joystick joystick1, Joystick joystick2);
            void initMotors();
            void driveMotor(Motor motor, MotorDirection direction);
            void sendSensorData();

};

It´s also available on github if you need more: Mechanum-Wheel-Car/Mechanum Wheel Car/src at main · CodingFactoryT/Mechanum-Wheel-Car (github.com)

@TomGeorge So if I only want to control one motor of every driver, only motor A works, the rest doesn´t want to move

How much voltage and current do your motors want to consume?
Measure the voltage arriving at the motors.

Why do you make these local variables, only here?

@DrDiettrich I have a potentiometer that controls the motor speeds, so I measured a range of 3.2V (lowest speed) - 5.5V (highest speed), but that's also due to the batteries not being charged fully up (7.5V, I will recharge them now, but I also tested it with fully charged batteries and it didn't work in every case as well).
The variables are local because they are different than the other ones on top of the switch-statement, they control different motor pairs. Its a thing of the mechanum wheels in order to let the car drive sideways.

Is that the rated motor voltage?

You know that the L29x drivers drop up to 4V and are inappropriate for battery operation?

May be, but thats obviously not the problem here, as the motors all spin if they are told to do so. But they dont work if every motor driver only has to run one motor.

@DrDiettrich @TomGeorge I ran another test where i wanted to drive each motor independently. With the front two motors (A and B), this works very well, but the rear ones (C and D) have issues. The problem is described in the comment:

#define MOTOR_A_EN 12
#define MOTOR_A_IN1 22
#define MOTOR_A_IN2 23

#define MOTOR_B_EN 11
#define MOTOR_B_IN1 25 // A  B
#define MOTOR_B_IN2 24 //
                       // C  D
#define MOTOR_C_EN 3
#define MOTOR_C_IN1 27
#define MOTOR_C_IN2 26

#define MOTOR_D_EN 5
#define MOTOR_D_IN1 28
#define MOTOR_D_IN2 29


void setup() {
  pinMode(MOTOR_A_EN, OUTPUT);  
  pinMode(MOTOR_A_IN1, OUTPUT);
  pinMode(MOTOR_A_IN2, OUTPUT);
  pinMode(MOTOR_B_EN, OUTPUT);
  pinMode(MOTOR_B_IN1, OUTPUT);
  pinMode(MOTOR_B_IN2, OUTPUT);
  pinMode(MOTOR_C_EN, OUTPUT);
  pinMode(MOTOR_C_IN1, OUTPUT);
  pinMode(MOTOR_C_IN2, OUTPUT);
  pinMode(MOTOR_D_EN, OUTPUT);
  pinMode(MOTOR_D_IN1, OUTPUT);
  pinMode(MOTOR_D_IN2, OUTPUT);

  delay(2000);
  analogWrite(MOTOR_C_EN, 255); //if this is commented, motor D wont spin, if this is uncommented, motor D will spin
  analogWrite(MOTOR_D_EN, 255);
  digitalWrite(MOTOR_D_IN1, HIGH);
  digitalWrite(MOTOR_D_IN2, LOW);
}

So in general, if you want to drive one of the rear motors, you have to enabled both motor pins, even if only one motor should spin.

Could this be a faulty motor driver or is there another solution I didnt thought about?

I changed the pins in the code a bit again and now it surprisingly works as expected. But thanks for all your ideas!

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