Week 11 - output device

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 = (1100) = 0.01 or 1%

anyway,

back to the servo motor: servo signal

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:

  1. GND
  2. Power
  3. Signal

to download the design file click on the link

the servo was connected to the board .. and only programming is left: servo connected to IO board

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

servo

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 ..