프로젝트 형태로 avr과 3d프린터로 

리그오브레전드(lol)의 블리치크랭크를 만드는 방법을 가르쳐 드릴게요.




기능은 간단하게 만들어 보도록 할게요.



장난감의 주 모터는 서보모터입니다.





기능들을 살펴보면

1. 서보모터 2개를 양팔에 부착

2. 등쪽에 텍트스위치 3개 부착

3. 스위치 입력에 따라 팔이 움직임

이렇게 간단히 3가지입니다.


서보모터 제어는 여기를 참고 해주세요.>> pwm 서보모터 제어법


텍트스위치를 사용한 간단한 소스가 있습니다.>> atmega led switch


위 링크는 참고 정도로 봐주세요.

여기서 서보모터와 스위치에 대해서 보충 설명을 해드릴게요.

(서보모터는 링크랑 병행해서 보시길 추천합니다.)


먼저 서보모터를 제어하기 위해서는 atmega 내부에서 주파수와 펄스를 조정시켜서 주어야 하죠.

이부분을 이해하는것이 정말 어렵더라고요. 저도 책을 3권을 찾아보고 이해 했어요.

데이터 시트에서 TCCR, COM bit, CS bit, WGM 이부분을 잘 보면서 이해하면 좋습니다.


이제 TCCR에 PWM을 사용할거라고 명령을 줄거예요.



atmega8 데이터시트에서 뽑아온 사진인데요.

TCCR가 수행하는 목록입니다. 

먼저 wgm으로 mode14(fast PWM)을 해줍니다.

다음 cs을 설정해 주세요. 저는 64로 해줬어요.

그리고 com은 3번째꺼로 사용합니다.


그럼 TCCR1A은 10100010 > 0xA2

TCCR1B는 0001101 > 0x1B

로 설정 해주면 끝.



이제 ICR1값을 설정해서 서보모터에 사용할 주파수를 만듭니다.

계산법이 좀 복잡해 보여도 겁먹지말고 잘 이해해 봅시다.


16MHz / 64 / (1+4999) = 50Hz = 20ms

16MHz는 크리스탈 주파수 64는 cs설정값 4999는 ICR에 입력할 값입니다.

16MHZ에 다 나눠주면 50Hz가 됩니다. 이건 주기가 20ms죠.(역수)


서보모터의 검출주기가 20ms이므로 주기에 맞게 설정해주는게 좋아요.


이제 펄스폭을 설정할수 있도록 OCR값을 찾아야합니다.

펄스폭구하는 식은 OCR*주기/ICR=펄스폭 입니다. 

우리는 OCR값을 모르지만 90도에 해당하는 펄스폭이 2.4ms인 것을 압니다.


(1+4999) * 2.4 / 20 = 600 

  ICR 값         펄스폭   주기      OCR 값
그래서 이렇게 계산을 해보면 OCR값에 600을 넣으면 90도가 된다는걸 구할수 있어요.



이제 600을 24개의 단위로 나눠줍시다. 
600 / 24 = 25
그럼 0.1ms당 25의 값이 필요하네요. 즉 10도 움직일려면 OCR을 25를 넣어주면 됩니다.

이제 0도가 되는 OCR 값을 찾습니다.

0.6, 1.5, 2.4ms => 150, 375, 600

375가 1.5ms(0도)가 되는 값이네요.



0도가 375고 1도 움직이는데 2.5씩 조정해줘야 하는데 너무 머리아프죠.

그러니 우리가 알고있는 각도 개념으로 값을 쓸 수 있도록 수식을 만들어 줍니다. 

OCR1 = (600 - 375)*X/90 +375 = 225*X/90 +375

이 수식 이해 가시나요?
글로 풀어보면 
(OCR최대값 - OCR중간값) 을 먼저 계산하고 우리가 원하는 미지수값(각도)을 곱합니다. 그리고 최대 각도값을 나눠줍니다. [-90도 -225/1=225, -45도 -225/2=-112.5, 0도 0/90=0, 1도 225/90=2.5 , 2도 225/45=5, 45도 225/2=112.5, 90도 225/1=225] 그리고 다시 중간값(0도)인 375를 더해주면서 OCR1에는 150~600의 수치가 들어가게됩니다.


자 이렇게 필요한 수식까지 다 만들었네요.


그럼 회로를 짜고

소스를 만들어 봅시다.






회로는 아주 간단합니다. 

주의점은 atmega8이라는 거? 그리고 16MHz구동가능한 제품으로 사셔야 한다는점?





소스도 기본 if문과 switch문 으로 만들어서 쉽게 따라갈수 있을겁니다.


소스


#include <avr/io.h>

#include "./../../header/delay.h"

#define  f_cpu 16000000ul;


// 모터 수식함수

void svangle1 (float angle)  

{

OCR1A  = angle*225/90 +375 +0.5;

}

void svangle2 (float angle3)

{

OCR1B  = angle3*225/90 +375 +0.5;

}

void svangle3 (float angle1, float angle2) //2개 동시 구동

{

OCR1A  = angle1*225/90 +375 +0.5;

OCR1B  = angle2*225/90 +375 +0.5;

}



int main(void)

{

int rhand = 0, lhand = 0;  //오른팔과 왼팔

        int i=0;

unsigned char keyr = 0x00;

unsigned char keyl = 0x00;

unsigned char keyb = 0x00;

DDRD = 0x00;

DDRB = 0xFF;

PORTB = 0x00;

TCCR1A= 0xA2;

TCCR1B= 0x1B;

ICR1 = 4999;

OCR1A = 330;

OCR1B = 550;

TCNT1 = 0x00;


while (1)

{

keyr = (PIND & 0x10); //오른팔용 스위치

keyl = (PIND & 0x02); // 왼팔용 스위치

keyb = (PIND & 0x01); //양팔용 스위치

if(rhand == 0)

{

         switch (keyr){

        case (0x10): delay_ms(400); svangle1(80);  delay_ms(400); rhand = 1; break;} 

   if(lhand == 0)

    {

  switch (keyl){

         case (0x02): delay_ms(400); svangle2(-10); delay_ms(400); lhand = 1; break;}

   switch (keyb){

case (0x01): for(i=0;i<=5;i++)

{delay_ms(200); svangle3(-10, 85); delay_ms(200); svangle3(80,-10);} rhand = 0; lhand = 0; break;}

            }

   else if(lhand == 1)

   {

   switch (keyl){

case (0x02): delay_ms(400); svangle2(85); delay_ms(400); lhand = 0; break; }

   switch (keyb){

case (0x01): for(i=0;i<=5;i++)

{delay_ms(200); svangle3(80, 85); delay_ms(200); svangle3(-10, -10);} lhand = 1;  rhand = 0; break; }

   }

}

else if(rhand == 1)

{

   switch (keyr){

case (0x10): delay_ms(400); svangle1(-10); delay_ms(400); rhand = 0; break;}

if ( lhand == 1)

{

                switch (keyl){

case (0x02): delay_ms(400); svangle2(85); delay_ms(400); lhand = 0; break;}

            switch (keyb){

case (0x01): for(i=0;i<=5;i++)

{delay_ms(200); svangle3(-10, 85); delay_ms(200); svangle3(80,-10);} rhand = 0; lhand = 0; break;}

}

else if ( lhand == 0)

{

   switch (keyl){

case (0x02): delay_ms(400); svangle2(-10); delay_ms(400); lhand = 1; break;}

   switch (keyb){

case (0x01): for(i=0;i<=5;i++)

{delay_ms(200); svangle3(80, 85); delay_ms(200); svangle3(-10, -10);} lhand = 1;  rhand = 0; break;}

}

}

}

}



소스에서 모터 구동전에 딜레이를 준 것은 스위치 노이징을 피하기 위해 줬습니다.

노이징에 관해서는 다음에 따로 작성하도록 하겠습니다.^^







이제 외관을 만들고 모터를 조립하면 동영상처럼 뒤에 스위치를 누르면 구동이 됩니다.


 



Posted by 탕구이

블로그 이미지
엔지니어를 꿈꾸는 공대생
탕구이

공지사항

Yesterday
Today
Total

달력

 « |  » 2024.5
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

최근에 올라온 글

글 보관함