[[12/8]]
* [[ADK 開発環境の構築]] の例題のプログラムを説明します。 [#b4900654]
- https://github.com/takashiyamanoue/AdkArduino01
** プログラムの内容 [#e781b71c]
- Arduino の光センサの状態をAndroid に表示、Android でArduino のLEDを点滅 
** 使い方 [#sd0103e8]
- Arduino とAndroid 端末を USB ケーブルで接続し、Android 端末でこのアプリケーションを起動します。
起動すると、最初、Android ロボットが寝た絵が表示された後、以下のような表示が出ます。
-- &ref(ADK利用プログラムの説明/adkarduino-1.jpg,30%);
- 表示画面上部の [In], [Out] タブで入出力表示を切り替えます。起動した直後は入力データを表示しています。
- 入力表示のとき、
-- a0 ... a7 の下の数字がArduino のアナログ入力ポートの A0 ... A7 の値を示します。
-- Digital Input: の右に並ぶ8つの数字(0 から 7) の背景の色が Arduino のポート 0 ... 7 に入力されたディジタル値を表します。白だったら0で 水色だったら1を表します。
- 出力表示のとき、以下のような画面になります。
-- &ref(ADK利用プログラムの説明/adkarduino-2.jpg,30%);
-- Arduino の 8 から 13 までの 6 のポートへの出力を制御し、表示します。
-- pin8 - pin13 の右が現在の出力を表します。
-- 各 pin のラジオボタンでデジタル出力か、アナログ出力の選択を行います。
-- デジタル出力の場合 [on] をタッチすると、その pin に 約5Vが出力されます。[0ff]をタッチすると、そのpinに約0V が出力されます。
-- アナログ出力の場合、スライドバーの位置で、PWM の比率を 0-255 階調で指定します。
- [Stop] タブを選ぶと、プログラムを終了します。ただし、再起動するとき、Android の設定画面でこのアプリケーションを強制終了しないと、再起動しないことがあります。
** 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.java [#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 を結びつけ、この間の情報交換を可能にします。
--- AdkArduinoActivity と AdkService の間の情報交換は、[[Handler:http://developer.android.com/reference/android/os/Handler.html]]を使って行います。 
** AdkService.java [#jc0dae4f]
- mUsbAccessory を AdkArduinoActivity から受け取り、Arduino との間のデータ交換を永続的に行います。
- Arduino へのデータ出力は、public void outputDevice(byte command, byte target, int value) を使います。
- Arduino からのデータ入力は AdkThread の中の run メソッドのループを通じて行います。
- 内部の IncomingHandler クラスは、AdkArduinoActivity との間の情報交換に使います。
-- Usb 通信に使う FileDescriptor も、このクラスでAdkArduinoActivity から受け取ります。FileDescriptor から、Arduino と通信を行う入出力ストリームを取り出します。 
** AdkThread.java [#q0cd643c]
- AdkService の startThread() により、インスタンスが生成され、run メソッド内の while ループが繰り返し実行されます。
- このループの中で,  Arduino 側からアナログデータが入力されると、そのデータをAdkService を通じて AdkArduinoActivity に送信し、そのデータが表示されます。また、AdkService の 
 arduinoProcessor.processAnalogInput(port, val);
が呼び出されます。
- このループの中で,  Arduino 側からディジタルデータが入力されると、そのデータをAdkService を通じて AdkArduinoActivity に送信し、そのデータが表示されます。また、AdkService の 
 arduinoProcessor.processDigitalInput(dd);
が呼び出されます。
** Arduino-Android(AdkService, AdkThread)間通信 [#fa09b056]
- Arduino から Android へは、以下の4バイトのデータを連続して送ります。
-- 最初の 1 バイト目 :  'a' または 'd' ... アナログデータかデジタルデータを表す。
-- アナログデータの場合の 2,3,4 バイト目の内容
--- 2 バイト目: アナログポート番号
--- 3 ,4 バイト目: 3バイト目の内容 << 8 | 4 バイト目の内容 が、そのポートのアナログ値を表す。 
-- デジタルデータの場合の 2,3,4 バイト目の内容
--- 2 バイト目: Arduino の 0-7 ポート の内容をこの順番で並べた値。
--- 3,4 バイト目: 未使用
- Android から Arduino へデータを送るときは、以下の 3 バイトを送ります。
-- 1 バイト目: 'a' または 'd' ... アナログデータかデジタルデータを表す。
-- 2 バイト目: Arduino のポート番号(8 - 13)
-- 3 バイト目: 値。デジタル値の場合は 0 か 1。アナログ値の場合は 0 - 255。
- AdkService の 
 public void outputDevice(byte command, byte target, int value) 
を使うことにより、アナログ値やディジタル値を送ることができます。引数の command は 'a' か 'd',  target はポート番号, value は値です。
** AdkService-AdkArduinoActivity間通信 [#udce8720]
- AdkService から AdkArduinoActivity(GUI) へは文字列のコマンドと値を
 public void sendCommandToActivity(String c, String v) 
を使って送ります。コマンド c には以下のようなものがあります。
-- set device a <port> <value>
---  Out タブで表示される画面において、pin の <port> 番号の部分のラジオボタンを アナログに設定し、スライドバーの位置を value の値が示す位置に変更します。sendCommandToActivity の第2引数の v は使いません。また、AdkService を通じて、Arduino の<port>pin に PWM で <value> の値を出力します。
-- set device d <port> <value>
--- Out タブで表示される画面において、pin の <port> 番号の部分のラジオボタンを ディジタルに設定し、ディジタルの値を、<value> に変更します。sendCommandToActivity の第2引数の v は使いません。また、AdkService を通じて、Arduino の<port>pin にディジタル値 で <value> の値を出力します。
-- set message 
--- In タブで表示される画面のメッセージ領域に、第2引数の v の値を表示します。
** ArduinoProcess.java [#w6c964c5]
- AdkThread において、Arduino から送られてきたディジタルデータが入力されると、このクラスの 
 public void processDigitalInput(int vals)
が呼び出されます。この中でそれに対応する処理を書くことで、GUI にコマンドを送ったり、Arduino の制御を行なったりすることができます。
- AdkThread において、Arduino から送られてきたアナログデータが入力されると、このクラスの 
 public void processAnalogInput(int port, int val)
が呼び出されます。この中でそれに対応する処理を書くことで、GUI にコマンドを送ったり、Arduino の制御を行なったりすることができます。

- このクラスは以下のようになっていて、processDigitalInput も processAnalogInput も、最初は以下のように、ほとんど空っぽでなにもしません。この中身を埋めることにより、様々な処理を行うことができます。
 public class ArduinoProcessor {
    private static final String TAG = "ArduinoProcessor";
    private AdkService adkService;
    private long lastTime;
    public ArduinoProcessor(AdkService s){ 
 	   adkService=s;
    }
    public void setAdkService(AdkService as){ 
 	   adkService=as;
    }
 
    public void processDigitalInput(int vals){
 	// ADK Accessory からデジタル入力, vals には、Arduino のポート 0-7 の 1 byte の値が入る
 	//	Log.d(TAG,"processDigitalInput-"+vals);
 	   
    }
   public void processAnalogInput(int port, int val){ // ADK Accessory からアナログ入力
 	//	Log.d(TAG,"processAnalogInput-port="+port+" val="+val);
 	   if(adkService==null) return;
 	   if(port==0){
 		   if(val<=10){
 //	this.adkService.parseSetCommand("out-d-8=1");
 		
 		   }
 		   else{
 		   }
 	   }
   }
   public void wait(int t){
 	   try{
 		   Thread.sleep((long)t);
 	   }
 	   catch(InterruptedException e){
 		   
 	   }
   }
 }
----
#counter


トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS