Tuesday, January 28, 2014

43. Full Control of a DC Motor using an H-Bridge

9000 page views!!
So far we have been able to drive a DC motor under software control from the Arduino.  We saw that precautions have to be made to protect the Arduino from 

  • too much power being drawn by the motor and
  • the possibility that inductive 'kick-back' from the DC motor can send a destructive negative spike through the circuit

and that smoothing by a capacitor is desirable because of the motor's 'noisy' power demand. 

We made use of a transistor as a fairly high-frequency (50Hz) switch, turning it on and off using software, in such a way that the 9V battery potential was applied as 9V power pulses with a pre-defined 'duty cycle'.  This made the motor behave as if the applied voltage was varying from maximum to minimum.  This of course was making use of pulse-width modulation (PWM).

However, we did not have full control over the motor, as reversing its direction would have entailed physically swapping over the motor wires.

Suppose we wanted to be able to turn a potentiometer knob (or trimmer screw) and control the DC motor so that turning the screw clockwise gradually increases the clockwise rotation speed of the rotor, and then turning the screw anti-clockwise gradually slows down the clockwise rotational speed, stops the rotor, and then gradually increases the anti-clockwise rotational speed.  By turning the trimmer to a central position, the rotor could be halted, and turning it to the left would cause anti-clockwise rotation, while turning to the right would cause clockwise rotation.  Further trimming to the left or right would increase the motor's spinning speed in that direction.

To achieve this we would need a switching arrangement something like this:



so that by arranging four switches, top left (TL), top right (TR), bottom left (BL) and bottom right (BR), the current can be allowed to flow left-to-right through the motor, or right-to-left.

If TL and BR are closed, while the other two diagonal switches are open, the current flows as indicated in the top diagram, let's say clockwise (cw).  If the alternative diagonal combination of switches is used (TL & BR open, TR & BL closed), the motor turns counter-clockwise (ccw).

Luckily, it's possible to obtain an integrated circuit (IC) which has these properties - the H-bridge.  It's called this because of the H-like arrangement of the integrated transistor switches.  One example of the H-bridge is the Texas Instruments L293DNE Quadruple Half-H Driver.  This 2-cm long, 16-legged IC has more circuitry than we need.  We require a pair of Half-H circuits for our switching requirements, but in fact the chip has twice this capability - it can independently control 2 DC motors at the same time, each motor being allowed to draw up to 600 mA at up to 36V!  (Remember that my current DC motor draws up to 350 mA at 8.2V).  

So here we will use half of its capability.

Here is the Quadruple Half-H Driver:


The chip has built-in thermal shutdown to protect against a short circuit - for example, if TL and BL were closed at the same time, or if TR and BR were closed at the same time.  These conditions would allow an un-impeded current to flow from the positive to the negative terminals of the 9V battery.  This would be very undesirable, as even 9V batteries when short-circuited, can release a lot of energy, and even explode in the process.

However, it is never good practice to rely on the built-in thermal shutdown, so the switches are disabled before changing their state between on and off.  For example, the switch between motor directions needs to be disabled because a momentary short circuit is just possible.  This is why there are 3 control connections - one for controlling switches 1 and 2, one for controlling switches 3 and 4, and one to enable the circuit.


The table above summarises the functioning of each half-H driver.  So, for each of the 1, 2, 3 and 4 half-H gates, if input A is set HIGH, the output Y is HIGH, but only if EN (enable) is set HIGH.  If input A is set LOW, then output Y is LOW, but again only if EN is HIGH.  Otherwise, if EN is LOW, then, regardless of the state of input A, the output Y will be OFF.

So the connections are as follows:

We are going to use the chip's gate 1 (chip pin numbers 1, 2 & 3and gate 2 (chip pin numbers 6, 7 & 8) to represent the (TL & BR) pair and the (BL & TR) pair of switches.

On the L293DNE:

Pin 1 (1,2EN) is used to enable and disable the driver on the left of the chip and is connected to the Arduino's Pin 9

Pins 2 (1A) and 7 (2A) are connected to Arduino Pin 3 and 2 respectively, and control the state of the switches 1 and 2.

Pins 3 (1Y)  and 6 (2Y) are the outputs from the chip's left hand driver's switches 1 and 2.

Pins 4512 and 13 (Heat sink and Ground) are connected to the common GND for both the 9V and Arduino's 5V supplies.

Pin 8 (VCC2) supplies the motor current, and is connected to the 9V battery's positive terminal.

Pin 9 is the enable for the IC's right hand driver, which is not used here, so it is best to connect it to GND.

Pins 10, 11, 14 and 15 do not need to be connected because they are for the chip's right hand driver which we're not using here.

Pin 16 (VCC1) supplies the chip's power, and is connected to the Arduino's 5V supply.

Here's the mug-shot:


And here it is working:


The trimmer I'm tweaking with a screwdriver is the blue component at the top right of the picture.  As I turn one way, the motor rotates faster and faster in one direction and then as I turn the other way, the rotation slows down to a halt and then starts to accelerate in the opposite direction.  Pretty good - eh?

Note that the role of the transistor, capacitor and diode has been taken over by the H-bridge, making a relatively neat circuit on the breadboard.  The battery box now has it's cover on and the mini breadboard and DC motor have been mounted on top of it with the good old ubiquitous rubber bands!

For completeness, here's the software, again attributable to Jeremy Blum from his excellent recent book Exploring Arduino - Tools and Techniques for Engineering Wizardry:

1:  /*  
2:  Exploring Arduino - Code Listing 4-3: H-Bridge Potentiometer Speed Control  
3:  http://www.exploringarduino.com/content/ch4  
4:    
5:  Copyright 2013 Jeremy Blum ( http://www.jeremyblum.com )  
6:  This program is free software: you can redistribute it and/or modify  
7:  it under the terms of the GNU General Public License v3 as published by  
8:  the Free Software Foundation.  
9:  */  
10:    
11:  //Hbridge Motor Control  
12:  const int EN=9;  //Half Bridge 1 Enable  
13:  const int MC1=3; //Motor Control 1  
14:  const int MC2=2; //Motor Control 2  
15:  const int POT=0; //POT on Analog Pin 0  
16:    
17:  int val = 0;   //for storing the reading from the POT  
18:  int velocity = 0; //For storing the desired velocity (from 0-255)  
19:    
20:  void setup()  
21:  {  
22:    pinMode(EN, OUTPUT);  
23:    pinMode(MC1, OUTPUT);  
24:    pinMode(MC2, OUTPUT);  
25:    brake(); //Initialize with motor stopped  
26:  }  
27:    
28:  void loop()  
29:  {  
30:    val = analogRead(POT);  
31:     
32:    //go forward  
33:    if (val > 562)  
34:    {  
35:      velocity = map(val, 563, 1023, 0, 255);  
36:      forward(velocity);  
37:    }  
38:     
39:    //go backward  
40:    else if (val < 462)  
41:    {  
42:      velocity = map(val, 461, 0, 0, 255);  
43:      reverse(velocity);  
44:    }  
45:     
46:    //brake  
47:    else  
48:    {  
49:      brake();  
50:    }  
51:  }  
52:    
53:  //Motor goes forward at given rate (from 0-255)  
54:  void forward (int rate)  
55:  {  
56:    digitalWrite(EN, LOW);  
57:    digitalWrite(MC1, HIGH);  
58:    digitalWrite(MC2, LOW);  
59:    analogWrite(EN, rate);  
60:  }  
61:    
62:  //Motor goes backward at given rate (from 0-255)  
63:  void reverse (int rate)  
64:  {  
65:    digitalWrite(EN, LOW);  
66:    digitalWrite(MC1, LOW);  
67:    digitalWrite(MC2, HIGH);  
68:    analogWrite(EN, rate);  
69:  }  
70:    
71:  //Stops motor  
72:  void brake ()  
73:  {  
74:    digitalWrite(EN, LOW);  
75:    digitalWrite(MC1, LOW);  
76:    digitalWrite(MC2, LOW);  
77:    digitalWrite(EN, HIGH);  
78:  }  
79:    

So looking at the code above, 
  • Arduino Digital pin 9 is defined as the half-bridge 1 enable pin, 
  • Digital pins 3 and 2 are connected to motor control 1 and 2 respectively, and 
  • the potentiometer's wiper is connected to Analog Pin 0

The void setup() function sets the digital pins as outputs and immediately invokes the brake() function.  We'll come back shortly to the brake() function.

There are some neat functions included:
brake(), forward() and reverse().

To see how these work, let's look at the following diagram:



We can think of diagonal TR to BL as switch 1A on the chip, and diagonal TL to BR as switch 2A.  
In diagram 1, all switches are open, ie nothing is enabled.
Look at the diagram 2:  
Forward: 1A is HIGH (switches closed) and 2A is LOW (switches open).  In diagram 3, 
Backward: 1A is LOW and 2A is HIGH
Now in diagram 4:
1A is LOW and 2A is also LOW

For each function, care is taken to disable before setting switches, followed by an enable:


53:  //Motor goes forward at given rate (from 0-255)  
54:  void forward (int rate)  
55:  {  
56:    digitalWrite(EN, LOW);  
57:    digitalWrite(MC1, HIGH);  
58:    digitalWrite(MC2, LOW);  
59:    analogWrite(EN, rate);  
60:  }  


62:  //Motor goes backward at given rate (from 0-255)  
63:  void reverse (int rate)  
64:  {  
65:    digitalWrite(EN, LOW);  
66:    digitalWrite(MC1, LOW);  
67:    digitalWrite(MC2, HIGH);  
68:    analogWrite(EN, rate);  
69:  }  


71:  //Stops motor  
72:  void brake ()  
73:  {  
74:    digitalWrite(EN, LOW);  
75:    digitalWrite(MC1, LOW);  
76:    digitalWrite(MC2, LOW);  
77:    digitalWrite(EN, HIGH);  
78:  } 

In the cases of forward and reverse, the degree of enablement, (EN, rate) and hence the speed, is dictated according to the value of rate.  The value of rate has been received from Analog pin 0 as follows:


30:    val = analogRead(POT);

This is making use of PWM as it is an analogWrite to a PWM-enabled pin on the Arduino.

The part of the program that deciphers the potentiometer's variable resistance is in the loop part:


28:  void loop()  
29:  {  
30:    val = analogRead(POT);  
31:     
32:    //go forward  
33:    if (val > 562)  
34:    {  
35:      velocity = map(val, 563, 1023, 0, 255);  
36:      forward(velocity);  
37:    }  
38:     
39:    //go backward  
40:    else if (val < 462)  
41:    {  
42:      velocity = map(val, 461, 0, 0, 255);  
43:      reverse(velocity);  
44:    }  
45:     
46:    //brake  
47:    else  
48:    {  
49:      brake();  
50:    }  
51:  }  

The value val of the potentiometer position is read in as an analogRead().  The analogue values read in in this way are converted into digital values between 0 and 1023.  Then the map() function is used to scale val's range to the range 0 to 255:
We have taken the pot's values between 0 and 1023, and divided this range into 3 areas - 0 to 461 is mapped to the range 0 to 255.  563 to 1023 is mapped to 0 to 255, and the region in-between is the braking ('Stopped') region.  

These mapped values are then used in the forward(), reverse() or brake() functions as required.

Isn't that marvellous?!!

No comments:

Post a Comment