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))