Raspberry Pi Motor Board
To control the two drive motors for Alexa M we are using the Raspberry Pi Motor Board from Seeed. It is based on the Freescale MC33932 dual H-Bridge Power IC, which can control inductive loads with currents of up to 5.0A peak per single bridge. It lets you drive two DC motors with your Raspberry Pi B/B+/A+ and Pi 2/3 Model B, controlling the speed and direction of each one independently.
The Raspberry Pi Motor Driver Board v1.0 supports input voltage from 6V~28V, the on board DC/DC converter provides a 5V power supply for the Raspberry Pi with 1000mA maximum current.
Thus, you just need one power supply to drive the motors and power up the Raspberry Pi and Motor Board.
The board has the following features:
- Operating Voltage: 6V ~ 28V
- DC/DC output: 5V 1000mA @ "5V" pin
- Output Current(For Each Channel ): 2A (continuous operation) / 5A(peak)
- Output Duty Range: 0%~100%
- Output short-circuit protection (short to VPWR or GND)
- Over-current limiting (regulation) via internal constant-off-time PWM
- Temperature dependant current limit threshold reduction
Wiring up the Motor Control Board
Wiring is pretty straight forward. The battery pack plugs into J1. We are using 6 x 1.5 AA batteries in the battery pack (i.e. 9V) which is sufficient to drive both motors without the Raspberry Pi browning out and rebooting.
The motors connect to J2. We connected:
- OUT1 - left motor red
- OUT2 - left motor black
- OUT3 - right motor red
- OUT4 - right motor black
The Raspberry Pi connects via the header. You need the pin details to control the motor control board and to ensure there are no conflicts with HAT's or other I/O.
The pins used by Alexa M are shown above. The blue highlighted ones are the Motor Control Board. In particular, the GPIO connected to the MC33932 pins are:
PWMA = GPIO 25
PWMB = GPIO 22
IN1 = GPIO 23
IN2 = GPIO 24
IN3 = GPIO 17
IN4 = GPIO 27
The block diagram of the MC33932 throttle control H bridge is shown below.
And the logic commands required to operate the chip are:
Luckily we don't have to write our own motor driver code as the folks at Seeed have already provided it. I have tweaked this a bit to make it Python 3 compliant and have also provided the required PiSoftPwm class as this is a bit difficult to track down.
To test your Motor Control Board, run the following:
#!/usr/bin/python import RPi.GPIO as GPIO import time import signal from PiSoftPwm import * #print 'Go_1...' #frequency = 1.0 / self.sc_1.GetValue() #speed = self.sc_2.GetValue() class Motor(): def __init__(self): # MC33932 pins self.PWMA = 25 self.PWMB = 22 self._IN1 = 23 self._IN2 = 24 self._IN3 = 17 self._IN4 = 27 # Initialize PWMA PWMB GPIO.setmode(GPIO.BCM) GPIO.setup(self.PWMA, GPIO.OUT) GPIO.setup(self.PWMB, GPIO.OUT) GPIO.output(self.PWMA, True) GPIO.output(self.PWMB, True) # Initialize PWM outputs self.OUT_1 = PiSoftPwm(0.1, 100, self._IN1, GPIO.BCM) self.OUT_2 = PiSoftPwm(0.1, 100, self._IN2, GPIO.BCM) self.OUT_3 = PiSoftPwm(0.1, 100, self._IN3, GPIO.BCM) self.OUT_4 = PiSoftPwm(0.1, 100, self._IN4, GPIO.BCM) # Close pwm output self.OUT_1.start(0) self.OUT_2.start(0) self.OUT_3.start(0) self.OUT_4.start(0) self.frequency = 0.01 self.duty = 60 def Setting(self, frequency, duty): self.frequency = frequency self.duty = duty def Go_1(self): self.OUT_1.changeBaseTime(self.frequency) self.OUT_2.changeBaseTime(self.frequency) self.OUT_1.changeNbSlicesOn(self.duty) self.OUT_2.changeNbSlicesOn(0) def Back_1(self): self.OUT_1.changeBaseTime(self.frequency) self.OUT_2.changeBaseTime(self.frequency) self.OUT_1.changeNbSlicesOn(0) self.OUT_2.changeNbSlicesOn(self.duty) def Go_2(self): self.OUT_3.changeBaseTime(self.frequency) self.OUT_4.changeBaseTime(self.frequency) self.OUT_3.changeNbSlicesOn(0) self.OUT_4.changeNbSlicesOn(self.duty) def Back_2(self): self.OUT_3.changeBaseTime(self.frequency) self.OUT_4.changeBaseTime(self.frequency) self.OUT_3.changeNbSlicesOn(self.duty) self.OUT_4.changeNbSlicesOn(0) def Stop(): self.OUT_1.changeNbSlicesOn(0) self.OUT_2.changeNbSlicesOn(0) self.OUT_3.changeNbSlicesOn(0) self.OUT_4.changeNbSlicesOn(0) if __name__=="__main__": motor=Motor() # Called on process interruption. Set all pins to "Input" default mode. def endProcess(signalnum = None, handler = None): motor.OUT_1.stop() motor.OUT_2.stop() motor.OUT_3.stop() motor.OUT_4.stop() GPIO.cleanup() exit(0) # Prepare handlers for process exit signal.signal(signal.SIGTERM, endProcess) signal.signal(signal.SIGINT, endProcess) signal.signal(signal.SIGHUP, endProcess) signal.signal (signal.SIGQUIT, endProcess) motor.Setting(0.01, 60) print('motor start...') while True: print('turning direction...') motor.Go_1() time.sleep(1) motor.Back_1() time.sleep(1) motor.Go_2() time.sleep(1) motor.Back_2() time.sleep(1)
The PiSoftPwm class needs to be saved in the same directory as the motor test code above.
# The original is aboudou ,the Source code is here : https://goddess-gate.com/dc2/index.php/pages/raspiledmeter.en # The modifier is ukonline2000 import RPi.GPIO as GPIO import threading import time class PiSoftPwm(threading.Thread): def __init__(self, baseTime, nbSlices, gpioPin, gpioScheme): """ Init the PiSoftPwm instance. Expected parameters are : - baseTime : the base time in seconds for the PWM pattern. You may choose a small value (i.e 0.01 s) - nbSlices : the number of divisions of the PWM pattern. A single pulse will have a min duration of baseTime * (1 / nbSlices) - gpioPin : the pin number which will act as PWM ouput - gpioScheme : the GPIO naming scheme (see RPi.GPIO documentation) """ self.sliceTime = baseTime / nbSlices self.baseTime = baseTime self.nbSlices = nbSlices self.gpioPin = gpioPin self.terminated = False self.toTerminate = False GPIO.setmode(gpioScheme) def start(self, nbSlicesOn): """ Start PWM output. Expected parameter is : - nbSlicesOn : number of divisions (on a total of nbSlices - see init() doc) to set HIGH output on the GPIO pin Exemple : with a total of 100 slices, a baseTime of 1 second, and an nbSlicesOn set to 25, the PWM pattern will have a duty cycle of 25%. With a duration of 1 second, will stay HIGH for 1*(25/100) seconds on HIGH output, and 1*(75/100) seconds on LOW output. """ self.nbSlicesOn = nbSlicesOn GPIO.setup(self.gpioPin, GPIO.OUT) self.thread = threading.Thread(None, self.run, None, (), {}) self.thread.start() def run(self): """ Run the PWM pattern into a background thread. This function should not be called outside of this class. """ while self.toTerminate == False: if self.nbSlicesOn > 0: GPIO.output(self.gpioPin, GPIO.HIGH) time.sleep(self.nbSlicesOn * self.sliceTime) if self.nbSlicesOn < self.nbSlices: GPIO.output(self.gpioPin, GPIO.LOW) time.sleep((self.nbSlices - self.nbSlicesOn) * self.sliceTime) self.terminated = True def changeNbSlicesOn(self, nbSlicesOn): """ Change the duration of HIGH output of the pattern. Expected parameter is : - nbSlicesOn : number of divisions (on a total of nbSlices - see init() doc) to set HIGH output on the GPIO pin Exemple : with a total of 100 slices, a baseTime of 1 second, and an nbSlicesOn set to 25, the PWM pattern will have a duty cycle of 25%. With a duration of 1 second, will stay HIGH for 1*(25/100) seconds on HIGH output, and 1*(75/100) seconds on LOW output. """ self.nbSlicesOn = nbSlicesOn def changeNbSlices(self, nbSlices): """ Change the number of slices of the PWM pattern. Expected parameter is : - nbSlices : number of divisions of the PWM pattern. Exemple : with a total of 100 slices, a baseTime of 1 second, and an nbSlicesOn set to 25, the PWM pattern will have a duty cycle of 25%. With a duration of 1 second, will stay HIGH for 1*(25/100) seconds on HIGH output, and 1*(75/100) seconds on LOW output. """ if self.nbSlicesOn > nbSlices: self.nbSlicesOn = nbSlices self.nbSlices = nbSlices self.sliceTime = self.baseTime / self.nbSlices def changeBaseTime(self, baseTime): """ Change the base time of the PWM pattern. Expected parameter is : - baseTime : the base time in seconds for the PWM pattern. Exemple : with a total of 100 slices, a baseTime of 1 second, and an nbSlicesOn set to 25, the PWM pattern will have a duty cycle of 25%. With a duration of 1 second, will stay HIGH for 1*(25/100) seconds on HIGH output, and 1*(75/100) seconds on LOW output. """ self.baseTime = baseTime self.sliceTime = self.baseTime / self.nbSlices def stop(self): """ Stops PWM output. """ self.toTerminate = True while self.terminated == False: # Just wait time.sleep(0.01) GPIO.output(self.gpioPin, GPIO.LOW) GPIO.setup(self.gpioPin, GPIO.IN)Next up we will pull everything together in a Robot python class.
No comments:
Post a Comment