아두이노 코딩-54: Processing 그래픽 처리에 의한 실시간 전압계

codingart(66)
Published in
#kr
Words
1081
Reading
5 min
Listen
Play
8y

noname13.png

아두이노에 설치한 가변 저항에서 발생하는 실시간 전압을 PC에서 Processing 그래픽 처리 코드에 의해 계기판을 애니메이션 해보자. 이 내용에 대해서는 5월 31일에 포스팅된

아두이노 코딩-53: Processing 아두이노 인터페이스에 의한 RGB LED Dimmering
https://steemit.com/kr/@codingart/53-processing-rgb-led-dimmering

댓글에서 urobotics@urobotics님의 질문에 대해서 codingman@codingman 님께서 비슷한 응용 사례에 관한 세세한 설명이 있었으니 참조하시기 바란다.

noname02.png

Processing의 스케치 탭에서 내부 라이브러리의 라이브러리 추가하기를 클릭하고 새 창이 뜨면 Filter 란에 meter를 입력하고 하단의 install 버튼을 클릭한다.

noname03.png

meter 로 명명된 라이브러리가 설치와 더불어 파일 탭에서 예제를 열어 Contributed Libraries에서 meter의 Arduino_3_Volt 예제를 불러오자. 이 예제는 아두이노 보드에 설치된 가변저항에 가해지는 전압을 아날로그 핀 A0 로 읽는다. A0에서 읽는 전압 데이터는 정수 0∼1023 까지의 범위를 가지게 된다. 이 정수 값을 map() 명령을 사용하여 0∼1023 사이의 값을 0∼255 사이의 정수형 전압으로 환산하여 8비트 즉 바이트 데이터를 만들어 시리얼 인터페이스를 통해 PC 의 Processing 코드인 Arduino_3_Volt에 송신하도록 한다. Processing 코드 Arduino_3_Volt가 아두이노로부터 바이트 데이터를 수신하면 그래픽 아날로그형 미터계의 바늘을 실시간으로 움직여 주게 된다.

noname04.png

한편 이 예제 코드의 전반부는 Processing 코드이며 후반부의 // 로 표시된 아두이노 코드가 첨부되어 있다. 따라서 후반부 코드를 복사하여 별도의 아두이노 코드로 만들어
파일명 Processing_VR_LED_01을 부여하여 저장하도록 한다.

아두이노 코드 Processing_VR_01를 살펴보자. 가변 저항의 입력은 아날로그 핀 A0에서 읽도록 한다. whiteLED = 7 즉 7번 핀에는 빨간색 소형 LED를 배치하였다. PC 의 Processing 코드로부터 request가 유효하다고 판단되면 이 빨간색 소형 LED를 ON 하기로 한다. 실제로 빠른 속도로 점멸하는 양상을 보여 준다.

noname05.png

noname06.png

redLED = 10 은 통신에 에러가 발생하면 켜지도록 코딩되어 있으나 통신 에러가 거의 없는듯하다.
greedLED = 11 은 센서 데이터 request 가 유효하면 즉 빨간색 소형 LED가 ON OFF를 반복하여 실제로 빠른 속도로 점멸하는 양상을 보여 주면 ON 된다.
핀 번호 6번에 RGB LED의 청색 LED 가 배선되어 있으나 코드에서 사용하지 않는다.

실제 배선은 아래의 사진을 참조하자.

noname07.png

아두이노 코드에서는 loop()의 if 제어문에서 Serial.available()을 체크하여 문자 데이터 ‘1’ 이 수신되었는지 확인이 되면 whilteLED를 ON 하고 아날로그 데이터 핀 A0에서 가변 저항의 현재 전압 값을 읽어 온다. 이 값의 범위가 0∼1023 이므로 map() 명령을 사용하여 바이트 데이터인 0∼255 로 변환한다. map() 명려을 사용하지 않으려면 쉽게 4로 나누어도 무방하다. 시리얼 인터페이스를 통해 ‘1,’에 이어서 8비트 데이터 값을 \n 과 함께 출력한다.
이 코드에서는 Serial.print() 또는 Serial.prinln()과 바이트 데이터를 전송하는 Serial.write()이 혼용되고 있으나 잘 작동이 되므로 그대로 사용하도록 한다.

noname08.png

Processing 코드 Arduino_3_Volt 코드를 살펴보자. 위와 같이 Kujawa 란 프로그래머가 이 코드를 작성하였다. 실행시켜 보니 아두이노에서 데이터를 수신하는 부분의 문제만 제외하고 잘 작동하였다. 따라서 수정해야 할 부분만 알아보기로 하자.

noname10.png

헤더 영역에서 계기판 그래픽 처리를 도와 줄 meter와 시리얼 인터페이싱을 지원하는 processing.serial 두 라이브러리를 불러들인다. Meter 의 클라스 명령 접두어 m을 선언한다.

정수형 변수 sensorNumber = 1 일때에 아두이노 코드에서 살펴 보아도 센서라곤 가변 저항 하나이기 때문에 특별한 용도는 어뵤어 보인다. 다만 이 코드를 확장하여 다수의 센서 데이터를 수신하게 될 경우 사용처가 있을 지도 모르므로 그대로 두도록 한다. 아울러 시리얼 인터페이스를 통해 바이트 데이터 송신을 위한 Serial 의 클라스 명을 port1 으로 선언한다. 이 port1 변수는 다음과 같이 코딩한다.

noname11.png

Processing 코드를 실행하여 현재 아두이노가 연결된 COM 포트 번호가 5라는 사실을 알고 있을 경우에는 아래와 같이 직접 “COM5” 를 입력해도 무방하다.

port1 = new Serial(this, "COM5", 9600);

한편 아두이노에서 Serial.println(outputValue) 명령에서 .println 명령 사용에 따라 데이터 하나를 보낼 때마다 반드시 ‘\n’ 이 첨부되므로 port1.bufferUntil(‘\n’) 명령의 조건이 만족되어 그 다음 줄로 넘어간다.

그밖에 클라스 접두어 m을 사용한 명령문들의 의미를 계기판에 나타내 보았으니 참고하기 바란다.

마지막으로 serialEvent() 루틴은 setup()의 bufferUntil() 명령과 연동하여 데이터를 주고 받는데 사용됨에 유의하자.

아두이노와 Processing 코드를 실행하여 가변저항을 돌리면서 전압계 바늘의 움직임을 동영상에서 관찰해 보자. 작은 빨간섹 LED 는 항상 점멸하며 큰 초록색 LED 가 계속 ON 이 되어 있는 상태이다.

//Processing_VR_LED_01 -- 아두이노 코드

// These constants won't change. They're used to give names
// to the pins used:
const int analogInPin = A0; // Analog input pin that the potentiometer is attached to
const int whiteLed = 7;
const int redLed = 10;
const int greenLed = 11;
int sensorValue = 0; // value read from the port

// Setup data buffer.
String inString;
int inByte = 0; // Incoming serial data byte.
int outputValue; // Sensor data to send to Processing.
boolean firstContact = false; // No valid data in buffer.
int i;

void setup() {
pinMode(whiteLed, OUTPUT); // valid sensor request received
pinMode(redLed, OUTPUT); // invalid sensor request
pinMode(greenLed, OUTPUT); // valid sensor request, sent sensor data

// initialize serial communications at 9600 bps:
Serial.begin(9600);
// Wait for serial port to connect. Needed for native USB port only.
while (!Serial) {
; // Do nothing until connection established.
}

while (Serial.available() <= 0) { // No data received.
Serial.println("0,0"); // 아두이노가 초기에 프로세싱에 보내는 데이타
Serial.flush();
delay(500);
}
digitalWrite(redLed, LOW); // 에러면 11번 핀 빨간색 RGB LED ON
}

void loop() {
if (Serial.available() > 0) {
digitalWrite(greenLed, LOW);
// Read serial data
inByte = Serial.read();
if (inByte > 0 && isDigit(inByte)) { // Expecting a "1" from Processing.
digitalWrite(whiteLed, HIGH); // Sensor data request received.
// read the analog voltage
sensorValue = analogRead(analogInPin);
// map it to the range of the analog out:
outputValue = map(sensorValue, 0, 1023, 0, 255);
// Send back the requested results
Serial.print("1,");
Serial.println(outputValue);
digitalWrite(greenLed, HIGH);
digitalWrite(whiteLed, LOW);
}
else {
// Error handling statements
digitalWrite(redLed, HIGH);
}
}
delay(20);
}//끝

//Arduino_3_Volt_01-- Processing code
import meter.;
import processing.serial.
;

Meter m;
boolean deBug = false;

int i = 0; // calculation variables following
boolean dataReceived = false;
int sensorNumber = 1; // Expected by microprocessor.
int sensorValue = 0; // Default for starting.

Serial port1;

void setup() {
size(600, 400);
background(255, 255, 200);

// Open the port that the board is connected to and use the same speed.

println("Available serial ports:");
println(Serial.list());
port1 = new Serial(this, Serial.list()[2], 9600);
// port1 = new Serial(this, "COM5", 9600);

// Set condition to read bytes into a buffer until a newline is received.
port1.bufferUntil('\n');

m = new Meter(this, 125, 25); // Instantiate a meter class.
// Change scale labels to coinside with 0.0 to 3.0 volt sensor range.
String[] scaleLabels = {"0.0", "1.0", "2.0", "3.0"};
m.setScaleLabels(scaleLabels);
m.setDisplayDigitalMeterValue(true);
m.setMaxScaleValue(3.0f);
m.setShortTicsBetweenLongTics(9);
}

void draw() {

// Request new sensor data from microprocessor if previous data has been processed
if (dataReceived == true) {
port1.write('1'); // Send request for sensorNumber data
dataReceived = false; // Waiting for new data

m.updateMeter(sensorValue);

}
}

void serialEvent(Serial port1) {
// The microprocessor should send initial zero value data to begin contact.
// The draw() loop will then request data from the microprocessor.
if (deBug == true) {
println("serialEvent entered");
}
String serialIn = port1.readStringUntil('\n');

// Remove anything but data and commas
serialIn = trim(serialIn);
if (deBug == true) {
println("serialIn: " + serialIn);
}
// Process data from the microprocessor
// Split the line at the commas and convert the data to integers
int sensorData[] = int(split(serialIn, ','));
int sensorDataArrayLength = sensorData.length;
sensorNumber = sensorData[i];
sensorValue = sensorData[i+1];
if (deBug == true) {
println("sensorDataArrayLength: " + sensorDataArrayLength);
for (int i = 0; i < sensorDataArrayLength; i += 2) {
println("Sensor: " + sensorData[i] + " SensorValue: " + sensorData[i+1]);
}
}
dataReceived = true;
}//End