超便利なライブラリ作ったのでこっち使うといいです → 橋本商会 » Android版ArduinoFirmataを作った

——-以下本文

なんか意外と簡単にできたし、まったくやってる人の情報が無いので書いておく。


Nexus7+Arduino(Seeduino)+サーボモータ を動かした


AndroidにArduino等のシリアルデバイスを直つなぎできる。
ADKやUSBホストシールドやIOIOと違って、むずかしい回路やプログラムはいらないし、電源もAndroid側から供給もできる。
マイコン側は単純にシリアル通信するだけ。Android側もUSBシリアルポートを探して接続するだけ。


Nexus7にはUSBポートとは別に充電ポートがあるのでそっちで充電させつつ、デバイス制御もできそう

必要な物は3つ

1. USBホスト機能に対応したAndroid端末
2. USBホストケーブル
3. Arduino等のUSBシリアルデバイス


USBホスト機能に対応したAndroid端末

Android 3.1(タブレット用)や4以上の端末はUSBホスト機能がある。
2012年夏ごろからの端末が該当していて、USBホストシールドやADKが必要なくなった。

Galaxy NexusやGalaxy S3以降でAndroid4以上の端末はokのはず。
Googleが各ベンダになるべくUSBホスト機能を持たせるように働きかけているってsonyの人が言ってた。
最近Nexus SにもAndroid4が配信されたけど、チップセットにUSBホストの機能が無いので無理。


USBホストケーブル

ようするに「AndroidにUSBキーボードやマウスを接続できる」と書いてあるケーブルのこと。
これをUSBポートに接続すると、AndroidはUSBホストモードになる。

USBケーブルは普通4ピンだ。VCC、GND、D+、D-ピンの4つ。
USB mini/microから、5ピンになった。IDピンが増えた。
USBホストケーブルを作るには、IDピンとGNDピンをショートさせるだけでいい。


これを買った。ぴったりで良い。


なお自作も可能。S2 » USBホストケーブルとUSBケーブルの違い にくわしく書いてある。
市販のUSB-マイクロUSB変換コネクタを分解して、IDピンを短絡させてる。


昔のArduinoと今後のArduino

Arduino UNO以降は、AVRマイコン内蔵のUSBシリアル機能を使うようになっている。
Arduino Duemillanove以前は、FTDI社のFT232というUSBシリアル変換ドライバICを使っている。
それぞれ違うデバイスドライバが必要だけど、両方対応できるようにAndroidアプリを実装可能。

このGoogle製ライブラリを使えばいい。勝手にデバイス判別してくれる。
ボーレートの設定とかも扱いやすい関数が揃ってて便利。
usb-serial-for-android – Android USB serial and Arduino device host support library. – Google Project Hosting

これを使わなくてもandroid.hardware.usb.UsbDeviceクラスを使えば自分で実装できるが、ソース見てみればわかるけどげんなりする処理が多いのでusb-serial-for-android.jarを使うのが良いと思います。

AndroidでArduinoとシリアル通信する


usb-serial-for-androidのDownloadsメニューからusb-serial-for-android-v010.jarをダウンロードして、Androidアプリのlibsディレクトリに入れる


AndroidManifest.xml のinternt-filterの中に追加
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />


さらにintent-filterと同列にmeta-dataを作る
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter" />


device_filter.xml を取得する。FTDIチップやArduinoのUSBベンダIDが書いてある。
wget http://usb-serial-for-android.googlecode.com/git/UsbSerialExamples/res/xml/device_filter.xml
mkdir res/xml
mv device_filter.xml res/xml/


接続する。
アクティビティ内で
import java.io.*;
import android.hardware.usb.*;
import com.hoho.android.usbserial.driver.*;

public void onCreate(Bundle savedInstanceState) {
UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
UsbSerialDriver usb = UsbSerialProber.acquire(manager);
if (usb != null) {
try{
usb.open();
usb.setBaudRate(9600);
start_read_thread(); // シリアル通信を読むスレッドを起動
}
catch(IOException e){
e.printStackTrace();
}
}
}


Arduino → Android
シリアル通信で受信したデータを読む。ArduinoでSerial.println(“文字列”)したデータがAndroid側で読める。
public void start_read_thread(){
new Thread(new Runnable(){
public void run(){
try{
while(true){
byte buf[] = new byte[256];
int num = usb.read(buf, buf.length);
if(num > 0) Log.v("arduino", new String(buf, 0, num)); // Arduinoから受信した値をlogcat出力
Thread.sleep(10);
}
}
catch(IOException e){
e.printStackTrace();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}


adb logcat | grep arduino
して見てみましょう。受信できているはず。


Android → Arduino
AndroidからArduinoに文字列「o」や「x」送信する。
while(true){
usb.write("o".getBytes("UTF-8"),1);
Thread.sleep(1000);
usb.write("x".getBytes("UTF-8"),1);
Thread.sleep(1000);
}


接続を閉じる。
try{
usb.close();
}
catch(IOException e){
e.printStackTrace();
}


Arduinoにはこんなのを書いておくと、シリアル通信でoとxが来たらLEDを点灯消灯させたりサーボモータを回したりできる。
char led_pin = 13;
char serial_recv;

void setup(){
pinMode(led_pin, OUTPUT);
Serial.begin(9600);
}

void loop(){
Serial.println(analogRead(0)); // アナログセンサの値をAndroidに送る
while(Serial.available() > 0){
serial_recv = Serial.read(); // シリアル通信を受信
switch(serial_recv){
case 'o':
digitalWrite(led_pin, true); // 基板上のLEDを点灯
analogWrite(11, 200); // サーボ回す
break;
case 'x':
digitalWrite(led_pin, false); // 消灯
analogWrite(11, 20); // サーボ回す
break;
}
Serial.println(serial_recv);
}
delay(10);
}


WiFiでAndroidアプリ開発

ArduinoをAndroidに接続しているとUSBケーブルがさせない。MacからWiFi経由でAndroidにプログラムを書くといい。
Nexus7が同じ無線LAN内の192.168.1.121にあるとする。
設定→タブレット情報→端末の状態 にIPアドレスが書いてある。
AndroidをMacにUSB接続してから
adb tcpip 5555
adb connect 192.168.1.121:5555
adb logcat
USBケーブルを抜く。

あとはもう、adb installもEclipseからのDebug Runも、logcatもWiFiでできるようになってる。


元に戻すには、USBケーブルを接続して
adb usb
これで戻る。


その他の作例

こういうのを作ってる人がいて、参考になった

Android USB Host + Arduino: How to communicate without rooting your Android Tablet or Phone | Using Android in Industrial Automation
android.hardware.usb.UsbDeviceを使ってArduino UNOとシリアル通信している

Android Host – Arduino間シリアル通信の実現 – アトリエのどか
FTDIドライバを使ってArduino Duemillanove以前とシリアル通信してる


9件のコメント

By: 生座本 on 2012 年 12 月 8 日

橋本さん

はじめまして、生座本(オザモト)と申します。

橋本さんもArduinoを扱っていらっしゃるのですね。
僕はついこの間、Arduinoキットを買って、ただ今実践勉強中です。

これからも参考にさせていただきます。

新しい記事お待ちしてますね(^^)

By: 田中 on 2013 年 1 月 1 日

はじめまして、田中と申します。
androidっ初心者なのですが、nexus7をホストにして、arduino unoとの通信をしたいと考えております。
橋本さんの書いていらっしゃる様に、device_filter.xmlを取得する所まではできるのですが、アクティビティ内での記述が良く分かりません。
分からないので、MainActivityのOncreateをオーバーライドするところを、上のソースファイルと書き換えたのですが、ContextやUsbSerialDriverが定義されていないとして、困っております。見当違いなことをしているかもしれませんが、もしよろしければその部分について、詳しく教えていただけるとありがたいです。

By: 田中 on 2013 年 1 月 1 日

橋本さん、先ほどコメントをお送りしたのですが、うまく送れていない可能性があるので、再送させていただきます。
アクティビティ内で・・・という記述の部分なのですが、既存のOncreateの部分を上のコードで書き換えたら、エラーが出てきました(Contecext UsbSerialDriverがないというエラーでした)android初心者で、見当違いなことをしている可能性がありますが、Mainactivityのコードを詳しく教えていただけるとありがたいです。

By: shokai on 2013 年 1 月 1 日

https://gist.github.com/4425125

MainActivityのコードです。試すためだけに書いたので汚いですが・・

By: 田中 on 2013 年 1 月 3 日

橋本さん、ありがとうございます!無事動かすことができました!@shokai

By: 中島 on 2013 年 3 月 12 日

橋下さん、こんちには
はじめまして、中島と申します。
android初心者ですが、いつも同じようなことを考えているのか
毎回ググると、なぜか橋下さんのページに来てしまいます。

自分の環境でも以下のような流れでうまく動作しました。
galaxy nexus -> USB host cable -> i2c(arudino uno) -> servo

いま、やりたいことは、以下のような流れです。
nfc tag card(mifare) -> galaxy nexus -> USB host cable -> i2c -> servo

nfc tag cardをnexusに翳したら、onCreateを実行、cardのIDmを取得し、
そのIDmがアプリに登録されている値と一致したら、i2cとコネクションを張り、servoにシリアルデータを送信する。


この場合、AndroidManifest.xmlをどのように記述すればよいのかわからなくなりました。
とりあえず、以下のような感じで書いているのですが、うまく動作しません。。
... ...
usb関連の設定(橋下さんの本記事内容と同じ設定) ...
nfc関連の設定(以前の橋本さんのphonegap関連の記事を参照) ...


すいませんが、どんなことでも良いので、ご教授ください。

By: T on 2013 年 3 月 12 日

はじめましてTです。
橋本さん、いつもたのしみに拝見しております。

本記事のとおりに以下のような流れで動かすことができました。
galaxy nexus ---------> arudiuno ----------> servo
usbhost

もし、以下のような流れにしたい場合、AndroidManifest.xmlはどのように
記述すればよろしいでしょうか?

nfc tag card --------> galaxy nexus --------> arudiuno --------> servo
touch usbhost

上記の流れでは、なるべくシンプルにIDmやらNDEFなどの情報には一切関与せず、
ただタッチしたらアプリが起動し、usb driverが有効なら、そこにデータをwriteする感じです。

すいませんが、こうしたらいけるかも?程度でよろしいので、ご教授ください。m_m

By: shokai on 2013 年 3 月 13 日

USBデバイス関係の事はAndroidManifestに書かなくて良いです。
この記事に書いてあるのはデバイスを刺した事を認識してアプリを起動させるManifest設定で、
デバイスからの起動ではなく普通にアプリアイコンから起動してもJava部分だけでUSB通信できます。

逆にNFCタグはIntentによるアプリ起動からでしか読み取れません。
つまりNFCタグタッチ→Intentを受信→(アプリ起動する)→JavaでIntentをparseしNTFタグのIDmを読む→JavaでUSBデバイスと通信
という流れになります。

AndroidManifest.xmlはNFCタグのやつでいいです。
まずはノーマルなAndroidManifestでUSBデバイスとの通信を試してみるところからやると良いと思います。

By: T on 2013 年 3 月 14 日

橋本さん、返信ありがとうございます。

とりあえず、AndroidManifest.xmlにはNFCだけ宣言し、
src/../Main*.javaの中でUSBデバイスのハッシュリストから適切なデバイスを取得後、
そのデバイスの使用許可をとり、BroadcastReceiverに登録した関数の中でデバイスにデータを送信するようにしました。
NFCを翳し、ちゃんとサーボが動くことを確認しました。ありがとうございます。

ps. ただ、この方法だと、毎回インタラクティブにデバイスの許可をするためのダイアログが出てきてしまうので
どうにか回避できないものだろうか?と考えていますが、、無理ですよね。。汗;

Comments RSS TrackBack Identifier URI

コメントする