Friday, December 7, 2007

Motors, servos, and back EMF, oh my!

I had a chance to play with my Arduino board some more. My first task was getting proper speed control of a DC motor using pulse-width modulation. I wrote a little program to vary the width (in time) of the HIGH pulse in set total pulse period. You can find the idea behind it here. The code for my manual PWM speed control is right below:


int highPulseWidth = 10000;
int totalPulseWidth = highPulseWidth;
int dir = 0;
int threshold = 3;

void setup()
{
  pinMode(11, OUTPUT);
}

void loop()
{
  digitalWrite(11, HIGH);
  delayMicroseconds(highPulseWidth);
  if( totalPulseWidth-highPulseWidth > threshold )
  {
    digitalWrite(11, LOW);
    delayMicroseconds(totalPulseWidth-highPulseWidth);
  }
  if( dir == 0 )
  {
    highPulseWidth = highPulseWidth-10;
    if( highPulseWidth < threshold )
    {
      highPulseWidth = threshold;
      dir = 1;
    }
  }
  else
  {
    highPulseWidth = highPulseWidth+10;
    if( highPulseWidth > totalPulseWidth )
    {
      highPulseWidth = totalPulseWidth;
      dir = 0;
    }
  }
}


The dir variable tracks what direction we're changing the pulse width (1 for increase, 0 for decrease). Something definitely worth noting, since it caused me some confusion early on, is where the delayMicroseconds() function is accurate. It's noted in the Arduino reference here; the function is only accurate in the range from 3 microseconds to 16383 (2^14-1) microseconds. This caused me problems because at first I was trying to delay for a second using the delayMicroseconds() function which means passing in one million, definitely over 16383. This also explains why I have that threshold variable there. So this program will decrease the HIGH pulse width from the total pulse width (full speed) to zero. When it reaches zero (well, reaches threshold) it changes directions and increases the HIGH pulse width until it reaches the total pulse width size. The idea is that the period of the pulse cycle remains constant (totalPulseWidth) so the delay on HIGH and delay on LOW added together stay that period.

Well, that's all nice and dandy but how does this interface with the motor itself? Well, that's where transistors come to the rescue. I just grabbed some random transistor (the TIP31 apparently) with a high voltage rating at Radio Shack.



This web page proved to be extremely useful. A transistor is just a gate. You'll notice that it has three pins: base, collector, and emitter. The idea is that if something is flowing through the base then the collector opens up. If nothing is flowing through the base then the collector is closed. What makes this useful is you can control a larger voltage source using a relatively small one. The voltage on the HIGH and LOW signals outputted by the Arduino board are only 3.3V or 5V, I forget which. This means you can't really drive a 9V motor with the digital signal alone. Instead you want to connect the motor to a 9V power source and use the transistor to control the motor's connection to the 9V power source. That's pretty much it.

So I used a regular ole' 9V batter as my power source.



So the first thing in setting up the circuit was to get the battery and the Arduino board to share the same ground so that the currents will flow where we want them to flow. So I just connected the battery's negative to the Arduino's ground.



Next I get the motor ready to be connected to the collector pin of the transistor. I also connect where the base of the transistor will be to my output pin, 11 (no reason I picked 11, could be any of them). Finally I have a wire going from where the emitter pin of the transistor will be to the ground. All of this is based on the diagram from here.





With the above the transistor is ready to be put in. My Arduino board is already loaded with the program I posted above.



After that the motor starts spinning. I'd get video of it up if I had it, maybe later.

Anyway, I still need to write on how to control a servo and how I used the back EMF from my motor to control the servo's rotation speed. That's for later I guess!

No comments: