위즈네트 아카데미

TUTORIAL

튜토리얼

Home  > 튜토리얼

Arduino Network Radar

WIZnet Academy 2016.07.14 16:52 조회 수 : 64

아래는 유투부에 올라가 있는 영상입니다. 'Arduino Radar Project' 인데, 우선 감상해 보시겠습니다.


이번 프로젝트는 본 영상을 참고로하여 인터넷 기술을 접목하여 제작한 Arduino Network Radar 입니다.

arduino_radar_1

이번 프로젝트에는 Arduino Mega를 플랫폼 보드로 사용하였으며, 초음파센서 모듈과 서보모터를 이용해서 레이더를 구현하였습니다. PC 화면에선 Radar를 표현해주기 위하여 Processing 이라는 개발툴을 사용하였습니다. Arduino에서 각도 값과 물체의 거리 값을 Serial 통신으로 PC로 전송하고, 그 값을 기반으로 Radar의 모습으로 표현을 합니다.

arduino_radar_2

Processing을 간단하게 알아보면, MIT미디어랩에서 만든 Java기반의 오픈소스 프로그래밍 IDE 입니다. 기존의 프로그래밍을 하는 사람이나 일반 사람들도 쉽게 사용할 수 있도록 만들어졌고, 이미지, 애니메이션, 인터렉션등 시각적으로 표현하는 것에 특화 되어있습니다. 오픈소스이기 때문에 무료로 사용이 가능하고 다양한 라이브러리나 예제들이 오픈되어 있어, 아두이노를 사용하는 사람이라면 아두이노와 연동을 해서 시각적인 효과를 표현하고 싶을 때 쉽게 표현을 할수 있습니다.

아래는 원작자가 소개하는 프로젝트 페이지입니다.

http://howtomechatronics.com/projects/arduino-radar-project/

Arduino Network Radar

위에 설명했던 Arduino Radar Project는 Arduino와 PC가 USB 케이블로 연결이 되어 서로 통신하는 방식입니다. 하지만 우리가 만들 것은 Ethernet Shield를 추가해서 Network(Ethernet)에 연결된 Arduino Radar를 만들어 보려고 합니다. PC의 Processing도 시리얼 통신으로 구현이 되어 있는 것을 Network 기능을 추가하여 작업할 예정입니다.

이렇게 함으로써 Arduino Radar Project는 Arduino와 PC가 한공간에 있어야 하지만, Arduino Network Radar는  Arduino와 PC 서로 떨어져 있는 원격지에서 Radar를 확인할 수 있는 장점을 가질 수 있습니다.

arduino_radar_3

우선 Arduino Network Radar를 만들기 전에 서보모터와 초음파센서에 대해서 간단히 알아보겠습니다. 아래 링크를 클릭하면 이번 프로젝트 저자가 정리해 둔 블로그 글을 통해 서보모터와 초음파 센서의 동작 원리와 다루는 방법 등을 학습할 수 있습니다.

Arduino로 Servo Motor를 제어해 보자.

Arduino와 초음파센서를 이용해서 거리를 측정해 보자.

아래 그림은 Arduino Network Radar의 구성도입니다.

arduino_radar_4

보시는 바와 같이 USB가 아닌 Ethernet을 통해 PC와 통신합니다. 아두이노는 Server, PC는 Client로 동작합니다.

위 구성도를 바탕으로 아래와 같이 회로도를 그립니다.  이더넷 쉴드는 아두이노에 Stacking 합니다.

arduino_radar_5

Arduino의 D3에 서보모터의 신호선을 연결하고, D2에 초음파센서의 Trig Pin, D4에 Echo Pin을 연결했습니다. 이렇게 선만 연결하고 따로 다른 회로를 구성할 필요는 없습니다.

아래는 실제로 구성한 모습입니다. 초음파센서의 브라켓을 3D 프린터로 출력해서 서보모터에 고정했습니다.

arduino_radar_6

아래는 Arduino Code 입니다. Client가 Connect 되고 데이터를 아무거나 넘겨주면, Arduino는 Client로 data를 전송합니다. Ethernet으로 전송되는 데이터의 포맷은 "각도,거리." 형태이며 string으로 전송됩니다. Ex) 55,55.

다른 코드설명은 주석으로 대체하겠습니다.
#include <Servo.h>        // 서보 라이브러리 추가 
#include <SPI.h> // SPI 라이브러리 추가
#include <Ethernet2.h> // 이더넷 라이브러리 추가

// 초음파 센서 하드웨어 핀 정의
const int trigPin = 2;
const int echoPin = 4;
// 서보 모터 하드웨어 핀 정의
const int servoPin = 3;
// MAC Addr 초기화
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
// 고정 아이피를 사용한다면, 사용할 IP 정의
IPAddress ip(192, 168, 1, 177);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 0, 0);

EthernetServer server(5000); // 이더넷 서버 객체 선언, port는 5000
Servo myServo; // 서보 모터 객체 선언

long duration; // 초음파 반사 시간 저장 변수 선언
int distance; // 물체와의 거리 저장 변수 언
char sendData[6] = "0,"; // 데이터 버퍼 선언
boolean alreadyConnected = false; // Connect 상태 변수 선언

void setup() {
Serial.begin(115200); // 시리얼 초기화
// 이더넷 초기화, 아래 둘중에 하나만 사용.
Ethernet.begin(mac, ip, gateway, subnet); //고정 IP를 사용
//Ethernet.begin(mac); //DCHP 사용
server.begin(); //서버로 동작 시작

pinMode(trigPin, OUTPUT); // trigPin을 Output으로 설정
pinMode(echoPin, INPUT); // echoPin을 Input으로 설정
myServo.attach(servoPin); // 서보 모터 초기화
// 디바이스의 IP 출력
Serial.print("Arduino Network Radar server address:");
Serial.println(Ethernet.localIP());
}
void loop() {
// 클라이언트 객체 선언, 서버가 받은 데이터가 있는지 확인
EthernetClient client = server.available();
// 클라이언트로 붙터 받은 데이터가 있으면
if (client) {
Serial.println("Hello client");
alreadyConnected = true; // 클라이어트가 접속 했다고 판단.
}
if (alreadyConnected == true) {
// 서보 모터는 15도 -> 165도로 회전
for (int i = 15; i <= 165; i++) {
myServo.write(i);
delay(30);
distance = calculateDistance(); // 물체와의 거리 산출
int j = 180 - i; // 디스플레이를 위한 각도 반전
sprintf(sendData, "%d%s%d%s", j, ",", distance, "."); // 각도 값과 거리 값을 합침
server.print(sendData); //클라이언트로 data 전송
Serial.print(sendData); //시리얼로 data 전송

}
// 서보 모터는 165도 -> 15도로 회전
for (int i = 165; i > 15; i--) {
myServo.write(i);
delay(30);
distance = calculateDistance();
int j = 180 - i;
sprintf(sendData, "%d%s%d%s", j, ",", distance, ".");
server.print(sendData);
Serial.print(sendData);
}
}
}
// 초음파 센서 동작, 거리 산출 함수
int calculateDistance() {
// 10us 펄스 발생
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);

duration = pulseIn(echoPin, HIGH); // 반사된 초음파 시간 측정
distance = duration*0.034 / 2; // 츨정된 시간을 바탕으로 거리 계산
return distance; // 거리 값 리턴
}

아래 그림은 PC에서 Ethernet Client Terminal을 이용해서 Arduino와 통신을 하는 화면을 캡쳐한 것입니다.

arduino_radar_7

Client에서 접속을 하고, "Hi" 라고 메시지를 보내면 Arduino에서 각도 데이터와 거리 데이터를 보내주는 것을 볼 수 있습니다. 위 그림에는 23번 포트이지만 최종 코드에서는 5000번 포트로 변경 합니다.

아래는 Processing Code입니다. 기본적인 code는 Arduino Radar와 동일하고, 시리얼 인터페이스 부분을 Network 인터페이스로 수정하였습니다..

저자의 경우 clientEvent 함수 부분에서 혼동스러웠다고 하는데,  패킷단위로 이벤트가 발생이 될줄 알았는데 바이트 단위로 이벤트가 발생하게 되면서 생긴 문제였습니다.  별도로 String으로 데이터를 받지 않고 한 바이트씩 받아 버퍼에 따로 저장하는 방식으로 수정하였습니다. 수정한 부분은 한글로 따로 주석처리를 했으니 참고하세요.
import processing.net.*;    // network 라이브러리 import
Client myClient; // client 객체 생성
// defubes variables
char dataIn; // ethernet data 임시 버퍼 선언
String sData=""; // ethernet data를 string 형태로 저장할 버퍼 선언

String angle="";
String distance="";
String data="";
String noObject;
float pixsDistance;
int iAngle, iDistance;
int index1=0;
int index2=0;
PFont orcFont;
void setup() {

size (960, 540); // ***CHANGE THIS TO YOUR SCREEN RESOLUTION***
//size (1920, 1080);
smooth();
myClient = new Client(this, "192.168.1.177", 5000); // Client로 초기화, 아두이노 IP 192.168.1.177 Port번호 5000으로 접소.
myClient.write("Hi"); // 아두이노에 접속이 되면 "Hi" 전송

orcFont = loadFont("OCRAExtended-30.vlw");
}
void draw() {

fill(98,245,31);
textFont(orcFont);
// simulating motion blur and slow fade of the moving line
noStroke();
fill(0,4);
rect(0, 0, width, height-height*0.065);

fill(98,245,31); // green color
// calls the functions for drawing the radar
drawRadar();
drawLine();
drawObject();
drawText();
}
// 데이터가 수신되면 호출되는 함수. 패킷단위로 호출될 줄 알았는데 바이트 단위로 호출 됨.
void clientEvent(Client myClient) {
dataIn = myClient.readChar(); // 수신된 데이터를 dataIn 변수에 저장.
sData += dataIn; // dataIn 변수의 데이터를 sData string 변수에 누적해서 저장.

// "."(점)이 전송될 때까지 sData에 저장만 한다.
if(dataIn == '.')
{
sData = sData.substring(0,sData.length()-1); // End 데이터인 "."을 제외하고 sData에 저장한다.
String[] list = split(sData, ","); // ","를 기준으로 데이터를 나누어 list 배열에 저장한다.

angle=list[0]; // list[0]는 각도 데이터 이고, angle 변수에 저장한다.
distance=list[1]; // list[1]은 거리 데이터 이고, distance 변수에 저장한다.

// 파싱된 데이터를 processing 콘솔창에 표시한다.
print("angle : ");
println(angle);
print("distance : ");
println(distance);
println("------------------");

iAngle = int(angle); // angle변수를 int 형으로 변환하고, iAngle 변수에 저장한다. iAngle변수는 화면에 표시될때 사용이 된다.
iDistance = int(distance); //distance변수를 int 형으로 변환하고, iDistance 변수에 저장한다. iDistance변수는 화면에 표시될때 사용이 된다.
sData = ""; // sData를 초기화 한다.
}
}
void drawRadar() {
pushMatrix();
translate(width/2,height-height*0.074); // moves the starting coordinats to new location
noFill();
strokeWeight(2);
stroke(98,245,31);
// draws the arc lines
arc(0,0,(width-width*0.0625),(width-width*0.0625),PI,TWO_PI);
arc(0,0,(width-width*0.27),(width-width*0.27),PI,TWO_PI);
arc(0,0,(width-width*0.479),(width-width*0.479),PI,TWO_PI);
arc(0,0,(width-width*0.687),(width-width*0.687),PI,TWO_PI);
// draws the angle lines
line(-width/2,0,width/2,0);
line(0,0,(-width/2)*cos(radians(30)),(-width/2)*sin(radians(30)));
line(0,0,(-width/2)*cos(radians(60)),(-width/2)*sin(radians(60)));
line(0,0,(-width/2)*cos(radians(90)),(-width/2)*sin(radians(90)));
line(0,0,(-width/2)*cos(radians(120)),(-width/2)*sin(radians(120)));
line(0,0,(-width/2)*cos(radians(150)),(-width/2)*sin(radians(150)));
line((-width/2)*cos(radians(30)),0,width/2,0);
popMatrix();
}
void drawObject() {
pushMatrix();
translate(width/2,height-height*0.074); // moves the starting coordinats to new location
strokeWeight(9);
stroke(255,10,10); // red color
pixsDistance = iDistance*((height-height*0.1666)*0.025); // covers the distance from the sensor from cm to pixels
// limiting the range to 40 cms
if(iDistance<40){
// draws the object according to the angle and the distance
line(pixsDistance*cos(radians(iAngle)),-pixsDistance*sin(radians(iAngle)),(width-width*0.505)*cos(radians(iAngle)),-(width-width*0.505)*sin(radians(iAngle)));
}
popMatrix();
}
void drawLine() {
pushMatrix();
strokeWeight(9);
stroke(30,250,60);
translate(width/2,height-height*0.074); // moves the starting coordinats to new location
line(0,0,(height-height*0.12)*cos(radians(iAngle)),-(height-height*0.12)*sin(radians(iAngle))); // draws the line according to the angle
popMatrix();
}
void drawText() { // draws the texts on the screen

pushMatrix();
if(iDistance>40) {
noObject = "Out of Range";
}
else {
noObject = "In Range";
}
fill(0,0,0);
noStroke();
rect(0, height-height*0.0648, width, height);
fill(98,245,31);
textSize(25);

text("10cm",width-width*0.3854,height-height*0.0833);
text("20cm",width-width*0.281,height-height*0.0833);
text("30cm",width-width*0.177,height-height*0.0833);
text("40cm",width-width*0.0729,height-height*0.0833);
textSize(25);
text("Object: " + noObject, width-width*0.875, height-height*0.0277);
text("Angle: " + iAngle +" °", width-width*0.48, height-height*0.0277);
text("Distance: ", width-width*0.26, height-height*0.0277);
if(iDistance<40) {
text(" " + iDistance +" cm", width-width*0.225, height-height*0.0277);
}
textSize(25);
fill(98,245,60);
translate((width-width*0.4994)+width/2*cos(radians(30)),(height-height*0.0907)-width/2*sin(radians(30)));
rotate(-radians(-60));
text("30°",0,0);
resetMatrix();
translate((width-width*0.503)+width/2*cos(radians(60)),(height-height*0.0888)-width/2*sin(radians(60)));
rotate(-radians(-30));
text("60°",0,0);
resetMatrix();
translate((width-width*0.507)+width/2*cos(radians(90)),(height-height*0.0833)-width/2*sin(radians(90)));
rotate(radians(0));
text("90°",0,0);
resetMatrix();
translate(width-width*0.513+width/2*cos(radians(120)),(height-height*0.07129)-width/2*sin(radians(120)));
rotate(radians(-30));
text("120°",0,0);
resetMatrix();
translate((width-width*0.5104)+width/2*cos(radians(150)),(height-height*0.0574)-width/2*sin(radians(150)));
rotate(radians(-60));
text("150°",0,0);
popMatrix();
}

이제 Arduino Code와 Processing Code가 완료 되었으며, Network으로 연결하고 테스트를 진행하겠습니다.

본 테스트에서는 공유기에 PC를 연결하고, Arduino도 같은 공유기에 연결 합니다. Arduino는 DHCP를 사용하지 않고 static IP로 설정을 했습니다. PC의 IP는 공유기를 통해서 DHCP로 받아 192.168.1.xxx 로 잡혔고, Arduino의 IP도 192.168.1.177로 같은 네트워크망이기 때문에 통신이 가능합니다.


보이시나요? 물체가 인식이되면 PC화면에는 빨간색으로 표시가 됩니다

글출처 : OSHW Alchemist