AdSense

2015年4月25日土曜日

Androidでアルコールチェッカーをつくる

アルコールセンサー(MQ-3)をもっと簡単に使いたいと思い、
Arduino経由でAndroidとつなげてみることにしました。


使うもの

・Android端末(Nexus6)
・Arduino UNO
・アルコールセンサー(MQ-3)



まず参考にしたのは、
Androidで簡単にArduinoと接続できるライブラリ

Physicaloid Library
https://github.com/ksksue/PhysicaloidLibrary

それを使ってアルコールセンサーを動かしているPocketDuinoです。

PocketDuino
http://www.physicaloid.com/wiki/doku.php?id=hardware:pocketduino


PocketDuinoがあれば良かったのだけど、既に販売終了しているようなので、
諦めてArduinoでやってみることにしました。



作業開始メモ

1.PysycaloidをEcripseに取り込んでサンプルソフトを実行する。
 しかしながら、シリアルのOpenが出来ない。Arduinoを認識していない模様。

 デバッグしようにも、Android端末のUsbがArduinoでふさがってる。
 なので、Wifiデバッグを試してみる。

 Wifiデバッグのやりかた
 ・PCのとAndroidをUSBで接続し、下記コマンドをうつ
  $ adb tcpip 5555
  $ adb connect 192.168.1.1:5555     ※IPアドレスはAndroidのやつを指定
 ・USBを抜いても、普通にログだしたりできます。
  $ adb shell logcat

 もとに戻すにははadb usbでOK

 無事デバッグ可能になりました。超簡単。

で、ログを見てみると、
UsbHostManagerはデバイス認識しているのだけど、UsbAccessorがpermissionで弾かれている?
デバイス接続が出来ない。


ログ
04-25 13:29:07.970: I/ActivityManager(812): START u0 {flg=0x10000000 cmp=com.android.systemui/.usb.UsbPermissionActivity (has extras)} from uid 1000 on display 0
04-25 13:29:07.973: V/WindowManager(812): addAppToken: AppWindowToken{3c1d4ade token=Token{162dfa19 ActivityRecord{2b414560 u0 com.android.systemui/.usb.UsbPermissionActivity t592}}} to stack=1 task=592 at 0
04-25 13:29:07.995: D/UsbAccessor(13195): Doesn't have permission device(0) : UsbDevice[mName=/dev/bus/usb/003/002,mVendorId=9025,mProductId=67,mClass=2,mSubclass=0,mProtocol=0,mManufacturerName=Arduino (www.arduino.cc),mProductName=null,mSerialNumber=A4139373630351102081,mConfigurations=[


http://developer.android.com/guide/topics/connectivity/usb/host.html
こちらを参考に、intent-filterとか設定してみる。
 →右USBを刺した時に起動されるようになった。そうじゃない。

Permissionが必要なのか?
 →SystemアプリじゃないとUSBのPermissionは設定出来ない。エラーになる。

ソースを解析する。
getPermission()にて、初回起動時はPermissionが無いので、ここでRequest permissionする。

04-25 15:24:48.562: D/UsbAccessor(23353): Request permission : UsbDevice[mName=/dev/bus/usb/003/002,mVendorId=9025,mProductId=67,mClass=2,mSubclass=0,mProtocol=0,mManufacturerName=Arduino (www.arduino.cc),mProductName=null,mSerialNumber=A4139373630351102081,mConfigurations=[


で、画面にPermission許可するダイアログがでる。ここで許可する。
04-25 15:32:16.609: I/ActivityManager(812): START u0 {flg=0x10000000 cmp=com.android.systemui/.usb.UsbPermissionActivity (has extras)} from uid 1000 on display 0

しかし、その後のログで、

04-25 15:25:21.747: D/UsbAccessor(23353): Doesn't have permission device(0) : UsbDevice[mName=/dev/bus/usb/003/002,mVendorId=9025,mProductId=67,mClass=2,mSubclass=0,mProtocol=0,mManufacturerName=Arduino (www.arduino.cc),mProductName=null,mSerialNumber=A4139373630351102081,mConfigurations=[

が出る。許可したはずなのに、Permissionが無いことになる。
↑嘘でした。ちゃんとダイアログでPermissionを許可してやれば大丈夫。xmlのパーミッション許可とか不要。


で、再度Debugで動かして、mSerialのmDeviceをみると、Arduinoがちゃんと接続されていることがわかる。

ただし何故かSerialが開けない。


Physicaloid.javaにて、mSerial openでfalseになる。これが原因ぽい。

ソースを潜ると
UsbCdcConnection.javaのopen()にて、falseを返しているのがおかしい。

どうも、既にOpenになっている場合は、else側に行くのだが、そっちだとFalseを返してしまうようだ。
なので、すでにOpenの場合もTrueを返すようにする。

UsbCdcConnection.javaを下記に修正
public boolean open(UsbVidPid ids, boolean isCdcAcm, int ch) {
if(ids == null) return false;
int devNum = 0;
int chNum = 0;
for(UsbDevice usbdev : mUsbAccess.manager().getDeviceList().values()) {
if(usbdev.getVendorId() == ids.getVid()) {
if(ids.getPid() == 0 || ids.getPid() == usbdev.getProductId()) {
for(int intfNum=0; intfNum < usbdev.getInterfaceCount(); intfNum++) {
if( (isCdcAcm && (usbdev.getInterface(intfNum).getInterfaceClass() == UsbConstants.USB_CLASS_CDC_DATA))
|| !isCdcAcm) {
if(ch == chNum) {
if(!mUsbAccess.deviceIsConnected(devNum)) {
if(mUsbAccess.openDevice(devNum,intfNum,ch)) {
if(DEBUG_SHOW){ Log.d(TAG, "Find VID:"+Integer.toHexString(usbdev.getVendorId())+", PID:"+Integer.toHexString(usbdev.getProductId())+", DevNum:"+devNum+", IntfNum:"+intfNum); }
mUsbConnectionEp.put(ch,new UsbCdcConnectionEp(mUsbAccess.connection(ch), getEndpoint(devNum, intfNum, UsbConstants.USB_DIR_IN), getEndpoint(devNum, intfNum, UsbConstants.USB_DIR_OUT)));
mCdcAcmInterfaceNum = intfNum;
return true;
}
}else{
return true; //********here*********
}
chNum++;
view raw gistfile1.java hosted with ❤ by GitHub


すると今度はInitのcontrolTransfer()で失敗する。

http://android.ohwada.jp/archives/tag/mbed
ここを参考にさせてもらうと、
Arduino Uno では、CDC ACM は、Interface 0 固定らしい。
元のソースでは変数mInterfaceNumになってて、これが1だったのが間違い。
これも0にしてやる。

2箇所でcontrolTransfer()が使われてるので、どちらも0にする。


UartCdcAcm.java

/**
* Initializes CDC communication
* @return true : successful, false : fail
*/
private boolean init() {
if(mConnection == null) return false;
//int ret = mConnection.controlTransfer(0x21, 0x22, 0x00, mInterfaceNum, null, 0, 0); // init CDC
int ret = mConnection.controlTransfer(0x21, 0x22, 0x00, 0, null, 0, 0); // init CDC for Arduino Uno
Log.d(TAG, "init:" + ret);
if(ret < 0) {
if(DEBUG_SHOW) { Log.d(TAG, "Fail to Init controlTransfer()"); }
return false;
}
return true;
}
view raw gistfile1.java hosted with ❤ by GitHub
/**
* Sets baudrate
* @param baudrate baudrate e.g. 9600
* @return true : successful, false : fail
*/
public boolean setBaudrate(int baudrate) {
byte[] baudByte = new byte[4];
baudByte[0] = (byte) (baudrate & 0x000000FF);
baudByte[1] = (byte) ((baudrate & 0x0000FF00) >> 8);
baudByte[2] = (byte) ((baudrate & 0x00FF0000) >> 16);
baudByte[3] = (byte) ((baudrate & 0xFF000000) >> 24);
//int ret = mConnection.controlTransfer(0x21, 0x20, 0, mInterfaceNum, new byte[] {
int ret = mConnection.controlTransfer(0x21, 0x20, 0, 0, new byte[] {
baudByte[0], baudByte[1], baudByte[2], baudByte[3], 0x00, 0x00,
0x08}, 7, 100);
if(ret < 0) {
if(DEBUG_SHOW) { Log.d(TAG, "Fail to setBaudrate"); }
return false;
}
mUartConfig.baudrate = baudrate;
return true;
}
view raw gistfile1.java hosted with ❤ by GitHub


これでようやくSerialがOpenできるようになる。
こうして無事アルコールセンサーの値がとれました。

組み合わせだけでいけると思ってましたが、意外に時間がかかりました。

まとめ:

1.AndroidアプリはPocketDuino用に作られたのを流用させてもらう

https://github.com/ohwada/PocketDuino

2.AndroidからArduinoを認識させるためにPhysicaloid Libraryをつかう

https://github.com/ksksue/PhysicaloidLibrary/tree/master/SampleProjects

 ただしこのままでは動かない。Arduino Uno用に上述した変更が必要。

3.ArduinoのスケッチもPocketDuino用に作られたのを流用。

https://github.com/ohwada/PocketDuino

  Sparkfunのサンプルでも良い
  http://wiring.org.co/learning/basics/airqualitymq135.html

4.アルコールセンサーはこちら

https://www.sparkfun.com/products/8880

  回路図は下記を参考
  http://wiring.org.co/learning/basics/airqualitymq135.html
  http://bildr.org/2013/10/mq3-arduino/


無事、簡易アルコールチェッカーができました。

Androidの電源だけで、Arduinoとアルコールセンサが動いています。


2 件のコメント:

  1. Dear author:
    Thanks a lot. I have the same issues to you when I use the library. Your solution is very helpful to me.

    返信削除
    返信
    1. Thank you for your comment. I'm glad you're with useful.

      削除