아두이노와 안드로이드를 USB-시리얼 통신으로 연결하는 방법 (OTG 케이블 사용)

아두이노와 안드로이드의 유선 연결은 크게 두 가지 방법이 있습니다. 

  1. 안드로이드의 USB Host 기능을 이용한 시리얼 통신 방법 
  2. ADK(Accessory Development Kit)을 이용한 연결 방법

그런데 2번 ADK 의 경우는 아두이노, 안드로이드 설정/조건이 까다롭고, 비싸고, 복잡한 관계로 다음에 분석하기로 하고(잘 모르기도 하고여기서는 가장 간단한 방법인 1번 USB Host 기능을 이용한 시리얼 통신 방법을 설명하겠습니다. 1번 방법은 안드로이드가 PC 역할을 하는 방법인데 OTG 케이블과 USB 케이블만 있으면 쉽게 아두이노와 통신이 가능합니다.

(이미지 출처 : http://blog.nemesys.co.kr/tt/entry/%EC%98%B5%ED%8B%B0%EB%A8%B8%EC%8A%A4-G-%ED%94%84%EB%A1%9C-OTG-%EA%B8%B0%EB%8A%A5-%ED%99%9C%EC%9A%A9%EB%B0%A9%EB%B2%95)

위 사진처럼 1번 방법은 (안드로이드 – OTG 케이블 – USB 케이블 – 아두이노) 순서로 연결됩니다. 안드로이드의 USB Host 기능을 이용하는 방법인데, 안드로이드 기기가 PC처럼 USB Host 기능을 해주는 것입니다. 이 기능이 아마 허니컴 버전 이상에서만 지원 될 겁니다.(제조사별로 차이가 있을듯 합니다.) 휴대폰과 연동하신다면 4.0 버전 ICS 이상에서 해보시길 권장합니다.

 

 

1. 아두이노

 

아두이노를 PC와 연결해서 시리얼 통신하는 것과 마찬가지로 USB 케이블과 OTG를 통해 안드로이드에 연결됩니다. 따라서 아두이노에서는 스케치를 작성할 때 시스템에서 기본으로 제공하는 Serial 통신 함수인 read(), write(), print(), println() 을 그대로 사용하면 됩니다. 

다만 이때 사용되는 버퍼가 1byte 배열임을 고려해야 합니다. 아두이노의 int 사이즈가 2byte 이므로 255 이상의 값을 송수신 한다면 어떻게 보내고 어떻게 받을지에 대한 적절한 고려가 필요합니다. (특히 음수나 실수의 경우)

 

 

2. 안드로이드

 

편의를 위해 안드로이드 앱을 미리 작성해 두었습니다. 안드로이드 앱은 다은과 같은 기능을 지원합니다.

  • a0.7823z  처럼 a~z 로 감싸여진 문자가 들어오면 UI 상단에 큰 폰트로 표시해 줍니다.
    예) a0.7823z 수신 ==> 0.7823 을 표시
  • 그 외의 데이터는 표시되지 않습니다. 더하고 싶은 기능이 있는 경우 소스코드를 직접 수정하셔야 합니다.
  • 하단의 4개의 버튼을 누를 경우 b1, b2, b3, b4 문자가 연결된 장치로 전송됩니다.

 

앱을 사용하는 방법은 아래와 같습니다. GitHub에서 예제로 만든 프로젝트를 다운로드 합니다.

https://github.com/godstale/Arduino-Serial-Controller

 

아래 링크에서 안드로이드 Host 연결을 지원하는 드라이버 소스코드를 다운로드 합니다. 둘 중 하나를 받으세요.

 

소스코드를 모두 받으면 아래 순서로 빌드해 볼 수 있습니다.

  1. usb-serial-for-android 드라이버 소스코드를 적당한 곳에 압축을 풉니다. 
  2. Eclipse 에서 Arduino Serial Controller 안드로이드 프로젝트를 불러옵니다.
  3. usb-serial-for-android 드라이버를 프로젝트에 넣어줘야 합니다. 프로젝트 이름에서 마우스 우클릭 후 [Build PathLink source]를 선택합니다. 그리고 드라이버 소스코드가 있는 경로를 지정해 줍니다. 이때 드라이버 소스코드 폴더 안에 있는 아래 폴더를 선택해 줍니다.
    [ Android\usbSerialForAndroid\src\main\java ]
  4. 빌드를 해보고 에러가 없는지 확인합니다.
  5. 앱을 실행해서 안드로이드 폰에서 확인합니다.

 

소스 전체를 보기는 힘드니 중요한 부분만 보도록 하겠습니다.

USB 장치가 OTG 케이블을 통해 연결되면 vendor-id와 product-id에 따라서 이 장치와 연결될 앱을 설정하는 부분이 있습니다. [res / xml / device_filter.xml] 파일에 기록된 아래와 같은 내용이 이런 역할을 합니다.

  • … 
  • <usb-device vendor-id=”9025″/> 
  • … 

하지만 device filter 는 우리가 처리할 usb device 목록일 뿐이고 앱이 이걸 처리할 수 있도록 연결해 주는 건 AndroidManifest.xml 파일입니다. 이 파일안에 아래 intent-filter 설정과 uses-feature 설정이 들어가야 합니다. 

        <!— 이 부분이 추가되는 부분 –>
        <uses-feature android:name=”android.hardware.usb.host” /> 
<!— 요기까지 –> 

        <activity
android:name=”com.mlab.aduinocontroller.AduinoControllerActivity”
android:label=”@string/app_name” >

<intent-filter>
<action android:name=”android.intent.action.MAIN” /> 

                <category android:name=”android.intent.category.LAUNCHER” />
</intent-filter>

<!— 이 부분이 추가되는 부분 –>
            <intent-filter> 
                <action android:name=”android.hardware.usb.action.USB_DEVICE_ATTACHED” /> 
            </intent-filter> 
            <meta-data 
                android:name=”android.hardware.usb.action.USB_DEVICE_ATTACHED” 
                android:resource=”@xml/device_filter” />        

<!— 요기까지 –>

</activity> 

 

이 단계에서 문제가 있다면 앱을 실행하고 아두이노를 연결한 다음 디바이스 목록을 얻어오고 아두이노 디바이스를 open 하는 단계에서 퍼미션 에러가 나거나 exception 이 발생합니다. 

 

여기까지 확인 되었으면 이제 실제 USB 장치와 통신할 수 있도록 port를 생성하고 컨트롤하는 부분을 보겠습니다. USB 장치와 통신하기 위한 준비과정과 통신을 도와주는 함수는 모두 SerialConnector.java 클래스에 들어 있습니다.

SerialConnector 클래스에 initialize() 함수가 있습니다. 여기서 USB 장치가 연결되면 FTDI 모듈에 맞는 드라이버를 통해 통신할 준비를 합니다. 불필요한 부분들을 지우고 보면 아래와 같은 순서로 진행됩니다.

		UsbManager manager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
		List<UsbSerialDriver> availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager);
		mDriver = availableDrivers.get(0);
		UsbDeviceConnection connection = manager.openDevice(device);
		mPort = mDriver.getPorts().get(0);
		try {
			mPort.open(connection);
			mPort.setParameters(9600, 0, 0, 0);		// baudrate, dataBits, stopBits, parity
		} catch (IOException e) {
		}
		// Everything is fine. Start serial monitoring thread.
		startThread();

UsbSerialPort 인스턴스인 mPort 를 눈여겨 보세요. 연결이 제대로 설정되면 이후부터 데이터를 주고 받는 작업은 모두 mPort를 이용해서 이루어집니다. 마지막에 startThread() 함수가 호출되면서 SerialMonitorThread 가 실행됩니다. 이 thread는 앱이 켜져있는 동안 데이터가 들어온게 있는지 확인하는 작업을 무한 반복 합니다. SerialMonitorThread 의 run() 을 보시면 데이터가 들어온 경우 UI에 들어온 데이터를 보내주도록 작성되어 있습니다.

 

반대로 데이터를 연결된 장치로 보낼 때는 필요할 때 sendCommand() 만 호출해주면 됩니다.

mPort.write(cmd.getBytes(), cmd.length());		// Send to remote device

안드로이드에 아두이노가 연결되어 있다면 아두이노에서 데이터가 오는지 계속 체크하고 있겠죠.

 

주의!! usb-serial-for-android 는 FT232R, ATmega8u2, CH34x 등의 FTDI 모듈을 지원하는 것으로 되어있지만 실제 연결해보면 에러가 발생하는 경우도 많습니다. 각자가 사용하는 FTDI 모듈에 따라 연결되지 않을 수도 있으며 이 경우 직접 디버깅을 하셔야 합니다.

 

You may also like...