바 그래프
햄스터 기초 - 근접 센서 사용하기 -
애완 로봇에서 작성한 코드에 프로세싱의 그리기 기능을 추가하여 바 그래프를 만들어 봅시다.
rectMode(CORNERS)를 사용하여 사각형을 그리는 방법을 변경하고 근접 센서 값에 따라 왼쪽 위 꼭짓점의 좌표를 계산하여 그려도 되지만,
여기서는 검은색 사각형을 그린 후 근접 센서 값에 따라 하얀색 사각형으로 검은색 사각형을 지우는 방법으로 해봅시다.
근접 센서 값 40을 기준으로 바퀴가 앞으로 이동하거나 뒤로 이동하는데,
기준 값 40에 해당하는 위치를 빨간색 선으로 표시합니다.
import org.roboid.runtime.*;
import org.roboid.hamster.*;
import org.roboid.robot.*;
Hamster hamster;
int leftProximity;
int rightProximity;
void setup() {
size(200, 210);
hamster = Hamster.create(this);
}
void draw() {
background(255);
// 검은색 사각형을 두 개 그린다.
fill(0);
noStroke();
rect(30, 20, 40, 160);
rect(130, 20, 40, 160);
// 센서 값을 표시한다.
text("Left: " + leftProximity, 30, 195);
text("Right: " + rightProximity, 130, 195);
// 하얀색으로 센서 값만큼 검은색 사각형을 지운다.
fill(255);
rect(30, 20, 40, leftProximity * 2);
rect(130, 20, 40, rightProximity * 2);
// 빨간색 선을 그린다.
stroke(255, 0, 0);
line(10, 100, 190, 100);
}
void run() {
int leftSpeed, rightSpeed;
while(true) {
leftProximity = hamster.leftProximity(); // 왼쪽 근접 센서 값
rightProximity = hamster.rightProximity(); // 오른쪽 근접 센서 값
// 왼쪽 바퀴
if(leftProximity > 15) {
leftSpeed = (40 - leftProximity) * 4; // 거리가 멀면 앞으로, 가까우면 뒤로 이동한다.
} else {
leftSpeed = 0; // 거리가 너무 멀면 정지한다.
}
// 오른쪽 바퀴
if(rightProximity > 15) {
rightSpeed = (40 - rightProximity) * 4; // 거리가 멀면 앞으로, 가까우면 뒤로 이동한다.
} else {
rightSpeed = 0; // 거리가 너무 멀면 정지한다.
}
hamster.wheels(leftSpeed, rightSpeed);
delay(20); // 너무 빨리 반복하지 않도록 한다.
}
}
마우스 조이스틱
마우스 이벤트를 사용하여 조이스틱을 만들어 봅시다.
화면 중심에 대한 마우스 커서의 위치에 따라 이동 속도와 방향을 다르게 합시다.
마우스 버튼을 누르고 있는 동안 움직이고, 버튼을 떼면 정지하도록 합시다.
프로세싱의 mousePressed 변수는 현재 마우스 버튼이 눌러져 있는지를 나타냅니다.
눌러져 있으면 true, 아니면 false의 값을 가집니다.
import org.roboid.runtime.*;
import org.roboid.hamster.*;
import org.roboid.robot.*;
Hamster hamster;
void setup() {
size(400, 400);
hamster = Hamster.create(this);
}
void draw() {
background(255);
fill(0);
ellipse(200, 200, 40, 40); // 화면 중심에 원을 그린다.
line(200, 200, mouseX, mouseY); // 화면 중심에서 마우스 커서 위치까지 선을 그린다.
}
void run() {
int dx, dy;
while(true) {
// 화면 중심과 마우스 커서 위치의 차이
dx = (200 - mouseX) / 2;
dy = (200 - mouseY) / 2;
// 마우스 버튼을 누르고 있고 차이가 너무 작지 않으면
if(mousePressed && (abs(dx) > 10 || abs(dy) > 10)) {
if(dy > 0) {
// 마우스 커서 위치가 화면 중심보다 위에 있으면 dy가 양수, 즉 앞으로 이동한다.
// 마우스 커서가 화면 중심보다 왼쪽에 있으면 dx가 양수, 즉 왼쪽 앞으로 이동한다.
hamster.wheels(dy - dx, dy + dx);
} else {
// 마우스 커서가 화면 중심보다 아래에 있으면 dy가 음수, 즉 뒤로 이동한다.
// 마우스 커서가 화면 중심보다 왼쪽에 있으면 dx가 양수, 즉 왼쪽 뒤로 이동한다.
hamster.wheels(dy + dx, dy - dx);
}
} else {
hamster.stop(); // 마우스 버튼을 누르지 않거나 차이가 너무 작으면 정지한다.
}
delay(20); // 너무 빨리 반복하지 않도록 한다.
}
}
햄스터 리모컨
햄스터 로봇의 가속도 센서를 사용하여 화면의 사각형을 움직여 봅시다.
햄스터 로봇의 앞을 위로 들거나 아래로 내리면서 X축 가속도 값을 관찰해 보면
-18000 ~ 18000까지 변함을 알 수 있습니다.
가속도 값을 100으로 나누어 사각형의 위치 값으로 사용해 봅시다.
import org.roboid.runtime.*;
import org.roboid.hamster.*;
import org.roboid.robot.*;
Hamster hamster;
void setup() {
size(400, 400);
background(255);
fill(255, 122, 0);
noStroke();
rectMode(CENTER);
hamster = Hamster.create(this);
}
void draw() {
background(255);
int y = 200 + hamster.accelerationX() / 100;
rect(200, y, 100, 100);
}
코드를 실행해 보면 햄스터 로봇의 앞을 위로 들거나 아래로 내렸을 때
사각형이 위아래로 잘 움직이기는 하지만 발발 떨면서 움직이는 것을 볼 수 있습니다.
가속도 센서는 굉장히 민감하게 반응하기 때문에 햄스터 로봇을 가만히 두어도 값이 계속 바뀌는 것을 관찰할 수 있는데,
가속도 센서 값의 변화를 좀 둔감하게 조정할 필요가 있습니다.
햄스터 로봇을 가만히 두었을 때에도 가속도 값이 1500 정도까지 왔다갔다 하는데
100으로 나누면 15가 됩니다. 즉, 사각형이 15 픽셀만큼 움직인다는 뜻입니다.
15 정도의 변화는 무시하도록 합시다.
15로 나눈 다음 반올림하고 다시 15를 곱하면 됩니다.
프로세싱의 round() 함수는 소수점 아래에서 반올림하여 정수 값으로 반환하는 함수입니다.
import org.roboid.runtime.*;
import org.roboid.hamster.*;
import org.roboid.robot.*;
Hamster hamster;
void setup() {
size(400, 400);
background(255);
fill(255, 122, 0);
noStroke();
rectMode(CENTER);
hamster = Hamster.create(this);
}
void draw() {
background(255);
int y = 200 + round(hamster.accelerationX() / 1500.0) * 15;
rect(200, y, 100, 100);
}
가로 방향의 움직임에 대해서도 똑같이 적용해 봅시다.
import org.roboid.runtime.*;
import org.roboid.hamster.*;
import org.roboid.robot.*;
Hamster hamster;
void setup() {
size(400, 400);
background(255);
fill(255, 122, 0);
noStroke();
rectMode(CENTER);
hamster = Hamster.create(this);
}
void draw() {
background(255);
int x = 200 - round(hamster.accelerationY() / 1500.0) * 15;
int y = 200 + round(hamster.accelerationX() / 1500.0) * 15;
rect(x, y, 100, 100);
}
코드를 실행해 보면 사각형이 15 픽셀 단위로 움직이기 때문에 움직임이 튀는 것을 볼 수 있습니다.
평균 값을 구하여 움직임을 좀 더 부드럽게 만들어야겠습니다.
가속도 센서 값을 어느 정도 모아서, 예를 들어 100개를 모아서 평균 값을 계산하면 100개가 모여졌을 때만 사각형을 움직일 수 있기 때문에 움직임이 뚝뚝 끊어져 보일 수 있습니다.
따라서 예전 값은 버리고 새로운 값을 넣어서 매번 평균 값을 구하는 방법을 사용합니다.
이를 이동 평균(Moving Average)이라고 합니다.
이동 평균을 구하는 방법은 여러 가지가 있는데 가장 간단한 방법으로 해보겠습니다.
우선 평균을 구할 값들을 모을 수 있는 장소가 필요합니다.
프로세싱의 IntList는 정수 값을 모을 수 있습니다.
가로 방향에 대한 IntList와 세로 방향에 대한 IntList를 만들도록 합시다.
IntList xlist = new IntList(); // 가로 방향에 대한 IntList
IntList ylist = new IntList(); // 세로 방향에 대한 IntList
평균을 구하기 위해서는 먼저 합을 계산해야 합니다.
가로 방향에 대한 합을 xsum, 세로 방향에 대한 합을 ysum이라고 하고, 합을 구하는 함수를 만들어 봅시다.
IntList xlist = new IntList(); // 가로 방향에 대한 IntList
IntList ylist = new IntList(); // 세로 방향에 대한 IntList
float xsum = 0; // 가로 방향에 대한 합
float ysum = 0; // 세로 방향에 대한 합
// sum: 합의 현재 값
// list: 정수 값들을 저장하는 곳
// value: 새로 추가하는 값
// num: 평균을 구할 값들의 최대 개수
// 반환 값: 가장 최근까지 저장된 값들의 합
float calcSum(float sum, IntList list, int value, int num) {
list.append(value); // 새로운 값 value를 list의 제일 뒤에 추가한다.
sum += value; // value를 sum에 더한다.
if(list.size() > num) { // num 개수만큼 모았으면
sum -= list.remove(0); // 가장 예전 값(list의 제일 앞, 즉 인덱스 0에 있는 값)을 저장소에서 제거하고 합에서 뺀다.
}
return sum;
}
전체 코드를 완성하면 다음과 같습니다.
import org.roboid.runtime.*;
import org.roboid.hamster.*;
import org.roboid.robot.*;
Hamster hamster;
IntList xlist = new IntList(); // 가로 방향에 대한 IntList
IntList ylist = new IntList(); // 세로 방향에 대한 IntList
float xsum = 0; // 가로 방향에 대한 합
float ysum = 0; // 세로 방향에 대한 합
void setup() {
size(400, 400);
background(255);
fill(255, 122, 0);
noStroke();
rectMode(CENTER);
hamster = Hamster.create(this);
}
float calcSum(float sum, IntList list, int value, int num) {
list.append(value);
sum += value;
if(list.size() > num) {
sum -= list.remove(0);
}
return sum;
}
void draw() {
background(255);
int x = 200 - round(hamster.accelerationY() / 1500.0) * 15;
int y = 200 + round(hamster.accelerationX() / 1500.0) * 15;
xsum = calcSum(xsum, xlist, x, 20); // 가로 방향에 대한 합 (값의 최대 개수는 20개)
ysum = calcSum(ysum, ylist, y, 20); // 세로 방향에 대한 합 (값의 최대 개수는 20개)
x = round(xsum / xlist.size()); // 가로 방향에 대한 평균
y = round(ysum / ylist.size()); // 새로 방향에 대한 평균
rect(x, y, 100, 100);
}
햄스터 로봇을 손목에 부착하여 화면의 그래픽을 제어하는 웨어러블 인터페이스 장치로 사용해 봅시다.
목차
수업 자료 내려 받기
- 원본 그림 2017.01.16 버전 (34.7 MB)
햄스터 고급
- 행위 기반의 로봇 제어
- 경로 탐색
- 자리 바꾸기
Copyright 로봇SW교육원 All rights reserved.
어려운 일이 있으면 광운대학교 로봇학부 박광현 교수(
akaii@kw.ac.kr)에게 연락하세요.