L298N motor controller voltages are weird

194 Views Asked by At

I have a Pi Pico hooked up to an L298N motor controller, -- all of it, i.e. IN1, IN2, ENA, IN3, IN4, ENB. And all is well up to a point; the voltage across OUT1 & OUT2 (going to one motor), likewise across OUT3 & OUT4 (going to the other motor), are as expected.

The trouble is that when I turn off one of the motors, its OUT pins are not at ground, but about the voltage I'm applying to the L298N's "5V" pin (the one in the bank of three terminal block connectors the other two of which are for ground and 12V).

This would not be a problem if I was driving two independent motors. Unfortunately what I'm doing with the L298N is powering the rails of a model train layout. The trains draw their power from the rails, and that would be fine too except that there are places where one set of tracks intersects another (or merges into another) and where that happens it's essential for all the rails' grounds to be the same.

Is this the expected behavior of an L298N motor controller? If it isn't, then that's a sign that the Micropython code I wrote for the Pico is wrong. But if it is expected behavior, can anyone think of a way out?

--------- new material added after reading David C. Rankin's comments -------

D-oh! I misunderstood what the "EN-5V jumper" meant. So thanks. But now (with a fresh, undamaged motor controller in place) I think this is a software issue now (and therefore appropriate for this StackExchange). In brief: I've found that trying to control the L298N with three pins -- IN1&IN2 for the direction, and ENA for PWM -- gives crazy results (the ones I mentioned regarding inconsistent ground voltages). And that the solution is to put the jumper back on ENA, and apply PWM to IN1 (or IN2, according to the desired motor direction). This solution, as it happens, appears to be the way the gpiozero module (unfortunately, available only on the "big" Raspberry Pis, not the Pico) does motor control.

Here's my code, written to make it easy to switch between the three-pin method (which gave me my weird results) and the two-pin "gpiozero" method (which is working perfectly), in case anyone besides me cares to experiment:

    #
    # Micropython code -- part of a RPi Pico's main.py.
    #
    from machine import Pin, PWM

    # Can switch from PWM to plain old Pin
    class MyPWM:
        # public
        def __init__(self, pin_num):
            self.pin_num = pin_num
            self.pin = Pin(pin_num, Pin.OUT) # default -- will change
    
        def logical_off(self):
            if type(self.pin) == PWM:
                self.pwm2pin()
            self.pin.off()
        def logical_on(self):
            if type(self.pin) == PWM:
                self.pwm2pin()
            self.pin.on()
    
        def pulsate(self, duty):
            if not 0 <= duty <= 1:
                raise Exception('duty must be on [0,1]')
            if type(self.pin) == Pin:
                self.pin2pwm()
            self.pin.duty_u16(int((pow(2,16)-1)*duty))
    
        # private
        def pin2pwm(self):
            self.pin.off()
            self.pin = PWM(self.pin)
            self.pin.freq(1000)
        def pwm2pin(self):
            self.pin.duty_u16(0)
            self.pin.deinit()
            self.pin = Pin(self.pin_num, Pin.OUT)
    
    class MyDCMotor:
        def __init__(self, *, mode, fwd_pin_num, bk_pin_num, en_pin_num=None):
            # argument validation
            if not mode in ('two_pin_pwm', 'two_pin_logical', 'three_pin'):
                raise Exception('Invalid MyDCMotor mode "' + mode + '"')
    
            self.mode = mode
            self.fwd_pin_num = fwd_pin_num
            self.fwd_pin = MyPWM(fwd_pin_num)
            self.bk_pin_num = bk_pin_num
            self.bk_pin = MyPWM(bk_pin_num)
            self.en_pin_num = en_pin_num
            self.en_pin = MyPWM(en_pin_num)
    
        def drive(self, *, direction, speed):
            if not 0 <= speed <= 1.0:
                print('Error: speed must be within [0,1].')
        if direction == 'forward':
            if self.mode == 'two_pin_pwm':
                self.bk_pin.logical_off()
                self.fwd_pin.pulsate(speed)
            else:
                self.bk_pin.logical_off()
                self.fwd_pin.logical_on()
                if self.mode == 'three_pin':
                    self.en_pin.pulsate(speed)
        elif direction == 'backward':
            if self.mode == 'two_pin_pwm':
                self.fwd_pin.logical_off()
                self.bk_pin.pulsate(speed)
            else:
                self.fwd_pin.logical_off()
                self.bk_pin.logical_on()
                if self.mode == 'three_pin':
                    self.en_pin.pulsate(speed)
        elif direction == 'stop':
            self.fwd_pin.logical_off()
            self.bk_pin.logical_off()
        else:
            raise Exception('Invalid direction: ' + direction)
    
        def forward(self, *, speed):
            self.drive(direction='forward', speed=speed)
        def backward(self, *, speed):
            self.drive(direction='backward', speed=speed)
        def stop(self):
            self.drive(direction='stop', speed=0)
    
    g_dcmotor = (MyDCMotor(mode='two_pin_pwm',
                   fwd_pin_num=12, bk_pin_num=13, en_pin_num=11),
                 MyDCMotor(mode='two_pin_pwm',
                   fwd_pin_num=19, bk_pin_num=18, en_pin_num=20))

1

There are 1 best solutions below

0
Theodore Sternberg On

OK, I was unaware of the fact not all the Pi Pico's PWM pins are actually independent. Specifically, the track that was exhibiting the strange behavior was under the control of a PWM pin that was, under the hood, the same as the PWM pin I was using to control another (third, unmentioned in my description above) track. Everyone who plans to use the Pi Pico's PWM functionality should read up on its "PWM slices". In a nutshell, though there are about 26 pins you can use for PWM, the total number of fully independent PWM pins is only eight (or sixteen if you're ok with quasi-independence).