ArduinoのADT対応スクリプト言語Sarida
ADTに対応したスクリプトの作成をしていました。基本的にLuaridaと同じですが、ADTはAndroid Ver2.3.4以降対応なので、Luaridaとは別物の姉妹プロジェクトとしてSaridaという名前で作っていきたいと思っています。
また、ADTは接続相手のマイコンや基板によって、少しずつ使用が変わるかもしれないので、Saridaという名前の後ろにサプコードをつけています。
今回のArduino用スクリプトはSarida_Ard1としました。先ずは、動作しているところの動画から。
Arduinoプログラム
現在、Sarida_Ard1に接続しているArduinoは、Duemilanoveです。これにUSBシールドを載せています。Arduinoのプログラムはブログの最後に書きます。いずれGitHubに公開する予定です。
Saridaの概要
Saridaは動画にあるようにADT接続されると自動的に起動します。そして、Luaridaと同様なメニュが出て、スクリプトを選択するとプログラムが走ります。
Arduinoを接続しないでSaridaを起動すると、下記のようなメッセージが出ます。
プログラムを作成するときは、Arduinoが接続されていなくても動作させたいこともあるので、選べるようにしました。ここで「いいえ」を選ぶと、Sarida_Ard1は終了します。
「はい」を選ぶと、プログラムが起動します。Arduinoとの通信は無視されて動作します。
サンプルプログラムは、「オープンソース」を使ってみよう (第18回 ADK編) 日本Androidの会神戸支部において吉田 研一さんが紹介されているAdkDaioProjと全く同じ動作をするスクリプトを書きました。
プログラムは下記です。
------------------------------------------ --ADK Daio Proj ------------------------------------------ --関数宣言-------------------------------- main={} --mainメソッド pictureInit={} --画像データの初期化 display={} --画面に表示する --グローバル変数宣言---------------------- Gwidth, Gheight = canvas.getviewSize() Btn = { x=0, y=0, val=0 } BtnNum = 2 Bar = { x=0, y=0, val=0, len=0, ofsx=0 } PwmNum = 3 Sw = { x=0, y=0, val=0, fon=16, txt={"OFF", "ON"} } SwNum = 4 An = { x=0, y=0, val=0 } AnNum = 0 ------------------------------------------ mt={} mt.__newindex=function(mtt,mtn,mtv) dialog( "Error Message", "宣言していない変数 "..mtn.." に値を入れようとしています", 0 ) toast("画面タッチで実行を続けます", 1) touch(3) end mt.__index=function(mtt,mtn) dialog( "Error Message", "変数 "..mtn.." は宣言されていません", 0 ) toast("画面タッチで実行を続けます", 1) touch(3) end setmetatable(_G,mt) --------以下が実プログラム---------------- ------------------------------------------ -- 画像の初期化 ------------------------------------------ function pictureInit() --ワーク画像エリアのクリア canvas.workCls() --ワークエリアの(0,0)-(122,41)に画像を読み込みます if( canvas.loadBmp( system.getAppPath().."/adkdaioprj.png", 0, 0,122, 41 )==-1)then dialog( system.getAppPath().."/adkdaioprj.png", "ロードに失敗しました",1 ) system.exit() return end --スプライトセットします sprite.init() sprite.clear() sprite.define( 1, 0, 0, 53, 41) --OFFボタン sprite.define( 2, 54, 0, 107, 41) --ONボタン --スライドバーを描いてワーク画像に取得します Bar.len = math.floor(Gwidth*0.85 +0.5) canvas.putCls( color(155,155,155) ) canvas.putRect( 0, 0, Bar.len, 20, color(76,76,76), 1) canvas.getg( 0, 0, Bar.len, 20, 0, 43, Bar.len, 43+20 ) sprite.define( 3, 0, 43, Bar.len, 43+20) --スライドバー下 sprite.define( 4, 108, 0, 122, 25) --スライドバーつまみ --ボタンの初期配置 Btn.x = math.floor(Gwidth/2+0.5) Btn.y = math.floor(Gheight/2-40) adk.digitalWrite(BtnNum, Btn.val) --スライドバーの初期化 Bar.x = math.floor(Gwidth/2+0.5) Bar.y = math.floor(Gheight/2+20) Bar.val = 0 sprite.move( 3, 2, Bar.x, Bar.y ) --スライドバー下(常時表示) Bar.ofsx = (Gwidth-Bar.len) / 2 adk.analogWrite(PwmNum, Bar.val*255) --スイッチ表示初期化 Sw.x = math.floor(Gwidth/2+0.5) Sw.y = math.floor(Gheight/2+50) Sw.val = adk.digitalRead(SwNum) --アナログ値初期化 An.x = math.floor(Gwidth/2+0.5) An.y = math.floor(Gheight/2+80) An.val = adk.digitalRead(AnNum) end ------------------------------------------ --画面に表示する ------------------------------------------ function display() --背景を黒に canvas.putCls( color(0,0,0) ) --ON/OFFボタン表示セット sprite.move( 1, 2-2*Btn.val, Btn.x, Btn.y ) --OFFボタン sprite.move( 2, 2*Btn.val, Btn.x, Btn.y ) --ONボタン --スライドバーつまみの表示セット local posi = Bar.val*Bar.len + Bar.ofsx sprite.move( 4, 1, posi, Bar.y ) --スライドバーつまみ --スプライト表示 sprite.put() --スライド位置まで塗りつぶす if(Bar.ofsx<posi-7)then canvas.putRect( Bar.ofsx, Bar.y-10, posi-7, Bar.y+10, color(9,175,237), 1) end --スイッチ表示 canvas.putTextCenter( Sw.txt[Sw.val+1], Sw.x, Sw.y, 20, color(255,255,255) ) --アナログ値表示 canvas.putTextCenter( (An.val /10.23).."%", An.x, An.y, 28, color(255,255,255) ) canvas.drawTextCenter( An.val.."/1023", An.x, An.y+24, 20, color(255,255,255) ) end ------------------------------------------ -- メイン関数 ------------------------------------------ function main() --画面を縦にする system.setScreen(1) --縦向きに変更 Gwidth, Gheight = canvas.getviewSize() --内部グラフィック画面設定の変更 canvas.setMainBmp( Gwidth, Gheight ) canvas.setWorkBmp( Gwidth*2, Gheight ) --Arduinoポートの初期化 adk.pinMode(BtnNum, 1) --LED出力 adk.pinMode(PwmNum, 1) --PWM出力 adk.pinMode(SwNum, 0) --スイッチ入力 adk.analogReference(0) --アナログ入力リファレンス電圧設定 -- 画像の初期化 pictureInit() local x,y,s --タッチ座標と状態用 local spTouch={} --スプライトタッチ判定結果用配列 local btnFlg = 0 --ボタンにタッチしていると1になる local psec = 0 --ループ間隔用 local cnt = 0 --アナログ取得間隔カウンタ用 while(true)do --ボタンが押されているか spTouch = sprite.touch( 1, 2 ) if(spTouch[1]==1 and btnFlg==0)then --1番にタッチされていた(ON) Btn.val = 1 adk.digitalWrite(BtnNum,1) btnFlg = 1 elseif( spTouch[1]==2 and btnFlg==0)then --2番にタッチされていた(OFF) Btn.val = 0 adk.digitalWrite(BtnNum,0) btnFlg = 1 elseif( #spTouch==0) then --タッチされていない btnFlg = 0 end --スライドバーがタッチされているか spTouch = sprite.touch( 3 ) if( #spTouch>0)then --タッチされていた x = touch() Bar.val = (x - Bar.ofsx) / Bar.len --PWM値のセット adk.analogWrite(PwmNum, Bar.val*255) end --スイッチデータの取得 Sw.val = adk.digitalRead(SwNum) --アナログデータの取得 cnt = cnt + 1 if(cnt>5)then cnt = 0 An.val = adk.analogRead(AnNum) end --画面表示 display() --1/30secループを作る while( psec>system.getSec() )do end psec = system.getSec()+0.033 end end main() system.exit()
最後にArduinoのプログラムを置いておきます
#include <Max3421e.h> //ADKを利用するための3つのライブラリを読み込む #include <Usb.h> #include <AndroidAccessory.h> //外部インテント指定:Androidアプリ側のaccesory_filter.xml内の属性と一致させる(2) AndroidAccessory acc("Luarida Works", //第1引数:組織名(manufacturer属性と一致) "Sarida_Ard1", //第2引数:モデル名(model属性と一致) "Sarida Ard1 - Arduino USB Host", //第3引数:ダイアログ表示メッセージ "1.0", //第4引数:バージョン(version属性と一致) "http://accessories.android.com/", //第5引数:ジャンプ先URL "0000000000000001"); //第6引数:シリアル番号 void setup() //最初に一度だけ実行される部分 { Serial.begin(115200); Serial.println("\r\nStart"); //初期化:デジタル・アナログ入出力のピンのポート指定(3) //0〜6を入力ポートに初期化する // 7〜13ピンは通信で使っています。 for(int i=0; i<=6; i++){ pinMode(i, INPUT); digitalWrite(i, HIGH); //内部プルアップ } //USBホスト機能を有効にする acc.powerOn(); Serial.println("--setup done--");//シリアルモニターにsetup()終了を出力 } void loop() //繰り返し実行される部分 { byte byteDat[16]; //Androidとやりとりするデータ //Androidとの接続処理(4) if (acc.isConnected()) { //Androidを起動・接続する命令を送る //communicate with Android application int len = acc.read(byteDat, sizeof(byteDat), 16); //ADK接続から読み込み if (len > 0) { if(byteDat[3]==0x01){ Serial.println("adk.pinMode\r\n"); adkPinMode(byteDat); } else if(byteDat[3]==0x04){ Serial.println("adk.analogWrite\r\n"); adkAnalogWrite(byteDat); } else if(byteDat[3]==0x02){ Serial.println("adk.digitalWrite\r\n"); adkDigitalWrite(byteDat); } else if(byteDat[3]==0x06){ Serial.println("adk.analogReference\r\n"); adkAnalogReference(byteDat); } else if(byteDat[3]==0x03){ Serial.println("adk.digitalRead\r\n"); adkDigitalRead(byteDat); } else if(byteDat[3]==0x05){ Serial.println("adk.analogRead\r\n"); adkAnalogRead(byteDat); } } } else { //set the accessory to its default state //Androidと接続されていないときの処理 //何もしない } delay(10); //10ミリ秒処理を停止(10ミリ秒おきにloop()を繰り返す) } //************************************************** // 2-B-5.アナログリード: adk.analogRead(0x0B05) // adk.analogRead(pin) // 0x03 0x06 0x0B05 0xXX 0x06 // 0xXXの値 // ピンの番号(アナログ0〜5) // // 受信 // 0x03 0x08 0x0B05 0xXX 0xHHHH 0x06 // 0xXXの値 // ピンの番号 // 0xHHHHの値 // 10ビットの値(0〜1023) //************************************************** void adkAnalogRead(byte byteDat[]) { byte result[] = { 0x03, 0x07, 0x0B, 0x03, 0x00, 0x00, 0x06 }; int v = analogRead(byteDat[4]); result[4] = v>>8; result[5] = v & 0xFF; acc.write(result, 7); //USBアクセサリ(Android)に書き込む } //************************************************** // 2-B-3.デジタルリード: adk.digitalRead(0x0B03) // adk.digitalRead(pin) // 0x03 0x06 0x0B03 0xXX 0x06 // 0xXXの値 // ピンの番号(0〜6) // // 受信 // 0x03 0x06 0x0B03 0xXX 0x06 // 0xXXの値 // 0:LOW // 1:HIGH //************************************************** void adkDigitalRead(byte byteDat[]) { byte result[] = { 0x03, 0x06, 0x0B, 0x03, 0x00, 0x06 }; result[4] = digitalRead(byteDat[4]); acc.write(result, 6); //USBアクセサリ(Android)に書き込む } //************************************************** // 2-B-6.アナログリファレンス: adk.analogReference(0x0B06) // adk.analogReference(type) // 0x03 0x06 0x0B06 0xXX 0x06 // 0xXXの値 // 0: DEFAULT // 1: INTERNAL // 2: EXTERNAL //************************************************** void adkAnalogReference(byte byteDat[]) { if(byteDat[4]==0){ analogReference(DEFAULT); } else if(byteDat[4]==1){ analogReference(INTERNAL); } else if(byteDat[4]==2){ analogReference(EXTERNAL); } } //************************************************** // 2-B-2.デジタルライト: adk.digitalWrite(0x0B02) // adk.digitalWrite(pin, value) // 0x03 0x07 0x0B02 0xXX 0xYY 0x06 // 0xXXの値 // ピンの番号(0〜6) // 0xYYの値 // 0: LOW // 1: HIGH //************************************************** void adkDigitalWrite(byte byteDat[]) { if(byteDat[5]==0){ digitalWrite(byteDat[4], LOW); } else{ digitalWrite(byteDat[4], HIGH); } } //************************************************** // 2-B-4.アナログライト: adk.analogWrite(0x0B04) // adk.analogWrite(pin, value) // 0x03 0x07 0x0B04 0xXX 0xYY 0x06 // 0xXXの値 // ピンの番号(PWM出力が出来るアナログ0〜5) // 0xYYの値 // 出力PWM比率(0〜255) //************************************************** void adkAnalogWrite(byte byteDat[]) { unsigned char v = byteDat[5]; analogWrite(byteDat[4], (int)v); } //************************************************** // 2-B-1.PINのモード設定: adk.pinMode(0x0B01) // adk.pinMode(pin, mode) // 0x03 0x07 0x0B01 0xXX 0xYY 0x06 // 0xXXの値 // ピンの番号(0〜6) // 0xYYの値 // 0: INPUTモード // 1: OUTPUTモード //************************************************** void adkPinMode(byte byteDat[]) { if(byteDat[5]==0){ pinMode(byteDat[4], INPUT); digitalWrite(byteDat[4], HIGH); //内部プルアップする } else{ digitalWrite(byteDat[4], LOW); //内部プルアップを切る pinMode(byteDat[4], OUTPUT); } }