not logged in | [Login]

I made a dual dc motor driver for my pyboard on a bit of 12x8 perfboard using nothing more than a Texas Instruments SN 754110 quad h-bridge, and it works fine. The accompanying module requires my pwm module for speed control (at the moment).

Each attached motor can be driven forwards or backwards at 0-255 different speeds. This is a 5v chip, so the logic needs to be driven by Vin Pin, not a 3.3v Pin and may be subject to risk if you power your pyboard via other than USB (although I've used it with the pyboard powered by a 9v battery and 'no harm came of it').

An external battery is required - this supplies the current that drives the dc motors ... an EE would be required to figure a shared power configuration.

The skin is designed to sit on either the Y or X orientation on the pyboard, in the Y position the two motors are referred to as Y1 and Y2 and in the X position as X1 and X2 (for initialising an instance of the class only).

Don't have a proper schematic of the skin, as it was botched together, my hookup was as follows, but the general code could easily be adapted to any configuration (note: on my skin the h-bridge chip is 'upside down' in relation to the pyboard, hence the odd pin numbering);

                     TI SN 754410 NE
                      Quad H-bridge
                 -----------------------
      Pin Vin -> |16 +ve        1,2EN 1| -> Pin Y8
       Pin Y1 -> |15 4A            1A 2| -> Pin Y7
      Motor 2 -> |14 4Y            1Y 3| -> Motor 1
Gnd & -ve Bat -> |13 Gnd          Gnd 4| -> Gnd & -ve Bat
Gnd & -ve Bat -> |12 Gnd          Gnd 5| -> Gnd & -ve Bat
      Motor 2 -> |11 3Y            2Y 6| -> Motor 1
       Pin Y2 -> |10 3A            2A 7| -> Y6
       Pin Y3 -> |9  3,4EN    +ve Bat 8| -> +ve Bat
                 -----------------------

usage

>>> import dcmotor
>>> m1 = dcmotor.DCMOTOR(dcmotor.Y1) #skin in Y position, create an object to control motor Y1
>>> m2 = dcmotor.DCMOTOR(dcmotor.Y2, reverse_pols=True) #reverse input to motor on Y2
>>> m1.forwards()      #run m1 forwards full tilt
>>> m1.backwards()     # backwards, full tilt
>>> m1.stop()          #stop
>>> m1.forwards(255/2) #forward half speed
>>> m1.stop()          #stop
>>> m1.state(255/2)    #forwards half speed
>>> m1.state(-255)     #backwards full tilt
>>> m1.state()         #return current speed
-255

the module

dcmotor.py

import pyb, pwm

FORWARDS  =  255
BACKWARDS = -FORWARDS
STOP      = 0

#possible dcmotor configurations, depends on skin orientation
Y1 = {'enable':pyb.Pin.board.Y8,'control0':pyb.Pin.board.Y6,'control1':pyb.Pin.board.Y7}
Y2 = {'enable':pyb.Pin.board.Y3,'control0':pyb.Pin.board.Y2,'control1':pyb.Pin.board.Y1}
X1 = {'enable':pyb.Pin.board.X8,'control0':pyb.Pin.board.X6,'control1':pyb.Pin.board.X7}
X2 = {'enable':pyb.Pin.board.X3,'control0':pyb.Pin.board.X2,'control1':pyb.Pin.board.X1}

class DCMOTOR:
  """dirty DC Motor Class"""

  def __init__(self, pins_dict, reverse_pols=False):

    self.__enable   = pins_dict['enable']
    self.__control0 = pins_dict['control0'] if not reverse_pols else pins_dict['control1']
    self.__control1 = pins_dict['control1'] if not reverse_pols else pins_dict['control0']

    self.__pwm = pwm.PWM(self.__enable)
    self.__control0.init(pyb.Pin.OUT_PP)
    self.__control0.low()
    self.__control1.init(pyb.Pin.OUT_PP)
    self.__control1.low()

  def state(self,value=None):
    """get or set motor state as -ve|0|+ve as backwards|stop|forwards"""
    if value == None:
      if self.__pwm.duty() > 0:
        if self.__control0.value() and not self.__control1.value():
          return -self.__pwm.duty()
        elif not self.__control0.value() and self.__control1.value():
          return self.__pwm.duty()
        else:
          raise ValueError('Inconsistent state')
      else:
        return 0
    elif value < 0:
      self.__control0.high()
      self.__control1.low()
      self.__pwm.duty(abs(value))
    elif value > 0:
      self.__control0.low()
      self.__control1.high()
      self.__pwm.duty(value)
    elif value == 0:
      self.__pwm.duty(0)
    else:
      raise ValueError('Invalid state value passed')

  def backwards(self,value=-BACKWARDS):
    self.state(-value)

  def forwards(self,value=FORWARDS):
    self.state(value)

  def stop(self):
    self.state(STOP)

  def emergency_stop(self,brakes_for=50):
    if self.state() != 0:
      self.__control0.value(int(not(self.__control0.value())))
      self.__control1.value(int(not(self.__control1.value())))
      pyb.delay(brakes_for)
      self.stop()