1

I'm currently working with the Talon SR Speed Controller and it requires a specific Input PWM Signal of 1-2 ms @ 333 Hz and an input resolution of 10-bit (1024 steps). Currently I use the Servo library to handle these requirements, but was having some issues of the motors jumping their dead-band from forwards to backwards really fast causing the motors to rock back and forwards a few millimeters. If the servo1.write(pwmValue); isn't my issues please let me know?

If there is a way to specifically achieve the 333Hz PWM signal for 4 motors of the same Uno or Due (most likely will transfer to a Due in a few days) I would like to implement that.

From my understand I can modify the timers registers for the arduino specifically, but don't know exactly how to do that or to achieve 333Hz. If someone could please help me understand this I would greatly appreciate it.

Speed SR Speed Controller Information:

Input voltage 6-28 VDC
Continuous current 60 A
Peak current 100 A
Input PWM signal 1-2 ms @ 333 Hz
Input resolution 10-bit (1024 steps)
Output resolution 10-bit (1024 steps)
Output switching frequency 15 kHz
4% neutral dead band
  • Does this have to do with FRC? I thought the build season was already over – TheDoctor Feb 24 '14 at 16:54
  • 1
    "modify the timers registers for the arduino specifically, but don't know exactly how to do that or to achieve 333Hz" Download the "Complete" version of the datasheet of ATmega328 from the atmel.com website and read the chapters about timers. The datasheet is surprisingly easy to read. Use the knowledge from that to ask a more specific question rather than asking for a complete solution. One hint: 333Hz equals 3ms period, find a timer that can time an accurate 3ms with sufficient resolution. – jippie Feb 24 '14 at 17:02
  • @thedoctor, No. This is collegic level robotics. – Steven10172 Feb 24 '14 at 17:35
  • @jippie, reading it right now. Hopefully it's better than the Arduino website. – Steven10172 Feb 24 '14 at 17:38
  • @Steven10172 - i applaud your choice in motor drivers – TheDoctor Feb 24 '14 at 17:49
4

I am playing on a Arduino UNO, you would have to compare the datasheets to determine differences.

For my research on this answer I am looking at:

Also:

  • we know PWM pins are D3, D5, D6, D9, D10, D11
  • I am using D11 for this since I can attach my oscilloscope to the MOSI pin of the ISCP
  • D11 maps to PB3 (MOSI/OC2A/PCINT3) (see datasheet or this cool gfx)

Normal usage

First, let's see what happens when we set an arbitrary PWM on pin 11

int DUTY = 25;
analogWrite(11, DUTY * 256 / 100);

results in:

  1. Freq: ~487Hz
  2. Duty: ~25%
  3. Time: ~2.05ms

This first point I will make is that with the given 490Hz the PWM duration is actually 2ms which seems to be close to what you want (you said between 1-2ms), maybe my misunderstanding there.


Playing with pre-scalers

From several of the links posted above, you will see that you have different pre-scalers available depending on which timer you are using: eg.

Pins 5 and 6: controlled by Timer 0 in fast PWM mode (cycle length = 256)

Setting     Divisor     Frequency
0x01        1           62500
0x02        8           7812.5
0x03        64          976.5625
0x04        256         244.140625
0x05        1024        61.03515625

TCCR0B = TCCR0B & 0b11111000 | <setting>;

Pins 9 and 10: controlled by timer 1 in phase-correct PWM mode (cycle length = 510)

Setting     Divisor     Frequency
0x01        1           31372.55
0x02        8           3921.16
0x03        64          490.20
0x04        256         122.55
0x05        1024        30.64

TCCR1B = TCCR1B & 0b11111000 | <setting>;

Pins 11 and 3: controlled by timer 2 in phase-correct PWM mode (cycle length = 510)

Setting     Divisor     Frequency
0x01        1           31372.55
0x02        8           3921.16
0x03        32          980.39
0x04        64          490.20
0x05        128         245.10
0x06        256         122.55
0x07        1024        30.64

TCCR2B = TCCR2B & 0b11111000 | <setting>;

(All frequencies are in Hz and assume a 16000000 Hz system clock.)

These are relatively simple to setup and use (the setting is at the bottom of each of the above code blocks), but you have to be mindful of playing with the pre-scaler of timer0 (which controls millis() and delay()). So if you have a choice, steer clear of timer0, or pwm pins 5 and 6.

Example of using just the inbuilt pre-scalers without any additional libraries:

#define PIN 11
void setup(){
    pinMode(PIN,OUTPUT);  // not absolutely required
    int DUTY = 20;
    TCCR2B = TCCR2B & 0b11111000 | 6;
}


void loop() {
  static long counter = 0;
  if(millis()%10==0){
      counter++;
      analogWrite(PIN, counter%255);
  }
}

I know you can manipulate the frequency better than that, and I have been playing with this for hours and then I finally stumbled upon the final link (which believe it or not, I found via YouTube!).


Using an External Library

To use the PWM library you will need to download it from Google Code, save/import/get it into your library folder, and restart the IDE. Once you do that, you can explicitly set the frequency (within limits, 333Hz is within those limits), and you should be set.

Code example:

#include <PWM.h>
int32_t frequency = 333;

#define PIN 10

void setup(){
    pinMode(PIN,OUTPUT);
    int DUTY = 20;
    InitTimersSafe();                    // won't touch timer0
    SetPinFrequencySafe(PIN,frequency);  // again, not timer0
    pwmWrite(PIN, DUTY * 256 / 100);
}

There is even a pwmWriteHR which allows for higher resolution, but that does not work with timer2 (which is only an 8-bit timer).

The matching, non-safe (ie initialises and uses timer0 as well) functions are:

InitTimer();  // and
SetPinFrequency(PIN,frequency);

The only limitation I have found so far is that it doesn't work with PWM pin D11. I have tested D3, D9 and D10 (they all worked fine), but I did not get around to testing D5 or D6.

Good luck, I hope this helps.

1

This will command a Talon SR from an Arduino. I used an Uno and had the Talon hooked up to a CIM motor & gearbox and it ran fine. I don't understand the code well enough to know if it's generating the 1-2ms PWM signal you asked about and your control resolution will definitely be limited to roughly 1% of range - all I know is that it works.

First, make sure your wiring is set up:

Black PWM wire goes to GND Red PWM wire goes to 5V (right next to GND on the Arduino) White PWM wire goes to pin 3 (or some other Arduino PWM pin)

Then try this code:

#include <Servo.h>  //This comes with the Arduino

int talon_pin = 3;

Servo talon;

/* The 'Servo.h' library allows you to control motors and servos by passing any value between
0 and 180 into the "write" method (talon.write() in this program).
For a motor:   0 is full power in one direction,
             180 is full direction in the opposite direction,
              90 is stop.
For a servo:   0 is all the way one direction,
             180 is all the way in the opposite direction,
              90 is the middle.
*/

int talon_max_forward = 180;  //this might not actually be forward
int talon_max_reverse = 00;    //this might not actually be reverse
int talon_stop = 90;          //this is definitely stop (if the Talon is calibrated right)

void setup() {  
  talon.attach(talon_pin);  //This tells the arduino to control this pin like it's a servo/motor  
}

void loop() {  
  talon.write(talon_max_forward);   //full power one way
  delay(2000);                      //wait 2 seconds
  talon.write(talon_stop);          //full power the other way
  delay(2000);                      //wait 2 seconds
  talon.write(talon_max_reverse);   //full power one way
  delay(2000);                      //wait 2 seconds
  talon.write(talon_stop);          //full power the other way
  delay(2000);                      //wait 2 seconds
}

The Talon I used was fresh out of the box and had never been calibrated before, so the "stop" didn't actually stop - it just moved slowly.

To calibrate it, use a paper clip or pen / pencil to press and release the CAL button on the Talon (next to the LED). You have to press AND release when commanded to stop (after going full + and full - in between), but the motor doesn't turn when the button is pressed. I calibrated by running the program above with the motor attached, waiting for the motor to "stop", then pressing and holding for 8 seconds. If you have trouble hitting it, increase one of the delays after a talon_stop command.

0

You'll need to edit the library file, Servo.h.

Find the line...

#define REFRESH_INTERVAL 20000 // minumim time to refresh servos in microseconds

And change the refresh interval - 20000us (20ms) is the standard 50Hz rate.

Change it to 3003 to get 333Hz rate.

This will permanently change the Servo library to 333Hz. If you need 50Hz servos, it would be best to duplicate the Servo library to Servo333 or something.

You will not be able to run both at the same time as they use the same timers.

(This is based on the standard Servo library in arduino 1.06)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.