Luaridaの回転命令サンプル
ドロイド君が回転するサンプルを作りました。Androidマーケットでも公開しています。とりあえず、動画から。
加速度センサのX,Yの値を使って、重力の方向を計算してドロイド君がまっすぐ向くように表示するサンプルです。せっかくのセンサなので、取得データに適当なフィルタを掛けるようにしました。フィルタは一次のIIRフィルタと移動平均を取るものです。
サンプルのダウンロードはこちらから(rotatesample.apk /sdcard/luarida/rotatesample/フォルダに保存されます)。
フィルタの選択画面
最初にドロイド君の画像とどのフィルタかを選ばせます。
------------------------------------------ --メインプログラム ------------------------------------------ function main() local w,h local wb, hb local k --ワークエリアをクリアする canvas.workCls() --ワークエリアの(0,0)-(79,93)に、アンドロイド画像を読み込みます if( canvas.loadBmp( Path.."droidkun.png", 0, 0, 79, 93 )==-1)then dialog( Path.."droidkun.png", "ロードに失敗しました",1 ) do return end end --画面サイズ取得 w,h = canvas.getviewSize() w = w-1 h = h-1 wb = 80+w hb = h --背景を白にする canvas.drawCls( color(255,255,255) ) --画面を背景にするために、ワークエリアに取り込む canvas.getg( 0, 0, w, h, 80, 0, wb, hb ) while(true)do item.clear() item.add( "一次フィルタ", 0 ) item.add( "移動平均", 0 ) item.add( "フィルタ無し", 0 ) item.add( "終 了", 0 ) k = item.list( "どのフィルタを選びますか" ) if( k==1 )then filter() elseif( k==2 )then moveave() elseif( k==3 )then rawdata() elseif( k==4 )then break end end end
一次フィルタ
測定した加速度に重み(omomi)を掛けて鈍らせています。単純なフィルタです。
axo = axo*omomi + ax*(1-omomi) ayo = ayo*omomi + ay*(1-omomi)
回転のコマンドは下記の2つです。中心にドロイド君、中心から半径70ピクセル離れたところに角度を表示しています。
canvas.putrotg( cx, cy, angle, 0, 0, 79, 93 ) canvas.putflush() canvas.drawTextRotate("θ="..angle, cx-70*x, cy+70*y, angle, 24, color(255,0,0))
回転角度は、アークタンジェントatan2()で計算しています。2つの引数が加速度XとYになります。ここでは縦がX軸、横がY軸となっているので、角度計算にXとYの値を入れ替えています。
関数は下記。
------------------------------------------ -- 一次フィルタ ------------------------------------------ function filter() local ax,ay,az,axo,ayo local aax,aay local w,h local wb, hb local kaku local omomi = 0.85 local cx, cy local pi = 3.141592 local x,y,s local angle local moji --画面サイズ取得 w,h = canvas.getviewSize() w = w-1 h = h-1 wb = 80+w hb = h cx = w/2 cy = h/2 moji,s = editText("フィルタ係数を入力してください(0<=〜<1)") if( s==nil or moji==nil or moji=="" or tonumber(moji)==nil )then omomi = 0.8 elseif( s==1 )then omomi = tonumber( moji ) if( omomi<0 or omomi>=1 )then omomi = 0.8 end else omomi = 0.8 end toast( "フィルタ係数を "..omomi.."に設定しました", 0 ) toast("ドロイドをタッチすると終了します", 0 ) axo, ayo, az = sensor.getAccel() while(true)do --加速度を取得 ax, ay, az = sensor.getAccel() axo = axo*omomi + ax*(1-omomi) ayo = ayo*omomi + ay*(1-omomi) kaku = math.atan2( -ayo, axo ) angle = math.floor(kaku/pi*180) x = math.sin(kaku) y = math.cos(kaku) canvas.putg( 0, 0, w, h, 80, 0, wb, hb ) canvas.putrotg( cx, cy, angle, 0, 0, 79, 93 ) canvas.putflush() canvas.drawTextRotate("θ="..angle, cx-70*x, cy+70*y, angle, 24, color(255,0,0)) --画面タッチで終了 x,y,s = touch() if( s~=1 )then if( x>=cx-79/2 and x<=cx+79/2 and y>=cy-93/2 and y<=cy+93/2 )then break end end end end
移動平均
移動平均は、データの平均を取っているだけです。ax、ayの配列を作って、リングバッファに使っています。平均と言いながら、今回は足し込むだけで、nで割っていません。それは、atan2の計算でXとYの比になるので、割る必要がないからです。画像の表示は一次フィルタと同じです。
------------------------------------------ -- 移動平均 ------------------------------------------ function moveave() local ax={} local ay={} local az local axt, ayt local i local n = 10 local aax,aay local w,h local wb, hb local kaku local cx, cy local pi = 3.141592 local x,y,s local angle local moji moji,s = editText("移動平均を取る数を入力してください(n=1〜)") if( s==nil or moji==nil or moji=="" or tonumber(moji)==nil )then n = 4 elseif( s==1 )then n = tonumber( moji ) else n = 4 end toast( n.."個の移動平均を取ります", 0 ) --画面サイズ取得 w,h = canvas.getviewSize() w = w-1 h = h-1 wb = 80+w hb = h cx = w/2 cy = h/2 axt = 0 ayt = 0 for i=1,n do ax[i], ay[i] = sensor.getAccel() axt = axt + ax[i] ayt = ayt + ay[i] end toast("ドロイドをタッチすると終了します", 0 ) i = 1 while(true)do axt = axt - ax[i] ayt = ayt - ay[i] --加速度を取得 ax[i], ay[i] = sensor.getAccel() axt = axt + ax[i] ayt = ayt + ay[i] kaku = math.atan2( -ayt, axt ) angle = math.floor(kaku/pi*180) x = math.sin(kaku) y = math.cos(kaku) i = i + 1 if( i>n )then i=1 end canvas.putg( 0, 0, w, h, 80, 0, wb, hb ) canvas.putrotg( cx, cy, angle, 0, 0, 79, 93 ) canvas.putflush() canvas.drawTextRotate("θ="..angle, cx-70*x, cy+70*y, angle, 24, color(255,0,0)) --画面タッチで終了 x,y,s = touch() if( s~=1 )then if( x>=cx-79/2 and x<=cx+79/2 and y>=cy-93/2 and y<=cy+93/2 )then break end end end end
生データ
生データは加速度のデータをそのまま使って角度を計算しているだけです。ソース添付は省略したいと思います。
以上、サンプル紹介を終わります。