본문 바로가기
프로젝트

아두이노 레이더 프로젝트 - 01. 준비 작업

by Bugwhale 2020. 2. 1.

이 글은 아두이노 레이더 프로젝트 - 01. 준비 작업에 대해 설명합니다.

1. 개요

이번 프로젝트는 아두이노 초음파 센서나 서보모터를 공부하면 한 번 쯤을 해봤을 레이더 만들기 프로젝트를 해볼 생각이다. 총 2가지 버전을 만들 건데 첫 번째로는 서보 모터(SG90)와 적외선 거리 센서(GP2Y0A21YK0F)로 180도 회전 레이더, 후속편에서 서보 모터 대신 스텝모터(28BYJ-48)를 이용하여 360도 회전하는 레이더를 만들 것이다. 적외선 거리센서 대신에 보통 많이 사용하는 초음파 거리 센서(HC-SR04)를 이용하는 소스코드도 같이 작성하였으니 필요시 사용하면 되겠다.

1.1 준비물

1. 개발 보드(아두이노 우노, 아두이노 나노) 2. 적외선 거리센서(GP2Y0A21YK0F) 또는 초음파 센서(HC-SR04) 3. 서모보터(SG90) 또는 스텝모터(28BYJ-48) 4. 점퍼선

2. 회로 구성 및 소스코드

이 글에서는 초음파 거리센서를 사용할 것인지 적외선 거리 센서를 사용함에 따라 회로 구성과 소스코드를 바꿔 사용하면 된다. 소스코드에 주석을 자세하게 적어놨으니 이해하는데 어려움이 없을 거라 예상된다.

2.1 적외선 거리 센서 사용

// Servo 라이브러리 사용
#include <Servo.h>

// 핀 번호 설정
#define PIN_SERVO 2
#define PIN_PSD A0

void setup () {
  // 객체 및 변수 선언
  Servo myServo;
  int angle, distance;
  
  // 핀 모드 설정
  myServo.attach(PIN_SERVO);
  pinMode(PIN_PSD, INPUT);
  
  // 시리얼 통신 초기화
  Serial.begin(9600);

  // 서보모터 위치 초기화
  myServo.write(0);
  delay(500);

  // loop 함수를 사용안하기 때문에 while(true) 로 무한반복 시켜준다.
  while(true) {
    for(int i = 0; i < 360; i ++){ // 서보모터가 시계방향 180도, 반시계방향 180도 가기위해 총 360번 반복
      if(i > 180) angle = 360 - i; // 180 이상이면 반대 방향으로 회전하기 위한 수식
      else angle = i; // 180 이하라면 그대로 넣어준다. 

      // 서보모터는 회전하고
      myServo.write(angle);
      // PSD 센서로부터 거리를 얻어온뒤
      distance = getDistance(analogRead(PIN_PSD));
      // 값을 시리얼모니터에 출력한다.
      // 여기서 출력의 의미는 Processing 으로 값을 전달하는 의미이기도 하다.
      Serial.print(angle);
      Serial.print("a");
      Serial.print(distance);
      Serial.print("\n");
      delay(20);
    }
  }
}

int getDistance(int sensorValue)
{
  return 27.728 * pow(map(sensorValue, 0, 1023, 0, 5000) / 1000.0, -1.2045);
}

2.2 초음파 거리 센서 사용

#include <Servo.h>

#define PIN_SERVO 2
// 초음파 센서 핀 번호 설정
#define PIN_TRIG 2
#define PIN_ECHO 3

void setup () {
  Servo myServo;
  int angle, distance;
  myServo.attach(PIN_SERVO);
  // 초음파 센서 핀 모드 설정
  pinMode(PIN_TRIG, OUTPUT);
  pinMode(PIN_ECHO, INPUT);
  Serial.begin(9600);
  myServo.write(0);
  delay(500);
  
  while(true) {
    for(int i = 0; i < 360; i ++){
      if(i > 180) angle = 360 - i; 
      else angle = i
      myServo.write(angle);
	  
      // 초음파 센서로부터 거리값을 얻어온다.
      distance = getDistance();
	  
      Serial.print(angle);
      Serial.print("a");
      Serial.print(distance);
      Serial.print("\n");
      delay(20);
    }
  }
}

int getDistance()
{
  long duration;
  int distance;
  digitalWrite(PIN_TRIG, LOW);
  delayMicroseconds(2);
  digitalWrite(PIN_TRIG, HIGH);
  delayMicroseconds(10);
  digitalWrite(PIN_TRIG, LOW);
  duration = pulseIn(PIN_ECHO, HIGH, 5882);
  distance = duration*0.034/2;
  return distance;
}

2.3 동작 결과

 위와 같이 시리얼 모니터에 "각도a거리"로 잘 출력된다. 여기서 각도와 거리 중간에 a는 나중에 프로세싱이라는 개발환경에서 각도와 거리값을 구분해줄 용도로 사용될 것이기 때문에 추가했다. 숫자만 아니라면 "a"가 아닌 문자를 사용해도 상관없다. 이제 아두이노에서 해야할 일은 끝났다.

3. 프로세싱(Processing)설치

우리가 위에서 작성한 코드는 어디까지나 거리와 각도값을 시리얼모니터에 띄우는 작업만을 해준다. 즉, 이제 이 값을 이용하여 시각적으로 표현해줘야하는데 우리가 사용하는 아두이노 개발환경(IDE)에서는 불가능하다. 그래서 우리는 시각적으로 표현해줄  프로세싱 개발환경을 사용할 것이다. 프로세싱 홈페이지에 가서 최신버전으로 다운받을 수 있다. 아래와같은 빨간 박스안에 자신의 컴퓨터에 맞는 OS를 클릭하면 자동으로 다운로드되고 다운받은 압축 파일을 한글이 없는 경로에 풀어주면 설치가 끝난다. 한글이 있는 경로에 풀어줘도 상관없지만 간혹가다 컴파일 도중 에러가 발생하는 경우가 있기 때문이다.

4. 아두이노와 프로세싱간 통신

이제 아두이노 보드에서 각도값과 거리값을 이용하여 시각적으로 표현해줄 일만 남았다. 근데 어떻게 프로세싱 개발환경에서 아두이노에서 측정한 각도값과 거리값을 알아내느냐? 아두이노와 프로세싱간에 시리얼 통신을 통하여 데이터를 전송할 것이다. 우리는 이미 데이터를 송신 해주는 작업을 해주었다. 위 소스코드에서 Serial.print()를 해줌으로써 시리얼 통신을 통하여 아두이노 시리얼 통신 포트에 값이 전송되고 있는 것이다. 여기서 아두이노에서 아두이노 개발환경으로 연결시키면(시리얼 모니터로) 값을 확인 할 수 있고, 아두이노를 프로세싱 개발환경으로 연결시키면 프로세싱에서 코딩을 통하여 데이터를 수신 받을 수 있게 되는 것이다. 말이 어렵게 됬는데 결론은 우리가 자주 사용하는 아두이노 시리얼 모니터에 값을 송신하는 것 대신에 프로세싱 개발환경으로 값을 송신할 것이다. 프로세싱는 사실 개발환경이면서 Java 기반의 독자적인 프로그래밍 언어이다. 아두이노만 사용해본 사람이라면 새로운 문법이 많아 이해하기 힘드니 여기서는 어떤 코드가 어떤 이유에서 쓰였는지 또는 어떠한 역할을 하는지 코드를 해석하는 방향으로 작성하였다. 우선 설치한 프로세싱 개발환경을 실행시켜 "파일-새스케치"를 생성하고 다음 코드를 작성해보자.

// 아두이노에서 #include <processing.serial.*> 같은 느낌으로 이해하면 된다. 
// 물론 실제로는 같지 않다. processing.serial 이하의 모든 패키지를 불러오는 의미이다.
import processing.serial.*;

// Serial myPort myPort 이름의 Serial 객체를 생성한다. 
Serial myPort;

void setup() {
	size(500, 500);
	myPort = new Serial(this, "COM3", 9600);
}

// 아두이노의 loop() 함수처럼 무한 반복되는 함수이다.
void draw() {
	// myString 문자열 생성(사실은 이 역시 객체)
	String myString;
	
	// 시리얼 통신으로부터 데이터가 존재한다면
	while(myPort.available() > 0) {
		// '\n' 문자가 올때까지 myString에 값을 저장한다.
		myString = myPort.readStringUntil('\n');
		
		// myString 값이 null 값이 아니라면, 빈 문자열이 아니라면
		if(myString != null) {
			// 배경화면을 rgb 값이 0,0,0 즉 검정색으로 만들어준다.
			// 출력할 문자열이 겹치지 않게 해줄 기능으로도 작용
			background(0, 0, 0);
			
			// 생성될 도형의 색상을 설정해준다. 여기서는 텍스트도 도형으로 취급
			// 차라리 객체의 색상을 설정해주는 걸로 봐도 이해하기 쉬울 것 같다.
			fill(30, 255, 30);
			// 20(x), 40(y) 좌표에 myString 내용을 출력한다.
			text(myString, 20, 40);
		}
	}
}
void setup() { size(500, 500); myPort = new Serial(this, "COM3", 9600); }

setup() 함수는 아두이노의 setup() 함수처럼 시작하면 한 번만 수행된다. size(x, y) 아두이노와 다르게 시각적인 표현을 위한 개발환경이라 시작하면 100*100 크기의 새 창이 띄어진다. size() 함수는 새 창의 사이즈를 바꿔주는 함수이다. myPort = new Serial(this, "COM3", 9600) myPort 객체의 초기화하는 과정이다. "COM3"포트에 9600 속도로 초기화 하는 의미이다. 여기서 "COM3" 부분을 자신의 아두이노의 포트번호와 일치시켜줘야 한다. 혹시 모른다면 아래 사진을 참조하자.

 위 소스코드에서 myPort = new Serial(this, "COM3", 9600) 부분의 "COM3", 포트 번호를 확인하는 방법이다. 포트번호를 변경하고 실행 시켜보면 다음과 같은 화면이 생성될 것이다. 참고로 아두이노 개발환경에서 시리얼 모니터가 켜져 있다면 프로세싱과 아두이노간에 통신이 안될 것이니 꺼줘야 한다. (시리얼 통신이 1:1 통신이기 때문이다.)

문제 없이 실행이 되었다면 위와 같은 새창이 뜰 것이다. 이제 아두이노에서 읽어드린 센서 값과 각도 값을 시리얼 통신을 통하여 프로세싱 개발환경에서 수신받기까지 완료했다.

5. 관련 블로그 글

5.1 프로젝트 관련

[series_list_posts] [series_list_related]

5.2 프로젝트 카테고리

프로젝트

6. 참조

아두이노 홈페이지 프로세싱 홈페이지

댓글