コンピュータを楽しもう!!

今、自分が面白くていろいろやってみたことを書き綴りたいと思います。連絡先はtarosa.yでgmail.comです。

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);
  }
}