Best code method for H-bridge with PWM

I am making a robot and using H-bridge and regular motors for motion, arms, gripper hands and other things. I am already kind of annoyed at all the digital pin writes and analog PWM writes to make the motors go the direction and speed I want. Code is filling up with groups of 4.
I use 1 digital and 1 PWM pin for each motor and control the speed with PWM. When one side is HIGH, the PWM number needs to be high for slow speed and when I need the motor to go the other direction the HIGH goes to LOW and the PWM number needs to be on the low end.

What's the cleanest way to do this? Am I stuck using 4 pin write commands each time or is it better to use functions and then call ForwardSlow(). Maybe there is some other trick I'm not aware of?

Show us how your driver is wired (svhematic please).

Usually per motor, one wire to choose direction, one wire for pwm stream.

You can use a NAND gate to invert the PWM signal when the direction pin is high.

Inverting the PWM signal changes a low duty cycle to a high duty cycle, and vice versa.

The motors are all low power so I'm using a small MX1508 H-bridge that just uses PWM at the input pins. So there is power, motor out and 2-pin signal in. One or both signal pins can be PWM.
https://www.amazon.com/dp/B075S368Y2

I can't see your code. But perhaps it's time to clean things up using arrays, functions, and struts. In fact, I'd go even more OOP by encapsulating functionality into C++ classes.

So yeah, def a function to do a group of four whatever.

If you make it flexible enough, it is possible to have all the motor output manipulation appear only once in your sketch, in this case in a motor control function.

You could make that function a bit more clever one day and use direct port manipulation, but no matter what you ever do, controlling stuff is gonna mean lotsa hands and knees twiddling of output pins.

a7

Here's a snippet I use for controlling an H-Bridge

/// @brief Turns motor on/off
/// @param dir
/// @param speed
void movePanel(bool dir, int speed)
{
#ifdef MOTOR_DISABLE
    return;
#endif
    if (speed == 0)
    {
        analogWrite(MOTOR_ENABLE_PIN, 0);
        digitalWrite(PANEL_MOTOR_SPEED_CW_PIN, LOW);
        digitalWrite(PANEL_MOTOR_SPEED_CCW_PIN, LOW);
    }
    else
    {
        if (dir)
        {
            digitalWrite(PANEL_MOTOR_SPEED_CW_PIN, LOW);
            digitalWrite(PANEL_MOTOR_SPEED_CCW_PIN, HIGH);
        }
        else
        {
            digitalWrite(PANEL_MOTOR_SPEED_CW_PIN, HIGH);
            digitalWrite(PANEL_MOTOR_SPEED_CCW_PIN, LOW);
        }
        analogWrite(MOTOR_ENABLE_PIN, PANEL_SPEED);
    }
}

Even this could be simplified, but I was experimenting with various methods at the time.
HTH

Or complexified.

Add pin numbers to the arguments to that function and it will control all your motors.

Or have the motors represented by objects that carry around the pins they are attached to with them.

a7

as already mentioned, create a class "Motor".
design an API of member functions you really need from each motor (setSpeed, setDirection,forward, forwardSlow, reverse... )
let the class handle that "invers" PWM depending on the set direction.
When you have one class, make several objects - one for each motor you need to control.

edit:
just as an idea,
far away from "best",
might be buggy or not fitting to your hardware:

/*
     Code for H-Bridge with PWM
     https://forum.arduino.cc/t/best-code-method-for-h-bridge-with-pwm/1182039/8
     2023-10-25 by noiasca
 */
 
class Motor {
  protected:
    const uint8_t pwmPin;    // the GPIO for PWM
    const uint8_t dirPin;    // the GPIO whih sets direction
    uint16_t speed = 0;      // current speed of motor
    int8_t direction = 1;    // 1 forward, // -1 reverse

  public:
    Motor (uint8_t pwmPin, uint8_t dirPin) : pwmPin(pwmPin), dirPin(dirPin) {}

    // to be called once in setup
    void begin() {
      pinMode(pwmPin, OUTPUT);
      pinMode(dirPin, OUTPUT);
    }

    // change speed of motor
    void setSpeed(uint16_t newSpeed) {
      if (newSpeed > 1023)
        speed = 1023;
      else
        speed = newSpeed;
      if (direction == 1)
        analogWrite(pwmPin, speed);
      else
        analogWrite(pwmPin, 1023 - speed);   // your logic when motor is in reverse 
    }

    // let the motor move forward
    void forward() {
      direction = 1;
      digitalWrite(dirPin, HIGH);
      setSpeed(speed);
    }

    // let the motor move backwards
    void reverse() {
      direction = -1;
      digitalWrite(dirPin, LOW);
      setSpeed(speed);
    }
};
// UNO PWM pins are 5,6,9,10,11,3
//           pwm dir
Motor motorA(5,   2);    // create a motor object and define the PWM pin and the direction pin
Motor motorB(6,   3);
Motor motorC(9,   4);

void setup() {
  motorA.begin();
  motorB.begin();
  motorC.begin();
}

void loop() {
  motorA.setSpeed(255);
  motorB.setSpeed(512);
  motorC.setSpeed(1023);
  delay(1000);  // dirty delay - just here in the demo
  motorA.setSpeed(512);
  delay(1000);  // dirty delay
  motorA.setSpeed(0);
  delay(1000);  // dirty delay
  motorA.reverse();
  motorA.setSpeed(128);
  delay(1000);  // dirty delay
}
//
1 Like

If you use variables/defines or an enum for the pin names in the arguments then understanding what the code does becomes even easier

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