아두이노 소나 & 프로세싱으로 실시간 거리 측정 및 시각화
부품 및 소모품
| 부품 | 수량 |
| 아두이노 우노 | 1 |
| SG90 마이크로 서보 모터 | 1 |
| 초음파 센서 HC-SR04 | 1 |
| 점퍼 와이어 | 1세트 |
| 브레드보드 풀 사이즈 | 1 |
필요한 도구 및 장비
앱 및 온라인 서비스
- 아두이노 IDE
- 프로세싱 (The Processing Foundation)
프로젝트 개요
장애물 회피 자동차 제작이 너무 흔해 보여, 서보 모터와 HC-SR04 초음파 센서를 이용해 소나(Sonar) 시스템을 만들기로 했습니다. TFT LCD 화면이 없어 프로세싱 IDE로 PC 화면에 소나 출력을 시각화했습니다. 초음파 센서를 서보에 글루건으로 고정해 180도 회전하며 스캔하고, 감지된 물체의 거리와 각도를 프로세싱에서 실시간으로 표시합니다.
회로도

코드
아두이노 IDE용 소나 코드 (C/C++)
#include
const int trigPin = 12;
const int echoPin = 11;
long duration;
int distance;
Servo s1;
void setup() {
Serial.begin(9600);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
s1.attach(9);
}
void loop() {
// 0도에서 180도까지 스캔
for(int i = 0; i < 180; i++) {
s1.write(i);
delay(30);
distance = calDist();
Serial.print(i);
Serial.print(",");
Serial.print(distance);
Serial.print(".");
}
// 180도에서 0도로 복귀 스캔
for(int i = 180; i > 0; i--) {
s1.write(i);
delay(30);
distance = calDist();
Serial.print(i);
Serial.print(",");
Serial.print(distance);
Serial.print(".");
}
}
int calDist() {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
distance = duration * 0.034 / 2;
return distance;
}
프로세싱 IDE용 시각화 코드 (Java)
import processing.serial.*;
Serial myPort;
String ang = "", distance = "", data = "";
int angle, dist;
void setup() {
size(2000, 800);
myPort = new Serial(this, "COM3", 9600);
myPort.bufferUntil('.');
background(0);
}
void draw() {
fill(0, 5);
noStroke();
rect(0, 0, width, height * 0.93);
fill(0, 255);
rect(0, height * 0.93, width, height);
drawRadar();
drawLine();
drawObject();
drawText();
}
void serialEvent(Serial myPort) {
data = myPort.readStringUntil('.');
data = data.substring(0, data.length() - 1);
int index1 = data.indexOf(",");
ang = data.substring(0, index1);
distance = data.substring(index1 + 1, data.length());
angle = int(ang);
dist = int(distance);
}
void drawRadar() {
pushMatrix();
noFill();
strokeWeight(0.5);
stroke(10, 255, 10);
translate(width/2, height - height*0.06);
line(-width/2, 0, width/2, 0);
arc(0, 0, width*0.5, width*0.5, PI, TWO_PI);
arc(0, 0, width*0.25, width*0.25, PI, TWO_PI);
arc(0, 0, width*0.75, width*0.75, PI, TWO_PI);
arc(0, 0, width*0.95, width*0.95, PI, TWO_PI);
// 각도 눈금선 그리기
for (int a = 30; a <= 150; a += 30) {
line(0, 0, (-width/2)*cos(radians(a)), (-width/2)*sin(radians(a)));
}
stroke(175, 255, 175);
for (int a = 15; a <= 165; a += 30) {
line(0, 0, (-width/2)*cos(radians(a)), (-width/2)*sin(radians(a)));
}
popMatrix();
}
void drawLine() {
pushMatrix();
strokeWeight(9);
stroke(0, 255, 0);
translate(width/2, height - height*0.06);
line(0, 0, (width/2)*cos(radians(angle)), (-width/2)*sin(radians(angle)));
popMatrix();
}
void drawObject() {
pushMatrix();
strokeWeight(9);
stroke(255, 0, 0);
translate(width/2, height - height*0.06);
float pixleDist = (dist / 40.0) * (width/2.0);
float x = -pixleDist * cos(radians(angle));
float y = -pixleDist * sin(radians(angle));
if (dist <= 40) {
line(-x, y, -x + (pixleDist*cos(radians(angle))), y - (pixleDist*sin(radians(angle))));
}
popMatrix();
}
void drawText() {
pushMatrix();
fill(100, 200, 255);
textSize(25);
text("10cm", width/2 + width*0.115, height*0.93);
text("20cm", width/2 + width*0.24, height*0.93);
text("30cm", width/2 + width*0.365, height*0.93);
text("40cm", width/2 + width*0.45, height*0.93);
if (dist <= 40) {
text("Distance: " + dist, width*0.7, height*0.99);
}
translate(width/2, height - height*0.06);
textSize(25);
text("30", (width/2)*cos(radians(30)), (-width/2)*sin(radians(30)));
text("60", (width/2)*cos(radians(60)), (-width/2)*sin(radians(60)));
text("90", (width/2)*cos(radians(90)), (-width/2)*sin(radians(90)));
text("120", (width/2)*cos(radians(120)), (-width/2)*sin(radians(120)));
text("150", (width/2)*cos(radians(150)), (-width/2)*sin(radians(150)));
popMatrix();
}