Creating your own PWM to control a servo.

Huy guys, I just got a package from Hobby King with servo's and they are HEXTRONIC HXT500 5gr minis'.

Iv'e tested them out with the Servo Library and they worked Perfetto! However i bought such little ones (they almost fit on your thumb!) for a special purpose. I want to make a light weight and little insect robot. If i want to build it and make it light then I have no option but remove the Arduino Uno from the project and use it only for prototyping. Instead, the robot's brain will be a Attiny 85.

The Attiny has a problem however, it doesn't support the Servo library for the Arduino. I know that there are Servo libraries for little Attinie's but I prefer to do the code by myself.

I wrote a code to control my servo by pulsing a pulse of between 1ms and 2ms and then a stop period of 19- 18ms (20 - 1 = 19 ms; 20 - 2 = 18 ms). The standard stop period is 20ms, which is 50HZ exactly suitable for the servo's. But the servo just sits still when i upload my sketch to my Arduino Uno. :frowning:

I have no idea how to alter the PWM signal from 500HZ (default) to 50HZ, so instead i decided to do it with the help of digitalWrite() and delay() functions.

Please suggest me how to create a suitable PWM signal for controlling a servo.

Here is the code:

int servo = 14;
 
void setup() { 
  
  pinMode(servo, OUTPUT); //OUTPUT setup
  
  for ( int i = 0; i > 5; i++){ // Set the possition to 90 degrees
   digitalWrite(servo, HIGH);
    delayMicroseconds(1500);
    digitalWrite(servo, LOW);
  }
  delay(2000);
} 
 
 
void loop() {
  for ( int i = 0; i > 50; i++){
    digitalWrite(servo, HIGH);
    delayMicroseconds(1000); // Set the possition to 0 degrees
    digitalWrite(servo, LOW);
    delay(19); 
  }
  for ( int i = 0; i > 50; i++){
    digitalWrite(servo, HIGH);
    delayMicroseconds(2000); //Set the possition to 180 degrees
    digitalWrite(servo, LOW);
    delay(18); 
  }
}

Thank you guys.

Untitled-165.jpg

Untitled-159.jpg

? int servo = 14;

Have not looked at the pin def's for the tiny85 which is a 8 pin device but pin 14 sounds wrong.

I don't think he 50Hz rate is a requirement, particularly not a lower limit. I'd try just sending a pulse to each servo each time through loop(). If your servos don't like that you could use the BlinkWithoutDelay example to send pulses only every 20 ms.

for ( int i = 0; i > 5; i++){ // Set the possition to 90 degrees
digitalWrite(servo, HIGH);
delayMicroseconds(1500);
digitalWrite(servo, LOW);
}

this loop has no delay after digitalWrite(servo, LOW); so it is effectively a high for 7.5 ms ?

Are you familiar with the blink without delay sketch?
It is a way to do timing more precise and it removes the blocking delays.
You need several extra variables to hold state.

Hi,
If you decide to follow this approach, for each servo that you add, you will use up 10% of your processing power, it also means that you will not be able to respond to inputs while your timing code is running. For a small robot that moves slowly and has few sensors to respond to, it should be fine, but its worth mentioning these limitations.

Duane B

rcarduino.blogspot.com

There is this servo library made specific for the Attiny 45/85

http://www.cunningturtle.com/servo8bit-library-version-0-6-released/

Thank you for your responses guys! there were many helpful ones! :))

I succeded to control a servo on an attiny 84 and attiny 85 with the following code

//Tested on attiny 84 with servo towerpro microservo 90 SG90
// 08/jan/2014 servo data on www.servodatabase.com
int servoPin = 6; // servo connected to digital pin 6

void setup()
{
pinMode(servoPin, OUTPUT); // sets the servoPin to be an output
}

void loop() // run over and over again
{
servowrite(servoPin, 0, 500, 2400);
servowrite(servoPin, 90, 500, 2400);
servowrite(servoPin, 180, 500, 2400);
// servotest();
}

void servowrite(int pin, int angle, int microzero, int micro180)
{
// pin for servo, angle to move, microseconds for zero degrees, microseconds for 180 degrees
int microvalue= map(angle, 0, 180, microzero, micro180); //map angle to microseconds
int i;
for (i = 0; i < 50; i++) //Send 50 pwm pulses with width microvalue uS
{
analogWrite(servoPin,255); //Pulse high for microvalue uS
delayMicroseconds(microvalue);
analogWrite(servoPin,0); //Pulse low for 15mS
delay(15);
}
delay(10); //Pause
}

void servotest()
// test servo
{
int i;

for (i = 0; i < 50; i++) //Send 50 pulses with width 500 uS
{
analogWrite(servoPin,255); //Pulse high for 500uS
delayMicroseconds(500);
analogWrite(servoPin,0); //Pulse low for 15mS
delay(15);
}
delay(100); //Pause for 100mS

for (i = 0; i < 50; i++) //Send 50 pulses with width 1.25mS
{
analogWrite(servoPin,255);
//Pulse high for 1.4 mS
delayMicroseconds(1400);
analogWrite(servoPin,0);
delay(15);
}
delay(100);

for (i = 0; i < 50; i++) //Send 50 pulses with width 2.4ms
{
analogWrite(servoPin,255);
delayMicroseconds(2400);
analogWrite(servoPin,0);
delay(15);
}
delay(100);

}

1 Like