The jonki

呼ばれて飛び出てじょじょじょじょーんき

Pebble Time Roundを日本語化する

Pebble Time Roundの日本語化パッケージを入れようとしたら"cannot install external language pack"と表示されてちょっとハマったのでメモ。

下記の有志の方からありがたくpbJapanese_j06.pblをダウンロードし、そのファイルを自分のDropBoxコピーします。

Pebble language pack: 日本語言語パック

その後、スマートフォンDropBoxアプリから直接pbJapanese_j06.pblを選択すると、開くアプリを聞かれるのでPebble Timeアプリで開けば大丈夫です。

Maker Faire Tokyo 2015 で LITTAI を出展してきた(ハードウェア解説編)

f:id:jonki:20150726173310j:plain

はじめに

8/1・8/2で東京ビッグサイトで開催された Maker Faire Tokyo 2015 に、id:hecomiid:AMANELITTAI というタイトルで展示してきました。熱も冷めやらぬうちにハードウェアの解説を行いたいと思います。認識やゲームに関してはid:hecomiの記事をご参考ください。tips.hecomi.com


www.youtube.com

ボタンガジェット

今回のHWの一番大きなポイントとしてリアルなボタンを押すと機体から弾がビュンビュンと振動とともに出るところです。Mont Blanc Pj.で行ったゲームと現実の融合というコンセプトを継承することができました。vine.co

仕組み

これはTWE-LiteというZigBeeに対応した無線マイコンモジュール(東京コスモス電機さん開発)を利用しています。低レイテンシ、低消費電力、長距離通信、とIoTなどの分野で大活躍しそうなモジュールです。2.4GHz帯で特別な免許もいらず日本では技適も通ってるので安心して利用できます。id:kssaoさんの投稿で知りました。
超小型IEEE802.15.4/ToCoNet無線モジュール TWE-Lite(トワイライト) - TOCOS-WIRELESS.COM
qiita.com


使ったTWE-Lite製品を参考に挙げておきます。

このUSBドングルは親機専用として非常に便利です。DIP用書き込み基板でも代用できますが、持ち運びや見栄えなどが良いので1個あると便利です。

こちらは書き込みに利用します。今回はDIP版のTWE-Liteを買いましたが、ピンヘッダの足をつけていません。それでも先端に5ピンのピンヘッダを取り付けることで書き込めます(使用例Cを参考

あとはボタンウィジェットに1個ずつこれが入ってます。

いろんな使い方が載っています。TWE-Liteについてまとめて一気に勉強したい人は情報がまとまっているのでオススメです。

回路

緑のLEDが常灯していてボタンを押すと黄色いLEDと振動アクチュエータも電圧がかかって動作します。またボタンのイベント検知はDI1とDI2をを利用しています。特徴的なのはDI2にはDI1を反転した値をTC7S04Fというインバータを利用して入力しているところです。ボタン1つで2ポートを利用している理由は、TWE-Liteは間欠モードという省電力モードでは立ち上がりor立ち下がりしか検知できないためです。東京コスモス電機さんのサポート担当者様によると今回使ったファームウェア(超簡単!無線マイコンTWE-Lite DIP)は立ち下がり設計とのことです。今回のゲームではボタンのPushDown/Upが取りたかったのでDI1とそれを反転したDI2を利用することで解決しました。
f:id:jonki:20150803235755p:plain
Fritzing Project – TWE-LITE Single Push Button


ガジェットの中にはスペースがほとんどないので苦労しましたが、便利な商品を見つけてなんとか乗り切りました。シール基板は特に面白く、ピッチ変換をしたりGNDなどに使うラインのタイプがあったりします。切り取って普通の基板に接着剤でくっつくのでとても便利でした。ハンダもつきます!また基板はハサミでちょきちょきと切れるので使い勝手がかなり良かったです。
f:id:jonki:20150721231000j:plain
f:id:jonki:20150806000359j:plain


ちなみに今回のボタンガジェットに必要な部品はすべて秋月電子千石電商、マルツパーツで手に入ります。店舗とオンラインストア、どちらでも入手できます。

TWE-Liteの設定

ファームウェア超簡単!TWE標準アプリのver 1.7.1を使ってます。赤色の部分が変更した値です。'Option Bits #1'の0x00000010はADCを利用しない場合に設定するとAD1~4の配線を省略できます。'Option Bits #2'でDI1とDI2でプルアップ停止にして電流を節約します。

CONFIG/TOCOS TWELITE DIP APP V1-07-1
a: set Application ID (0xXXXXXXXX)
i: set Device ID (12=0x0c)
c: set Channels (18)
x: set Tx Power (3)
t: set mode4 sleep dur (1000ms)
y: set mode7 sleep dur (1000s)
f: set mode3 fps (32)
z: set PWM HZ (1000)
o: set Option Bits (0x00000010)
O: set Option Bits #2 (0x00000011)
b: set UART baud (38400)
p: set UART parity (N)

他の項目は下記を参考にしてみてください。
設定変更(インタラクティブ)モード - TOCOS-WIRELESS.COM

通信

構成としてはボタンガジェットにあるTWE-Liteの子機とゲームを動かすMacにトコスティック(親機)を挿し、Macで動いているUnityで親機からくるシリアルデータを読み取っています。そのときid:hecomiにリリースしたコードはgithubにあげてあります。github.com

シリアルデータの読み込みとイベント発火はSerialHandlerクラスで行っています。ここでは簡単に読み込みとイベント発火の部分を説明します。

スレッドでのデータ読み込み
Updateでは60fpsしか出ないので、スレッドを動かしてmessageQueue_に対して高速にデータを格納していきます。私の環境ではThread.Sleepがないとloopが高速に回りすぎてUnityがクラッシュしてしまいました。下のRead_関数がThreadクラスに渡している関数になります。

private void Read_()
{
    while (isRunning_ && serialPort_ != null && serialPort_.IsOpen) {
        try {
            if (serialPort_.BytesToRead > 0) {
                lock(guard_) {
                    messageQueue_.Enqueue(serialPort_.ReadLine());
                }
            }
            Thread.Sleep (0); // for avoiding busy loop
        } catch (System.Exception e) {
            Debug.LogWarning(e.Message);
        }
    }
}

格納したデータの利用
スレッド内で格納したデータはUpdate内でコピーし、そのコピーしたデータをイベントとして発火します。

void Update()
{
    Queue<string> tmpQueue = null;
    lock(guard_) {
        while(messageQueue_.Count > 0) {
            tmpQueue = new Queue<string>(messageQueue_);
            messageQueue_.Clear();
        }
    }

    if(tmpQueue	!= null) {
        while(tmpQueue.Count > 0) {
            // シリアルデータの送信(略)
        }
    }
}

イベント(定義)
C#ではeventという便利な仕組みがあります。これを公開用に定義しておきます。

public delegate void SerialDataHandler(int id);

public static event SerialDataHandler Pressed = (int id) => {};
public static event SerialDataHandler Pressing = (int id) => {};
public static event SerialDataHandler Released = (int id) => {};
public static event SerialDataHandler SwitchOn = (int id) => {};
public static event SerialDataHandler SwitchOff = (int id) => {};

イベント(受信)
あとは上の公開されたイベントを登録することでポーリングすることなく、イベントをコールバック形式で受信することができます。

void onPressed(int id) {
    Debug.Log (System.DateTime.Now + " onPressed: " + id);
}

void onPressing(int id) {
    Debug.Log (System.DateTime.Now + " onPressing: " + id);
}

void onReleased(int id) {
    Debug.Log (System.DateTime.Now + " onReleased: " + id);
}

void onSwitchOn(int id) {
    Debug.Log (System.DateTime.Now + " onSwitchOn: " + id);
}

void onSwitchOff(int id) {
    Debug.Log(System.DateTime.Now + " onSwitchOff: " + id);
}

void Start () {
    SerialHandler.Open();
    SerialHandler.Pressed += onPressed;
    SerialHandler.Pressing += onPressing;
    SerialHandler.Released += onReleased;
    SerialHandler.SwitchOn += onSwitchOn;
    SerialHandler.SwitchOff += onSwitchOff;
}

3Dモデル

f:id:jonki:20150716005312j:plain
ボタンとTWE-Liteなどを格納するケースとそのケースに付ける擬似レゴの3Dモデルです。
3Dプリンター(Up Plus 2)と123D Designを使ったCADによる簡単な3Dモデル作成のスキルは習得済みだったので、今回のMaker Faireから早速活用出来ました。実際にプリントして試行錯誤できるのはMy 3Dプリンターの強みだと改めて感じました。また一度モデルが完成してしまえば見栄えが良くまったく同じものを多く作ることができるのでMakerのみなさんにはやはりおすすめしたいですね。www.123dapp.com
www.123dapp.com

セイミツ工業 PS-14-DN-K ゲームスイッチφ24 ネジ式 スケルトン クリア


ちなみに今回本物のレゴを使わなかった理由は2つです。

  • 上から見た時(ユーザー目線)、下から打ち上げているプロジェクターの光がレゴをほとんど透過しないため暗い部屋では真っ暗に見えてしまった。そのため3Dプリンターで作った密度の粗いレゴを利用し、見た目が光る(下からの光が透ける)ようにした
  • 接地面から2段目より上のレゴは認識できないという技術的制約があるため、取付部を設けて機体のカスタマイズ方法を限定させた。

裏側も工夫しています。擬似レゴを使ったため素材の密度が粗く、認識に使う赤外線カメラの赤外線の反射率が悪化しました。そこで薄いプラ版をレゴ裏面に貼ることで反射率を稼ぐことにしました。下が蓋みたいになるので、結果的に段を重ねるような遊び方を子供に抑えさせることが出来ました。本当はあまり制約は与えたくはないんですけどね。つけ心地もイマイチだったのでレゴに頼らない形状なども引き続き検討していきたいです。
f:id:jonki:20150807004453j:plain

課題と今後に向けて

長くなってしまいましたが最後に簡単に課題と今後について書きます。

省電力化

今回消費電力を真面目に検討しなかった結果、ボタン電池を30分に1回は交換するレベルでした。振動アクチュエータが電池をかなり食ってるのは分かっていますが、ちゃんと計測して最低起動電圧は次回までに正しく調査しようと思っています。また今回TWE-LiteのOption Bits #2の値を間違えていてプルアップ分の電流がずっと流れていた、というのも1つの原因で有りそうです。

専用基板

今回無理やりマイコン類を入れましたが、小型化とショート防止などのために専用基板を次回は起こしたいと思っています。Seeed Studioなど自分のスキルアップ&経験値アップのためこれもマストで行いたいですね。

筐体

今回のデモ筐体は時間もなかったため、カラーアングルをただ組み立てただけ、投影面もアクリル板にトレーシングペーパーを貼っただけど、かなりお粗末な見た目でした。持ち運びも難しいためデモを外でするにも一苦労です。今度は専用の組み立て式の筐体で見た目も綺麗な筐体に仕上げたいです。

ボタン以外のガジェット作成

今回本当はプッシュボタン以外に切り替え式のスイッチ(上の写真に載ってます)も作っていたのですが、うまい使い方が考えきれずお蔵入りとなりました。ボタン以外のも分かりやすいインタフェースは多いのでこの辺り遊び方含めてもっとアイデアを出していきたいです。

無線通信

TWE-Liteは2.4GHzですが、当日の会場では無線が混みあいすぎて想定以上にイベントをドロップしました。
ミクミンP/Kazuhiro Sasao on Twitter: "MFT会場、超低消費電力モードだと厳しい。この距離でも繋がらない、、。 http://t.co/Mn1FavTnI3"

会場を訪れた方にも、赤外線を使った方が良いというコメントが多くもらいました。これは確かにそうで、次回に出す機会があれば、赤外線を使ってイベントの通知やウィジェットのトラッキングを行いたいと思っています。この辺り技術的に面白そうなネタを温めているので近いうちに記事を書きたいと思っています。

レザークラフト始めました

f:id:jonki:20150314151701j:plain

唐突ですが、レザークラフト始めました。理由としては色々あるんですが、これまで電子工作、3D CADなどでやってきたように、自分と遠い分野のスキルを色々身につけたいと思ったのが大きな理由の一つ。とりあえず何も知識ないまま開始しました。

まずは道具集め!ということでAmazonでクラフト社のセットをポチ。クラフト社はレザークラフト界では大手だと思います。これが1万円ちょっと。更に知識0だったので初心者本も購入。作例が7つぐらいあってチュートリアル式に少しずつレベルを上げることができます。知識0からレザークラフトの作業をひと通り学べました。ちなみにこのスタンダードセットにはカード入れケースの工作セットがあるので、これだけでレザークラフトデビューができます。

はじめてのレザークラフト

はじめてのレザークラフト

本には写真がかなり詳しく書いてありますが、ところどころわかりにくいところなど下記サイト管理者様の初心者用動画に助けられました。実店舗、ネット店舗のオススメも出してくれているので助かります。

お買い物

東京の実店舗としては、浅草や秋葉原に多くあるようですが、近場のこの辺に行っています。

誠和という大手の直営店が入っています。そこまで広くないですが、道具も革もひと通り揃っています。お買い得品が多いわけではないですが、それでも十分な製品カバーだと思います。

ユザワヤって布だけかと思ってましたが、立派なレザークラフトコーナーがありました。キーチェーンやハトメなどの小物ももちろんあります。革もやすいハギレから大きなものまで一通りありました。ただコーナーが綺麗に整理されていないので少し探しにくいかも。

実用レベルを目指して

本に合った内容を一通り(7品くらい)作ってみたところ、完成度としてはかなり微妙、というか失敗ばかり。もちろん機能的には問題ありませんが、貼り合わせやコバ磨きが汚すぎて到底使おうとは思えませんでした。。そこでこれまたAmazonで下記の本をポチリ。

大人のレザークラフト [一流プロがこっそり教える] (Professional Series)

大人のレザークラフト [一流プロがこっそり教える] (Professional Series)

  • 作者: スタジオタッククリエイティブ
  • 出版社/メーカー: スタジオタッククリエイティブ
  • 発売日: 2013/01/25
  • メディア: 単行本
  • この商品を含むブログを見る

内容としては、初心者用というよりは脱初心者、完成度の上げ方、にフォーカスをあてている本です。解説も丁寧なので作り方が分からない、というところはないと思います。この本に載っているものをいくつか作ったので記念に写真を載せています。残念ながら私の作ったものは本の作例と比べるとかなり残念…。ですが、貼り合わせやコバ磨きなど、きれいな仕上げのための方法が満載なので、何回もトライしてレベルを上げろ!って感じです。ちなみに材料費は革によってピンきりです。使った革は1DC(100cm2)の値段が30円~300円ぐらいです。動物の種類、色、加工処理、厚さ、糸(色、厚さ)いろんな組わせを試せるので自分好みに仕上げられて楽しいです。


f:id:jonki:20150314151546j:plain

キーケース
f:id:jonki:20150314151824j:plain

カード入れ
f:id:jonki:20150314151853j:plain

ミニ財布
f:id:jonki:20150314152021j:plain

コインケース
f:id:jonki:20150314152132j:plain

最後に

3個ぐらい作ったところで飽きるかと思ってましたが、意外にもハマってます。上に載せたキーケースは実際に使ってます。もっと上達していけば、実用的でオリジナルな作品が作れるそうです。また電子工作とか3Dプリンターとかもせっかくやってきているので、このあたりの異分野コラボ作品も作っていきたいです。

おうちハック発表会#2 でLTしてきた

おうちハック発表会#2で、おうちハックアドベントカレンダーで書いた下の記事を発表してきました。


ちょっと未来のティッシュケースを考えてみた - The jonki


発表してきた記事はこちらです。

今回は3Dプリンターで作ってきたものも持っていったのですが、興味がある人が結構たくさんいて嬉しかったですね。今後ともたくさん役に立つたくさん記事を書きたいですね。

f:id:jonki:20150201215536j:plain

JavaScript/Node.jsで使えるステートマシンライブラリMachina.jsを試してみた

Machina.jsJavaScript/Node.jsでステートマシンを扱えるフレームワークです。最近私が書いているNode.jsのコードでステートマシンを導入したら、便利になりそうなところがあったので導入してみました。Machina.jsを日本語で取り扱っている記事が見当たらなかったので、参考になればと思います。なんと呼べばよくわかりませんが、とりあえず私はマキナと呼んでいます。

ステートマシンって?

いわゆる有限オートマトンFSM:Finite State Machine)です。システムの有限個の状態とその関係を遷移という矢印でつないだものですね。if文をたくさん書いて汚いコードになってしまった時、UMLのステートマシン図とかに落として整理しますね。

Machina.jsを選んだ理由

npmで'fsm'などの検索ワードで検索してダウンロードが多いモノを選びました。Machina.jsのgithubリポジトリを見ると現在の時点でスター数が893でした。これは間違いなさそうです。ライセンスもMITです。

インストール

Node.jsを利用している場合はnpmで入ります。通常のJavaScriptで使う場合は、公式ページサイトから、あるいはgithubからcloneしてきて、中にあるlib/machina,min.jsを使えば良さそうです。

$ npm install machina

基本的な使い方

公式のReadmeでも良いのですが、他にも例を探していたらわかりやすい記事があったのでそれをベースに解説します。

たとえば車のギヤのステートマシンを定義したいと思います。状態はN(ニュートラル)がデフォルト、1速、R(バック)の3つのギヤを考えます。下記の例ではそれぞれの状態においてアクセルを踏んだ時(accelerate)したときに車がどのように振る舞うかがわかります。かなりシンプルですし、コメントをたくさん書いたので見てみてください。

// コンストラクタ版 
var machina = require('machina'); 
var Car = machina.Fsm.extend({ 
  initialState: 'N',  // ステートマシンの初期状態
    states: {  // 状態を定義
      'N': {  // 各状態
        accelerate: function() { // その状態が扱う振る舞い(関数) 
          console.log('the gear is not set'); 
        } 
      }, 
      'R': { 
        accelerate: function() { 
          console.log('move back'); 
        } 
      }, 
      '1': { 
        accelerate: function() { 
          console.log('move forward'); 
        } 
      }, 
    }, 
}); 

var car = new Car(); 

car.on('transition', function(data) {
  console.log('state change:', data.fromState, 'to', data.toState);
});

// handleはcarインスタンスの現在の状態の関数(振る舞い)accelerateを探して、実行します
// transitionは引数で与えられたステートに遷移します
car.handle('accelerate'); // -> 'the gear is not set'
car.transition('1');      // -> 'state change: N to 1'
car.handle('accelerate'); // -> 'move forward'
car.transition('R');      // -> 'state change: 1 to R'
car.handle('accelerate'); // -> 'move back'


上記の例はコンストラクタ版ですが、インスタンス版でも良いと思います。

var machina = require('machina'); 
var car = new machina.Fsm({
  ///////略
});


またhandleをラップするとタイポなどがあった場合に早く見つけられそうです。

var machina = require('machina'); 
var Car = machina.Fsm.extend({ 
  initialState: 'N', 
    states: { 
      ///////略
    }, 
    accelerate: function() { 
      this.handle('accelerate'); 
    }, 
    shift: function(newGear) { 
      this.transition(newGear); 
    }, 
}); 

var car = new Car();  
car.shift('1'); 
car.accelerate(); 
car.shift('N'); 
car.accelerate();

よく使いそうなもの

machina.Fsm Prototypeとして公式に一覧がありますが、よく使いそうなものを上げていきます。initialState、handle、transitionは既に前例で登場済みなのでスキップします。

_onEnter/_onExit

こちらはそのステートに入ったタイミングと次のステートに切り替わるタイミングで呼ばれます。例えば先程のRのステートのところにこれを追加すると下記のような結果になります。そのステートにおけるinitialize/finalizeはこの中ですると良さそうです。

      'R': { 
        _onEnter: function() {
          console.log('R: _onEnter');
        },
        accelerate: function() { 
          console.log('move back'); 
        },
        _onExit: function() {
          console.log('R: _onExit');
        },
      }, 
  • 出力結果
state change: N to R                                                                           
R: _onEnter
R: _onExit
state change: R to 1
emit/on/off

emitではオリジナルのイベントを呼び出すことができます。作ったイベントはon/offでコールバックの登録、解除ができます。ここでは例で'broken'イベントを作ってみます。非常にJavaScriptらしい書き方でイベントとコールバックを登録できますね。

///////略
      'R': { 
        accelerate: function() { 
          this.emit('broken', 'aiueo');
        },
      }, 
///////略

var car = new Car(); 

car.on('broken', function(data) {
  console.log('broken!', data);
});

car.shift('R'); 
car.accelerate();
  • 出力結果
broken! aiueo
deferUntilTransition

これは次のTransitionまでその関数(振る舞い)をキューイングしてくれます。例を見るのが一番分かりやすい思います。例えばネットワークのステートを考えた時にrequestHttpという何かしらのサーバーにリクエストするような関数を考えてみます。ただし、これがoffline状態の時に呼ばれてしまうとクライアント側は再度requestHttpをしないといけません。そこで、このdeferUntilTransitionを呼んでおけばrequestHttpという振る舞いがmachinaにキューに積まれます。そして、deferUntilTransitionの引数にはonlineを与えているので、ステートがonlineになっただけでonlineステートのrequestHttpが実行され、安全に処理できます。
これを使いこなせれば上級者の仲間入りができそうです。ちなみにdeferUntilTransitionの引数に何も入れないと、何らかのステートに変わったら発動する、という条件に変わるようです。

var machina = require('machina'); 
var Network = machina.Fsm.extend({ 
  initialState: 'offline', 
    states: { 
      'offline': { 
        'requestHttp': function() {
          console.log('requestHttp is deferred');
          this.deferUntilTransition('online'); 
        },
      }, 
      'online': { 
        'requestHttp': function() {
          console.log('request...');
        },
      }, 
    }, 
}); 
var network = new Network(); 

network.on('transition', function(data) {
  console.log('state change:', data.fromState, 'to', data.toState);
});

network.handle('requestHttp');
setTimeout(function() {
  network.transition('online');
}, 1000);
  • 出力結果
requestHttp is deferred                                                                        
state change: offline to online
request... // -> deferされてたrequestHttpが1秒後のステートがonlineに変わったところで呼ばれる
アスタリスク(*)

関数としてアスタリスク(*)を書いておけば、定義されていない関数が呼ばれた場合にそれで受け止めることができます。色々例を探していると前述のdeferUntilTransitionを組み合わせて、ステートが変わったタイミングで再度その関数を呼ぼうとする例が多かったですね。これでクライアントからの呼び出しをちゃんとキャッチできる訳です。

///////略
      'N': { 
        '*': function() {
          console.log('handler is not defined');
        },
///////略

var car = new Car(); 
car.handle('hogehoge');
  • 出力結果
handler is not defined 

まとめ

JavaScript/Node.jsで使えるステートマシンライブラリのMachina.jsを試してみました。非常にシンプルでカスタマイズ性のあるフレームワークになっているのが分かりました。ただ一番重要なのはステートマシンをしっかり設計し、それを実際にコードに落とすことですね。結局設計がしょぼいと純粋にif文を羅列したほうがわかりやすいときもあるので、本末転倒にならないようにしたいところです。