The jonki

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

おうちハック発表会#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文を羅列したほうがわかりやすいときもあるので、本末転倒にならないようにしたいところです。

壁掛けのヘッドホンハンガーを3Dプリンターで作ってみた

f:id:jonki:20150118133239j:plain
f:id:jonki:20150118132755j:plain
f:id:jonki:20150118131134j:plain


ヘッドホンが溜まってきて置き場所に困っていたのと、壁掛けの棚を作ってみたいと思い、上の写真で上げたようなものを作ってみました。

壁掛け棚

壁にかける棚も自分で作ってみました。近所の島忠で板を買ってきてL字金具で止めただけです。無印でも安いので良かったのですが、せっかくなので自分で作りました。また賃貸なのでホッチキスで壁に固定する金具も買いました。


今回使った3Dモデル

特になんの工夫もないですが、何となく曲面にしてヘッドフォンへの負担を軽減させています。またケーブルを引っ掛ける突っ張りも作りました。

Headphone hanger 3D Model Made with 123D 123D Design


今回使ったフィラメント

今回はwinboという会社のUP Plus互換のABSフィラメントを使いました。公式のPP3DPオリジナルフィラメント(ABS樹脂500g)は税抜きで4644円なのでgあたりで9.288円。今回使ったのは700g 2780円なのでgあたり3.97円。なんと半額以下です。またホイールが透明なので、残量も見えて便利です。
私は公式フィラメントしか知らないのであまり参考にならないと思いますが、プリントしやすさも見た目もあまり遜色ないように思いました(サポート材と内部構造が見える画像を下に貼りました)。ただ注意点としては、ホイール経が少し大きいのでホイール保持部と少し干渉します。ここは3Dプリンターで自分で作ることもできますが、ちょっとぐいっと上の部分曲げてあげればホイールが回転できるので特に問題なはさそうです。(写真参考)


f:id:jonki:20150118141640j:plain
f:id:jonki:20150118131202j:plain

まとめ

今回ヘッドフォンの壁掛けスタンドを作ってみました。私が持っている3Dプリンターはそんなに大きいものも精度の良い物も作れませんが、こういった日常をちょっと便利にするものはすぐ作れるので面白いですね。自分が欲しいベストサイズのものを作れるのが嬉しいです。今回作ったヘッドフォンスタンドは既存の完成した製品がたくさんあるので、それを参考にしつつ自分のオリジナルに組み込んでいく知的活動はたまらないものがあります。

Xperiaの卓上ホルダを縦型にするアダプターを3Dプリンターで作ってみた

f:id:jonki:20150112214653j:plain

Xperiaシリーズには卓上ホルダという充電Dockスタンドが付いていて便利です。ただ基本的には私は縦向きでしか使わないので、これを縦型でも使えるようなアダプターを自分で作ってみました。卓上ホルダ用の穴を開けておき、そこにハメて使うようなスタイルです。スマホは卓上ホルダの磁力だけで浮いています。

見た目

f:id:jonki:20150112214726j:plain

f:id:jonki:20150112214024j:plain

f:id:jonki:20150112221220j:plain

3D Model

今回も123D Designでモデルを作り、UP Plus2でプリントしたものになります。

Xperia Dock Stand 3D Model Made with 123D 123D Design


実はこの前に一回失敗してます。下の画像の左が最初モデリングしたもの、右側が成功したものになります。左のものは角度をキツくし過ぎたために取り付けると前に倒れてしまいました。そこで傾斜を緩くし、土台も広めにしてバランスを良くしました。この辺りの失敗しながら試行錯誤できるのは、3Dプリンターオーナーのメリットですね。

f:id:jonki:20150112220241j:plain

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

この記事はおうちハックアドベントカレンダー22日目の記事です。


家にある身近なモノをハックしてみようと思い、ちょうど手頃なティッシュケースをハックしてみました。ティッシュを取るという行為が分かれば、いろいろと面白い使い方ができるのではないかと思った次第です。今回は作った1例として、ティッシュが1枚ずつしか取れないエコなティッシュケースを紹介してみます。「何を言ってるんだお前?」と思うかもしれませんが、まずは動画を御覧ください。
f:id:jonki:20141217004601j:plain


動機

最近いろんなガジェットが家の中に溢れてハックされるようになっています。ただ、いざ自分の部屋を見るとティッシュ、傘、机、椅子、コンロ、シャワーといったように、特にIT系の進化の恩恵を受けていない"昔ながら"のモノが大半を占めています。下手に新しいガジェットを生み出すよりも、こういった"昔ながら"のモノをハックした方が面白いのではないかと最近はずっと考えていました。
そこで今回おうちハックアドベントカレンダーが開催されることを知り、ネタ無しだったのですが何かできるだろうというノリで申し込みました。

とりあえず身近にあって扱いやすそうなのがティッシュでした。ティッシュにはティッシュを取るという分かりやすい人とのインタラクションがあります。これを検知するために、マイクや測距センサーをティッシュケースの内部に仕込みましたが、そこまで分かりやすいデータは取得できず。。。最終的には、加速度センサーや曲げセンサーを取り付けるのが良さそう、という案がでてきました。そこで手元にあった加速度センサーで簡単に試したところ、いい感じにティッシュが加速度センサーに引っかかり傾き変化からティッシュ取得アクションが取れることが分かりました。今回時間があまりなく、曲げセンサーやもっと小型の加速度センサーを使って小型化できなかったのは課題ですね。曲げセンサをケース内部にしまうのが一番スマートだと思います。
下は加速度センサーで簡単にプロトしたところです。ティッシュを取得すると内部に設置したLED群が綺麗に光ります。

f:id:jonki:20141207170140j:plain

仕様

今回動画で紹介したモノはこんな感じで動いています。

  1. ティッシュを取る
  2. 加速度センサーがティッシュアクションを検知
  3. ケース内部のLEDが点灯
  4. サーボに付いたバーがティッシュケースの開口部に回転し、ティッシュを取れないよう邪魔する
  5. タイマーのLEDが一定時間アニメーション
  6. タイムアウト後にバーが元の位置に戻る

構成と材料

構成はこんな感じです。1つのArduinoで加速度センサ、サーボ、LEDを操作しています。
f:id:jonki:20141217013813p:plain
f:id:jonki:20141217013745p:plain

今回のティッシュ箱は市販のティッシュケースを使って加工してます。また各デバイスには3Dプリンタで作ったケースを装着して見た目を整えています。利用したプリンタはUP Plus2で一般人向けの3Dプリンタでは現時点でおそらく一番よいシロモノでです。会社のベテランのメカ・デザインのエンジニアの方が言っていたので間違いないでしょう(笑)。ちなみに私はただのUIエンジニアなのでCADもメカの知識もゼロでしたが、一応使えてます。


今回作ったデバイスのケースです。上からGY-521のケース、GY-521ケースの蝶番、サーボのケース、サーボに取り付けるバー、リングLEDのケースになります。すべて123D Designで作っていて公開してるので、改変も自由です。





123D DesignはAutodeskが出している完全なフリーソフトのCADです。CADなんて触ったことありませんでしたが、この123D Designは初心者向けに機能をぐっと抑え、わかりやすいインタフェースで提供されています。渡しの場合は下の2つの本で簡単に使い方を覚えて、あとは身近な小さなケースなどを作っていきました。何回も採寸を間違えましたが、3Dプリンタで印刷しつつ何回もデザインを修正していくうちに少しずつ身についてきました。ある程度使い方を覚えたら自分の作りたいモノを作っていくほうが力になる感じがありますね。それぞれのモデルは設定にもよりますが1時間もしない間にプリントできます。

身近なモノの計測としてデジタルのノギスを使っていますが、深さとかも測れるしかなりいいですね。1万ぐらいすると思ってましたが、下のは3千円ぐらいで使い勝手もよく、早く買っておけばよかったと後悔するぐらいです。精度に関しても日曜工作ではまったく問題なさそうです、というのも、そもそもUP Plus2のプリント誤差のほうがでかいと思います。

シンワ デジタルノギス 大文字 15cm ホールド機能付 19975

シンワ デジタルノギス 大文字 15cm ホールド機能付 19975


傾きを取る

加速度センサーを使って回転角を取得します。加速度とジャイロを搭載したMPU-6050のボードがAmazonで安くてに入ったのでこちらを利用します。今回の用途ではジャイロは不要なので、秋月のKXR94という加速度センサーのみを搭載した小型のものを利用したほうが良かったかもです。


MPU-6050はMEMSの加速度センサーとジャイロセンサーを内蔵した6軸センサーで16ビットADCのI2C通信モジュールです。MPU-9150という地磁気センサーを載せた9軸の上位互換もあります。またI2Cの理解が適当だったので別記事でまとめています。

GY-521(MPU6050)
  • VCC: 3V~5Vの電源入力
  • GND: グランド
  • SCL: Serial CLock。I2Cの信号線 =>Arduino UNOではA5ピンに繋ぐ
  • SDA: Serial DAta。I2Cのデータ線 =>Arduino UNOではA4ピンに繋ぐ
  • XCL: eXternal CLock? 外部センサ用のI2C信号線
  • XDA: eXternal DAta? 外部センサ用のI2Cデータ線
  • AD0: Address。何も繋がないとき(内部抵抗を通ってGNDになっている)は0x68、HIGHにすると0x69になる。つまり同時に2個利用可能。それより多くのMPU-6050を使うときはArduino.ccに書いてあるTrickを利用する必要がある。
  • INT: Interrupt。割り込み出力

こちらの使いかたですが、Arduinoの公式のページに幾つかサンプルが載っています。

今回はメインのコードをスッキリさせたいので下記のライブラリを使わせてもらうことにしました。下記を落としてきてArduino\libraries\以下にI2CdevとMPU6050フォルダを丸ごとコピーしてください。

サンプルのMPU6050_raw.inoを参考に角度を求めます。出力される値を見ると値域は-16384〜16383っぽく15bitの符号付き整数として出力されていました(MPU-6050のADCは16bit)。これが分かればあとは角度(度数)に変換すればOKです。今回は比較的簡易な用途なので特にフィルターなどもなしで計算します。この計算式では360度の回転などは取れませんが、今回の用途ではx軸の0度〜90度が取れれば十分です。

f:id:jonki:20141206220301p:plain

#include "Wire.h"

#include "I2Cdev.h"
#include "MPU6050.h"

#define MAX_VAL 13684.0

MPU6050 accelgyro;

int16_t ax, ay, az;
int16_t gx, gy, gz;

float xdeg;
float ydeg;

void setup() {
  Serial.begin(38400);

  accelgyro.initialize();

  Serial.println("Testing device connections...");
  Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
}

void loop() {
  accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);


  xdeg = 90.0 * (ax / MAX_VAL);
  ydeg = 90.0 * (ay / MAX_VAL);
  Serial.print(xdeg); Serial.print("\t"); Serial.println(ydeg);
}

LEDについて

LEDはAdafruitのNeoPixelシリーズを使っています。使い方に関しては下記の記事を参考にしてください。

今回は2箇所にLEDを配置しています。1つはティッシュケース内に仕込んであるLEDです。こちらはティッシュを取得した時にティッシュケース内部を綺麗に照らすように作っています。これは下記の製品を2つ使って(LED30個分)半円としてケース内部に仕込んであります。製品ページの写真では完全な円になっていますが、こちらの製品は1/4の円なので注意です。つまり完全な円が作りたければ4つポチる必要があります。

もう1つはティッシュのリキャストタイムを示すものです。以前の記事でも使ったものですが、16個のLEDがリング上に配置されたものになります。

サーボについて

サーボモーターはSG90という小型で安いモノを使いました。トルクはないですが、今回はバーを動かす程度なのでこれで十分です。サーボの例はArduinoIDEに付属されているので使い方はスキップします。[スケッチの例]→[Servo]→[Sweep]など参考になると思います。電源はArduinoの5Vピンで大丈夫です。

ソースコード

今回作ったモノのArduinoソースコードです。NeoPixelに命令を送るとサーボにノイズが入ってプルプルと動いてしまったため、暫定対処としてLEDとサーボを排他的に動かしています。かなりイケてないです。とりあえず今回はタイムアウトということでソースも期待内ですが、公開します。

課題とまとめ

今回昔ながらのティッシュケースをハックし、ティッシュとのインタラクションを考えてみました。ちょっと作ったモノがネタっぽくなり、見た目もゴツゴツしてしまいましたが、ティッシュケースの題材選択は良かったかなと思います。誰でも使い方が分かる上に絶対に家にありますからね。今回できなかったですが、色々とネタは温めてあります。

  • ティッシュの残枚数を表示する
  • ティッシュが切れそうになったら赤く光って知らせてくれる
  • 家の各部屋に有るティッシュが連動して光る
  • 離れた家に住まう家族のティッシュが連動して光る

などなど、妄想は止まりませんね。冬休みに入って時間もあるのでまた何か作れればと思います。
明日のおうちハックはid:hecomi先生になります。