Monday, July 15, 2013

Controlling two DC motors with Raspberry Pi and the L293D dual H-bridge motor driver


In order to move our Raspberry Pi powered rover, we will need at least two DC motors to power a left and right set of wheels. The motors will be used to move the rover forward and reverse, as well as rotate left and right.

To accomplish this, we figured out how to modify the DC motor tutorial on adafruit.com  to go from controlling one DC motor to two independent DC motors. Controlling two DC motors was accomplished with one L293D dual H-bridge motor driver chip, additional wiring configuration and code modifications.

Let's first look at the L293D dual H-bridge motor driver and GPIO wiring:

In the above figure, all connections in blue and purple are used identically in the original tutorial which demonstrates how to control one DC motor.

Used to control direction of motor 1:
  • GPIO 4
  • GPIO 17
Pulse with modulation control (PWM):
  • GPIO 18
DC motor connections:
  • M1+
  • M1-
Power source connections:
  • Battery+
  • 5v Pi
Ground:
  • GND
The annotations in green are what was added in order to get the second DC motor to work with the shared L293D dual H-bridge motor driver.

Used to control direction of motor 1:
  • GPIO 23
  • GPIO 24
Pulse with modulation control (PWM): 
(NOTE THIS IS INTENTIONALLY SHARED WITH MOTOR 1!)
  • GPIO 18

DC motor connections:
  • M2+
  • M2-
Ground (not sure if necessary):
  • GND

At this time, we are using the PWM kernel module included in Occidentalis v0.2. This module is used to controll the rotational speed of the motors, which should both rotate at the same speed. Having both motors sharing GPIO 18 seems to work fine. The drawback of using the PWM module is that there is only one, and we cannot use it for both DC motors and servos. If we find that the default maximum speed of the two motors is fine, we may later free up GPIO 18 in order to add a servo.

Our large breadboard was getting messy from other projects, and this one requires a good amount of wiring, so I cleaned out everything from previous projects before starting this one.



I place the L293D dual H-bridge motor driver on a separate half-size bread board in order to keep all motor related wiring isolated on one board and left the GPIO breakout on the large breadboard (since we will be connecting more stuff to it later on).

Lets now look at the code. In order to have efficient code for the motors, I created a Motor class, so we can instantiate two motors with one class definition.

Motor class:


  1. class Motor(object):
  2.         def __init__(self, in1_pin, in2_pin):
  3.                 self.in1_pin = in1_pin
  4.                 self.in2_pin = in2_pin
  5.                
  6.                 GPIO.setup(self.in1_pin, GPIO.OUT)
  7.                 GPIO.setup(self.in2_pin, GPIO.OUT)
  8.        
  9.         def clockwise(self):
  10.                 GPIO.output(self.in1_pin, True)    
  11.                 GPIO.output(self.in2_pin, False)
  12.         def counter_clockwise(self):
  13.                 GPIO.output(self.in1_pin, False)
  14.                 GPIO.output(self.in2_pin, True)
  15.                
  16.         def stop(self):
  17.                 GPIO.output(self.in1_pin, False)    
  18.                 GPIO.output(self.in2_pin, False)


In the Adafruit tutorial, there is a helper function called set(), which I left as is outside of the class. I may incorporate it into a class later on, but I have not yet decided where it would best fit.

set() function:


  1. def set(property, value):
  2.     try:
  3.         f = open("/sys/class/rpi-pwm/pwm0/" + property, 'w')
  4.         f.write(value)
  5.         f.close()      
  6.     except:
  7.         print("Error writing to: " + property + " value: " + value)


Below is the main code that will pull it all together:


  1. import RPi.GPIO as GPIO
  2. GPIO.setmode(GPIO.BCM)
  3. left_in1_pin = 4
  4. left_in2_pin = 17
  5. right_in1_pin = 23
  6. right_in2_pin = 24
  7. class Motor(object):
  8.         def __init__(self, in1_pin, in2_pin):
  9.                 self.in1_pin = in1_pin
  10.                 self.in2_pin = in2_pin
  11.                
  12.                 GPIO.setup(self.in1_pin, GPIO.OUT)
  13.                 GPIO.setup(self.in2_pin, GPIO.OUT)
  14.        
  15.         def clockwise(self):
  16.                 GPIO.output(self.in1_pin, True)    
  17.                 GPIO.output(self.in2_pin, False)
  18.         def counter_clockwise(self):
  19.                 GPIO.output(self.in1_pin, False)
  20.                 GPIO.output(self.in2_pin, True)
  21.                
  22.         def stop(self):
  23.                 GPIO.output(self.in1_pin, False)    
  24.                 GPIO.output(self.in2_pin, False)
  25.                
  26. def set(property, value):
  27.     try:
  28.         f = open("/sys/class/rpi-pwm/pwm0/" + property, 'w')
  29.         f.write(value)
  30.         f.close()      
  31.     except:
  32.         print("Error writing to: " + property + " value: " + value)
  33.        
  34. try:
  35.         set("delayed", "0")
  36.         set("frequency", "500")
  37.         set("active", "1")
  38.         left_motor = Motor(left_in1_pin, left_in2_pin)
  39.         right_motor = Motor(right_in1_pin, right_in2_pin)
  40.        
  41.         direction = None
  42.        
  43.         while True:    
  44.                 cmd = raw_input("Command, f/r/o/p/s 0..9, E.g. f5 :")
  45.                
  46.                 # if enter was pressed with no value, just stick with the current value
  47.                 if len(cmd) > 0:
  48.                         direction = cmd[0]
  49.                 if direction == "f":
  50.                         left_motor.clockwise()
  51.                         right_motor.clockwise()
  52.                 elif direction == "r":
  53.                         left_motor.counter_clockwise()
  54.                         right_motor.counter_clockwise()
  55.                 elif direction == "o"# opposite1
  56.                         left_motor.counter_clockwise()
  57.                         right_motor.clockwise()
  58.                 elif direction == "p":
  59.                         left_motor.clockwise()
  60.                         right_motor.counter_clockwise()        
  61.                 else:
  62.                         left_motor.stop()
  63.                         right_motor.stop()
  64.                
  65.                 # only need to adjust speed if we want to      
  66.                 if len(cmd) > 1:
  67.                         speed = int(cmd[1]) * 11
  68.                         set("duty", str(speed))
  69.                
  70. except KeyboardInterrupt:
  71.         left_motor.stop()
  72.         right_motor.stop()
  73.         print "\nstopped"


download the code here

to run:
$ sudo python rover.py 

Command, f/r/o/p/s 0..9, E.g. f5 :f

f == forward
r == reverse
o == opposite directions
p == opposite directions
s == stop

CTRL-C gracefully stops the motors.

Here it is in action!

Coming soon. Web GUI driven DC motors...

15 comments:

  1. It's pulse wiDth modulation. Not pulse with [sic] modulation.

    ReplyDelete
  2. hi
    I've used this circuit.
    The motor speed is too "slow".
    But when I connect the battery directly to the motor speed is "high".
    I'm using 4 batteries 1.5 volt.
    Please help me.

    ReplyDelete
  3. nice article..i had troubles in controlling two Gear DC Motors..now i figured it out :)

    ReplyDelete
  4. great article on Gear DC Motor i had issues but now they are resolved..thankyou :))

    ReplyDelete
  5. What would I need to worry about if I were to do this with a 24v power wheels motor?

    ReplyDelete
  6. could i use this h bridge to controll a 12v trolling motor, the amps are high, like like possibly 2 amps? please help. jacob.fowler@outlook.com

    ReplyDelete
  7. i am doing this project and both motors can run in both direction as per coding require but motors are not going to rotate as per command 0..9 various speeds so i want to know that i can be run on various speed as per i will give f1,f2 f3 like or its just run on one speed? if u want to ask me more contact me chaks08forever@gmail.com

    ReplyDelete
  8. Thanks guys for your appreciative efforts, you really have done the awesome searching for your blog! electric motor sales

    ReplyDelete
  9. hello, i have a question. why we use Cobbler Breakout?
    I have searching about Cobbler Breakout but i dont know why we use that. can you tell me why we use the Cobbler Breakout?

    ReplyDelete
    Replies
    1. Cobbler breakout just moves all the GPIO pins to the breadboard. You don't have to us it if you don't want to.

      Delete
  10. This post is really nice and informative. The explanation given is really comprehensive and informative. I am feeling happy to comment on this post.
    12v dc gear motor

    ReplyDelete
  11. Jost’s Material Handling provides innovative solutions for internal material handling needs for its customers so that it improves the efficiencies of their processes.

    Jost's Electric operated Stackers are ideal, simple and effective solutions for storage (stacking) and retrieval of pallets at vertical storage spaces in warehouses and are used in the widest range of applications imaginable. Jost's electric Stackers are designed for flexible and retrieval handling of specialized loads, increased performance at great heights, comfortable maneuverability in narrow aisles, high residual capacities and long usage times.
    PIV
    Boom Lifts

    ReplyDelete
  12. Pioneer Cranes and Elevators is TOP 3 EOT Crane Manufacturers in India. We used high quality raw material and used modern and latest technology for our best JIB Crane manufacturing. The entire product range is available in size and design variation that the client can choose as per their suitability and beside these the facilities of the machine handling equipment customization is also provided by us that the customers can avail in case of any special requirement.

    ReplyDelete
  13. We are the main Gantry Cranes Manufacturers in India. We used high quality raw material and used modern and latest technology for our best Goliath Cranes manufacturing. The business foundation is very much evolved and arranged out, have all the advanced machine, simple availability around the world, and so forth.

    ReplyDelete