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);
}

터미널을 통해 두 모터의 duty값 전송

 서보모터가 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

+ Recent posts