JAVA > Tip&Tech > 아두이노(Arduino)와 자바(Java) 통신 RXTX
 
JAVA
Library
Tip&Tech
Q&A
java공식사이트
Java  Platform Standard Edition 6 의 API 스펙
Tip&Tech
  HOME > JAVA > Tip&Tech
 
작성일 : 14-03-18 19:05
아두이노(Arduino)와 자바(Java) 통신 RXTX
 글쓴이 : 덩벙이 (211.♡.155.27)
조회 : 2,242   추천 : 0   비추천 : 0  

아래와 같이 세팅하고 이클립스에서 돌려봤는데 잘 동작합니다. 퍼온자료입니다. 저는 이클립스로 테스트해서 rxtx자바 라이브러리를 다운받고 제컴환경인 64bit windows에 맞게 dll, path추가, jar 복사, 마지막으로 이클립스에서 외부라이브러리에 등록하니 잘 돌아갑니다. 나중에 웹에 물려봐야 겠네요^^

아두이노(Arduino)와 자바(Java) 통신

오늘은 한번 자바 프로그램으로 아두이노를 제어하는 방법에 대해서 살펴보도록 하겠다.

 

아두이노는 아두이노 IDE를 자바로 구현하였다. 그래서 아두이노와 자바의 연결에 대해 아주 간단하게 처리할 수 있도록 RXTX 자바 라이브러리[다운로드]를 제공하고 있다. 이 라이브러리는 자바 Communications API와 매우 유사하다.

 

RXTX 자바 라이브러리를 사용함에 있어서 먼저 유의해야 할 것은 이전에 사용하고 있었던 시리얼 포트를 기억하는 API가 지원되지 않으므로 코딩시 당신의 아두이노가 사용하고 있는 포트를 알아야 한다는 것이다. 마지막으로 사용자가 사용한 포트를 당신의 프로그램에서 기억하게 하는 것을 구현하여 사용하도록 하면 좋을 것이다. 이것에 대해서는 빠르고 쉽게 데이터를 로컬 파일에 저장시키고 다시 검색할 수 있게 지원하는 자바 Preferences API를 이용하는 것이 좋을 것이다.

 

아두이노 보드 설정

 

아두이노 보드가 자바 프로그램과의 통신을 위해 하는 일은 Serial 통신에 대한 게시물에서 소개한 것과 같은 방법으로 setup()함수에서 Serial.begine()함수로 통신 속도를 정한 후 loop()함수에서 Serial.read(), Serial.print() 등의 함수로 데이터를 주고 받는 것이다. 이것에 대한 자세한 것은 "아두이노와 컴퓨터를  Serial을 이용해 통신하기"에서 살펴보기 바란다.

 

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

void loop(){
    Serial.println("Hello world");
    delay(1000);
}

 

위의 스케치를 아두이노 보드에 업로드 한다.

 

RXTX 라이브러리 설정

 

RXTX 라이브러리는 RXTXcomm.jar 파일과 운영체제별로 지원하는 JNI 라이브러리로 구성되어 있다. 자바 프로그램이 이 라이브러리를 사용하게 하려면 JNI 라이브러리를 자바 가상머신이 참조할 수 있고 RXTXcomm.jar에 있는 클래스와 인터페이스를 자바 클래스가 참조할 수 있도록 classpath에 지정하는 것이다.

 

그러므로 설정하는 방법은 2가지가 있다. 첫 번째는 java 의 JNI 라이브러리의 위치를 지정하는 -Djava.libraries.path 와 클래스들의 위치를 지정하는 -cp 옵션을 사용하는 것이다. 만약 당신이 윈도우즈를 사용하고 있고 RXTX 자바 라이브러리를 다운로드 받아 C:\rxtx-2.2pre2-bins에 압축을 풀었다면 뒤에 있는 자바 예제를 다음과 같이 컴파일하고 실행하면 된다.

 

javac -cp C:\rxtx-2.2pre2-bins\RXTXcomm.jar SerialTest.java

java -Djava.libraries.path=C:\rxtx-2.2pre2-bins\win32 -cp C:\rxtx-2.2pre2-bins\RXTXcomm.jar SerialTest

 

두 번째는 운영체제에 설치된 자바가 빌트인으로 참조하는 디렉토리에 RXTX 자바 라이브러리를 복사해 놓는것이다. RXTX 자바 라이브러리를 압축푼 디렉토리를 보면 각 운영체제 별로 JNI 라이브러리 파일이 구분되어 있으므로 해당 운영체제의 것을 다음과 같이 복사한다.

 

윈도우즈 32비트

 

  • win32/rxtxSerial.dll 을 C:\Windows\System32에 복사
  • 혹은 rxtxSerial.dll 이 포함되어 있는 디렉토리를 PATH 환경 변수에 추가
  • RXTXcomm.jar는 [JavaHome]\jre\lib\ext에 복사

 

윈도우즈 64비트

 

  • win32/rxtxSerial.dll 을 C:\Windows\SysWOW64에 복사
  • 혹은 rxtxSerial.dll 이 포함되어 있는 디렉토리를 PATH 환경 변수에 추가
  • RXTXcomm.jar는 [JavaHome]\jre\lib\ext에 복사

 

리눅스

 

  • i686-pc-linux-gnu에 있는 모든 파일을 /jre/lib/i386에 복사
  • RXTXcomm.jar는 /jre/lib/ext에 복사
  • 만약 64비트를 사용한다면 x86_64-unknown-linux-gnu에 있는 파일들을 사용하기 바란다.

 

맥 OS X

 

  • RXTXcomm.jar를 /Library/Java/Extensions에 복사
  • mac-10.5/librxtxSerial.jnilib를 /Librarya/Java/Extensions에 복사
  • 혹은 librxtxSerial.jnilib 파일이 포함되어 있는 디렉토리를 DYLD_LIBRARY_PATH 환경변수에 추가
  • 만약 64비트를 사용한다면 http://blog.iharder.net/2009/08/18/rxtx-java-6-and-librxtxserial-jn... 에서 컴파일 된 것을 다운받아 사용하기 바란다.

 

샘플 자바 코드

 

다음은 아두이노에서 제공하는 자바 샘플 코드이다. 이 코드를 복사하여 SerialTest.java 파일명으로 저장하기 바란다. 그리고 PORT_NAMES의 포트 이름을 당신의 아두이노가 연결된 시리얼 포트로 변경해야 한다.

 

import java.io.InputStream;
import java.io.OutputStream;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import java.util.Enumeration;

public class SerialTest implements SerialPortEventListener {
    SerialPort serialPort;
        /** 당신의 아두이노와 연결된 시리얼 포트로 변경해야 한다. */
    private static final String PORT_NAMES[] = {
            "/dev/tty.usbserial-A9007UX1"// Mac OS X
            "/dev/ttyUSB0"// Linux
            "COM3"// Windows
            };
    /** 포트에서 데이터를 읽기 위한 버퍼를 가진 input stream */
    private InputStream input;
    /** 포트를 통해 아두이노에 데이터를 전송하기 위한 output stream */
    private OutputStream output;
    /** 포트가 오픈되기 까지 기다리기 위한 대략적인 시간(2초) */
    private static final int TIME_OUT = 2000;
    /** 포트에 대한 기본 통신 속도, 아두이노의 Serial.begin의 속도와 일치 */
    private static final int DATA_RATE = 9600;

    public void initialize() {
        CommPortIdentifier portId = null;
        Enumeration portEnum = CommPortIdentifier.getPortIdentifiers();

        // 당신의 컴퓨터에서 지원하는 시리얼 포트들 중 아두이노와 연결된
                // 포트에 대한 식별자를 찾는다.
        while (portEnum.hasMoreElements()) {
            CommPortIdentifier currPortId = (CommPortIdentifier) portEnum.nextElement();
            for (String portName : PORT_NAMES) {
                if (currPortId.getName().equals(portName)) {
                    portId = currPortId;
                    break;
                }
            }
        }

        // 식별자를 찾지 못했을 경우 종료
        if (portId == null) {
            System.out.println("Could not find COM port.");
            return;
        }

        try {
            // 시리얼 포트 오픈, 클래스 이름을 애플리케이션을 위한 포트 식별 이름으로 사용
            serialPort = (SerialPort) portId.open(this.getClass().getName(),
                    TIME_OUT);

            // 속도등 포트의 파라메터 설정
            serialPort.setSerialPortParams(DATA_RATE,
                    SerialPort.DATABITS_8,
                    SerialPort.STOPBITS_1,
                    SerialPort.PARITY_NONE);

            // 포트를 통해 읽고 쓰기 위한 스트림 오픈
            input = serialPort.getInputStream();
            output = serialPort.getOutputStream();

            // 아두이노로 부터 전송된 데이터를 수신하는 리스너를 등록
            serialPort.addEventListener(this);
            serialPort.notifyOnDataAvailable(true);
        } catch (Exception e) {
            System.err.println(e.toString());
        }
    }

    /**
     * 이 메서드는 포트 사용을 중지할 때 반드시 호출해야 한다.
     * 리눅스와 같은 플랫폼에서는 포트 잠금을 방지한다.
     */

    public synchronized void close() {
        if (serialPort != null) {
            serialPort.removeEventListener();
            serialPort.close();
        }
    }

    /**
     * 시리얼 통신에 대한 이벤트를 처리. 데이터를 읽고 출력한다..
     */

    public synchronized void serialEvent(SerialPortEvent oEvent) {
        if (oEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
            try {
                int available = input.available();
                byte chunk[] = new byte[available];
                input.read(chunk, 0, available);

                // 바로 출력
                System.out.print(new String(chunk));
            } catch (Exception e) {
                System.err.println(e.toString());
            }
        }
        // 다른 이벤트 유형은 무시한다. 만약 당신이 필요한 이벤트가 있으면 추가하면된다.
        // 다른 이벤트에 대한 것은 SerialPortEvent 소스를 참조
    }

    public static void main(String[] args) throws Exception {
        SerialTest main = new SerialTest();
        main.initialize();
        System.out.println("Started");
    }
}

 

[소스 다운로드]

 

위의 코드는 오직 데이터가 있을 때만 호출하므로 CPU 오버헤드가 매우 낮다. (위의 코드는 한글 주석이 있어 아마 컴파일시 파일 인코딩이 운영체제와 안맞아 에러가 발생할 수 있다. 만약 그렇다면 [소스 다운로드]를 선택하여 다운로드 받은 소스를 이용하기 바란다.)

 

샘플 사용하기

 

만약 자바 가상 머신이 자동으로 인식하는 디렉토리에 복사해놓았다면 다음과 같이 간단하게 컴파일하여 사용하면 된다.

 

javac SerialTest.java
java SerialTest

 

그러나 복사해놓지 않았다면 다음과 같이 옵션을 이용해야 한다. (RXTX 자바 라이브러리의 RXTXcomm.jar 파일과 운영체제의 JNI 라이브러리가 자바 소스와 같은 디렉토리에 있다고 가정한다.)

 

javac -classpath RXTXcomm.jar:. SerialTest.java
java -Djava.library.path=. -cp RXTXcomm.jar:. SerialTest

 

만약 당신이 맥 OS X의 64비트를 사용한다면 위에서 소개한 링크에서 JNI 라이브러리를 다운받았을 것이다. 그러나 이 라이브러리는 2.1-7 버전을 지원한다. 그러므로 만약 2.2pre2 버전이면 에러가 발생하므로 2.1-7 버전을 다운받아 사용하기 바란다.

 

그리고 2.1-7을 사용한다면 RXTX 라이브러리의 lock 파일이 /var/lock 디렉토리에 생성하도록 구현되어 있다. 그러나 이 디렉토리는 관리자 권한이 있어야 접근할 수 있다. 그러므로 실행시 다음과 같이 sudo 를 앞에 붙이고 실행시켜야 한다.

 

sudo java -Djava.library.path=. -cp RXTXcomm.jar:. SerialTest

 

마지막으로 다음과 같은 에러가 발생할 수 있다.

 

gnu.io.PortInUseException: Unknown Application

 

이것이 발생하면 lock 파일이 위치할 /var/lock 디렉토리가 없기 때문이다. 만약 없으면 자바 애플리케이션에서 /var/lock 디렉토리의 존재 유무를 체크한 후 없으면 디렉토리를 생성하도록 구현한다.

 

만약 성공하면 다음과 같이 터미널 창에 Hello world가 출력될 것이다.


 
 

Total 13
번호 제   목 글쓴이 날짜 추천 비추천 조회
13 [안드로이드 스튜디오] 퍼미션 부분 정리 덩벙이 09-08 0 0 113
12 콘솔에서 jar파일 만들기 덩벙이 09-05 0 0 107
11 아두이노(Arduino)와 자바(Java) 통신 RXTX 덩벙이 03-18 0 0 2243
10 진수변환 16진수를 10진수로 10진수를 16진수로 덩벙이 03-18 0 0 1606
9 java.util.Timer 를 사용하여 잡 스케줄링 하기 덩벙이 06-07 0 0 7406
8 JAVA C++참조 덩벙이 05-04 0 0 5369
7 java soap 사용하기 덩벙이 05-03 0 0 5311
6 java socket(소켓) 샘플코드 덩벙이 02-16 0 0 6199
5    java socket(소켓) 샘플코드 덩벙이 06-08 0 0 7529
4 자바관련 추천사이트 덩벙이 12-16 0 0 5141
3 java 인코딩 테스트를 한번에 (한글깨졌을때, 한글깨짐..) 덩벙이 08-19 0 0 13507
2 byte 단위로 문자열자르기1 덩벙이 07-13 0 0 10875
1 byte 단위로 문자열자르기 덩벙이 07-13 0 0 8258
 
개인홈페이지 덤벙닷컴은 프로그래머와 디자이너위한 IT커뮤니티 공간입니다.
Copyright ⓒ www.dumbung.com. All rights reserved.