1. 서보모터
서보모터를 제어하기 위해서는 20ms의 간격으로 1~2ms 폭의 펄스(사각파)를 생성 해야 하며, 펄스의 폭에 의해서 각도가 정해집니다. 구동 범위가 0~180°인 서보모터의 경우 아래와 같이 최소값을 1.0ms 최대값을 2.0ms로 잡고 백분위를 이용해 계산하여 제어를 할 수 있습니다.
이번 프로젝트에서 사용하는 RDS5160의 경우에는 360° 구동이 가능한 모터이기 때문에 0°를 1.0ms, 그리고 360°를 2.0ms로 계산하면 됩니다.
2. 360도 서보모터 제어하기
서보모터는 Timer 3의 Fast PWM mode를 이용해 주기를 맞춰주었습니다.
[main.c]
#include "mcu_init.h"
int cnt = 0;
int adc_array[8] = {0, };
int i = 0;
float servo1 = .080;
float servo2 = .075;
int duty1, duty2;
// duty 2.5~12.5
int num1 = 0;
int num2 = 0;
char a = 13;
int flag;
int number = 0;
int sign = 0;
// UART 통신
ISR(TIMER2_OVF_vect)
{
cnt++;
TCNT0 = 131; // 4ms
a = UART1_Receive();
if(a == ',')
{
if(sign == 1) num1 = -num1;
flag = 1; sign = 0;
}
else if(a == 13)
{
if(sign == 1) num2 = -num2;
flag = 2; sign = 0;
}
if(flag == 0) Receive_num1();
else if(flag == 1) Receive_num2();
else if(flag == 2)
{
UART1_TransNum(num1);
UART1_Transmit(',');
UART1_TransNum(num2);
UART1_Transmit(13);
if((num1 >= 40) && (num1 <= 110)) servo1 = (double)num1 / 1000;
if((num1 >= 35) && (num1 <= 105)) servo2 = (double)num2 / 1000;
num1 = 0; num2 = 0; flag = 0;
}
MOTOR_Direction(servo1, servo2);
if(cnt == 25) // 100ms
cnt = 0;
}
void Receive_num1() // 첫번째 수를 입력받는다.
{
num1 *= 10;
number = a - 48;
if(a == '-') sign = 1;
if((number >= 0) && (number <= 9)) num1 += number;
}
void Receive_num2() // 두번째 수를 입력받는다.
{
num2 *= 10;
number = a - 48;
if(a == '-') sign = 1;
if((number >= 0) && (number <= 9)) num2 += number;
}
ISR(INT0_vect) // 인터럽트 0번 발생시 1번 서보모터 duty비 80%
{
servo1 = .080;
}
ISR(INT1_vect) // 인터럽트 1번 발생시 2번 서보모터 duty비 75%
{
servo2 = .075;
}
int main(void)
{
UART1_INIT();
Timer2_INIT();
BUTTON_INIT();
SERVO_MOTOR_INIT();
ADC_INIT();
sei();
while(1);
}
서보모터가 UART 통신을 통해 수신받은 값으로 잘 움직이는 것을 확인할 수 있었습니다. 그러나, 속도는 조절할 수 없다는 단점 때문에 움직임이 뚝뚝 끊겨보이는 문제가 생겼습니다.
이 문제는 다음과 같이 서보모터가 목표값에 도달할 때까지 제어주기마다 1씩 OCR값을 변화시켜주는 방법으로 해결할 수 있었습니다.
if(abs(OCR3C - (1250 * servo1)) > 1) {
if(OCR3C < (1250 * servo1)) OCR3C += 1;
else if(OCR3C > (1250 * servo1)) OCR3C -= 1;
}
if(abs(OCR3B - (1250 * servo2)) > 1) {
if(OCR3B < (1250 * servo2)) OCR3B += 1;
else if(OCR3B > (1250 * servo2)) OCR3B -= 1;
}
'BARAM 동아리 프로젝트 > 동작을 따라하는 2-DOF Robot Arm' 카테고리의 다른 글
프로젝트 기획 (0) | 2021.08.05 |
---|---|
[Hardware] 손 만들기 (0) | 2021.08.05 |
OpenPose로 좌표값 받아오기 (2) | 2021.08.05 |
완성작 (0) | 2021.08.05 |