Thursday, April 14, 2011

H-Bridge Configuration

So, the ultimate goal here is to be able to drive a set of two motors through a gear box to convert the direction and to create one axis of rotation within a hamster ball.  The ball will act as the wheel and the drive components will be inside the wheel.  In order to do this, I needed to drive a couple of motors with an Arduino.  Turns out, the output current from the Arduino is not sufficient to power even one motor, much less two.  Some FETs are the solution and through some research online, a nice H-Bridge was found that has all the FETs set up for me ready to go! Sparkfun has some available for about $2.35, which isn't too bad. The datasheet gives the voltage range as 4.5V all the way up to 36V at 1A.  This should be more than enough power to drive the ball.

I found a nice set of instructions online for how to set this up for one motor here.  For testing it out and understanding how the H-Bridge functions, this tutorial was quite helpful.  What I needed, was two motors to drive instead. This was a matter of simply copying the existing code for one side and mirroring it to the other side.  Connecting two potentiometers, one for motor one, and one for motor two, the speeds could be controlled by setting the "enable" pins on the H-Bridge as an analogRead() function.  The enable pins (pin 1 and 9 on the H-Bridge) control the speed of the motor.  Depending on the voltage supplied to the enable pins (between 0 and 5V) will determine the speed.  this is done using pulse width modulation since the Arduino can only write a HIGH (5V) or a LOW (0V) to any pin.  A very good description of how this works is on Wikipedia.  Essentially, the Arduino will write a HIGH value followed by a LOW value, each for a certain length of time where the average value becomes  the desired voltage.  For example, writing a HIGH value for 2.5 seconds and a LOW value for 2.5 seconds will give you an average voltage of 2.5V.

Next, I decided to purchase a Joystick shield from Sparkfun (here).  The goal here was to use the joystick to control the speed and direction of the motor instead of two potentiometers and a pushbutton switch.  The hardest part on configuring the joystick portion was setting the center point.  One would think the center point would be 512 since the input ranges from 0 to 1023, however, on the X-axis, the center is 505 and the Y-axis is 489.  Despite this annoying set back, the simple fix was to read the value of the stick in the initial setup when the Arduino starts up.  Ultimately, the directions had to be divided so all positive axes movement resulted in clockwise rotation and all negative movement resulted in counter-clockwise motion.  An example of this is below:


That version of the program does not function correctly, it needed some debugging.  Turns out, the values were being read so quickly the joystick didn't have time to adjust and send the values (mechanical problems).  This was fixed by setting a "deadspace" into the program.  This deadspace was a range where the joystick could move on each axes and the value would not be translated.  In other words, it would write a LOW to the pins.

The following code displays the final code used for this joystick setup.  There are some bad programming habits within it, including calculations and reading during each condition, however, for the purposes of testing out the joystick, it functioned perfectly.  The next step, setting up the two XBees to run the joystick wirelessly, has corrected these values.
// X axis is A0
// Y axis is A1
#define switchPin 2 // switch input
#define motor1Pin 3 // Motor 1 leg 1 (pin 2, 1A)
#define motor2Pin 4 // Motor 1 leg 2 (pin 7, 2A)
#define motor3Pin 6 // Motor 2 leg 1
#define motor4Pin 7 // Motor 2 leg 2
#define enable1Pin 9 // Motor1 enable pin
#define enable2Pin 10 // Motor2 enable pin
#define ledPin 13 // Reset LED
#define slack 50 // Slack in joystick
float joy0;  // Defines scaling factor for joystick A0
float joy1;  // Defines scaling factor for joystick A1
float joyA0; // Defines starting position of X axis
float joyA1; // Defines starting position of Y axis
void setup()
{
        // Sets scaling factors at program start
        joy0 = 1023/analogRead(A0);
        joy1 = 1023/analogRead(A1);
        // Determines and reads starting positions of X and Y axis
        joyA0 = analogRead(A0);
        joyA1 = analogRead(A1);
      
        // set the switches as an input:
pinMode(switchPin, INPUT);
// set all the other pins you're using as outputs:
pinMode(motor1Pin, OUTPUT);
pinMode(motor2Pin, OUTPUT);
pinMode(motor3Pin, OUTPUT);
pinMode(motor4Pin, OUTPUT);
pinMode(enable1Pin, OUTPUT);
        pinMode(enable2Pin, OUTPUT);
pinMode(ledPin, OUTPUT);
      
        // set enablePin high so that motor can turn on:

// blink the LED 3 times. This should happen only once.
// if you see the LED blink three times, it means that the module
// reset itself,. probably because the motor caused a brownout
// or a short.
blink(ledPin, 3, 100);
        Serial.begin(9600);   //Turn on the Serial Port at 9600 bps
}
void loop()
{
        // Reads position of A0 and A1 (X and Y axis)
        int stickX = analogRead(A0);
        int stickY = analogRead(A1);
//        Serial.println(stickX);

        // Used to determine position of joystick
//        Serial.print("X:");
//        Serial.print(stickX);  // Prints original X
//        Serial.print(",Less:");
//        Serial.print(abs(stickX-510)/2);  // Less than X center
//        Serial.print(",Greater:");
//        Serial.print((stickX-512)/2);  // Greater than X center
//        Serial.print(" Y:");
//        Serial.print(stickY);  // Prints original Y
//        Serial.print(",Less:");
//        Serial.print(abs(stickY-510)/2);  // Less than Y center
//        Serial.print(",Greater:");
//        Serial.println((stickY-513)/2);  // Greater than Y center
      
        // Reads the position of A0 and determines direction and speed
        if (stickX < joyA0-slack)
        {
          analogWrite(enable1Pin, abs(stickX-510)/2);
          digitalWrite(motor1Pin, HIGH); // set leg 1 of the Motor1 high
 digitalWrite(motor2Pin, LOW); // set leg 2 of the Motor1 low
        }
        if (abs( stickX - joyA0 ) < slack)  // Sets deadspace on stick
        {
          digitalWrite(enable1Pin, LOW);
        }
        if (stickX > joyA0+slack)
        {
          analogWrite(enable1Pin, (stickX-512)/2);
          digitalWrite(motor1Pin, LOW); // set leg 1 of the Motor1 low
          digitalWrite(motor2Pin, HIGH); // set leg 2 of the Motor1 high
        }
      
        // Reads the position of A1 and determines direction and speed
        if (stickY < joyA1-slack)
        {
          analogWrite(enable2Pin, abs(stickY-510)/2);
          digitalWrite(motor3Pin, HIGH); // set leg 1 of the Motor2 high
 digitalWrite(motor4Pin, LOW); // set leg 2 of the Motor2 low
        }
        if (abs(stickY - joyA1) < slack)  // Sets deadspace on stick
        {
          digitalWrite(enable2Pin, LOW);
        }
        if (stickY > joyA1+slack)
        {
          analogWrite(enable2Pin, (stickY-513)/2);
          digitalWrite(motor3Pin, LOW); // set leg 1 of the Motor2 low
 digitalWrite(motor4Pin, HIGH); // set leg 2 of the Motor2 low
        }
}
//blinks an LED
void blink(int whatPin, int howManyTimes, int milliSecs)
{
int i = 0;
for ( i = 0; i < howManyTimes; i++)
{
digitalWrite(whatPin, HIGH);
delay(milliSecs/2);
digitalWrite(whatPin, LOW);
delay(milliSecs/2);
}
}

No comments:

Post a Comment