아두이노프로세싱 프로그래밍

초보자를 위한 프로세싱과 아두이노 시리얼 통신 인터페이스: 가변 저항에서 발생하는 전압 데이터 Processing에서 실시간 그래픽

coding art 2017. 3. 19. 16:40
728x90


ESP8266 NodeMCU 와이파이에 의한 스마트폰과의 인터페이스도 흥미롭지만 시리얼 통신에 의한 Processing 프로그램과의 인터페이스 또한 매력적이다. 비록 무선은 아닐지라도 프로그래밍이 대단히 간편하여 배워두면 쉽게 유익한 시스템을 만들어 낼 수 있다.

특히 실험실에서 아두이노에 센서를 설치해 사용한다면 너무나 쉽게 그 데이터를 PC로 읽어 와 저장하거나 심지어 비쥬얼하게 실시간 그래픽 처리를 할 수 있다. 따라서 그 방법이 너무나 간단하므로 절대로 놀라지 말기 바란다.

아두이노에서의 센서로서 가변저항을 선택하여 5V 및 GND , 그리고 가운데 전압이 나오는 배선은 아날로그 A0에 배선하자.


다음은 아두이노의 프로그램이다. setup()에서 Serial.begin()을 보통 9600으로 설정하나 여기서는 그 10배 이상인  115200으로  둔다. 빠를수록 좋다.

loop()에서 읽어들이는 아날로그 전압데이터는 정수형으로 0∼1023까지 분포한다. 따라서 4분하여 0∼255로 조절한다. 이는 아두이노 PWM  명령인 analogWrite()에서 최대 256 단계를 쓴다는 취지의 연장선상이라 보자.

단 읽어들인 센서 값은 반드시 Serial.write()를 쓰도록 하자.   Serial.print() 명령에서는 문자를 대상으로 ASCII 코드화 해서 데이터를 주고받음에 비해 이 Serial.write()명령은 1 바이트 크기의 8비트 데이터를 상대측으로 출력한다.  하지만 Processing에 접수된 데이터를 출력하여 콘솔 창에서 정상적인 데이터를 볼 수 있음에 유의하자.

한가지 주의해야 할 점은 아두이노가 시리얼 통신으로 데이터를 PC로 보낼 때에 PC에서는 반드시 프로세싱 프로그램만이 시리얼 포트를 쓰도록 유의하기 바란다. 멀티태스킹 하는 것은 좋으나 프로세싱 프로그램 실행 중에는 절대 다른 프로그램이 시리얼 COM 포트 사용을 금하도록 하자.
워낙 짧은 프로그램이므로 직접 입력하도록 한다.


//Analog data sending to Processing

void setup() {
  Serial.begin(115200);
}

void loop() {
 int analogValue = analogRead(A0)/4; // read the sensor value
 Serial.write(analogValue);          // send a byte binary value serially
}//프로그램 끝


프로세싱 프로그램 구성해 보자. 도입부에서 시리얼 통신 인터페이스를 지원하기 위한 라이브러리에 해당하는 import processing.serial.* 실행이 필수적이다. 아울러 시리얼 통신 인터페이스를 myPort로 명명해둔다.


import processing.serial.*;
Serial myPort;


실시간 그래픽 작업을 준비하기 위해서 다음과 같이 실수형태로 원점을 정의한다.


 // Graphic setting
float xPos = 0; // horizontal position of the graph
float yPos = 0; // vertical position of the graph


setup()에서 그래픽 화면 크기를 800X260으로 정한다. 높ㅇ 260은 256 보다 조금 큰 편이다.
배경 색은 거의 검정색으로 선택한다.
장치관리자처럼  가용한 시리얼 포트를 조사해서 출력한다. 특히 아래의 장치 관리자 포트와 비교해 보면 현재 아두이노의 USB-2-시리얼 커넥터가 “COM17“에 연결 인식되고 있음을 알 수 있다.

따라서 다음과 같이 코딩해서 사용해도 무방하며
port = new Serial(this, "COM17", 115200);
아니면 Serial.list()[2] 즉 콘솔 창 출력 결과의 3번째 COM 포트를 의미하는 아래의 명령도 좋다.
port = new Serial(this, Serial.list()[2], 115200);

초보자라면 이 부분에 주의를 기울이기 바란다.






 void setup() {
 size(800, 260);
 background(#081640);
 
 println("Available serial ports:");
 println(Serial.list());

 //port = new Serial(this, "COM17", 9600);
 myPort = new Serial(this, Serial.list()[2], 115200);
 }


아두이노에서 보내는 데이터를 받아들이기 위해서 프로세싱 프로그램은 반드시 serialEvent() 방식의 루틴을 사용한다. 현재 데이터 받아들이는 작업 뿐이므로 아두이노는 무조건 시리얼 통신에 Serial.write() 해주면 프로세싱이 serialEvent 루틴에 의해  알아서 데이터를 읽어 들이는 방식이다.

  void serialEvent (Serial myPort) {
  // get the byte:
  int inByte = myPort.read();
  println(inByte);
  yPos = height - inByte;
}


아두이노로부터 전송된  전압 데이터를 inByte에 저장하여 그래픽 스크린에 적합하도록 연산 후 yPos에 저장한다.

실시간 그래픽을 위한 draw()에서는 읽어 들인 데이터에 맞춰 스크린 아랫 바닥 선에서 yPos 까지 높이에 해당하는 수직선을 긋는다. 속도가 충분히 빠른 편이다. 스크린 오른쪽 한계에 도착하면 전체를 배경색으로 초기화 하고 다시 그래픽을 시작한다.


Processing_receiving_data_from_Arduino_01


import processing.serial.*;
Serial myPort;
 
 // Graphic setting
float xPos = 0; // horizontal position of the graph
float yPos = 0; // vertical position of the graph


 void setup() {
 size(800, 260);
 background(#081640);
 
 println("Available serial ports:");
 println(Serial.list());

 //port = new Serial(this, "COM17", 115200);
 myPort = new Serial(this, Serial.list()[2], 115200);

 }
 
  void serialEvent (Serial myPort) {
  // get the byte:
  int inByte = myPort.read();
  println(inByte);
  yPos = height - inByte;

}

 void draw() {
  // draw the line in a pretty color:
  stroke(#A8D9A7);
  line(xPos, height, xPos, yPos);

  // at the edge of the screen, go back to the beginning:
  if (xPos >= width) {
    xPos = 0;
    // clear the screen by resetting the background:
    background(#081640);
  } else {
    // increment the horizontal position for the next reading:
    xPos++;
  }

 }//End of Processing program