[[FrontPage]]

* 12/8 Arduino と Android の接続 ... ADK [#ffa552f2]
** ADK の概要 [#x88417b5]
- ADK ...Accessory Development Kit
- ADK はAndroid のアクセサリを作成するための、参考的な実装です。これは、ハードウェア会社や電子工作を趣味としている人々のスタートポイントとして利用できます。各ADKのリリースは、ソースコードとハードウェアの仕様が一緒に供給されます。これにより、あなた自身のアクセサリを簡単に作ることができます。新しい、これと異なるADKのハードウェアを作ることを推奨します。 &br;
Android の機能を強化するため、オーディオのドッキングステーションや、運動機器や、個人的な医療検査機器や、電子百葉箱や、その他の外部ハードウェア機器などがAndroid アクセサリとして使えます。&br;
アクセサリは、Android Open Accessory (AOA)プロトコルを使って、USB ケーブルやBluetooth 接続を通じて、Android デバイスと通信します。もし、USB を使うアクセサリを作成する場合、あなたのアクセサリハードウェアとAndroid が通信するために、どのようにAOAプロトコルを実装するか、理解する必要があります。より詳しくは、 [[Android Open Accessory protocol:http://source.android.com/tech/accessories/]] をみてください。
- 参考ページ/文献
-- http://itpro.nikkeibp.co.jp/article/NEWS/20110511/360206/
-- http://developer.android.com/tools/adk/index.html
--  Smartphone World Volume. 3「Android × Arduino 即効プログラミング」CQ出版社
** 簡単なADK応用プログラムの開発例 [#j9744a01]
- http://y-anz-m.blogspot.jp/2011/12/androidhello-adk.html
** ADK 開発環境の構築 [#s8ca8b11]
- http://developer.android.com/tools/adk/adk.html
*** 1. Arduino (1.0 以上)の開発環境をインストール [#w1805f29]
- http://arduino.cc/en/Main/Software
*** 2. ADK パッケージのダウンロード [#nbaea27a]
- https://dl-ssl.google.com/android/adk/adk_release_20120606.zip
*** 3.  Arduino の例題プログラムやライブラリやハードウェアの仕様が入ったパッケージをダウンロードして、解凍 [#l997c43f]
- app, arduino_libs, hardware ディレクトリがある。
-- https://dl-ssl.google.com/android/adk/adk_release_20120606.zip
-- http://developer.android.com/tools/adk/adk.html
*** 4. Arduino開発環境にADKライブラリのインストール [#g5f335b0]
- arduino_libs/AndroidAccessory と arduino_libs/USB_Host_Shield directories を <arduino_installation_root>/libraries/にディレクトリごと、すべてコピー。
*** 5. Arduino のスケッチ(firmware)を作成し、Arduinoに書き込み [#u8adfbb2]
- 以下、ADKの firmware の簡単なスケッチの例(今後、ずっとこれを使います) 
 #include <Max3421e.h>
 #include <Usb.h>
 #include <AndroidAccessory.h>
 /*
  data format
  pin
    A0-A7 ... analog input
  
    4-7 ... digital input
    8-11 ... digital/analog(pwm) output
 
 receive 
 [
   'a' or 'd'
   pin,
   data,
 ]
 
 send
 [
   4 (=data_length(byte)),
   'a' 
   port,
   data(high),
   data(low)
 ]
 or
 [
    4 (=data_length(byte)),
   'd'
   data  (pin 0-7)
   data  (0x00)
   data  (0x00)
 ]
 
 */
 #define analogInMax 8 
 #define digitalInMax 8
 #define digitalOutMax 14
 int analogIns[analogInMax];
 int digitalIns[digitalInMax];
 int digitalOuts[digitalOutMax];
 int digitalVal;
 
 AndroidAccessory acc("Google, Inc.",
 		     "AdkTwitter",
 		     "DemoKit Arduino Board",
 		     "1.0",
 		     "http://www.android.com",
 		     "0000000012345678");
 void setup();
 void loop();
 
 void setup()
 {
    Serial.begin(115200);
    Serial.print("\r\nStart");
    for(int i=0;i<digitalInMax;i++) digitalIns[i]=i;
    for(int i=0;i<digitalOutMax;i++) digitalOuts[i]=i;
 
    for(int i=0;i<digitalInMax;i++)
       pinMode(digitalIns[i],INPUT);
    for(int i=digitalInMax;i<digitalOutMax;i++)
       pinMode(digitalOuts[i],OUTPUT);
 //   pinMode(ledPin, OUTPUT);
 //   pinMode(b3Pin, INPUT);
    analogIns[0]=A0;
    analogIns[1]=A1;
    analogIns[2]=A2;
    analogIns[3]=A3;
    analogIns[4]=A4;
    analogIns[5]=A5;
    analogIns[6]=A6;
    analogIns[7]=A7;
    acc.powerOn();
 }
 
 void loop()
 {
    byte inMsg[3];
    byte outMsg[4];
    if (acc.isConnected()) {
      int len = acc.read(inMsg, sizeof(inMsg), 1);
      int i;
      byte b;
      if(len>0){
        if(inMsg[0]=='a'){
          if(inMsg[1]<digitalOutMax)
             analogWrite(digitalOuts[inMsg[1]], inMsg[2]);
        }
        else
        if(inMsg[0]=='d'){
          if(inMsg[1]<digitalOutMax){
              if(inMsg[2]==1)
                 digitalWrite(digitalOuts[inMsg[1]], HIGH);
              else
                 digitalWrite(digitalOuts[inMsg[1]], LOW);            
          }
        }
      }
      
      digitalVal=0;
      for(int i=0;i<digitalInMax;i++){
        int b=0;
        if(digitalRead(digitalIns[i])==HIGH)
           b=1;
        digitalVal=digitalVal<<1 | b;
      }
      outMsg[0]='d';
      outMsg[1]=digitalVal & 0xff;
      outMsg[2]=0;
      outMsg[3]=0;
      acc.write(outMsg,4);
      int sensorValue;
      for(int i=0;i<analogInMax;i++){
           sensorValue = analogRead(analogIns[i]);
           outMsg[0]='a';
           outMsg[1]=i;
           outMsg[2]=(sensorValue>>8) & 0xff;
           outMsg[3]=sensorValue & 0xff;
           acc.write(outMsg,4);
      }
    }
    delay(100);
 }

*** 6.  Android 側開発環境構築 [#k817d114]
- Eclipse の Android SDK マネージャ のアイコンをクリックして起動し、Android 4.0 ( Google APIs 14 を含む) をインストールします。
-- &ref(12/8/eclipse-adk-1.png,50%);
-- &ref(12/8/eclipse-adk-2.png,30%);
*** 7. Android 側アプリ開発 [#m657b89d]
- Eclipse の上で、UsbAccessory などを使ったAndroid のプロジェクトを作成します。既存の、ソースが公開されているプロジェクトをダウンロードして、それを書き換えることで、開発が比較的楽にできます。ここでは、 https://github.com/takashiyamanoue/AdkArduino01 のページから、ZIP に固められたプロジェクトをダウンロードして利用することにします。
-- &ref(12/8/AdkArduino01GitHub-1.jpg,50%);
- ダウンロードした AdkArduino01-master.zip を解凍します。解凍するとAdkArduino01-master ディレクトリの中に AdkArduino01 ディレクトリが入っています。
- Eclipse を起動し、[File]->[New]->[Other] を選びます。
-- &ref(12/8/Android-eclipse-2.jpg,50%);
- Android Project from Existing Code をクリックし、[Next]ボタンをクリックします。
-- &ref(12/8/Android-eclipse-3.jpg,50%);
- 解凍したディレクトリ内にある AdkArduino01 ディレクトリを選んで、[Finish]をクリックし、Eclipse にダウンロードしたプロジェクトを読み込みます。
-- &ref(12/8/Android-eclipse-4.jpg,50%);
- Eclipse の Package Explorer に org.yamalab.android.AdkArduino01.AdkArdinoLaunch が現れます。この段階では、エラーがあることを示す赤い四角内に白いバツ印のアイコンが表示されています。
-- &ref(12/8/Android-eclipse-5.jpg);
- 読み込んだプロジェクトの properties の android の項目で Google APIs, Platform 4.0, API Level 14 を選びます(講習会で使う ICONIA TAB の場合)。このAPI を選ぶことにより、ADK で利用するUSB アクセサリなどが利用できるようになります。これでエラーが消えます。
-- &ref(12/8/android-eclipse-1.png,25%);
- 読み込んだプロジェクトのソースコードを書き換えます。
-- AdkArduinoActivity.java の
 boolean emulatorDebug= ... ;
の行が
 boolean emulatorDebug= false ;
であった場合、これを
 boolean emulatorDebug= true ;
に書き換えます。このプロジェクトの場合、emulatorDebug を true にすることにより、Arduino との通信を行わないようにしてGUI のデバッグなどが行えるようになります。
*** 8. Eclipse 上のデバッグ [#u84835dc]
- Eclipse のデバッグ機能、 LogCat、Emulator を使ってデバッグします。
*** 9. パッケージの生成、実機へのインストール、実機でのデバッグ [#yd81d0df]
- AdkArduinoActivity.java で
 boolean emulatorDebug= false ;
とし、Package Excplorler の、このプロジェクトを右クリックして、パッケージを作成します。
- Android 端末を USB ケーブルで PC と接続し、 Android 側アプリをAndroid 端末の SDカードに保存し、アプリをインストールします。
-- アストロファイルマネージャなどを利用
*** 10. 実行。 [#q1a71d18]
- 接続
-- Android端末(ICONIA TAB) は電源ケーブルで電源を供給し、USB ケーブルで、Arduino Mega の B 端子(平べったい端子)と接続します。
-- Arduino Mega の A端子(四角い端子)とパソコンをUSB ケーブルで接続し、Arduino Mega に電源を供給します。
-- 接続が終わると、Android 端末に、先ほどインストールした、AdkArduino を起動するか?を尋ねるウィンドウが表示されます。このときは、起動をキャンセルします。
- 起動
-- Android のアプリ一覧を表示し、AdkArduino をタップして起動します。最初、Android ロボットが寝た画像が表示されますが、しばらくすると、デバッグで見た画像に変わり、変化するA0の値などが表示されます。

** プログラムの説明 [#e8ed11de]
*** プログラムの内容 [#e781b71c]
- Arduino の光センサの状態をAndroid に表示、Android でArduino のLEDを点滅 
*** ADK利用の流れ [#n3745f4b]
- 1. BroadcastReceiver を利用して、ACTION_USB_PERMISSION を判定する。
- 2. UsbAccessoryのインスタンスを取得する。
- 3. UsbAccessoryのインスタンスよりParcelFileDescriptorを取得する。
- 4. ParcelFileDescriptorよりFileDescriptorを取得し、FileInputStreamとFileOutputStreamを取得する
- 5. 各Streamを利用し、入出力の処理を行う。
*** Manifest の内容 [#i71ade82]
- Android 端末とADKのデバイスがUsb で接続されるか、または、Android 端末のアプリケーションのリストから、このアプリケーション(AdkArduino01) がクリックされたら、AdkArduinoActivity が起動されます。
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
 	package="org.yamalab.android.AdkArduino01" android:versionCode="1"
 	android:versionName="1.0">
 
 	<uses-sdk android:minSdkVersion="10" android:targetSdkVersion="11" />
 	<uses-permission android:name="android.permission.INTERNET"/>
 	<uses-permission android:name="android.permission.PERSISTENT_ACTIVITY"/>
 	
 	<application android:icon="@drawable/ic_launcher_demokit"
 		android:label="@string/app_name" android:theme="@android:style/Theme.NoTitleBar">
 		<uses-library android:name="com.android.future.usb.accessory" />
 		<activity android:name=".AdkArduinoLaunch" android:label="@string/app_name"
 		    android:configChanges="orientation|keyboardHidden" >
 			<intent-filter>
 				<action android:name="android.intent.action.MAIN" />
 				<category android:name="android.intent.category.LAUNCHER" />
 			</intent-filter>
 		</activity>
 		<activity android:name="org.yamalab.android.AdkArduino01.UsbAccessoryActivity" android:label="AdkArduino"
 			android:taskAffinity="" android:launchMode="singleInstance">
 			<intent-filter>
 				<action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
 			</intent-filter>
 			<meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
 				android:resource="@xml/accessory_filter" />
 		</activity>
 		<activity android:name=".AdkArduinoActivity" android:label="@string/app_name"
 			android:screenOrientation="portrait">
 		</activity>
         <service android:name=".AdkService" />
 	 </application>
 </manifest>
-- UsbAccessoryActivity
--- Usb ケーブルをADKと接続すると、暗黙的 intent が発行され、intent-filter を通じて、UsbAccessoryActivity が起動します。UsbAccessoryActivity は 明示的 intent を使って、AdkArduinoLaunch を起動します。AdkArduinoLaunch は明示的 intent を使って AdkArduinoActivity を起動します。
-- AdkArduinoLaunch
--- Android 端末のアプリケーションのリストから、このアプリケーション(AdkArduino01) がクリックされたら、暗黙的 intent が発行され、AdkArduinoLaunch が起動されます。
--- intent-filter の「android.intent.action.MAIN」は、actionタグの親のactivityが、このアプリケーションのエントリーポイント、開始画面として設定されていることを表します。ランチャーからアプリケーションを起動して、一番最初に表示されるわけです。
--- ランチャーを叩くと、ACTIONが「ACTION_MAIN」であるIntentがアプリケーションに対して投げられ、それを処理できる「android.intent.action.MAIN」のintent-filterを持つactivityがintentを受理し、AdkArduinoLaunch が起動されます。「android.intent.category.LAUNCHER」は、categoryというのはactionを受理する際に付加的な情報を付け加えます(http://blog.haw.co.jp/android/?p=54)。
--- AdkArduinoLaunch は明示的 intent を使って AdkArduinoActivity を起動します。
-- AdkArduinoActivity
--- 本アプリケーションのGUI とUsb 接続開始を担当するクラスです。
-- AdkService
--- Arduino との通信を担当するサービスです。永続的に動作させるため、Service を使っています。
--- AdkArduinoActivity の内部で明示的intent を使って AdkService が起動されます。
*** AdkArduinoActivity [#qae80e20]
- 本アプリケーションの GUI を担当しているクラスです。UsbAccessory の起動なども行います。
- このActivity の起動時に onCreate(), onStart() と共に, onResume() がシステム側から起動されます。
-- onResume() 内で prepareUsbConnection() が呼び出され、prepareUsbConnection() 内で mUsbManager を作成します。
-- また、prepareUsbConnection() では、Usb が接続されたときに、それを認識する準備を行います。この準備により、Usbが接続されたとき、以下の部分によってそれが受信され、Usb との接続が行われます。
     private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver(){
         @Override
         public void onReceive(Context context, Intent intent){
      		Log.i(TAG, "BroadcastReceiver-onRecieve");
        	    String action = intent.getAction();
 			if (ACTION_USB_PERMISSION.equals(action)) {
 	     		Log.i(TAG, "BroadcastReceiver-onRecieve- ACTION_USB_PERMISSION");
 				synchronized (this) {
 					UsbAccessory accessory = UsbManager.getAccessory(intent);
 					if (intent.getBooleanExtra(	UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
 						openAccessory(accessory);
 				        startService();
 				        doBindService();
 					} else {
 						Log.d(TAG, "permission denied for accessory "
 								+ accessory);
 					}
 					mPermissionRequestPending = false;
 				}
 			} else if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
 	     		Log.i(TAG, "BroadcastReceiver-onRecieve- ACTION_USB_ACCESSORY_DETACHED");
 				UsbAccessory accessory = UsbManager.getAccessory(intent);
 				if (accessory != null && accessory.equals(mAccessory)) {
 					closeAccessory();
 				}
 			}
         }
      };
-- openAccessory(accessory); で 入出力ストリームが作成され、startService(); で AdkService を起動します。
--- AdkService が ADK を使って、Arduino との情報交換を行います。
-- doBindService(); は、AdkArduinoActivity と AdkService を結びつけ、この間の情報交換を可能にします。

*** AdkService [#jc0dae4f]
*** AdkThread [#q0cd643c]

*** Arduino-Android(AdkService, AdkThread)間通信 [#fa09b056]
*** AdkService-AdkArduinoActivity間通信 [#udce8720]
*** ArduinoProcess [#w6c964c5]
** デバッグ [#p0b08f6e]
- LogcatViewer [#z89dd6d3]
-- http://d.hatena.ne.jp/bs-android/20100519/1274206549
** Android で、LED 点灯自動制御 [#t0389563]
** 総合演習 [#ydd1ed5b]
- 隣どおし、または前後で2-4人のグループを作って、今までのプログラムを参考にしたり、改造したりして、何か面白いものを作ってください。
----
#counter

トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS