連載インデックスへ
次世代のインプットを考えよう(4)
──マウスとキーボードを超えたフィジカルコンピューティング

じゃんけんグローブ「絶対!ぬぎPON」の作り方


浦野大輔(うらのだいすけ)
サイバーエージェント 新規開発局所属
2009/5/19

Flashアプリの作成

- PR -

 グローブのグー・チョキ・パーに合わせてビジュアルが変化するアプリを作成します。

 FunnelManagerは各曲げセンサの値から手の形(グー・チョキ・パー)を判定するロジッククラスです。 人差し指と薬指の2本の指の曲がり具合からグー・チョキ・パーを決定します。人差し指と薬指が両方開いているときをグー、人差し指が開いて薬指が閉じているときをチョキ、人差し指と薬指が両方閉じているときをパーとします。

 各センサの値はFunnelライブラリを使ってアクセスします。ライブラリは\libraries\actionscript3\srcに、ドキュメントは\libraries\actionscript3\asdoc-outputに入っています。以下、ライブラリの使い方と併せてソースコードを解説していきます。

package {
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.IOErrorEvent;
        
    import funnel.Configuration;
    import funnel.Fio;
    import funnel.FunnelEvent;
    import funnel.OUT;
    import funnel.Scaler;

    public class FunnelManager extends Sprite{
        private var fio:Fio;

        private var scaler0:Scaler;
        private var scaler2:Scaler;
        private var value0:int=3;
        private var value2:int=3;
        private var state:int=0;

        public var onReceive:Function;

        public static const NOT_DETERMINED:int=0;
        public static const PAPER:int=1;
        public static const SCISSORS:int=2;
        public static const ROCK:int=3;

        // 要チューニング
        private static const INDEX_FINGER_OPEN:Number = 0.4
        private static const INDEX_FINGER_CLOSE:Number = 0.27;
        private static const RING_FINGER_OPEN:Number = 0.48;
        private static const RING_FINGER_CLOSE:Number = 0.39;

        public function FunnelManager(){
            // FIOのFirmata用標準コンフィギュレーションを選択 
            var config:Configuration=Fio.FIRMATA; // --【1】
            // 通信トラフィックを最小限にするために
            // A0(人差し指)とA2(薬指)以外を出力に設定する
            config.setDigitalPinMode(13, OUT); // D13 // --【2】
            config.setDigitalPinMode(15, OUT); // A1 // --【2】
            config.setDigitalPinMode(17, OUT); // A3 // --【2】
            config.setDigitalPinMode(18, OUT); // A4 // --【2】
            config.setDigitalPinMode(19, OUT); // A5 // --【2】
            config.setDigitalPinMode(20, OUT); // A6 // --【2】
            config.setDigitalPinMode(21, OUT); // A7 // --【2】

            // Fioのインスタンスを生成
            // 引数:FIOのID、コンフィギュレーション、アドレス、
            // ポート番号、サンプリング間隔
            fio=new Fio([1],config,"localhost",9000,12);// --【3】

            // イベントリスナを追加
            fio.addEventListener(IOErrorEvent.IO_ERROR, trace);
            fio.addEventListener(FunnelEvent.READY
            ,onReady);// --【4】

            // スケーラーの初期化
            scaler=new Scaler(INDEX_FINGER_OPEN, 
             INDEX_FINGER_CLOSE, 0, 100); // --【5】
            scaler2=new Scaler(RING_FINGER_OPEN, 
             RING_FINGER_CLOSE, 0, 100); // --【5】
        }

        /**
         * I/Oモジュールの初期化が完了したときの処理
         */
        private function onReady(e:Event):void{
            trace(this, "onReady");
            addEventListener(Event.ENTER_FRAME, loop);
        }

        /**
         * 毎フレーム行う処理
         */
        private function loop(event:Event):void{
            // 人差し指の値をスケーリングする
            value0=scaler0.processSample
            (fio.ioModule(1).analogPin(0).value); // --【6】
            // 薬指の値をスケーリングする
            value2=scaler2.processSample
            (fio.ioModule(1).analogPin(2).value); // --【6】

            // グーを認識
            if (value0 > 60 && value2 > 60 
            && state != ROCK) // --【7】
            {
                trace(this, "グー");
                state=ROCK;
            }
            // チョキを認識
            else if (value0 < 20 && value2 >60 
            && state != SCISSORS) // --【8】
            {
                trace(this, "チョキ");
                state=SCISSORS;
            }
            // パーを認識
            else if (value0 < 20 && value2 < 20 
            && state != PAPER) // --【9】
            {
                trace(this, "パー");
                state=PAPER;
            }

            if (onReceive != null)
                onReceive(state); // --【10】
         }
    }
}
  • 【1】 ConfigurationはI/Oモジュールのコンフィギュレーションを設定するためのクラス。Fio.FIRMATAでFIO用のデフォルトのコンフィギュレーションを取得
  • 【2】 A0ピン(人差し指)とA2ピン(薬指)の入力のみ欲しいので、必要のないピンを出力設定にして通信トラフィックを最小限にする
  • 【3】 FioクラスはFunnel I/Oモジュールを扱うためのクラス。コンフィギュレーションはFioインスタンス作成時に引数で指定
  • 【4】 Fioインスタンスにイベントリスナを追加。 FunnelEvent.READYは、FIOの初期化が完了したとき送出される
  • 【5】 Scalerクラスは、ある範囲の入力をある範囲にスケーリングするためのクラス。scaler0は人差し指用、scaler2は薬指用のインスタンス。開いているときが0、閉じているときが100になるようにスケーリングする。ここでの入力値は私の環境でいい感じになる値なので、うまく動作しないときはチューニングが必要。Funnelライブラリには、値のスケーリング、移動平均やハイパスフィルタなど、入出力をより簡単に扱うためのフィルタが用意されている
  • 【6】 ioModuleメソッドで指定した番号のI/Oモジュールを取得。取得したI/OモジュールのA0ピンとA2ピンの入力値にスケーリングのフィルタをそれぞれ適用する。value0とvalue2にはスケーリング後の値がそれぞれ入る
  • 【7】 グーを判定するロジック。 人差し指と薬指の値がそれぞれ60以上(半分以上閉じている)とき、手の形をグーと見なす
  • 【8】 チョキを判定するロジック。 人差し指の値が20以下(大体開いている)かつ薬指の値が60以上のとき、手の形をチョキと見す
  • 【9】 パーを判定するロジック。 人差し指と薬指の値がそれぞれ20以下のとき、手の形をパーと見す
  • 【10】 手の状態を通知

 Mainはアプリのドキュメントクラスです。FunnelManagerインスタンスからの通知に合わせてビジュアルを変更します。

package {
    import flash.display.Sprite;

[SWF(width="200",height="200",frameRate="30",
       backgroundColor="#FFFFFF")]

    public class Main extends Sprite{
        private var funnelManager:FunnelManager;
        private var playerView:PlayerView;
 
        public function Main(){
            funnelManager = new FunnelManager();// --【1】
            funnelManager.onReceive = onReceive;// --【1】

            playerView = new PlayerView(); // --【2】
            addChild(playerView);
        }

        private function onReceive(state:int):void // --【3】
        {
            if(state == FunnelManager.ROCK){
                playerView.rock();
            }else if(state == FunnelManager.SCISSORS){
                playerView.scissors();
            }else if(state == FunnelManager.PAPER){
                playerView.paper();     
            }
        }
    }
}
  • 【1】 FunnelManagerインスタンスを作成して、手のグー・チョキ・パーが変わったときのイベントリスナを追加
  • 【2】 PlayerViewはプレイヤーを表すビュークラス
  • 【3】 手の状態を受け取って、ビューを更新

 サンプルアプリのプロジェクトはこちらからダウンロード可能です。

[funnel.zip]

funnel\
    bin-release\Main.swf (アプリ)
    libs\(Funnelライブラリ)
    src\(ソースコード)
     assets\(ビジュアル素材)
     FunnelManager.as(FIOとの通信、グー・チョキ・パーを決定するクラス)
     Main.as(ドキュメントクラス)
     PlayerView.as(プレイヤーを表すビュークラス)

チョキを判定したときの画面

おまけ

 以下の写真は、Adobe MAX Japan 2009 のFlash OOPブースに出展した際のグローブコントローラです。

I/OモジュールにArduinoを使っているグローブコントローラ

 I/OモジュールにArduinoを使っており、今回紹介したグローブのベータ版的なものです。

 「絶対!ぬぎPON」ではできる限り回路を隠したかったのですが、FIOに差し替えることでいい感じにスリム化することができました。

 またツールキットにFunnelを使っていたため、アプリ側の変更も小さいコストで行うことができました。

 このように、目的に応じてI/Oモジュールやプログラミング言語を使い分けることができる懐の深さがFunnelの特徴の1つだと思います。

 最後に、電子工作やフィジカルコンピューティングを学ぶ際にぬぎPON制作チームが重宝している書籍をいくつか紹介します。興味がある方はぜひ参考にしてください。

Making Things Talk -Arduinoで作る「会話」するモノたち

+GAINER―PHYSICAL COMPUTING WITH GAINER

ネットでものを生み出すということ―電子楽器からプロトタイピングメソッドまで「発想を形にするヒント」

浦野大輔(うらのだいすけ)
株式会社サイバーエージェント新規開発局所属。
インタラクティブデザイナー。
主なプロジェクトはAmeba、プーペガールなど。
http://uranodai.com

3/3  

 INDEX
次世代のインプットを考えよう
──マウスとキーボードを超えたフィジカルコンピューティング(4)

じゃんけんグローブ「絶対!ぬぎPON」の作り方
  Page1
グー・チョキ・パーに対応するアプリを作成
絶対!ぬぎPON
アプリの仕組み
  Page2
Funnelのセットアップ
グローブコントローラの作成
Page3
Flashアプリの作成
「発想を形にするヒント」とか

【関連記事】

chumby開発者が語る誕生秘話とビジネスモデル
D89クリップ(2) かわいらしいルックスとハッキングのしやすさが注目を集める「chumby」。chumbyの生みの親が、ガジェットに対してユーザーが受け身でいられる自由を語る
テレビでYahoo!―デバイスが変わればUIデザインも
WebとUIをつなぐトリックスター(2) 制作の要となるエンジニアとデザイナのチームワークのツボを探る連載。今回はヤフーのテレビ向けサービスのデザイン担当に話を聞いた
Flashの基礎を無料で習得! ActionScript入門
ActionScriptを知っていますか? Flash技術の要となる言語で無料で簡単にFlashアプリケーションを作れます。そのActionScriptについて初心者のために一から丁寧に解説していきます
Flash制作を簡単にするActionScriptライブラリとは?
Flasherに便利なオープンソース「Spark project」
 Flashの複雑なアニメーションや機能をどのように制作していますか? 実は、無料で簡単に実現する方法があります



 Smart&Social フォーラム トップページへ



Smart & Social フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Smart & Social 記事ランキング

本日 月間