Hbridge motor - not understanding platform for pin a/b

I’m new to ESP32’s and ESPHome but, goodness me, it has been superb in getting started. I’m having a bit of a problem understanding how to use an hbridge (L298N) with my board to get a PWM controlled motor though, and hoping someone might be able to give some advice.

This is my config as it is:

output:
- platform: ledc
  pin: GPIO12
  id: motor_speed_pin
- platform:
  id: motor_forward_pin
  pin: GPIO5
- platform:
  id: motor_reverse_pin
  pin: GPIO4

fan:
- platform: hbridge
  id: my_fan
  name: "Speed"
  pin_a: motor_forward_pin
  pin_b: motor_reverse_pin
  enable_pin: motor_speed_pin
  decay_mode: slow   # slow decay mode (braking) or fast decay (coasting).

Using the h-bridge component for ESPHome.

The docs there not that pin_a and pin_b need to point to a float. I tried using platform: gpio but get:

ID ‘motor_forward_pin’ of type gpio::GPIOBinaryOutput doesn’t inherit from output::FloatOutput. Please double check your ID is pointing to the correct value.

Fair enough. So two questions:

  1. I thought those pins on the h bridge were simply high or low and the “enable” pin can be used for PWM speed control. I don’t understand why the should be floats?
  2. What do I use for the platform? I can’t figure it out from the docs.

Many thanks,
Allan

1 Like

For platform use an output component that supports float ESPHome — ESPHome

Your motor forward and motor reverse pins should be platform “gpio”.

1 Like

I have this same issue and I do not believe this statement is correct. hbridge is expecting output:float and gpio can only be binary or switch.

I believe you are supposed to use a PWM. According to the ESPHome manual, you have three choices (not counting Slow PWM):

I tested only the first. The ESPHome documentation for the fan module is not optimal. Below is what worked for me:

output:
  # Leads (+) and (-) for motor
  - platform: esp8266_pwm
    id: mot_p
    pin: GPIO5
  - platform: esp8266_pwm
    id: mot_n
    pin: GPIO4

fan:
  # Motor controller
  - platform: hbridge
    id: mot
    name: "Motor"
    pin_a: mot_p
    pin_b: mot_n

Hope that helps.

Cheers, AndBu

1 Like

Seeing your reply just now, sorry!
Just had a look in the docs and it seems you are correct.
That, however, doesn’t make any sense to me at all. The h-bridge is expecting a binary state on pin a and pin b. It would work with pwm 0% and 100% as well, but what’s the benefit?
Very curious now as well.

PWM is considered “analog” in the microcontroller output context, because a 50% duty cycle pwm is half the voltage for an inductive load, and half as bright for an LED (as a simplification).

I agree that PWM is wrong here.
Yes we need a PWN for the motor speed.
But a binary for the INx / PIN_x. since they only expect low/high. ( pin_a = forward, pin_b = backwards spin)

Did you find any solution to this?

PWM is not wrong. It is just not properly documented.

Did you try my solution posted above? Before you can use PWM, you have to assign the respective pins under the output section - and you obviously have to have an H-bridge wired to these pins in your physical circuit to drive the motor. You could for example use the cheap DRV8833 or the L293N integrated motor drivers with appropriate external passive components connected.

Cheers, AndBu

I know this is old, but this seems to be the only relevant discussion on the topic now that I too am trying to control a hbridge -in my case it’s a bts7960- and am not getting it from the documentation nor the additional information given here.

I feel my (and possibly others) confusion comes from the fact that the module has 4 control pins: LPWM + L_EN and RPWM + R_EN, with the both PWM pins described as needing a PWM signal and the EN pins described as needing a logic signal. but the hbridge platform defines 3 pins and all 3 expect a float output.

RPWM and LPWM are described to need a PWM signal, i.e. this suggests to apply one of the available PWM output platforms, which then get assigned to the hbridge platform’s pin_a and pin_b. Float output seems appropriate here.

L_EN and R_EN are however described as 2 binary controls on the module according to f.e. https://electronics.stackexchange.com/questions/430642/how-to-control-bts7960-43a-motor-driver-directions. HIGH and LOW are listed as valid values for these pins. This feels like I should define 2 switch platforms to drive these, not one of the PWM platforms. However if I connect a switch gpio, I get an error “ID ‘motor_enable’ of type gpio::GPIOSwitch doesn’t inherit from output::FloatOutput. Please double check your ID is pointing to the correct value.”.

So not only does it feel strange that the hbridge platform provides only 1 enable_pin instead of 2, it also seems weird that this enable_pin expects a float output where the module requests a binary input.

What am I misunderstanding or is there a mismatch or even a bug in the hbdrige platform’s enable_pin definition?

On top of this, as Sieben points out in his answer, the usage of the pins seems to be totally the other way around from the intuitive interpretation from their names: it seems we should provide a PWM signal on the both L_EN and R_EN pins to specify the speed, then use 2 separate logic pins to select one of the modes for the both PWM pins: forward (1-0), reverse (0-1), idle (0-0), brake (1-1). This matches my experience when doing a rudimentary test with the module alone and a 18650 battery: the module would not run the motor unless both L_EN and R_EN were high, making RPWM high would run the motor forward, making LPWM high would run the motor in reverse.

Can anyone that did successfully implement the hbridge platform to run a motor please share their setup so we can learn from it?

Tie both enable pins together and connect to single gpio switch.
Don’t use enable-pin option on h-bridge component.
Then RPWM and LPWM to pin_a and pin_b.

There are many different motor drivers and they have different logics.
For example L298N is driven correctly by PWM on enable pin and high/low on direction pins.

Does that not keep the motor powered on all the time? I’m building a solar tracker controller (hence the high power motor controller) and the device is going to be on 24/7. f.e. I don’t want to waste energy keeping the motors powered all day while it really only needs to move for a couple of seconds once or twice every hour or so.

Would it be possible for you to give me some example yaml that defines a float output that is accepted for the enable_pin: of the hbridge platform and makes a gpio pin go high or low so I can test for any differences in behaviour?

A simple H-bridge cannot keep a DC motor “powered on”. Whenever voltage is applied at the motor terminals, a current flows, which is converted into a mechanical force, resulting in the motor applying torque, making it turn (unless blocked).

In reverse conclusion, this means you also cannot pin a DC motor in position like you can with a stepper motor (unless we are talking of a servo motor with closed-loop control, which is not the discussion here).

The braking mode of an H-bridge does not “power on” the motor either unless it is turning. In this mode, the supply voltage is applied “in reverse” at the motor terminals to counteract a motor current and therewith the rotation. The direction of the voltage is determined by the current flowing through the H-bridge’s freewheeling diodes because the FETs are off, and the voltage is effectively zero once the current is zero and the diodes are no longer conducting.

Maybe you are confusing this with some motor drivers’ own power saving mode, which can be used to shutdown the driver itself. Or maybe you are confusing it with common stepper motors, which need to be kept “powered” to stay in position.

Point taken about the motor power.

But what about an example yaml to define a float output that will be accepted by the hbridge platform for the enable_pin? Why would the enable_pin be defined as it is if you can’t define an output pin that can be connected to it?

I never noticed as I never used this. And I am with you, this makes no sense for a simple enable pin … so I browsed the source code just now to see what it does … only to become more confused. It looks like this is used as a form of additonal “speed control” maybe for special drivers that support this? But I honestly think this whole thing is just an error in the code as the “speed control via enable pin” does not appear to be consistently applied throughout the different operating modes. Maybe I am missing something fundamental here.

Anyways, as @Karosm said above: forget the “enable pin” function of the hbridge component and just control the physical enable pin on your device with a GPIO outside the hbridge component if you really need it (or hardwire it, which is what I do).

Ok, thank you for looking it up and glad to hear that I’m not the only one that thinks that enable_pin doesn’t make sense. It’s just a little bit annoying that I now have to use 4 PWMs to control 2 linear motors. I was hoping to use 1 PWM per motor and controlling direction by using the EN pins. But at least it works now.

For anyone else reading, here’s what I did:
I connected the both L_EN and R_EN to 3.3v and the LPWM and RPWM to GPIO4 and 5 per the above suggestions on my ESP32-S3-WROOM-1 (board: esp32-s3-devkitc-1), using ledc as the PWM platform. This is what I’ve put in as the definition that now lets me successfully control the both motors run via 2 bts7960 modules:

output:
  # east - west
  - platform: ledc
    frequency: 25000Hz
    pin: GPIO04
    id: motor_ew_lpwm
  - platform: ledc
    frequency: 25000Hz
    pin: GPIO05
    id: motor_ew_rpwm

  # north - south
  - platform: ledc
    frequency: 25000Hz
    pin: GPIO06
    id: motor_ns_lpwm
  - platform: ledc
    frequency: 25000Hz
    pin: GPIO07
    id: motor_ns_rpwm

fan:
  # east - west
  - platform: hbridge
    id: motor_ew
    name: "Motor E-W"
    pin_a: motor_ew_lpwm
    pin_b: motor_ew_rpwm
    decay_mode: slow
    speed_count: 100

  # north - south
  - platform: hbridge
    id: motor_ns
    name: "Motor N-S"
    pin_a: motor_ns_lpwm
    pin_b: motor_ns_rpwm
    decay_mode: slow
    speed_count: 100

The cover platform is probably a better fit for what I want to do, so I am going to try that next. But this was the first thing I encountered and I now know I can successfully control the motors.

Correct setup. If you want to control enable, connect them to gpio switch.