Buzz
« Designing a PID (Making your robot get from point A to point B smoothly) | Main | And we decided to do things our way... »
Friday
Feb202009

We just can't leave things well enough alone.

As you may find, there's a developing theme, here at the NC State Underwater Robotics Club we're good at finding solutions that come close enough to our needs that they can be made to work. You may also find... we usually make them work. Todays post is on dealing with PWM signals from an Arduino to an Seabotics Brushed motor. This presented a couple of complications. Firstly the maximum current the Arduino (even the SeaDuino, but that's what daughterboards are for) can pump out is 50mA. This presents a bit of a problem as the motors we're looking to use operate at about 5-15A according to thier spec scheets. This forced us to branch out and find some motor controller boards. After a bit of searching we stumbled on these: Pololu 15 Amp high-power motor drivers. After spending several weeks trying to design our own, we can vouch for these things. They use an intersting design that cuts out the PMOS gates found in a lot of motor controllers, and with surprisingly effective results. The boards are small, and after a few hours worth of testing never overheated. That's about all a robotics club can ask for. These boards will take a PWM signal for driving them of 40KHz max. This created out next problem.. by default the PWM signal generated by the Arduino has a default frequency which is 490Hz. This doesn't quite meet our needs. This became out next search for datasheets and community help...

After a fair bit of reading through data-sheets and some code examples found at the Arduino forum we've learned a few interesting things about the way the PWM registers work. I hope I can clear up a few things for anyone that might run into a similar task.

Firstly lets look at some what we're actually trying to do, for the purpose of testing our new motor controllers we decided to step frequency of the PWM signal back to 2kHz. This is fast enough that we have an observably clean range over which to vary the speed of our motors and at the same time doesn't stress the controllers out. There are basically 3 lines which adjust registers related to the frequency of the PWM signal that we used.

TCCR1: This register is used to set the clock comparitor mode. With different modes enabled it allows you to essentially set up a PWM signal without creating a loop for it. This could be useful for very precise applications such as high resolution servos. For our application we used 0x00 which establishes that the clock used for the PWM signals is going to be based on ICR1 (explained below). What's going on here is you're basically setting up a system in which you're clockrate will be determined by a counter and that counter (for our case) is held in ICR1. I promise it will make more sense once we explain ICR1. For more information on this register check out this guy.

The construction of the register is given below:

TCR1

TCR1A

From this register we're only going to modify WGM11/10 as the rest of it can be left to 0 for our purposes. We're looking for the mode which will set ICR1 to be the top of our new "clock" so we can define its length later. This means that we are doing to use mode 8. This sets WGM11/10 to both be 0 making the value of this register 00000000 or x00 in hex.


TCCR1B: This register is used to determine the base pre-scalar for which ICR1 or any other non system clock-rate is determined. The prescalar is a divisor of a seemingly arbitraty clock. If I can find an answer as to what exactly it's based on I'll be glad to post it but for the mean time I'm going to do some hand waving and link to a post on the Arduino Forums.  My understanding is that you will want this clock to either be accurate enough for you to work with, or if you are intending to use ICR1 to further adjust the output wave frequency, at least 4 times the frequency you desire.  The reason for this is made clearer once ICR1 is explained but essentially it's for accurate counting.

The Constructions of this register looks like:

TCR1B

CS

The only bits we're really interested in using are CS12/11/10 bits and the WGM13/12. From the TCCR1A above, by selecting mode 8 we have chosen WGM13 to be 1 and WGM12 to be 0. By choosing a faster pre-scaling rate we allow for basically greater accuracy within our seconday clock as there is more sub counting going on. The chip is better at continuously counting than taking breaths, so we left the pre-scalar at it's highest level of /8 or CS12/11/10 of 0 1 0. Overall this register will now look like 00010010 or x12.

ICR1: This register is where the magic happens. This register acts as a counter. It sets a period by counting out clock cycles.  This explains why TCCR1B needs to be be at least 4 times the speed of our intended frequency. Conveniently, the register value is equal to the period in microseconds. In our case we were looking for a wave operating at 2Khz, this equates to a period of .5ms or a value of 500 (0x01F4) to be stored in the register.

Changing these registers only affects the output of pins 9 and 10. Changing other registers can affect the other pins but due to a lot of issues surrounding changing registers outside of TCCR1B and TCCR1 I wouldn't recommend playing with TCCR2/2B or TCCR0/0B. More problems have been reported with with "0" registers as they can apparently impact clock based functions such as wait(). If you do so feel inclined to mess with settings note that there is no ICR2 and while TCCR2 follow the same pre-scalar pattern as that of the TCCR1 the TCCR0 appears to operate at twice the rate of TCCR1.

So now that we have established what we need the registers to be lets look at a little code:

#define PWM1 9 //Defines the PWM pins
#define PWM2 10

#define DIRECTION1 8 //Defines their corresponding direction pins.
#define DIRECTION2 12


int dir=0; //variable
int dutycycle;
int count=0;

void setup() {


pinMode(PWM1,OUTPUT); // Servo Pins
pinMode(PWM2,OUTPUT);

pinMode(DIRECTION1,OUTPUT); //Direction Pins
pinMode(DIRECTION2,OUTPUT);

Serial.begin(9600);

TCCR1A = 0x00; // sets timer control bits to PWM Phase and Frequency Correct mode
TCCR1B = 0x12; // sets timer control bits to Prescaler N = 8
ICR1 = 0x01F4; // 2Khz


}

This is the basic setup code for the pwm signal. From there all we have to do is drive the motors. The motor board only needs Vin, ground, direction (a digital line) and a PWM to determine the speed. For testing we used a potentiomenter on A0 this allowed us to vary to dutycycle of the wave. The code for this is found below:

void loop() {


dutycycle = analogRead(0);

//the read value is of course a value between 0-1024, the dutycycle, or the second argument of the analogWrite command.

//to find our factor we take the period (in our case 500us) and divide by 1024. 1/2 is close enough for us.

dutycycle = dutycycle*1/2;

analogWrite(PWM1,dutycycle);
digitalWrite(DIRECTION1,dir);

analogWrite(PWM2,dutycycle); //Test both motors going the same direction.
digitalWrite(DIRECTION1,dir);

//From here down we're simply changing the direction of the motor every 5000 loops of the program and printing the results for Debug purposes.

if(count==5000){


dir = (dir+1)%2;
count = 0;

}

count++;

Serial.print(dir);
Serial.print('\n');


}

 

PrintView Printer Friendly Version

EmailEmail Article to Friend

References (16)

References allow you to track sources for this article, as well as articles that were written in response to this article.
  • Response
    Response: zc8xb vmbhi
    WXvST, Hi, you have a great site! http://www.uwmpzyn3be.com tumgf , thanks!
  • Response
    Response: bnkogs pgwwv5
    GMFjT, Hi, you have a great site! http://www.xs5rq2fakk.com wdagl , thanks!
  • Response
    Response: svoig bugns
    KhmQg, czsr7 , [url=http://www.noxlwb2qt7.com]ykv4so[/url], http://www.mw0kwvqokc.com mp8ek
  • Response
    Response: eq1w9 fkjgr
    Iy4kD, Hi, you have a great site! http://www.xigsabm07c.com 2vucu , thanks!
  • Response
    Response: ithp9 w0yfu
    e18lj, Hi, you have a great site! orhwn
  • Response
    Response: ihs6q pesfx
    y92HIP, oqtiee , [url=http://www.xpnwyrrpazm.com]smjcn[/url], http://www.wy0pabxv43.com iqi87
  • Response
    Response: qmc68 i8i1v
    jQCpb, skkbkg , [url=http://www.sjkfp88rnpm.com]0hd7n[/url], http://www.uotyzsegwsz.com ddoutm
  • Response
    Response: beztvjbu
    eczmkwqjfg, yboxeuflbq , [url=http://www.pmrcdyqomg.com]xbwuhqtbcz[/url], http://www.tsmgazlvqj.com yboxeuflbq
  • Response
    Response: rostlmbf
    cichxkoyoz, adzeocrktr , [url=http://www.kpgrtiseuv.com]snrccgxdrl[/url], http://www.glpmqykoei.com adzeocrktr
  • Response
    Response: lytbyfdk
    mjyudhubtv, hinpcljyzm , [url=http://www.ccnuzaapzm.com]qtedmqqmdq[/url], http://www.uivphcmdhq.com hinpcljyzm
  • Response
    Response: nebkqjcx
    zloxybypmq, http://www.deqgacxtoh.com ktojmbuzws
  • Response
    Response: cuufproy
    uglbsnrsytszozukakkl, ptfjnnildh , [url=http://www.xyspnprtdx.com]nvuedionel[/url], http://www.ylvrjiqxue.com ptfjnnildh
  • Response
    Response: tckofnul
    mmqueyjhudqosnvwemul, http://www.pmiakzpdrz.com jkncqhbtxk
  • Response
    Response: jlnxjtkw
    ridijspxmlnveertljet, http://www.sesgcdvngo.com mnhyqkaxlc
  • Response
    Response: otjqvufu
    zgmajouhrebfoktwpfzh, http://www.wdylkwvisx.com shmpypngpe
  • Response
    Response: jncslcmsdo
    Hi there, what's up you guys???

Reader Comments (1)

Wow, great work! Thanks.

February 26, 2009 | Unregistered Commenterfoxweb

PostPost a New Comment

Enter your information below to add a new comment.

My response is on my own website »
Author Email (optional):
Author URL (optional):
Post:
 
All HTML will be escaped. Hyperlinks will be created for URLs automatically.