다운로드 교육자료 문제해결 레퍼런스 구입방법

교육 자료 : C 언어 : 센서 두 개를 사용한 라인 트레이서

개요
지난 시간에는 햄스터 로봇의 바닥 센서 한 개를 사용하여 검은색 선을 따라 주행하는 방법을 알아보았습니다. 이번에는 햄스터 로봇의 바닥 센서 두 개를 사용하여 주행하는 방법을 알아보도록 하겠습니다.
첫 번째 방법
A4 용지를 준비하고 햄스터 로봇이 이동할 직선을 검은색 테이프 또는 펜으로 그립니다. 검은색 선의 폭은 양쪽 바닥 센서의 간격보다 약간 작은 정도(0.8cm)로 하는 것이 좋습니다. 미리 제작된 파일을 프린터로 인쇄해도 됩니다.

라인 트레이서 실습판 내려 받기 PDF PPT

기본적으로는 앞으로 이동하면서 햄스터 로봇의 왼쪽 바닥 센서가 검은색 선 위에 있으면 중앙으로 가기 위해 왼쪽으로 움직이고, 오른쪽 바닥 센서가 검은색 선 위에 있으면 중앙으로 가기 위해 오른쪽으로 움직이면 됩니다.

     

원리는 간단한데 이를 실제로 구현하기 위해서는 두 가지가 필요합니다.

우선 왼쪽 바닥 센서와 오른쪽 바닥 센서의 값을 관찰해 봅시다. 바닥 센서가 하얀색 종이 위에 있을 때와 검은색 선 위에 있을 때 센서 값이 어떻게 다른지 확인해 봅시다.

#include <stdio.h> // printf() 함수 때문에 필요하다.
#include "roboid.h"

int main(int argc, char *argv[]) {
    hamster_create();

    while(1) {
        printf("%d, %d\n", hamster_left_floor(), hamster_right_floor());
        wait(20); // 너무 빨리 반복하지 않도록 한다.
    }

    return 0;
}

측정된 센서 값으로부터 햄스터 로봇의 바닥 센서가 하얀색 종이 위에 있는지, 검은색 선 위에 있는지 판단하기 위해서는 크기를 비교하면 됩니다. 기준이 되는 숫자가 필요한데 앞에서 측정한 센서 값의 중간 값을 사용해 봅시다. 하얀색 종이 위에 있을 때 센서 값이 100, 검은색 선 위에 있을 때 센서 값이 0이었다면 기준이 되는 숫자는 50으로 하면 됩니다. 왼쪽 바닥 센서가 검은색 선 위에 있는 경우를 다음과 같이 표현할 수 있습니다.

hamster_left_floor() < 50

마찬가지로 오른쪽 바닥 센서가 검은색 선 위에 있는 경우를 다음과 같이 표현할 수 있습니다.

hamster_right_floor() < 50

이제 햄스터 로봇을 왼쪽 또는 오른쪽으로 움직여야 합니다. 기본적으로는 앞으로 이동하고 있기 때문에 제자리에서 회전하는 방법을 사용해 봅시다. 왼쪽으로 회전하기 위해서는 왼쪽 바퀴를 뒤로 움직이고 오른쪽 바퀴를 앞으로 움직이면 됩니다.

hamster_wheels(-30, 30);

오른쪽으로 회전하기 위해서는 왼쪽 바퀴를 앞으로 움직이고 오른쪽 바퀴를 뒤로 움직이면 됩니다.

hamster_wheels(30, -30);

둘 다 검은색 선 위에 없는 경우가 있기 때문에 왼쪽 바닥 센서가 검은색 선 위에 있는 경우와 오른쪽 바닥 센서가 검은색 선 위에 있는 경우를 모두 검사해 주어야 합니다. 앞으로 이동하면서 왼쪽 바닥 센서가 검은색 선 위에 있으면, 즉 왼쪽 바닥 센서의 값이 50보다 작으면 왼쪽으로 회전하고, 오른쪽 바닥 센서가 검은색 선 위에 있으면, 즉 오른쪽 바닥 센서의 값이 50보다 작으면 오른쪽으로 회전하도록 코드를 작성해 봅시다.

hamster_wheels(30, 30);
if(hamster_left_floor() < 50) {
    hamster_wheels(-30, 30);
} else if(hamster_right_floor() < 50) {
    hamster_wheels(30, -30);
}

이제 이 코드를 계속 반복하면 됩니다.

#include "roboid.h"

int main(int argc, char *argv[]) {
    hamster_create();

    while(1) {
        hamster_wheels(30, 30);
        if(hamster_left_floor() < 50) {
            hamster_wheels(-30, 30);
        } else if(hamster_right_floor() < 50) {
            hamster_wheels(30, -30);
        }

        wait(10); // 너무 빨리 반복하지 않도록 한다.
    }

    return 0;
}

다음 그림과 같이 햄스터 로봇의 중앙이 검은색 선 위의 중앙에 있도록 올려 놓고 작성한 코드를 실행해 봅시다.

크기를 비교하는 기준이 되는 숫자 50을 변경하면 햄스터 로봇의 동작이 어떻게 달라지는지 관찰해 봅시다.

첫 번째 방법으로 하였을 때 햄스터 로봇이 검은색 선을 따라 비교적 잘 이동하는 것처럼 보입니다. 하지만 다음 그림과 같이 중앙에서 벗어나 출발하는 경우와 약간 비스듬하게 출발하는 경우, 곡선을 주행하는 경우에는 햄스터 로봇의 움직임이 부드럽지 않습니다. 특히 90도 꺾어진 길을 주행할 때는 90도 꺾어진 부분에서 검은색 선을 잘 따라가지 못하고 선을 벗어나게 됩니다. 곡선을 따라 주행하거나 90도 꺾어진 길도 잘 달려갈 수 있어야 물건을 이곳저곳으로 운반할 수 있는 멋진 햄스터 로봇이 될 수 있습니다.

두 번째 방법
첫 번째 방법에서 햄스터 로봇의 움직임이 부드럽지 않은 이유는 왼쪽 바닥 센서 또는 오른쪽 바닥 센서의 위치에 관계 없이 일정한 속도로 움직이기 때문입니다. 중앙의 검은색 선을 약간 벗어났을 때는 조금만 움직여도 되지 않을까요?

검은색 선을 따라 주행하는 원리는 같습니다. 다른 점은 왼쪽 바닥 센서와 오른쪽 바닥 센서의 값에 따라 왼쪽 바퀴와 오른쪽 바퀴의 속도를 변경한다는 것입니다. 규칙을 한번 생각해 봅시다.

이를 왼쪽 바퀴와 오른쪽 바퀴의 관점에서 정리하면 다음과 같습니다.

즉, 왼쪽 바퀴의 속도는 왼쪽 바닥 센서의 값과 정비례 관계를 가지고, 오른쪽 바퀴의 속도는 오른쪽 바닥 센서의 값과 정비례 관계를 가집니다. 바닥 센서의 값은 0 ~ 100의 범위이고 바퀴의 속도는 -100 ~ 100의 범위인데, 앞으로 이동해야 하기 때문에 바퀴의 속도도 0 ~ 100의 범위가 되도록 해야 합니다. 이를 수식으로 표현하면 다음과 같습니다.

햄스터 로봇의 속도가 너무 빠르면 곡선을 주행하거나 90도 꺾어진 길에서 급하게 회전하기가 어려워지기 때문에 최대 속도가 50이 되도록 0.5를 곱하여 다음과 같이 코드를 작성해 봅시다.

#include "roboid.h"

int main(int argc, char *argv[]) {
    double left_speed, right_speed;

    hamster_create();

    while(1) {
        left_speed = hamster_left_floor() * 0.5;
        right_speed = hamster_right_floor() * 0.5;
        hamster_wheels(left_speed, right_speed);

        wait(10); // 너무 빨리 반복하지 않도록 한다.
    }

    return 0;
}

어떤가요? 우선 직선을 주행해 보도록 합시다. 중앙에서 벗어나 출발하는 경우와 약간 비스듬하게 출발하는 경우, 곡선을 주행하는 경우 모두 실험해 보고 햄스터 로봇의 움직임이 어떻게 달라졌는지 확인해 보도록 합시다. 곱한 숫자 0.5를 변경하면 햄스터 로봇의 움직임이 어떻게 달라지는지도 살펴 보도록 합시다.

90도 꺾어진 길을 주행할 때는 어떻게 되는지 실험해 봅시다. 여전히 90도 꺽어진 길은 힘겨운가 봅니다. 더 큰 문제는 90도 꺾어진 부분에서 회전하다가 양쪽 바닥 센서 모두 검은색 선 위에 올라갈 수 있다는 것입니다. 이 코드에서 바퀴의 속도는 바닥 센서의 값과 정비례 관계를 가지기 때문에 양쪽 바닥 센서의 값이 모두 아주 작은 값이 되면 햄스터 로봇이 정지하게 될 수도 있습니다. 또한, 검은색 선의 폭이 양쪽 센서의 간격보다 넓은 경우에는 마찬가지로 양쪽 바닥 센서의 값이 모두 아주 작은 값이 되어서 햄스터 로봇이 움직이지 않을 수 있습니다. 다른 방법을 생각해 보아야겠습니다.
세 번째 방법
다시 원점으로 돌아가서 아래 그림을 보고 다르게 생각해 봅시다. 기본적으로는 앞으로 이동하면서 햄스터 로봇의 왼쪽 바닥 센서가 검은색 선 위에 있으면 중앙으로 가기 위해 왼쪽으로 움직이고, 오른쪽 바닥 센서가 검은색 선 위에 있으면 중앙으로 가기 위해 오른쪽으로 움직이면 됩니다.
그런데 왜 바닥 센서가 검은색 선 위에 있다는 것을 기준이 되는 숫자와 크기를 비교하여 판단할까요? 바닥 센서의 값이 50보다 작으면 검은색 선 위에 있다고 판단할 필요가 있을까요?
아래 그림을 자세히 살펴보면 햄스터 로봇이 중앙에서 오른쪽에 있는 경우에는 오른쪽 바닥 센서의 값이 왼쪽 바닥 센서의 값보다 커지게 됩니다. 반대로 햄스터 로봇이 중앙에서 왼쪽에 있는 경우에는 왼쪽 바닥 센서의 값이 오른쪽 바닥 센서의 값보다 커지게 됩니다. 즉, 기준이 되는 숫자를 사용하지 않고 왼쪽 바닥 센서 값과 오른쪽 바닥 센서 값의 크기를 비교하면 됩니다.

     

첫 번째 방법의 코드를 약간 수정해 봅시다.

#include "roboid.h"

int main(int argc, char *argv[]) {
    int left_floor, right_floor;

    hamster_create();

    while(1) {
        left_floor = hamster_left_floor();
        right_floor = hamster_right_floor();
        hamster_wheels(30, 30);
        if(left_floor < right_floor) { // 중앙에서 오른쪽에 있으면 왼쪽으로 회전한다.
            hamster_wheels(-30, 30);
        } else if(left_floor > right_floor) { // 중앙에서 왼쪽에 있으면 오른쪽으로 회전한다.
            hamster_wheels(30, -30);
        }

        wait(10); // 너무 빨리 반복하지 않도록 한다.
    }

    return 0;
}

조금 더 수정하면 다음과 같이 됩니다.

#include "roboid.h"

int main(int argc, char *argv[]) {
    int diff;

    hamster_create();

    while(1) {
        diff = hamster_left_floor() - hamster_right_floor();
        hamster_wheels(30, 30);
        if(diff < 0) { // 중앙에서 오른쪽에 있으면 왼쪽으로 회전한다.
            hamster_wheels(-30, 30);
        } else if(diff > 0) { // 중앙에서 왼쪽에 있으면 오른쪽으로 회전한다.
            hamster_wheels(30, -30);
        }

        wait(10); // 너무 빨리 반복하지 않도록 한다.
    }

    return 0;
}

왼쪽 바닥 센서 값과 오른쪽 바닥 센서 값의 차이인 diff가 음수이면 햄스터 로봇이 중앙에서 오른쪽에 있고, 양수이면 왼쪽에 있다고 할 수 있습니다. 이제 햄스터 로봇의 위치에 따라 바퀴의 속도를 다르게 해봅시다. 규칙은 다음과 같습니다.

왼쪽 바퀴와 오른쪽 바퀴의 관점에서 정리하면 다음과 같습니다.

이를 수식으로 표현하면 다음과 같습니다.

햄스터 로봇이 앞으로 이동하는 것은 우리가 자동차를 운전할 때 가속 폐달을 밟는 것과 같고, diff 값에 따라 왼쪽, 오른쪽으로 회전하는 것은 자동차의 운전대를 돌리는 것과 같습니다. 이 두 가지를 결합하면 왼쪽 바퀴의 속도와 오른쪽 바퀴의 속도는 다음과 같이 됩니다.

여기서 고민이 한 가지 있습니다. 가속 폐달과 운전대, 두 가지를 어느 정도 비율로 결합해야 할까요? 가속 폐달 값은 30으로 유지한다고 했을 때 운전대를 얼마나 빨리 돌려야 할까요? 햄스터 로봇이 길에서 조금 벗어났다고 해서 운전대를 너무 빨리 돌리면 좌우로 왔다갔다 불안정하게 움직일 것 같습니다. 그렇다고 운전대를 너무 천천히 돌리면 90도 꺾어진 길에서 빠르게 회전하지 못할 것 같습니다. 적절한 값이 필요한데 우선 0.4로 해보도록 하겠습니다.

코드로 작성하면 다음과 같이 됩니다.

#include "roboid.h"

int main(int argc, char *argv[]) {
    int diff;

    hamster_create();

    while(1) {
        diff = hamster_left_floor() - hamster_right_floor();
        hamster_wheels(30 + diff * 0.4, 30 - diff * 0.4);

        wait(10); // 너무 빨리 반복하지 않도록 한다.
    }

    return 0;
}

90도 꺾어진 길을 잘 따라가는지 실험을 통해 확인해 보도록 합시다. 90도 꺾어진 부분에서 회전을 잘 하지 못하면 0.4의 값을 조금 더 크게 하고, 직선을 주행할 때 좌우로 왔다갔다 하면 0.4의 값을 조금 더 작게 하면 됩니다. 곱하는 숫자 0.4를 변경하면서 햄스터 로봇의 움직임이 어떻게 달라지는지 살펴 보도록 합시다.
정지선 지키기
다음 그림과 같이 검은색 선의 마지막에 정지선을 그리고, 햄스터 로봇이 검은색 선을 따라 주행하다가 정지선을 만나면 정지하도록 해봅시다.

라인 트레이서 실습판 내려 받기 PDF PPT

검은색 선을 따라 주행하는 방법은 앞서 설명한 것과 같고, 정지선을 감지하여 정지하는 것만 추가하면 됩니다. 햄스터 로봇이 정지선을 만나면 양쪽 바닥 센서가 모두 검은색 선 위에 있게 되므로, 양쪽 바닥 센서의 값이 모두 50보다 작으면 정지선 위에 있는 것으로 판단할 수 있습니다. 하지만 90도 꺾이는 부분에서 순간적으로 양쪽 바닥 센서가 모두 검은색 선 위에 올라갈 수도 있기 때문에, 양쪽 바닥 센서의 값이 모두 50보다 작다고 해서 무조건 정지하면 90도 꺾이는 부분을 따라 돌다가 햄스터 로봇이 정지할 수도 있습니다.

정지선 근처에 햄스터 로봇을 올려 놓고 정지선을 지나 갈 때 양쪽 바닥 센서가 모두 50보다 작은 상태를 얼마나 오래 동안 유지하는지 세어 봅시다.

#include <stdio.h> // printf() 함수 때문에 필요하다.
#include "roboid.h"

int main(int argc, char *argv[]) {
    int left_floor, right_floor, diff;
    int count = 0;

    hamster_create();

    while(1) {
        left_floor = hamster_left_floor();
        right_floor = hamster_right_floor();

        if(left_floor < 50 && right_floor < 50) { // 정지선 위에 있으면
            ++ count;
            printf("%d\n", count);
        } else { // 정지선이 아닌 경우 카운트를 0으로 초기화한다.
            count = 0;
        }

        diff = left_floor - right_floor;
        hamster_wheels(30 + diff * 0.4, 30 - diff * 0.4);

        wait(10); // 너무 빨리 반복하지 않도록 한다.
    }

    return 0;
}

햄스터 로봇이 주행하는 속도에 따라 다를 수 있는데 실험 결과 12로 측정되었다고 하면 2로 나누어 6을 기준으로 정지선을 판단하도록 합시다. 이제 정지선으로 판단되면 햄스터 로봇을 정지하고 break문으로 무한 반복문을 빠져 나와 실행을 종료하면 됩니다. 햄스터 로봇을 다시 출발 지점에 올려 놓고 실행해 봅시다.

#include "roboid.h"

int main(int argc, char *argv[]) {
    int left_floor, right_floor, diff;
    int count = 0;

    hamster_create();

    while(1) {
        left_floor = hamster_left_floor();
        right_floor = hamster_right_floor();

        if(left_floor < 50 && right_floor < 50) { // 정지선 위에 있으면
            ++ count;
        } else { // 정지선이 아닌 경우 카운트를 0으로 초기화한다.
            count = 0;
        }

        if(count > 6) {
            hamster_stop();
            break;
        } else {
            diff = left_floor - right_floor;
            hamster_wheels(30 + diff * 0.4, 30 - diff * 0.4);
        }

        wait(10); // 너무 빨리 반복하지 않도록 한다.
    }

    dispose_all(); // 통신 연결을 종료하고 메모리를 해제한다.

    return 0;
}
브레이튼버그의 로봇으로 라인 트레이서 만들기
브레이튼버그의 로봇 중에서 내성적인 로봇을 약간 수정하면 라인 트레이서를 만들 수 있습니다.

라인 트레이서 실습판 내려 받기 PDF PPT

먼저 근접 센서를 바닥 센서로 바꾸도록 합시다. 바닥 센서의 값은 하얀색 종이 위에서 100에 가까운 값이므로 바퀴의 속도가 너무 빠르게 됩니다. 속도를 3으로 나누도록 합시다.

#include "roboid.h"

int denoise(int value) {
    return (value < 10) ? 0 : value; // 값이 작으면 무시한다.
}

int main(int argc, char *argv[]) {
    int left_speed, right_speed;

    hamster_create();

    while(1) {
        // 왼쪽 바닥 센서 값으로 왼쪽 바퀴의 속도를, 오른쪽 바닥 센서 값으로 오른쪽 바퀴의 속도를 설정한다.
        left_speed = denoise(hamster_left_floor()) / 3;
        right_speed = denoise(hamster_right_floor()) / 3;

        hamster_wheels(left_speed, right_speed);

        wait(10); // 너무 빨리 반복하지 않도록 한다.
    }

    return 0;
}

햄스터 로봇의 중앙이 검은색 선 위의 중앙에 있도록 올려 놓고 작성한 코드를 실행해 봅시다. 라인 트레이서가 가능한 이유를 생각해 봅시다.
목차
수업 준비
  1. 하드웨어 살펴보기
  2. 햄스터 · 햄스터S · USB 동글 PDF · PPT
  3. 소프트웨어 설치
  4. PDF · PPT
  5. 로봇과 컴퓨터 연결
  6. PDF · PPT
  7. 예제 프로젝트 실행
  8. PDF · PPT
기초
  1. 새 프로젝트 만들기
  2. 클라우드 컴퓨터 환경에서 작업하기 (선택 사항)
  3. 말판 이동하기 #1 (순차, 횟수 반복)
  4. 이동하고 회전하기
  5. LED 켜고 소리 내기
  6. 순서대로, 반복하여 명령하기
  7. 키보드 이벤트
  8. 근접 센서 사용하기
  9. 말판 이동하기 #2 (~인 동안 반복)
  10. 바닥 센서 사용하기
  11. 밝기 센서와 가속도 센서 사용하기
  12. 브레이튼버그의 로봇
심화
  1. 보드 게임 만들기
  2. 센서 한 개를 사용한 라인 트레이서
  3. 센서 두 개를 사용한 라인 트레이서
  4. 햄스터 친구 따라가기 (2인 1조)
  5. 여러 대의 햄스터 로봇 제어하기 (선택 사항)
  6. 벽 따라가기
  7. 로봇 청소기 흉내 내기
  8. 라인 트레이서 교차로 주행하기
  9. 미로 탈출
확장 키트
  1. 조립하기
  2. 핀/소켓 배치 살펴보기
  3. 디지털 입력 - 버튼을 누르면 삐 소리가 나요
  4. 디지털 출력 - 어두우면 LED 불이 켜져요
  5. 디지털 출력 - 반짝반짝 LED를 깜박여요
  6. 디지털 출력 - 기울이는 방향으로 LED가 켜져요
  7. 아날로그 입력 - 포텐셔미터를 돌리면 음 높이가 달라져요
  8. 아날로그 입력 - 뜨겁지 않게 해주세요
  9. 아날로그 입력 - 빛을 따라 움직여요
  10. PWM 출력 - LED 불이 부드럽게 밝아졌다 어두워져요
  11. PWM 출력 - LED 촛불이 바람에 흔들려요
  12. 아날로그 서보 출력 - 햄스터 로봇에게 꼬리가 생겼어요
고급
  1. 행위 기반의 로봇 제어
  2. 경로 탐색
  3. 자리 바꾸기
Copyright 로봇SW교육원 All rights reserved.
어려운 일이 있으면 광운대학교 로봇학부 박광현 교수(akaii@kw.ac.kr)에게 연락하세요.