0

加速度センサMMA7361をArduino Firmataで試した

一昨日発売の加速度センサを使ってみた。計測範囲を±6Gか±1.5Gか選択できる。450円。
3軸加速度センサモジュール MMA7361: センサ一般 秋月電子通商 電子部品 ネット通販

ピンだけ自分ではんだづけする必要がある。
秋月の通販ページにデータシートもある。


今まで日本でよく使っていたKXM52という加速度センサが1000円に値上げされて後継のKXR94が同じ850円で入ってきて、秋月から私達に「もうKXM52オワコンだから新しいのに移行してね」というシグナルが送られてきている。

MMA7361はKXR94のさらに半額で安いし、出力も安定してて良いと思う。


回路

マイコンは千石で買ったArduino Micro。
x,y,zをアナログ出力する3軸加速度センサなので、analog input 0,1,2に接続した。
MMA7361+ArduinoMicro


加速度センサ MMA7361の各ピンの役割



VDDピン
3Vを入れる

GNDピン
0Vに接続

gSピン
g-selectピン。計測範囲を±6Gか±1.5Gか選択できる。LOWかオープン状態で高感度な±1.5G、HIGH(3Vでいい)を入れるとレンジの広い±6Gになる。

0gピン
重力ゼロ、つまり自由落下している時にHIGHを出力するらしい。デフォルトでLOW。今回は試していない。

STピン
平らな場所に置いてHIGHにするとx=0, y=0, z=1Gとして自動キャリブレーションしてくれるらしい。今回は試していない。

SLピン
sleepピン。HIGHの時にスリープ解除なので、使うときは3Vを入れるか、Arduinoからdigital writeを入れてやる必要がある。LOWかオープン状態でsleepモードになる。
名前からしてHIGHにしたらsleepになると思って、30分ぐらい悩んだけどデータシート読み直したらHIGHでスリープ解除って書いてあった。そういう機能ならenableとかwakeupとかONとかdisable sleepって名前にしろよと思った。


加速度センサとArduinoの動作電圧

動作電圧は2.2~3.6Vまで。!!!5Vを入れてはならない!!! Arduinoには3V出力ピンがあるのでそれを加速度センサの電源電圧として使う。

Arduinoで3Vのセンサーを使う時は、3Vピンと隣のRFピンを接続しておかないと正しいアナログ入力値が計測ができない。
RFはAVRマイコンのAREFピン(アナログ変換器基準電圧ピン)で、これに入っている電圧を最大値1023として、6つのanalog inputピンの電圧が計測される。

この部分



プログラム

例によってArduino Firmata on Rubyを使った。

% gem install arduino_firmata

arduino_accel.rb
#usr/bin/env ruby
require 'rubygems'
require 'arduino_firmata'

arduino = ArduinoFirmata.connect

loop do
acc = {
:x => arduino.analog_read(0), # x,y,z軸
:y => arduino.analog_read(1),
:z => arduino.analog_read(2)
}
p acc
arduino.digital_write(12, acc[:z] > 512 ) # 表の時にLED点灯、裏返した時は消灯
sleep 0.1
end


実行。センサはgSピンをオープンにして±1.5Gの高感度モードにした。
% ruby arduino_accel.rb
{:x=>525, :y=>531, :z=>714}
{:x=>527, :y=>534, :z=>712}
{:x=>528, :y=>533, :z=>712}
{:x=>527, :y=>532, :z=>710}
{:x=>525, :y=>532, :z=>713}
{:x=>528, :y=>532, :z=>711}
{:x=>525, :y=>533, :z=>711}
{:x=>526, :y=>531, :z=>713}
{:x=>525, :y=>534, :z=>714}
z軸だけ多いのは重力加速度。約180(約0.58V)ぐらいGで増える。基盤を裏返したらz = 350ぐらいになった。

0

ピエゾ素子で振動センサを作る

回路

参考:http://arduino.cc/en/Tutorial/Knock

上と同じように、ピエゾ素子と抵抗4MΩを並列にして、GNDとAnalog input 0の間に接続した。
ピエゾはたしか千石で80円で買った奴。



振動を取る

道具箱の中に接着剤がついたゴム板があったので、サンドイッチしてみたらとても調子よくなった。
ゴムのどの位置を叩いてもピエゾ素子の真ん中に振動が伝わるようにする必要があるので、思い切り接着した。

これを床のカーペットに仕込んだら足音がバッチリ取れた。


最初に作った物。
ドラムセットにつけてみたけど、セロテープで付けたのでちゃんと伝わっていない。



プログラム

RubyのFirmataで書いた。
analog readして、最近1000回分を配列に保存しておいて最大値のみをterminalに表示する。(細かい数字がバラバラ出ると見づらいので)
#!/usr/bin/env ruby
require 'rubygems'
require 'arduino_firmata'

arduino = ArduinoFirmata.connect
puts arduino.version

buf = []
loop do
buf << arduino.analog_read(0)
puts buf.max
buf = [] if buf.size > 1000
end

0

RubyとArduinoとTwitterで天気予報を見る

こういうのを数年おきに、その時の近代的な実装で作りなおしてみるとプログラミング環境の進歩がわかる。


1. 今日傘が必要かどうか表示してくれるてるてる坊主

晴れの時


雨が降る可能性がある時

ウチでは15分おきにその日の天気予報を取得して表示している。うちテレビ無いけどこれのお陰で傘を忘れたりしなくなった。


プログラムはものすごい単純になっている。Rubyのみ。
Macで開発してRaspberry Piにデプロイした。Ruby動くUNIX系ならどこでも動くはず。
require 'rubygems'
require 'arduino_firmata'
require 'weather_jp'

arduino = ArduinoFirmata.connect
weather = WeatherJp.get '東京'
if weather.today.rain > 30 # 降水確率30%以上
arduino.digital_write 13, true ## 青色LED
else
arduino.digital_write 12, true ## 赤色LED
end
taiki45さんのweather_jpと俺のarduino_firmataを合わせると超綺麗に書ける。
MSN天気からデータを取ってきている。
6年ぐらい前に作ったときはPerlのCGI+XPortだったり、4年ぐらい前はRubyからArduinoにシリアル通信したりでもっと行数多かった。


ちなみにzakuniさん作のweather-reportはlivedoor weatherからデータを取ってきていて、降水量情報がない代わりに雨/雪/雹の可能性を示すumbrella?メソッドが在る。
require 'rubygems'
require 'arduino_firmata'
require 'weather-report'

arduino = ArduinoFirmata.connect
weather = WeatherReport.get '横浜'
if weather.today.umbrella? ## 傘が必要な時
arduino.digital_write 13, true ## 青色LED
else
arduino.digital_write 12, true ## 赤色LED
end


地名や降水確率のしきい値を実行時引数に渡せる仕様にして、githubに置いておいた。
ProcfileもあるのでMacやRaspberry Pi等にサービスとしてインストールできる。
shokai/teruteru · GitHub


回路は、昔秋月で買ったRGBフルカラーLEDを使った。
アノード3本/カソード1本のスタンダードな奴。

arduinoのどのピンにRGBが接続されているかはプログラム中に書いてある

こういうシールドにして、その上にティッシュかぶせて顔を書けば完成です。



2. 今日雨が降りそうだったら教えてくれるtwitter bot


雨が振りそうな日の朝に、こういうのが来る

Twを使うとtwitter botが簡単に作れる。
天気botこれだけで書ける。
require 'rubygems'
require 'tw'
require 'weather_jp'

tw = Tw::Client.new
tw.auth 'shokai_log' ## botアカウントで認証
weather = WeatherJp.get '東京'
if weather.today.rain > 30 # 降水確率30%以上
tw.tweet "@shokai #{weather.today}" ## @shokaiにmention送る
else
puts weather.today ## 予報の文章をterminalに表示するだけ
end

降らない時にも「今日の天気は晴れ」とか送ってるとだんだん見なくなるので、雨降る日だけtweetするようにした。

これも多少使いやすくしてgithubにコード置いておいた。
shokai/twitter-weather-alert · GitHub
cronで朝実行するようにしている。

1

ino使うとCUIでArduinoをビルドできて便利

実際Arduinoは.inoを.cppにしてavrgccしてavrdudeしているだけなので、CUIだけで書き込むのは難しくないんだけど
いいツールがあったので今後はこれ使っていく事にしたい。

モニタついてないサーバーに接続したArduinoを直す時とかにも便利。
というかArduino IDE微妙だからいつもemacs使ってるし、もうinoでいいんじゃないかな

http://inotool.org

動作にはpythonが必要。


インストール

MacのMountain Lionでは最初からpythonとeasy_installが入っているので
% sudo easy_install ino
% which ino


プロジェクトを作る

プロジェクトのディレクトリは作ってくれない
% mkdir testapp
% cd testapp
% ino init
ディレクトリが2つ、libとsrcができる


src/sketch.ino に普通にArduinoのプログラムを書く
void setup(){
pinMode(13, OUTPUT);
}

void loop(){
digitalWrrrrrrrrrrrrrrite(13, HIGH);
delay(1000);
digitalWriteeeeeeeeeee(13, LOW);
delay(1000);
}


ボード一覧を確認

% ino list-models
Arduino Leonardoを使うので、以後のコマンドに “-m leonardo” というオプションを付ければいい


ビルド

% ino build --help
% ino build -m leonardo

ちゃんとコンパイルエラーも出る


src/sketch.inoを直す
void setup(){
pinMode(13, OUTPUT);
}

void loop(){
digitalWrite(13, HIGH);
delay(1000);
digitalWrite(13, LOW);
delay(1000);
}

ちゃんとhexができた


書き込む

% ino upload -m leonardo
“Guessing serial port”の後、
成功するとReading/Writing/Readingと3つのプログレスバーが100%まで伸びる。
失敗すると、最後だけ見るとdoneとか言ってるけどprogrammer is not respondingなどエラーが出る。

-p /dev/tty.usbmodem1234 のようなオプション付けるとシリアルポートを指定できる


シリアル通信

をモニタできる。


picocomが必要なのでインストールする。debian/ubuntuのaptにもあるらしい。
% brew install picocom

とりあえずSerial.printlnするようにプログラム直して
void setup(){
pinMode(13, OUTPUT);
Serial.begin(9600);
}

void loop(){
digitalWrite(13, HIGH);
delay(100);
Serial.println("on");
digitalWrite(13, LOW);
delay(100);
Serial.println("off");
}

% ino serial

ctrl+a ctrl+x で終了できる

0

Sinatra RocketIOで家のRaspberry PiのArduinoをリアルタイムで見る

RocketIOのサンプルとして、それなりに激しい処理が低スペックマシンで動くかテストするために作った。

http://status.shookai.org

ソースコード
https://github.com/shokai/rocketio-arduino-sample


こういうのが表示されてるはず


物理的な意味ではこうなってる
R0020611


Arduino Firmata on Rubyで、ADコンバータに温度センサと明るさセンサを付けたArduinoを読んで0.3秒毎にSinatra RocketIOでブラウザにpushしている。

5秒毎にCPUとメモリ使用量もpushしてる。
あと新規接続/切断がある度に全クライアントに接続数を通知してる。


60行ぐらいのSinatra40行ぐらいのJavaScriptでできてる。


JavaScript側を抜粋すると、こんな感じでそれぞれイベント待ちしておいて

io.on("arduino", function(data){
$("#temp").text("気温:"+data.temp+"度");
$("#light").text("明るさ:"+data.light);
});

io.on("stat", function(data){
$("#cpu").text("CPU:"+data.cpu+"%");
$("#mem").text("メモリ:"+data.mem+"%");
});

io.on("clients", function(data){
$("#websocket").text("websocket:"+data.websocket);
$("#comet").text("comet:"+data.comet);
});


サーバー側はsinatraの中にArduinoでセンサーを読むEventMachineのタイマーをベタ書き。
io = Sinatra::RocketIO

## Arduino sensors
io.once :start do
begin
arduino = ArduinoFirmata.connect ENV['ARDUINO'], :eventmachine => true
rescue => e
STDERR.puts "#{e.class} - #{e}"
next
end
EM::add_periodic_timer 0.3 do
light = arduino.analog_read 0
$logger.debug "light : #{light}"
temp = arduino.analog_read(1).to_f*5*100/1024
$logger.debug "temperature : #{temp}"
io.push :arduino, :temp => temp, :light => light
end
end
CPUとメモリは同じ要領で、psコマンドの結果をparseして送ってる。


Sinatra側で定期的に行う処理は、 Sinatra::RocketIO.once :start の中で登録すると良いです。
“start”はeventmachineとwebsocketサーバーの準備が整ったら発火するイベント。
onではなくonceなのは1回目だけ呼ばれるという意味。


あと、Arduino Firmataの最近のバージョンからeventmachine用の起動オプションを付けた。
ArduinoFirmata.connect "/dev/tty.usbデバイス名", :eventmachine => true
EM::runの中でこうやって起動するとThreadのかわりにeventmachineで動くようになった。
Sinatraの中で動かすときはこうしないと、タスク切り替えがうまくいかない。