I had half a H bridge (transistor switches to enable motor + and motor - (i.e. forward)) working earlier today but then I broke it somewhere by trying to add the other half in. I'll have to carefully build it up step by step testing each bit as I go along. Probably on a totally separate breadboard.
Wont be able to do anymore until next week at some point but I think I have everything together now in theory.
I've been struggling a bit with getting my head around talking to the MCP23008 and making it do what I want reliably. It's got lots of registers that need to be configured properly before it will do what I want it to do.
I've also gone back to using the Quick2Wire API for now, mainly because there's more in the way of example code to work from but it's been a bit of a slog. I'm still trying to decide whether to use smBus or Quick2wire. Smbus only works with Python 2 and Quick2wire with Python 3. Smbus is stable but runs on a (possibly) soon to be deprecated language, Quick2Wire runs on Python 3 which is probably going to be more widely used for education.
I've knocked up a fairly simple BigTrak motor control test program using Quick2Wire this evening but am yet to test it. It's based around the MCP23008 test code I was using earlier to fire off a single transistor and make the motor turn. Here it is ...
- Code: Select all
#!/usr/bin/env python3
import quick2wire.i2c as i2c
import time
address = 0x20
#define all the registers
IODIR=0x00 # 0 = out 1 = in
IPOL=0x01 #input/output polarity on gpio. bit 7 -> bit 0. If bit set, gpio value will reflect the inverted value
GPINTEN=0x02 #interrupt on change. bit 7 -> bit0 If bit is set then will generate an interrupt if that pin changes
DEFVAL=0x03 #default value to compare against GPINTEN. bit 7 -> bit0. If bit is set, opposite value on corresponding pin will generate interrupt
INTCON=0x04 #interrupt control register. If bit is set then corresponding IO pin will be compared against that set in DEFVAL register
IOCON=0x05 #setup / config. bit 5 = sequential operation. bit 4 slew rate. bit 3 not used. bit 2 open drain. bit 1 interrupt polarity sets polarity of INT pin. ONly functions if open drain bit is clear
GPPU=0x06 #gppu pull up resistor, bit 7 -> bit 0. if bit set, if bit set and pin is input then this will pull up the pin with 100k resistor
INTF=0x07 #interrupt flag register. bit7 -> bit 0. bit set means the associated pin will generate an interrupt. A set bit in this register tells us which pin caused the interrupt. READ ONLY.
INTCAP=0x08 #interrupt capture. Captures GPIO value at time of interrupt. bit 7 -> bit 0. Remains unchanged until interrupt cleared via a read of INTCAP or GPIO
GPIO=0x09 #the GPIO. bit7 -> bit 0
OLAT=0x0A #output latches
#reset the mcp23008
self.master.transaction(
#set IODIR as OUTPUT
i2c.writing_bytes(address, IODIR, 0b00000000))
#reset all the other registers
for reg in [IPOL, GPINTEN, DEFVAL, INTCON, IOCON, GPU, INTF, INTCAP, GPIO, OLAT]:
self.master.transaction(
i2c.writing_bytes(address, reg, 0b00000000))
#Set the GPIO's to turn on / off transistors in H bridge. See associated circuit diagram.
#GPIO 0 - 1 = motor 1 fwd.
#GPIO 1 - 1 = motor 1 fwd.
#GPIO 2 - 1 = motor 1 rev.
#GPIO 3 - 1 = motor 1 rev.
#GPIO 4 - 1 = motor 2 fwd
#GPIO 5 - 1 = motor 2 fwd
#GPIO 6 - 1 = motor 2 rev
#GPIO 7 - 1 = motor 2 rev
#-----------------IMPORTANT DANGER IMPORTANT-----------------
#IF GPIO 0, 1 is "1" THEN GPIO 2, 3 must be "0" ELSE transistor short circuit and "Bang!"
#IF GPIO 4, 5 is "1" THEN GPIO 6, 7 must be "0" ELSE transistor short circuit and "Bang!"
#------------------------------------------------------------
#set all GPIO off
self.master.transaction(
i2c.writing_bytes(address, GPIO, 0b00000000))
#test motor 1 and motor 2 FWD for 3 secs
self.master.transaction(
i2c.writing_bytes(address, GPIO, 0b00000011))
time.sleep(3)
#set all GPIO off
self.master.transaction(
i2c.writing_bytes(address, GPIO, 0b00000000))
time.sleep(1)
#test motor 1 and motor 2 REV for 3 secs
self.master.transaction(
i2c.writing_bytes(address, GPIO, 0b00001100))
time.sleep(3)
#set all GPIO off
self.master.transaction(
i2c.writing_bytes(address, GPIO, 0b00000000))
time.sleep(1)
#test hard right turn for 1 sec
self.master.transaction(
i2c.writing_bytes(address, GPIO, 0b11000011))
time.sleep(1)
#test hard left turn for 1 sec
self.master.transaction(
i2c.writing_bytes(address, GPIO, 0b00111100))
time.sleep(1)
#set all GPIO off
self.master.transaction(
i2c.writing_bytes(address, GPIO, 0b00000000))
If it works, next steps will be to make the program take arguments of (motor direction, motor run time)
After that it would be good to control the speed (motor direction, motor speed %, motor run time)
I'm thinking of just using a very rough PWM to control the motor speed by specifying a percentage to modify the duty cycle with time.sleep but as I will also be using time.sleep to specify the motor run time I think that means I will need concurrent threads. Anyway, that's for later, one step at a time.
At some point I will add opto-encoders to calculate distance travelled (an LED shining through regular holes in a gear in the BigTrak to a receiving photo-diode) which will make the motor run time parameter redundant anyway.

