[30호]6족 보행 로봇 ‘벅벅이’
6족 보행 로봇 ‘벅벅이’
글 | 고려대학교 과학기술대학 제어계측공학과 류예슬
심 사 평
싱크웍스 시연동영상으로 볼때 작품의 완성도가 높았고, 학생 수준에서 구할 수 있는 재료들을 잘 사용해서 만든 것 같다. 작품을 만들면서 많은 공부가 되었을 것 같다.
JK전자 유선 조이스틱으로 조정하여 단순히 보행만 하는 기능 이외에 보행을 하면서 할 수 있는 부가적인 기능이 추가되었으면 더 좋았을 것 같다. 예를 들면 사람이 갈수 없는 곳을 탐사하여 영상을 전송하는 기능이나, 물건을 집어서 옮기는 기능 등이 된다면 조금 더 실용성이 높아질 것이다. 어쨌든 여러 사람이 아닌 혼자서 기구부 제작과 소프트웨어 개발까지 했다는 것은 쉬운 일은 아니었을 것이다. 마음이 맞는 좋은 파트너와 코웍을 하면 조금 더 실용성이 높은 작품이 나올것 같다.
뉴티씨 매우 잘만든 6족로봇 작품으로 판단된다. 다만, 빠른 이동은 좀 어려운 점이 약간 아쉽다. 미끄러움을 방지하기 위하여, 끝부분에 고무 같은 재질을 사용한 점도 좋은 점으로 착안하였다. 좀 더 잘 만든다면, 구조로봇 같은 형태로도 만들어질 수 있을 것으로 생각되며, 계단 등도 다른 작품처럼 올라갈 수 있을 것으로 생각된다. 기술적인 난이도는 매우 높지도 낮지도 않지만, 전체적인 작품의 완성도가 높은 것으로 판단되며, 기구적인 부분에서도 창의적인 아이디어로 재료 선택 등에서도 무게도 줄이고 잘 만든 것 같다. 향후, 학습하면서 좋은 작품을 만들 수 있을 것으로 기대한다.
작품 개요
■ 프로젝트 개발 동기
최근 산업 현장 외에도 일상생활에서 사람을 도와줄 수 있는 로봇의 필요성이 높아지고 있다. 이러한 요구를 충족시키기 위한 로봇에 있어 이동의 기능은 필수적인 기술이 되었다. 특히 6족 로봇은 오프로드에서도 바퀴로 이동하는 모바일로봇 또는 다른 종류의 보행 로봇보다 안정된 보행을 할 수 있다는 장점을 가졌고, 또한 전쟁, 행성탐사, 무너진 건물 속의 인명탐사 등에 활용 될 수 있다.
하드웨어 및 소프트웨어에 열정이 있는 사람들의 모임인 과 내 학술소모임 다가치(KUCIRA)에서 학술제를 목표로 보행로봇을 프로젝트로 기획하던 중, 보행 로봇에 대한 정보를 수렴한 결과 위와 같은 장점을 가진 6족 로봇이 가장 적절하다 생각되어 개발하게 되었다.
■ 프로젝트 구현 목표
· 6족 로봇의 보행 메카니즘과 구조 이해 (전진, 후진, 회전)
· Atmega 128 (MCU) 이해 및 AVR 프로그래밍 이해
· 서보모터의 이해 [fast pwm제어]
· 2축 조이스틱(가변저항)을 이용한 유선제어 [AD Convertor]
■ 제목의 의미
이 프로젝트의 가장 큰 특징은 로봇의 다리가 6개라는 점이다. 이 점을 감안하여 6개의 다리를 가진 곤충과 관련된 이름을 지어주려고 하였는데, 첫 프로젝트인 느낌을 살리기 위해 ‘bug’의 ‘벅’을 한국식으로 바꾸어 ‘벅벅이’라 이름을 붙여주게 되었다.
작품 설명
■ 주요 동작 및 특징
‘벅벅이’의 주요 동작은 보행이다. 로봇의 다리는 6개이고 각 다리 당 2개의 관절을 가진 12관절 구조이다. 몸통과 가까운 모터를 ‘위 관절’이라 하고 바닥과 가까운 모터를 ‘아래 관절’이라고 칭하면, 위 관절은 가고자 하는 방향결정에 중요한 역할을 한다. 아래 관절은 위 관절이 이동을 할 때에는 발을 바닥에서 들어주고 이동을 마친 후에는 바닥으로 발을 찍어주어 바닥의 마찰을 이용하여 이동하게 해주는 역할을 한다.
구현한 보행의 종류는 크게 세 가지이다. 전진, 후진, 좌/우로의 회전이다. 그리고 정육각형 형태의 프레임을 가졌기 때문에 앞뒤 구분이 필요하였다. 이를 위해 led를 삽입하였고 앞뒤 구분의 역할과 동시에 동작에 따라 led가 다른 알고리즘을 수행하게 하였다. 마지막으로 2축 조이스틱을 이용하여 조이스틱의 기울기(위치)에 따라 ‘벅벅이’를 제어하였다.
1. 전진/후진
위 사진처럼 다리의 번호를 1번부터 6번까지로 표현하였다. 위 관절의 모터를 먼저 얘기하면 2번과 6번, 3번, 1번과 5번, 4번 이렇게 각각의 세트를 4개의 MCU PORT에 연결하였다. 아래 관절은 2, 3, 6번 그리고 1, 4, 5번 다리가 또 다른 2개의 PORT에 연결하였다. 이렇게 연결한 이유는 6족 로봇의 보행 매카니즘과 관련이 있다. 동영상으로 시연영상을 보면 바로 파악하기는 어려우나 자세히 보면 모터의 동작 순서는 다음과 같다.
위 관절의 1번+5번 모터를 A, 4번 모터를 B, 2번+6번 모터를 C, 3번 모터를 D라 하고, 아래 관절의 1번+4번+5번 모터를 E, 2번+3번+6번 모터를 F라 하자. 정지 상태에서 위 관절의 모든 모터는 각도를 0˚부터 180˚범위에서 90˚이고, 아래 관절의 모든 모터는 40˚인 상태이다.(위 오른쪽 사진 참고) 전진을 위한 과정은 다음과 같다.
1) 먼저 전진을 위해서는 E모터를 90˚로 해준다. 이것은 먼저 이동할 다리를 움직일 수 있도록 발을 바닥에서 해체시켜주는 것이다. (모터의 RESET(정지)상태는 ABCD모터는 모두 90˚ 이고, EF모터는 모두 40˚이다.)
2) A모터는 110˚, B모터는 75˚가 동시에 되도록 한다.
3) E번 모터를 40˚로 한다. 이것은 발을 바닥으로 내려주는 역할을 한다.
4) F모터를 90˚로 하여 반대편 다리를 든다. (위 관절의 한 세트라도 방향 제어를 할 경우에는 다른 반대쪽 아래 관절의 다리는 들려있어야 한다.)
5) A모터를 70˚B모터는 110˚가 동시에 되도록 한다. 아래 관절의 모터로 인해 발이 바닥에 닿아 있는 상태이기 때문에 마찰에 의하여 로봇이 앞으로 움직이게 된다.
6) 위와 같은 원리로 C모터는 70˚, D모터는 110˚가 동시에 되도록 한다.
7) F모터를 40˚로, E모터를 90˚로 한다.
8) C모터는 110˚, D모터는 80˚가 동시에 되도록 한다. 마찬가지로 F모터로 인해 마찰에 의하여 로봇이 전진하게 된다.
위 과정의 알고리즘은 다음과 같다. 실제 코딩(모터의 분류)은 A, B, C, D, E, F가 아닌 숫자로 되어있지만 위에 그렇게 표현하였기 때문에 바꿔 첨부하였다. Motor(int x, int y)함수는 x번 모터를 y˚만큼 각도변환 시키는 함수이다. delay를 얼마만큼 주는지에 따라 보행 속도가 결정된다.
*후진은 전진과 방향만 반대일 뿐 보행 원리는 같다.
void GOBACK()
{
PORTA=0X00;
Motor(E,90); //들고(1번다리)
delay_ms(230);
Motor(A,110);
Motor(B,75); // 1번다리 회전
delay_ms(230);
Motor(E,40); //1번다리 내리고
delay_ms(230);
Motor(f,90); // 2번다리 들고
delay_ms(230);
Motor(A,70);
Motor(B, 110); //1번다리 반회전
delay_ms(230);
Motor(C,70);
Motor(D,110); // 2번다리 회전
delay_ms(230);
Motor(F,40); //2번다리 내리고
delay_ms(230);
Motor(E,90); //1번다리 들고
delay_ms(230);
Motor(C,110);
Motor(D,80); //2번다리 반회전
}
2. 좌/우 회전
좌/우 회전의 매카니즘 이해는 전진/후진보다 훨씬 쉽다. 간단하게 말하면 다리를 반으로 나누어 회전하고자하는 방향으로 회전을 시켜주면 된다. 내가 구현한 알고리즘은 회전시킬 다리의 아래 관절을 들고 그 다리를 회전시키고 나머지 반의 다리들도 앞과 같이 해주면 된다. 아래 관절을 이용해 발을 드는 동작과 위 관절을 이용해 다리를 회전시키는 동작 사이의 시간을 줄여줄수록 모션을 좀 더 부드럽게 제어할 수 있다.
아래는 실제 알고리즘이다. 중간에 들어간 read_adc()에 대한 조건문은 뒤에서 조이스틱 파트에서 설명하기로 한다.
//좌우
if(read_adc(1)>900 //오른쪽으로 회전
{
PORTA=0xf0;
Motor(1,90); //들고(1번다리)
delay_ms(100);
Motor(3,110);
Motor(4,110); //1번다리 회전
delay_ms(200);
Motor(1,40); //1번다리 내리고
delay_ms(200);
if(read_adc(1)>=300 && read_adc(1)<=700)
STOP();
else if(read_adc(1)>900)
{
Motor(2,90); // 2번다리 들고
delay_ms(100);
Motor(3,90);
Motor(4,90); //1번다리 반회전
delay_ms(200);
Motor(5,110);
Motor(6,110); // 2번다리 회전
delay_ms(100);
Motor(2,40); //2번다리 내리고
delay_ms(200);
if (read_adc(1)>=300 && read_adc(1)<=700)
STOP();
else if(read_adc(1)>900)
{
Motor(1,90); //1번다리 들고
delay_ms(100);
Motor(5,90);
Motor(6,90); //2번다리 반회전
}
3. 동작에 따른 LED
알고리즘 상의 ‘벅벅이’의 보행종류는 앞서 말했듯이 전진, 후진, 회전으로 나눠진다. 원한다면 각 동작에 다른 led제어구문을 삽입할 수 있다. 나는 로봇의 정지 상태와 동작 상태만을 구분하기 위해 정지 상태에는 8개의 LED가 방향을 바꾸어 가며 순차점등을 하도록 하였고, 동작 상태에서는 눈과 같다는 인상을 심어주기 위해 양 끝 LED만 켜지게 하였다. (이것은 ‘눈’을 연상시키게 함이다.) 실제 알고리즘은 다음과 같다.
정지상태의 LED 동작
좀 더 정확한 초 계산을 위해 타이머 normal 모드를 통해 LED를 제어하였다.
Void STOP()
{
if(i<8)
{
if(cnt1>1)
{
PORTA=~(RLED<<i);
i++;
cnt1=0;
}
}
else if(i==8)
{
if(j<8)
{
if(cnt1>1)
{
PORTA=~(LLED>>j);
j++;
cnt1=0;
}
}
else i++;
}
else
{
i=0;
j=0;
}
동작상태의 LED 동작
양 끝 LED를 계속 키고 있는 상태를 코딩하는 것은 쉽다. 내가 구성한 회로의 LED의 PORT가 아닌 쪽이 Vcc와 연결되어 있기 때문에 LED와 연결된 PORT의 출력레지스터 설정을 한 후, LOW신호를 흘려주면 그 부분의 LED는 불이 들어오게 된다.
우선 사용한 2축 조이스틱은 두 개의 가변저항으로 만들어진 컨트롤러이다. 먼저 한 축은 보행의 전진, 후진을 제어하고, 나머지 한 축은 좌/우로의 회전을 제어한다. 여기서 사용되는 AVR의 기능은 ADC라는 기능이다.
ADC란 ‘Analog Digital Convertor’라는 줄임말로 아날로그 신호를 디지털로, 혹은 디지털 신호를 아날로그 신호로 바꿔주는 기능이다. 여기서 내가 사용한 것은 아날로그 신호를 디지털 신호로 바꿔준 기능이다. 2축 조이스틱의 방향을 바꿔줄 때마다 가변저항의 값이 변한다. 이것이 바로 아날로그 신호이다. 이런 아날로그 신호를 MCU에 전달해주고 그 신호 값에 따라 코딩한 알고리즘이 구현된다. 이것이 아날로그신호가 디지털 신호로 바뀌는 과정이다. 로봇의 각 모션에 따른 알고리즘은 길기 때문에 위에서 잠깐 봤던 회전 알고리즘에서 설명을 하도록 하겠다.
ADC를 사용하기 위해서는 먼저 그것에 대한 초기 레지스터 설정을 해주어야 한다. 레지스터 설정은 Code Vision의 Wizard (사용하고자 하는 기능의 툴을 제공)을 사용하였다.
레지스터 설정은 간단하게 넘어가고, 아날로그 신호를 디지털 신호로 어떤 식으로 변환하는지에 대해서 살펴보자. 밑의 사진은 ‘좌/우 회전’ 동작에서도 봤던 알고리즘이다. 중간 중간에 read_adc(1)의 값에 따른 조건문이 삽입되어 있다. 이것이 바로 가변저항 즉, 아날로그 신호를 디지털 신호로 변환시킨 값이다.
가변저항의 값에 따라 read_adc(1)의 값이 어떻게 변하는지는 보통 통신을 통해서 정확한 값을 확인한다. 하지만 정확한 값을 받아야 하는 센서를 사용하는 것이 아니고 내가 원하는 지점에서부터 작동하기만 하면 되기 때문에 처음 테스트는 read_adc(1)의 값에 따라 LED를 통해 확인했고 그 값을 토대로 알고리즘을 작성할 수 있었다.
조이스틱을 오른쪽으로 기울였을 때 내가 원하는 위치에서의 adc값은 900이었다. 그 이상일 때 회전하는 알고리즘을 넣어주었고 다시 조이스틱이 가운데로 돌아왔을 때는 정지하는 내용도 중간 중간에 넣어 있다.
//좌우
if(read_adc(1)>900 //오른쪽으로 회전
{
PORTA=0xf0;
Motor(1,90); //들고(1번다리)
delay_ms(100);
Motor(3,110);
Motor(4,110); //1번다리 회전
delay_ms(200);
Motor(1,40); //1번다리 내리고
delay_ms(200);
if(read_adc(1)>=300 && read_adc(1)<=700)
STOP();
else if(read_adc(1)>900)
{
Motor(2,90); // 2번다리 들고
delay_ms(100);
Motor(3,90);
Motor(4,90); //1번다리 반회전
delay_ms(200);
Motor(5,110);
Motor(6,110); // 2번다리 회전
delay_ms(100);
Motor(2,40); //2번다리 내리고
delay_ms(200);
if (read_adc(1)>=300 && read_adc(1)<=700)
STOP();
else if(read_adc(1)>900)
{
Motor(1,90); //1번다리 들고
delay_ms(100);
Motor(5,90);
Motor(6,90); //2번다리 반회전
}
다른 동작들도 아래와 같은 방식의 알고리즘으로 되어있다.
■ 전체 시스템 구성
1. 6족 보행 로봇을 만들기 위한 최소 관절(모터)의 개수 파악
6족 로봇으로 보행하기 위해서는 위의 매커니즘을 이해하면 알 수 있듯이 최소 다리 당 2개 즉, 12개가 필요함을 파악했다.
2. 서보모터 각도 제어
서보모터의 각도를 제어하기 위해서는 모터구동의 원리를 이해할 필요가 있었다. 서보모터는 모터에 흘려주는 Pulse의 주기에 따라 각도가 제어된다. Pulse를 변형시켜주기 위해 타이머의 ‘Fast pwm’기능을 사용하였고, 프레임 제작 전 원하는 각도를 넣었을 때 그 각도가 되도록 하는 실습을 하였다.
3. 프레임 제작 계획
사용하기로 한 모터의 토크는 3kg.cm은 그리 좋은 스펙은 아니다. 그러나 사람들이 만든 여러 블로그를 참고하여 프레임의 무게를 최소화할 수 있다면 문제가 될 부분은 아니었다. 그리하여 가장 프레임의 재료는 100% 포맥스로 정하였다.
4. 보행 매카니즘 파악
모터의 각도제어를 실습하였고, 프레임이 완성된 후 6족 로봇의 보행 매카니즘을 파악하였다. 목표는 전진/후진/좌우로 회전이었기 때문에 제어방법을 가장 효율적으로 하고자 공통된 모터는 묶어 제어하기로 결정하였다.
5. MCU 선정 / 회로구성
MCU는 쓰고자 하는 기능들(I/O, Interrupt, ADC, Timer)을 쓸 수 있는 ‘Atmega128’을 선정하였다. 회로에서는 가장 중요한 전원부는 ‘LM2576’이라는 레귤레이터를 사용하여 구성하였다. 처음에는 ‘LM7805’로 전원부를 구성했었는데, 두 레귤레이터 모두 출력전압을 5V로 바꿔준다는 특징은 같으나 output의 전류에서 차이가 있었다. 7805는 1A까지만 전류가 흐르지만 2576은 3A까지 흐를 수 있는 스펙을 갖고 있다. 그런 이유로 전원부는 시행착오를 거쳐 다시 제작하였다. 전류 값이 중요한 이유는 모터가 병렬로 연결되어 있어 전류가 조금이라도 부족하면 작동이 되지 않기 때문이다.
6. 조이스틱의 원리이해
ADC를 이용하여 조이스틱의 방향에 따라 원하는 대로 제어하는 원리에 대하여 이해하였고 그것을 LED로 먼저 확인한 후, 모터에도 적용시켜 구현할 수 있었다.
■ 개발환경
- MCU : Atmega 128
- 개발 언어 : C
- Tool : AVR Studio 및 Code Vision AVR
단계별 제작 과정
■ 프레임 제작
1. 제작 전 구상도
2. 제작 과정
1. 재료 구매 (포맥스) | 2. 몸체 제작 (정 6각형 구조) |
3. 몸체+모터 제작 | 4. 위 관절 제작 |
5. 아래관절 제작 | 6. 발 제작 (충분한 마찰을 주기 위함) |
7. 프레임 전체 완성 |
■ 하드웨어 제어부 제작
전원부 |
모터부 |
스위치 |
LED |
■ 컨트롤러 제작
조이스틱 |
조이스틱(납땜) | 조이스틱과 모드 선택 스위치 |
■ 소스코드
모터의 각도 제어함수
I/O 레지스터 설정
Interrupt 레지스터 설정
Timer 레지스터 설정
ADC 레지스터 설정
GOSTR() 함수 : 전진
GOBACK() 함수 : 후진
STOP() 함수 : 정지