Skip to content
isdnetworks
Go back

색 넷을 가르는 기준

leJOS 로 로봇이 폐쇄된 공간을 돌면서 구역을 구분하는 과제다. 구역이 넷이고 바닥 색이 다르며 ColorSensor 하나로 가려야 한다.

Table of contents

Open Table of contents

값이 조명에 따라 흔들렸다

I2CSensor 를 물려받은 이 클래스에는 getColorNumber() 가 있어서 0에서 17까지의 색 번호를 바로 준다. 그걸 먼저 써 봤는데 같은 바닥에서 번호가 왔다 갔다 했다. 센서가 어떤 기준으로 가르는지는 안에 있어서 손댈 수가 없다. 그래서 getRed()getGreen()getBlue() 로 원시 값을 받아 직접 가르기로 했다.

같은 바닥에서 여러 번 읽어 봤다. 빨강 성분이 198, 205, 187, 210, 193으로 나온다. 읽을 때마다 다르다. 위치를 바꿔 가며 재 보니 창가에서는 값이 크고 구석에서는 작았다. 같은 바닥인데 주변 밝기가 조금만 달라져도 값이 움직인다.

처음에는 getRed() 가 200을 넘으면 빨강으로 보려고 했는데 이 방식은 밝기가 바뀌면 그대로 틀린다. 대신 세 값의 비율을 보기로 했다. 빨강 바닥은 R이 크고 G와 B가 작고, 파랑 바닥은 B가 크다. 밝기가 변하면 셋이 같이 커지거나 작아지므로 비율은 덜 흔들린다.

그래도 노랑과 흰색은 헷갈렸다. 노랑은 getRed()getGreen() 이 크고 getBlue() 가 작은데 흰색은 셋 다 크다. B만 보면 갈리기는 하는데 그 차이가 작았다.

여러 번 읽고 멈춰서 판단했다

한 번 읽고 판단하는 대신 다섯 번 읽어 평균을 냈다. 흔들림은 줄었는데 판단이 느려졌다. 로봇이 움직이는 중이면 다섯 번 읽는 사이에 구역을 지나가 버린다.

그래서 구역 경계에서 잠깐 멈추고 읽게 했다. 직진하다가 경계를 감지하면 정지하고 읽어서 판단한 다음 다시 움직인다. 그러니 경계를 어떻게 아느냐가 다음 문제가 됐다.

값이 갑자기 바뀌는 순간이 경계였다. Math.abs 로 직전 값과의 차이를 재서 일정 이상이면 경계로 봤다.

if (abs(now - prev) > THRESHOLD) { 경계 }

얼마나 바뀌면 경계인지는 정해야 했다. 낮게 잡으면 흔들림까지 경계로 잡고 높게 잡으면 진짜 경계를 놓친다. 여러 값으로 돌려 보고 정했다.

시나리오를 먼저 정했다

값을 조정하기 전에 로봇이 어떻게 돌지를 먼저 적었다. 시작 지점에서 출발해 직진하다가 경계를 만나면 정지하고, 색을 판단해서 그 색에 정해진 방향으로 회전한 뒤 반복한다. 다섯 단계다.

시나리오가 있으니 무엇을 만들지가 정해졌다. 직진과 정지와 색 판단과 회전 넷이다. 값부터 조정했으면 그게 얼마나 정확해야 하는지를 모르고 조정했을 것 같다.

여기서 하나가 크게 달라졌다. 모든 색을 정확히 알아낼 필요가 없다. 후보가 넷이면 그중 가장 가까운 것을 고르면 된다.

가장 가까운 기준값 고르기

각 색의 기준값을 ColorSensor 로 미리 재 두고 읽은 값과의 거리를 비교했다.

int best = -1; double min = MAX;
for (int i = 0; i < 4; i++) {
    double d = distance(read, ref[i]);
    if (d < min) { min = d; best = i; }
}

이 방식은 틀려도 넷 중 하나가 나온다. 임계로 가르면 아무것도 안 걸릴 때 모름으로 멈추는데, 거리로 고르면 항상 하나가 나와서 멈추지 않는다. 과제에서는 이쪽이 나았다. 틀려도 다음 구역에서 다시 판단하게 된다.

마지막으로 기준값을 코드에 박아 두지 않고 시작할 때 재게 했다. 시작 전에 네 구역을 한 번씩 지나면서 getRed() 계열 값을 저장하면 그날 조명에 맞춘 기준이 된다. 대신 시작 전 준비 시간이 생긴다. 박아 두면 바로 시작할 수 있는 대신 조명이 다른 날에 틀리는데, 환경이 매번 바뀌는 과제라 재는 쪽이 맞았다.

정리


Share this post on:

Previous Post
일이 없던 기간에 읽은 것들 — 빅데이터라는 말이 막 퍼지던 때
Next Post
누르는 자리가 너무 작았다