1

LeapMotionとRubyでTumblr dashboard reblogging

マルかくとreblog、空中タップで下に進む。腕が疲れる。



研究室にleapmotionがあったのでかずすけ食べながらbabaくんと仕様を検討し、rubyから使うためにgemを作った

インストール


gem install leapmotion

できたてです。
指の位置と本数、腕の位置、手のひらき具合、ジェスチャー(circle、keyTap、swipe、screenTap)がわかる。
Websocket APIを使っているのでLeap Motion.appをインストール&起動しておく必要がある。
起動するとwebsocketサーバーになる。特に設定はいらない。

サンプルコードなどはgithub

使い方


:data イベント登録すると
require 'rubygems'
require 'leapmotion'

leap = LeapMotion.connect

leap.on :connect do
puts "connect"
end

leap.on :data do |data|
puts "hands #{data.hands.size}"
puts "pointables #{data.pointables.size}"
puts data
puts "-"*5
end

leap.on :disconnect do
puts "disconnect"
exit
end

leap.wait

手や指の座標が取れる。pointable(指)にはhandIdが付いていてどの手に属しているかわかる。
sphereRadiusは手の握り具合なのだが、どういう意味かはどの言語でもいいのでドキュメントを読むとわかる


ジェスチャー

leap = LeapMotion.connect :gestures => true

leap.on :gestures do |gestures|
gestures.each do |g|
puts g.type # => "circle", "screenTap", "keyTap", "swipe"
puts g
end
puts "-"*5
end

leap.wait

あらかじめプリセットされた4種類のジェスチャーが取得できる。
ご覧のとおり1度に複数のジェスチャーが認識される事があるし、swipeやcircleは連続して大量に発生するので扱いには工夫が必要。

ジェスチャーでtumblrを操作

上の動画の実装。
rubyでleapmotionのジェスチャーを読み取って、キーボード入力を発生させている。
chromeはchromekeyconfigとtomblooで、キーボードのjktで操作できる状態にしてある。

5

ArduinoとRubyで赤外線リモコン作ってWebから操作できるようにした

(追記)色々改良された → ArduinoとRubyで赤外線リモコン をgemにした

————-

帰宅前にスマホからクーラーをつけれるようにした。Arduinoと合計150円ぐらいの部品と、このRubyで書いたアプリ https://github.com/shokai/arduino_ir_remote だけで使える。

ソフトウェア部分はまだアップデートされるだろうけど、(rubygemにするとか)ハードウェアはもうこれ以上変更しないので是非自作してお試しください。
動かなかったり欠陥があったら、githubのissueかtwitterで@shokaiにどうぞ。


動いている証拠動画

実際に使いたいのはエアコンだけど、エアコンは地味なのでテレビでやってみた。


研究室にあるパナソニックとシャープのテレビで試したら両方とも動いた。
パナソニックのテレビから学習した赤外線データはgistに貼った。
データフォーマットについてもこの記事の下の方で解説してます。


経緯など

Linda家の温度を見れるようにしたら、だれもいない部屋の温度が高すぎるのが見えてしまい、帰るのが嫌になったので作った。日当たりが良すぎる。

以前KURO-RSという赤外線学習リモコンをRubyから使えるようにしたのだが、
うちの日立のエアコンの信号が特殊らしく操作できなかったので、赤外線学習リモコンも自作した。

日立エアコンだけでなく、富士通のエアコンでも動いたし、パナソニックやシャープのテレビも大丈夫だったから、たぶんどのメーカーの製品でも動くと思う。
赤外線学習リモコンが動かない理由は2つ考えられる。1.単に赤外線のデータが長くて保存しきれていない 2.信号をちゃんと解析しているタイプの学習リモコンの場合は解析に失敗している、のどちらか。
うちの日立のエアコンは富士通のに比べて3倍ぐらいデータが長かったので、たぶん電源on/offだけでなく温度風向き風量など現在の状態も全て送信している。
というわけでこの2つの問題に対処するために、1.大きめのbufferに保存するようにして 2.信号を解析せずに保存し再現出力するだけ、という仕様にした。


さらにRuby用のライブラリも作って、Sinatra RocketIOでWebアプリも作った。
赤外線学習リモコン


動かす

ソースコードはgithubに全部あり、回路も簡単なのでまず動かし方・設置方法を説明する。


材料

  • Ruby1.8.7以上が動くMacかLinuxマシンかRaspberry Pi
  • ArduinoとUSBケーブル 1個
  • 赤外線LED 1個(昔秋月で100個700円で買った)
  • 38kHz 赤外線リモコン受光器 1個(100〜150円ぐらい)

以上。
ArduinoはLeonardoMicroで動作確認した。
Seeduino v2(duemillanove互換)では動かなかった。下のほうに書いた赤外線LEDを38kHzで点滅させる処理が面倒くさい問題のせいだと思う。Arduinoコードのdelay時間をちょっといじればなんとかなると思うのでそのうちやる

Rubyが動くマシンやArduinoはそのへんに落ちているだろうし、150円ぐらいの追加で作れるのでやってみるといいのでは。


回路

回路は大変簡単だった。

Arduinoのデジタル3番ピンに赤外線リモコン受光器、 12番ピンに赤外線LEDを付けた。
赤外線リモコン受光器はいろいろあるけど、どれも5V/GND/DATAの3ピンで動く。
赤外線学習リモコン
これをエアコンの方に向ければいい。
けっこう離れていても届くけど、市販の赤外線LEDは指向性が強いので光が当たらない事がある。しっかり狙うか、LEDの頭を切断して拡散させるかするといい。

別の赤外線受光器も試してみたけど、ちゃんと動いた。
Learning IR-remote with Arduino and Ruby


インストール

githubからリポジトリをcloneして、
このファームウェアを書き込んで
https://github.com/shokai/arduino_ir_remote/blob/master/arduino/arduino.ino

あとはREADMEに書いてある通りに必要なgemをbundle installすればok


赤外線を読む

binディレクトリ内にCUIで赤外線読み書きできるツールが入っている。
ruby bin/arduino_ir_remote /dev/tty.usb-devicename


readして2.5秒以内に赤外線リモコンを照射したら、ターミナルに読み取ったデータがprintされる。
writeすると、1回前に読み取ったデータを発射する。


赤外線のデータを保存する

読み取った赤外線データは data.yml に保存しておくと名前を指定して発射できる。 sample.data.ymlみたいにすればいい。

sample.data.yml
"on" : "34,15,5,11,5,3,5,3,5,3,5,3,5,3,5,3,5,3,5,3,5,3,5,3,4,3,5,11,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,12,4,3,4,12,4,12,4,12,4,12,4,12,4,12,4,3,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,12,4,12,4,3,4,3,4,12,4,12,4,12,4,12,4,3,4,3,4,12,4,12,4,3,4,3,4,3,4,12,4,3,4,3,4,12,4,3,4,3,4,12,4,12,4,3,4,12,4,12,4,3,4,12,4,12,4,3,4,12,4,12,4,3,4,3,4,12,4,3,4,3,4,3,4,3,4,3,4,12,4,12,4,3,4,12,4,12,4,12,4,3,4,3,4,12,4,3,4,3,4,12,4,12,4,3,4,12,4,12,4,3,4,12,4,12,4,3,4,3,4,12,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,12,4,12,4,12,4,12,4,12,4,11,4,12,4,12,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,3,4,3,4,12,4,12,4,3,4,3,4,3,4,3,4,12,4,12,4,3,4,3,4,12,4,12,4,12,4,3,4,3,4,3,4,12,4,3,4,12,4,12,4,3,4,12,4,12,4,12,4,3,4,12,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,0"

"off" : "34,15,5,11,5,3,5,3,5,3,5,3,5,3,5,3,5,3,5,3,5,3,5,3,5,3,4,11,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,12,4,3,4,12,4,12,4,12,4,12,4,12,4,12,4,3,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,12,4,12,4,3,4,3,4,12,4,12,4,12,4,12,4,3,4,3,4,12,4,11,4,3,4,3,4,3,4,12,4,3,4,3,4,12,4,3,4,3,4,12,4,12,4,3,4,12,4,12,4,3,4,12,4,12,4,3,4,12,4,12,4,3,4,3,4,12,4,3,4,3,4,3,4,3,4,3,4,12,4,12,4,3,4,12,4,12,4,12,4,3,4,3,4,12,4,3,4,3,4,12,4,12,4,3,4,12,4,12,4,3,4,12,4,12,4,3,4,3,4,12,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,3,4,3,4,12,4,12,4,3,4,3,4,3,4,3,4,12,4,12,4,3,4,3,4,12,4,12,4,12,4,3,4,3,4,3,4,3,4,3,4,12,4,12,4,3,4,12,4,12,4,12,4,12,4,12,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,3,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,12,4,0"


赤外線データの記録方式

上の数字列は34,15,5,11の場合、3400マイクロ秒間38kHzの赤外線を発射、1500マイクロ秒間停止、500マイクロ秒間38Khzの赤外線を発射、11マイクロ秒停止という意味。

赤外線リモコンは自然光と区別するために38kHzの赤外線が300〜600マイクロ秒続く状態をon、何もなし状態が300〜600マイクロ秒続く状態をoffとして送信する。メーカーによって時間が違う。

elm-chan.orgの解説がわかりやすい。
赤外線リモコンの通信フォーマット

これを赤外線リモコン受光器に入力すると、38kHzの赤外線が入っている時にLOW、何もなし状態の時にHIGHが出力される。

信号データの内容を解析するのは面倒だったので、リモコンから来たのと同じ赤外線を再現するようにした。
赤外線リモコン受光器を監視して、出力がHIGH/LOWで変化した時間をmicros()で保存した。
データが1byteに収まるように、100マイクロ秒を1単位とした。


Webから使えるようにする

WebUIディレクトリ内にSinatraアプリがある
READMEに書いてある通りbundle installしてrackupすれば起動する。
上のディレクトリのdata.ymlを読む。

環境変数ARDUINOにArduinoのデバイス名を渡しておく必要がある。

赤外線学習リモコン

アプリは外から勝手に操作できないようにbasic認証を付けられる。
環境変数BASIC_AUTH_USERNAMEとBASIC_AUTH_PASSWORDで設定する。


サービスとしてインストール

WebUIのREADMEに書いてあるとおりforemanで家のMacのlaunchdにインストールした。
nginxのvirtual hostでremote.shookai.orgに置いてる。


苦労したことなど

そもそもちゃんと赤外線が読めているのか、ちゃんと38khzで発射できているのかがよくわからず苦労した。

試作

これを作る前に、2種類の方式で赤外線学習リモコンを試作した。
200マイクロ秒ごとに38kHz赤外線のon/offをbool配列で記録するbinary方式と、on/offが切り替わるまでの時間を記録するinterval方式を作った。

これはbinary方式。デジタルピン2番にスイッチを接続して、pushしたら2.5秒以内に赤外線リモコンを読ませる。シリアル通信で赤外線データを出力してくる。


38kHzを作るのが難しい

binary方式interval方式でdelayMicrosecondsの時間が違う。
ループや条件式の計算の処理時間があるので、それぞれの方式で別のdelay時間になってしまった。

そもそもPWMを使って38kHzを作ればいいんだけど、最初はStandardFirmataに赤外線学習リモコン機能を付けた物を作りたくてdelayとIO操作のみという縛りでやっていて、信号は読み書きできるんだけどRAM容量が足りなくて動かなかったからこうなった。
FirmataじゃないのになんでPWM使わない縛りやってるんだろうって気分に今なってる。

0

Macの「次のウィンドウを操作対象にする」をなぜ設定しないのか

わからない。

自分以外、だれも使っているのを見たこと無いし、自分が使っているとよくナニソレって聞かれるので書いておく

設定

[システム環境設定]→[キーボード]→[キーボードショートカット]
「次のウィンドウを操作対象にする」に適当にさわりやすい所ショートカットキーを設定する。command+spaceにしている。
command+spaceはデフォルトではIMEを順に切り替えるのに割り当てられているが、英数・かなキーがあるのでいらない。USキーボードはおっさんが使えばいい


どうなるかというと

左上のウィンドウでコード書いている時に、もうひとつのウィンドウに行きたい場合


command+spaceを押すと入れ替わる。
blog書くために複数ブラウザ開いている時なんかにも便利。keynoteやイラレで複数のドキュメント開いている時も便利。chromeと開発パネルを交互に見比べる時も便利。


こんな感じで

入れ替わる


別アプリへのフォーカス移動は、デフォルトでcommand+tabが割り当てられている。
同じアプリどうしの別ウィンドウにすばやくフォーカス移動するために、command+space設定しておくと便利。

0

Rubyのhoistingみたいなの

めんどうくさくてRuby1.8.7から上げていないままのアプリがあって、ちょっと修正したら動かなくなった。

JavaScriptにホイスティングというのがあって〜〜という話を〓が前に言っていて、へぇ〜と思っていたらRubyでも似たのが発生していた

hoisting.rb

urls = ["http://shokai.org/blog", "https://shokai.github.com", "http://example.com"]
url = "hoge"

puts url

urls.delete_if{|url| url =~ /shokai/ }
p urls

puts url


各Rubyで実行した結果


1.8.7だけ、変数urlの中身が書き換わっている。


どうしょうもないので、何かイテレータにしか使わなそうな名前を使うとか、_urlみたいな変数名を使うとかしないとならない。
urls.delete_if{|i| i =~ /shokai/ }

4年ぐらいRuby使ってるけど始めて遭遇したと思う

0

RubyのlambdaやProcとblock渡しとコールバック関数

先日のRuby初級入門2013で事前に「Rubyのlambdaとかblockとか教えて」と言われていたけど、どうみても初心者向けの内容ではないので無視していたので解説する


lambda{ コード }とProc.new{ コード }の差がよくわからない

ここ読め
RubyでlambdaとProcの違いは? – QA@IT
rubyのlambdaとprocの比較実験 – Qiita [キータ]
まとめると
内部でreturnした時と、引数の数が違うときの挙動が違うそうです


block渡しを使ったイベント登録について

do 〜 endブロックで渡された処理はすぐにyieldで返さなくてもいい


block渡しを受け取れる関数を宣言する方法

例えば、フィボナッチ数列を次々と生成する場合を考える。
フィボナッチ数列は無限に続くので、計算が終わらない。
無限に終わらない処理は結果をreturnで返せないので、1つフィボナッチ数を生成するごとにコールバック呼び出しで結果を通知する仕様にする。

Fib#start(&block) 関数を宣言すると、その中の block_given? でブロック渡しされたか判定できる
# -*- coding: utf-8 -*-
## フィボナッチ数列を1つずつ計算し、1つずつコールバックで返す

class Fib
def initialize
@f0 = 0
@f1 = 1
end

def start(&block)
loop do
f2 = @f0 + @f1 # フィボナッチ数列を計算
@f0 = @f1
@f1 = f2
if block_given? # ブロック渡しされているかどうかチェック
yield f2 # コールバック呼び出し
else
puts f2 # コールバック関数が登録されてない場合、自前で標準出力する
end
break if f2 > 1000000 # キリがないので終了
end
end
end

## フィボナッチ数計算開始 ##

## コールバックなしで計算スタート
Fib.new.start


## コールバック関数登録しつつ、計算スタート
Fib.new.start do |num|
puts "フィボナッチ数列 #{num}"
sleep 1
end
このように、時間がかかるor無限に計算が終わらない処理はコールバックで結果を返すといいと思います。
Webクローラとか。
〜〜のページを取得中、完了、などを計算する側でprint出力しているとコードが汚くなります。経過をお知らせするのもコールバック関数を登録する方式でやればいい。


コールバック関数を何個でも登録できるようにする

Fib#start 関数を実行する前に、コールバック関数を登録しておく。
長い処理の場合、計算の経過を通知・計算結果を表示・ファイルに保存・twitterに通知・・・等と色々やりたい場合がある。
コールバックを1つしか登録できないよりも、複数のコールバックを登録できるようにした方がいい。

コールバック登録関数 Fib#regist_callback(&block) を作り、&blockを普通に配列に貯めて、あとで使う。
# -*- coding: utf-8 -*-
## 複数のコールバックを登録する例

class Fib
def initialize
@f0 = 0
@f1 = 1
@callbacks = Array.new # コールバック関数を保存しておく配列
end

def regist_callback(&block) # コールバック関数を登録する
raise ArgumentError, "block not given" unless block_given? # 正しくblockが渡されない場合、エラーを投げる
@callbacks.push block
end

def start
loop do
f2 = @f0 + @f1 # フィボナッチ数列を計算
@f0 = @f1
@f1 = f2
@callbacks.each do |c| ## 全てのコールバック関数を順に呼び出す
c.call f2
end
break if f2 > 1000000 # キリがないので終了
end
end
end

## フィボナッチ数計算開始 ##
fib = Fib.new

# 1つ目のコールバック関数を登録する
fib.regist_callback do |num|
puts "フィボナッチ数列 #{num}"
end

# 2つ目のコールバック関数を登録する
fib.regist_callback do |num|
puts "result = #{num}"
end

fib.start ## 計算開始


&blockとは何か

do 〜 endが&blockに渡る。
&blockをprintしてみれば何なのかわかる。
# -*- coding: utf-8 -*-

def func(arg0, arg1, &block)
if block_given?
puts "blockとは -> #{block}"
block.call "ほげ", "ふが"
else
puts "block not given"
end
end

func 1, 2 do |a, b|
puts "this is block (#{a}, #{b})"
end

proc = Proc.new{|a, b|
puts "this is block 2 (#{a}, #{b})"
}
func(1, 2, &proc)

結果
blockとは -> #<Proc:0x007ff85410ca08@block.rb:12>
this is block (ほげ, ふが)
blockとは -> #<Proc:0x007ff85410c850@block.rb:16>
this is block 2 (ほげ, ふが)
&blockはProcだった。
doで渡しても、Proc.newを参照渡ししても同じように動く。


EventEmitterでコールバックを管理する場合

コールバック関数を登録するための関数を自分で用意する必要がなくなる、EventEmitterというrubygemを作りました。

インストール

gem install event_emitter

使ってみる

クラスにincludeするとイベント管理機能が追加されます。だいぶ綺麗に書けるようになりましたね
# -*- coding: utf-8 -*-
## 複数のコールバックをEventEmitterで管理する例

require 'rubygems'
require 'event_emitter'

class Fib
include EventEmitter # EventEmitterを使う

def initialize
@f0 = 0
@f1 = 1
end

def start
loop do
f2 = @f0 + @f1 # フィボナッチ数列を計算
@f0 = @f1
@f1 = f2
emit :number, f2 # numberイベントを発行
break if f2 > 1000000 # 終了
end
emit :end # 終了イベントを発行
end
end

fib = Fib.new

# 1つ目のコールバック関数を登録する
fib.on :number do |num|
puts "フィボナッチ数列 #{num}"
end

# 2つ目のコールバック関数を登録する
fib.on :number do |num|
puts "result = #{num}"
end

# 終了イベントを登録する
fib.on :end do
puts "終了しました"
end

fib.start ## 計算開始
コールバック関数を分類できるようになってる。
この例では:numberと:endという2種類のコールバックを登録している。それぞれ、新しいフィボナッチ数が作られた時と、計算が終わった時に呼び出される。
event_emitterにはコールバック解除のremove_listener関数や、1回呼び出されたら消滅するコールバック once なども付いてきて大変便利。


最近作ったもので、わかりやすい例

を紹介すると
twitterでエゴサーチしてSkypeに通知するやつや、gyazzの差分を監視してSkypeに通知するやつは両方共event_emitterを活用していてエラーもクロールの経過報告も取得したページも全部コールバックを登録して受け取るようになっています。