this post show the work of how to control servo motor ..
first to describe how to control servo motor (the small modules) .. you have to produce a signal for them ..
first lets describe the PWM signal briefly
PWM:
the signal is called (PWM)Pulse width Modulated
which means that the pulse has variation in its width
- Ton is the time for the high pulse
- Toff is the time for the low pulse
- duty cycle is the percent of Ton to pulse width (Ton+Toff)
so 1ms Ton 99ms Toff would make the following: Ton = 1ms Toff = 99ms period = 100ms Frequency= 1/(1*10^-3) = 10Hz Duty cycle = (1⁄100) = 0.01 or 1%
anyway,
back to the servo motor:as you can see from the photo… the signal is 20ms width which means the frequency is (1/(20*10^-3)) = 50Hz
to generate this signal im going to use Attiny44 microcontroller, using the knowledge that i learned from previous weeks. i’ve designed this circuit:
pcb design
as you can see, the circuit contains servo pads which are designed to match common servo connectors:
- GND
- Power
- Signal
to download the design file click on the link
the servo was connected to the board .. and only programming is left:
programming:
i wrote the code from scratch, an ideal code would be using PWM from the microcontroller instead of using delay function which will hang the CPU in a waiting loop. however, this is also simple code that is demostrating the porpose of controlling a servo through its control signal.
/*
this code is used to demonstrate how to use servo motor and it just (blinks the servo)...
this code is written for Attiny44 and im using IO_board v1.0
*/
#define F_CPU 20000000UL
#include <avr/io.h>
#include <util/delay.h>
//Servo is connected to PA7 in IO_board v1.0
//led to PB2 in IO_board v1.0
#define seton(port,pin) port|= 1 << pin
#define setoff(port,pin) port&= !( 1<<pin )
volatile static uint8_t x = 1;
int main(void)
{
//port direction
DDRA = 1<< PA7; //servo pin
DDRB |= 1<<PB2; //led
seton(PORTB,PB2);
while(1)
{
for ( i= 0 ; i < 100; i++)
{ //1ms on - 19ms off
seton(PORTA, PA7);
_delay_us(1000);
setoff(PORTA, PA7);
_delay_us(1000);
_delay_us(18000);
}
for ( i= 0 ; i < 100; i++)
{ // 2ms on - 18 ms off
seton(PORTA, PA7);
_delay_us(2000);
setoff(PORTA, PA7);
_delay_us(18000);
}
}
}
so i compiled the code:
avr-gcc -Wall -g -Os -DF_CPU=$F_CPU -mmcu=$MMCU -o main.bin main.c
avr-objcopy -O ihex main.bin main.hex
flash it:
avrdude -F -p t44 -P usb -c avrisp2 -U flash:w:main.hex
avrdude -F -p t44 -P usb -c avrisp2 -U lfuse:w:0x5E:m
and run it .. the result:
well, wait ? its shaking ..
if you notice im zooming into the board to show that the led is blinking which means the
microcontroller is reseting …
so to solve that i just decided to bring a capacitor to the servo motor
because its taking power and it reset the mcu (BOD is not enabled in the fuses btw)
…
so i place a capacitor
and run it:
the result:
still shaking..
so there is a problem,
i decided to go for a blink code just to check the timing .. with the fuse settings there was a problem ..
but fuses are correct !!
so there is somthing wrong .. i decided to add one code for the clock Prescaler
..
i didnt know whats the default value of it ..
however, by changing the prescaler, we can see that the problem is fixed
final code:
/*
this code is used to demonstrate how to use servo motor and it just (blinks the servo)...
this code is written for Attiny44 and im using IO_board v1.0
*/
#define F_CPU 20000000UL
#include <avr/io.h>
#include <util/delay.h>
//Servo is connected to PA7 in IO_board v1.0
//led to PB2 in IO_board v1.0
#define seton(port,pin) port|= 1 << pin
#define setoff(port,pin) port&= !( 1<<pin )
volatile static uint8_t x = 1;
int main(void)
{
// CLOCK prescaler to /1
CLKPR = (1 << CLKPCE);
CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0);
//port direction
DDRA = 1<< PA7; //servo pin
DDRB |= 1<<PB2; //led
seton(PORTB,PB2);
while(1)
{
for ( i= 0 ; i < 100; i++)
{ //1ms on - 19ms off
seton(PORTA, PA7);
_delay_us(1000);
setoff(PORTA, PA7);
_delay_us(1000);
_delay_us(18000);
}
for ( i= 0 ; i < 100; i++)
{ // 2ms on - 18 ms off
seton(PORTA, PA7);
_delay_us(2000);
setoff(PORTA, PA7);
_delay_us(18000);
}
}
}
and finally its working:
Note: the capacitor is not required, i removed it ..