0

ArduinoとRubyで赤外線リモコン をgemにした

これを大改修した。
ArduinoとRubyで赤外線リモコン作ってWebから操作できるようにした
特徴は以下のとおり

  • Arduinoに約110円分の電子部品を追加すれば赤外線学習リモコンが作れる
  • 市販の学習リモコンが対応していないような長大なデータでも読み書きできる
  • 学習リモコン機能を自作アプリに組み込めるRubyライブラリ付き

最近は多少涼しくなった気もするけど、いまだに夕方の閉めきった部屋の中は40度近くまで上昇していて危ない。このツールで家に帰る前に冷房をonにしておくと助かる。

gitリポジトリはここ https://github.com/shokai/arduino_ir_remote


機能追加・変更された事

  • rubygemにした。赤外線学習リモコンをライブラリとして自作アプリに組み込める。
  • 学習した赤外線データを別々のアプリ間で共有できるように、データを管理する機構もgemに含めた。
  • 6つのアナログピンの数値をRubyで読めるようにした。温度センサなどを追加できる。
  • CUIから赤外線リモコンを使えるコマンド “arduino_ir_remote” もgemに同梱した。ssh接続可能なmac/linuxサーバーにArduinoを接続し、このrubygemをインストールするだけでリモートから赤外線機器をコントロールできる。
  • webブラウザから赤外線リモコンを操作できるアプリは別のgitリポジトリに移動した。READMEに書いてある通りに起動すれば動くしサービスとして常駐させられる。


回路

たったこれだけの回路で作れる。
デジタル12ピンに赤外線LED、デジタル3ピンに赤外線リモコン受光器を接続。
このfirmwareをArduinoに書き込む。

Arduino IR Remote


インストール

gem install arduino_ir_remote
which arduino_ir_remote
arduino_ir_remoteコマンドもインストールされる。


赤外線の読み書き


まずarduino_ir_remoteコマンドを使う例。 -helpで使い方が表示される

読む

arduino_ir_remote -read 名前
で赤外線を読む。

reading…と表示されてから1.5秒以内に赤外線リモコンを当てると、デコードされて表示される。
データは ~/.ir_remote.yml にyaml形式で保存されている。

部屋の蛍光灯が赤外線リモコンと同じ波長・周波数をだして邪魔になる事があるので、調子が悪い時は電気を消してから学習させてください。


書く

arduino_ir_remote -write 名前
で発射する。

とりあえずCUIから赤外線が読み書きできる。


このコマンドはサーバーに赤外線リモコンを付けている場合に便利。
sshはコマンドを渡せるので、
ssh shokai@サーバー名 arduino_ir_remote -write エアコンON
とかでリモートからエアコンつけられる。

一覧

arduino_ir_remote -list
で保存した全データが確認できる。


赤外線の読み書き(アプリから)

READMEにも書いたが、ライブラリとして使用して自作Rubyアプリにも組み込める。

読む

接続時にデバイス名は指定しなくても自動的にArduinoらしきデバイスを探す。
require 'rubygems'
require 'arduino_ir_remote'

ir = ArduinoIrRemote.connect # use default device
## ir = ArduinoIrRemote.connect "/dev/tty.usb-devicename"

ir.read do |data|
p data
ArduinoIrRemote::DATA["tv_on"] = data
ArduinoIrRemote::DATA.save # ~/.ir_remote.yml に保存される
end
ir.wait
コールバックでデータを読んで、Hashとして扱えるArduinoIrRemote::DATAにデータを保存できる。


書く

これでテレビの電源がつく。
ir.write ArduinoIrRemote::DATA["tv_on"]
ir.wait

読むのはarduino_ir_remoteコマンドでやっちゃって、書くところだけ自作アプリで作ったUIからやるとかでいいと思う。


外部センサーの追加

Arduinoなので赤外線リモコン専用というわけではなく、センサーを追加できる。
うちではこんな風になっている。
Analog 0にLM35DZ温度センサ、Analog 1にCdS照度センサを接続した。
Arduino IR Remote

上から見た図
Arduino IR Remote with Temperature&Light Sensors


外部センサーを読む

Ruby側でanalog_readできる。値は300ミリ秒毎にArduinoから送られてきている。
require 'rubygems'
require 'arduino_ir_remote'

ir = ArduinoIrRemote.connect # use default device

loop do
puts ir.analog_read 0 # アナログ0ピンを読む
puts ir.analog_read 1
end
部屋の明るさだけでなく、テレビに近づければ電源がついているかも判別できると思う。

温度センサLM35DZを読む

LM35DZは安くて定番なんだけど数値を摂氏に変換する手間がある。
ライブラリ内でやっておいた。
ir.temp_pin = 0  # set temperature sensor pin

loop do
puts ir.temp_sensor
end
これで温度がチェックできる。室温が40度とかになっててエアコンつけざるをえない事がわかる。

温度はコマンドからも見れる。
手元から自宅の温度が1行で取得できて便利。エアコン切って1時間ぐらいで37度になるとかヤバイ


サンプルアプリ

webから赤外線リモコンを操作できるインタフェースを作った。トータルで100行ぐらいで実装されているので見るといいと思う。
もちろんgit cloneすれば手元ですぐ動かせる。
https://github.com/shokai/arduino_ir_remote_webui

2013-08-19 05.01.48


要望・バグなど

@shokaigithubのissueにどうぞ

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

ドアノックで研究室の鍵が開くようになった

偶然の産物だったけどうまく動いている。




ピエゾ素子で作った振動センサーと、サーボモーターでドアをあけるやつ(最近Arduinoで実装しなおした)をLinda RocketIOで接続した。

もともとドア周辺の人間の歩行をセンシングしたくてセンサーを置いてみたのだけど、ドアのある場所をうまくノックすると反応していたのでノックで電子錠を開けれるようにした


これ
AndroidとNFCで研究室の鍵を開けるシステムができた
のどすこい認証バージョン

0

1台のArduinoを複数のRubyプロセスで共有できるようになった

Arduinoを複数のRubyプロセスで共有したいの続き


Arduino Firmata on Ruby使うと複数のプログラムで同時に1台のArduino動かせるようになった。

v0.2.9をリリースした

gem install arduino_firmata


結局dRuby使う必要は無かった。
昔はserialport gemは1つのプロセスがportを専有してしまっていた気がするのだが、そうでもなくなってた。
Firmataの初期化プロセスを見なおしたら複数プロセスから使えるようになった。


サンプルの
arduino_firmata/samples at master · shokai/arduino_firmata · GitHub
– led_blink.rb
– on_analog_read.rb
– servo.rb
– digital_read.rb
を同時に動かせた。


1つのArduinoにあるセンサーを同時の複数のアプリから読み取ったりできるようになってコードがすっきりします。
1台で複数アプリ動かせて、アプリがそれぞれ別々にバージョン管理できるというのはものすごい利点です。よほど速度が重要な処理でない限りArduinoにコード直書きやめて、Ruby Firmata使いましょう。

0

Arduinoを複数のRubyプロセスで共有したい

Arduino Firmata gemにdRubyを用いたプロセス間共有機能を標準で入れようと考えている。
マイコンを複数プロセスで共有して同時に使えると、実にコードが綺麗になってRubyらしくていいと思う。

ここで試している
share an arduino with dRuby · Issue #25 · shokai/arduino_firmata


Arduinoを複数プロセスで共有したい

Lindaで色々やっていると、センサーで色々値を取ったり、モーターを動かしたり、色々やりたくなる。

Arduinoを複数のプロセスで共有し、プログラムの密結合を解きアプリケーションごとに別のコードとして分けたい。

ハードウェアをネットワークに接続して複数のプロセスを起動し、色々なサービスを同時に走らせる時に、1つの仮想シリアルポートは1プロセスからしか同時アクセスできない問題がある。(Arduinoはいまだに仮想シリアルポートなのだ)

解決方法は2つで、Arduinoを複数使う。しかしこれは格好悪いし金もかかるし電気も食うから良くない。
もしくは1つのプログラム内でThreadを立てて、1プロセスで複数のアプリケーションを動かす方法があるけどこれも格好悪い。プログラムをアプリケーション毎にバージョン管理できない。


dRuby

dRubyはRubyに標準で付いている分散オブジェクトライブラリであり、複数プロセス間でオブジェクトが共有できてメソッド呼び出しもできる。
marshalされたオブジェクトがTCP上で飛んでいくらしい。$stdoutなんかも別プロセスに渡せる。
先日のRubyHirobaでのtoRubyの人たちによるワークショップでちょっと触った瞬間にArduino共有したいと思った。


実験

0.5秒間隔で13番ピンのLEDを点滅させるプログラムと、
0.1秒ごとにADコンバータでセンサーを読んで11番ピンにPWM出力するプログラムを1台のArduinoで同時に走らせた。

server.rb
require 'rubygems'
require 'arduino_firmata'
require 'drb/drb'

arduino = ArduinoFirmata.connect
DRb.start_service "druby://localhost:5010", arduino

loop do
arduino.digital_write 13, true
sleep 0.5
arduino.digital_write 13, false
sleep 0.5
end


client.rb
require 'drb/drb'

DRb.start_service

arduino = DRbObject.new_with_uri "druby://localhost:5010"

loop do
ad = arduino.analog_read 0
puts ad
arduino.analog_write 11, ad/4
sleep 0.1
end

すんなりと両方同時に1台のArduinoの上で動いた。というのも当たり前で、firmataはArduinoから逐次送られてくるinput系の値はRuby VM上のArduinoFirmataインスタンスに貯めておくし、write系は即時にシリアル通信で送られてArduinoの出力ピンに反映される。通信は全二重で行われるので複数プロセスが1台のArduinoにfirmataで同時にアクセスしても何も問題はない。

無理なのはlambda渡しでイベント登録してコールバック受ける arduino.on(:analog_read, &block) や arduino.on(:sysex, &block) で、これはしょうがないかもしれない。
常に使う機能では無いし。


問題

開いているポートを探す

普通、RubyでTCPSocketなどを使おうとするとportが開いていなかったら例外が発生するのだが、dRubyでstart_serviceするとそのまま開けてしまう。
他のプロセスにもdRubyのメッセージが行ってしまう。

先にTCPSocket開いてそのインスタンスをdRubyで使うとかしたい。


だれがサーバーになるか

普通に考えて最初にArduinoを開いた人がサーバーになるだろうけど、その人が強制終了したら全員死んでしまいます。


オプションでもいい気がしてきた

arduino = ArduinoFirmata.connect "デバイス名", :share => true
とかでいいかも