Pages: [1]   Go Down
Author Topic: Better ways of interfacing Servos  (Read 1372 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi folks,

i'm trying to implement servos in one of my projects - however pretty much
every bit of code I came up with uses the delay or delayMicroseconds function -
and thus stops execution of the main program for the time the signal is generated.

The other option i went after was using PWM with analogOut - however the only
usable PWM-frequency for driving servos would be 8ms (via CPU clock divider),
which leaves a mere 64 possible servo positions (8ms = 256 => 2ms (servo pulsewidth) = 256/4 = 64).

So my questions are:

-How can i set the frquency of the PWM output more accurately
 (say 50hz for servo applications)?
-How can i set the resolution of the PWM to 10 or probably 12 bits?
-Are there any better ways/ ideas how to drive servos without interrupting
 the execution of the main program for a longer period of time?

Thanks for your upcoming ideas smiley-wink

Moe
Logged

Forum Administrator
Cambridge, MA
Offline Offline
Faraday Member
*****
Karma: 12
Posts: 3538
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

A method for setting the PWM frequency is definitely on the list of priorities (and getting higher all the time).  In the meantime, doing this will require some low-level hacking.  See the timer sections in the datasheet for the ATmega8 (or ATmega168).
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for your hints, Mellis.

After some hours of diggin' in datasheets and webpages i finally came up with a solution that works:
(hope it's of any interest)

Quote
/* ServoPWM
 * ---------------
 *
 * Comments
 *
 * (copyright notice) 2007 by Moe
 * <http://youraddress.here>
 * <mailto:you@youraddress.here>
 *
 */

int val = 0;

void setup(void) {
  pinMode(9,OUTPUT);  // Servo Pin
  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 = 0x0FA0;      // Upper Timer Limit = 4000 (in hex) equals 4ms => 1/5 of servo frequency

}

void loop(void) {
  val = analogRead(0);      // read potentiometer
  val = (val * 1.76) + 600; // convert potentiometer reading to value in microseconds (my servo responds to signals in the 600us - 2400us range)
  analogWrite(9,val);       // pulse servo
  Serial.println(val);      // output servo value

}

what it does:

- it initializes the PWM timer so its frequency is 4ms - 1/5 of the servo's frequency of 20ms
  (as all of the servo's signals fall in between the 0.5ms - 2.5ms range).
- analogWrite now takes values from 0 to 4000 (for us = 0.001ms)

EDIT:

it currently only works on pins 9 and 10 as Timer1 only drives these two.

best regards,
Moe
« Last Edit: February 01, 2007, 05:02:17 pm by Moe » Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 15
I love YaBB 1G - SP1!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

This is very interesting.... my question follows on nicely....

I am using IR recievers and emitters. The recievers (vishay tsop 4838) accept a carrier frequency of 38khz. If there is an ability to change the frequency of PWM in Arduino I was hoping to pulse my IR emitters (leds) at 38khz using analogWrite.... does this sound sensible?.... if so could anyone give some ideas on how to change the PWM freq to 38khz? I am quite new to all this! :-[

If this doesnt sound sensible what is a better way of pulsing the leds? I have started a new topic for this question elsewhere...

Thanks! smiley
Logged

0
Offline Offline
Full Member
***
Karma: 1
Posts: 223
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

This is really great to know. I'm using the delay method to control three servos with no problems with accuracy or code stopping, at least for my robot, but this is a much better solution.

Is there something special about pin 11?

-Z-
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 6
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Thanks for your hints, Mellis.

After some hours of diggin' in datasheets and webpages i finally came up with a solution that works:
(hope it's of any interest)

Quote
/* ServoPWM
 * ---------------
 *
 * Comments
 *
 * (copyright notice) 2007 by Moe
 * <http://youraddress.here>
 * <mailto:you@youraddress.here>
 *
 */

int val = 0;

void setup(void) {
  pinMode(9,OUTPUT);  // Servo Pin
  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 = 0x0FA0;      // Upper Timer Limit = 4000 (in hex) equals 4ms => 1/5 of servo frequency

}

void loop(void) {
  val = analogRead(0);      // read potentiometer
  val = (val * 1.76) + 600; // convert potentiometer reading to value in microseconds (my servo responds to signals in the 600us - 2400us range)
  analogWrite(9,val);       // pulse servo
  Serial.println(val);      // output servo value

}

what it does:

- it initializes the PWM timer so its frequency is 4ms - 1/5 of the servo's frequency of 20ms
  (as all of the servo's signals fall in between the 0.5ms - 2.5ms range).
- analogWrite now takes values from 0 to 4000 (for us = 0.001ms)

EDIT:

it currently only works on pins 9 and 10 as Timer1 only drives these two.

best regards,
Moe

Very interesting code. Thanks.

One question though. I thought that you were only supposed to give the servo pulse every 20 - 30ms. If i'm reading the code correctly, it will just give one pulse right after another.

I probably just need to go read up on timers...
Logged

Pages: [1]   Go Up
Jump to: