- Bookmark the following link: me
- Access a wikipedia page: (how about Lagrange multipliers)
- Run the bookmarked script
2012年1月18日水曜日
A scriptlet to let you access Wikipedia in the blackout
If you're desperate to access Wikipedia even during the blackout...
2012年1月5日木曜日
ウェアラブルにおいセンサを作ってみよう その1
概要
[編集 12/01/05 01:25]
屁を測ってみたら0.74になった。
キムチ臭いとか言ってる場合じゃなかった。
こんなことがしてみたい:
- 一日のいつなにをしたあと口臭が増える?
- 足について同上
- 世界臭いマップを作ってみたい(パリとNYは臭い。ロンドンはそうでもない。)
- 大のほうの臭いを定量測定して健康管理
材料
てなわけで・・・
作ってみた。(図1)
1段目はArduino Uno
2段目はSDカードとRTCの自作シールド。RTCには電気二重層コンデンサがバックアップ電源として繋がっているので、電池の抜き差しにも強い。
3段目は温度センサ(左後方でグチャグチャしてるケーブル)とにおいセンサ
3段構造になってしまったが、スマホ用ポーチには入った(図2)。
ピカソで売ってた「ファンシーポーチ」に入るんだからきっと着こなせる。
1秒に一回ぐらい測定して、時刻情報と共にSDカードに保存するように実装。
出す値は0から1で、高い程臭い。
![]() |
図2 決してデカすぎることはない。と思う。 |
測ってみよう
実験1 部屋 vs キムチ
部屋の通常時: 0.35
キムチが入ってた容器を水洗いしたものにかかげる: 0.60
- 水洗いしたのにキムチはムチャクチャ臭いね。
- キムチ嗅がせた後、5分間くらい0.60から値が下がらなくなり、焦った。なにか付着するのだろうか。
- なお、外に数分掲げても0.31だったので、家が臭い等という事は無い。
- ちなみに私の息は0.43だった。さっきキムチ食ったからだね。うん。
[編集 12/01/05 01:25]
屁を測ってみたら0.74になった。
キムチ臭いとか言ってる場合じゃなかった。
次やること
- GPS持って臭そうなところに散歩にでかけてみよう(動物園とか)
- 毎日の大便臭の記録取って見る
ken@臭いのは今日だけ 12/01/05
2011年12月25日日曜日
Arduinoでミリ秒まで出力出来るRTC8564のライブラリ
秋月電子のRTCモジュール(RTC-8564NB搭載のこいつ)は最小で秒単位の出力しか行えない。
まずは・・・
ベースとして以下のライブラリを拝借させてもらう:
このライブラリはbegin()を呼ぶだけでRTCの初期化を全部やってくれて、available()を呼ぶと最新の時刻を取得、そしてyear(), month(), etcで年,月,...をそれぞれ取得出来る。
これを改造して、ms()でミリ秒も取得できるようにしよう。
ついでに、available()という命名が気に入らないので、updateTime()に変更。
秒毎の頭のmillis()を覚える
基本的な考え方は:
まずはヘッダ:
メンバ変数の説明:
メンバ関数の説明:
次に、コンストラクタ:
こちらを参考に、RTCモジュールのピン3をD2かD3に繋げる。
3行目: currentRTCに自分を覚えさせる。interruptのハンドラ(interruptHandler())はグローバル関数しか渡せないので、処理の対象をcurrentRTCで覚える。だったらそもそもsingletonとして設計しろって話だが、そのうち配列で覚えるよ。
7-9行目: 渡されたinterruptピンを念のためINPUTモードにし、interruptHandler(後述)を電圧降下時のinterruptとして登録する。
以降: 1秒に一回interruptが呼ばれるように設定
次は、interruptのハンドラ:
これが呼ばれたということは秒が変わったということなので、currentRTCで登録されたオブジェクトのlastSecUpdateMSに今のmillis()を格納する。
次に、RTCの最新時刻を取得するupdateTime() (旧available())
RTCから年〜秒情報を読み込む。
更に、今のmillis()から、現在秒の頭で記憶したmillis()を引いて、差分を現在時刻のミリ秒として格納。
millis()は数ヶ月?ぐらいでオーバーフローするので、オーバーフロー時は適当に処理する。誤差の範囲だ誤差の。
ms(), years(), などはそのまんまの実装。
RTCに時刻を設定するための関数setTimeも、大して難しいことはない。詳しくは下記添付参照。
ライブラリ
RTC8564ms [zip]
以上ファイルをダウンロードして、Arduinoのlibrariesフォルダに置く。
実行してみる
projects: Biotope: Arduinoとリアルタイムクロック -1: 定周期タイマー割り込み & スリープで公開されている回路図に基づいて組んで、以下のサンプルコードを動かしてみる:
実行;
でもセンサ情報の記録(特に1Hz以上で)するんだったら、ミリ秒管理も必要だよね?
秒毎のinterruptとmillis()を組み合わせて、ミリ秒管理も可能なRTCライブラリを作ろう。
まずは・・・
ベースとして以下のライブラリを拝借させてもらう:
このライブラリはbegin()を呼ぶだけでRTCの初期化を全部やってくれて、available()を呼ぶと最新の時刻を取得、そしてyear(), month(), etcで年,月,...をそれぞれ取得出来る。
これを改造して、ms()でミリ秒も取得できるようにしよう。
ついでに、available()という命名が気に入らないので、updateTime()に変更。
秒毎の頭のmillis()を覚える
基本的な考え方は:
- 1秒に一回、秒が変わったタイミングをinterruptで受け取って、現在の秒の頭時点でのmillis()(=システム起動後の経過時間)を覚える(lastSecUpdateMS)
- 時刻取得を要求(updateTime())されたら、現在のmillis()からlastSecUpdateMSを引いて、ミリ秒を計算する。
まずはヘッダ:
class RTC8564ms { public: //time (in millis()) of the start of current second unsigned long lastSecUpdateMS; uint8_t data[7]; int _ms; RTC8564ms(int); void updateTime(); void setTime(long years, uint8_t months, uint8_t weekdays, uint8_t days, uint8_t hours, uint8_t minutes, uint8_t seconds); int ms(); uint8_t seconds(); uint8_t minutes(); uint8_t hours(); uint8_t days(); uint8_t weekdays(); uint8_t months(); long years(); bool century(); String toString(); };
メンバ変数の説明:
- lastSecUpdateMSに、現在の秒の頭millis()を格納
- data[]に、最後にupdateTimeを呼んだ時刻のyears〜secondsを格納
- _msに、最後にupdateTimeを呼んだ時刻のミリ秒を格納
メンバ関数の説明:
- ms(): _msを返す
- seconds()〜century(): そのまんま
- toString(): フレンドリーな文字列を返す
次に、コンストラクタ:
RTC8564ms::RTC8564ms(int interruptPin) { currentRTC=this; lastSecUpdateMS =millis(); _ms=0; //make sure we're in input mode pinMode(interruptPin,INPUT); //attach input for input handler attachInterrupt(interruptPin-2, interruptHandler,FALLING); for(int i=0;i<7;i++) data[i]=0; Wire.begin(); Wire.beginTransmission(RTC8564_SLAVE_ADRS); Wire.write((byte)0x01); //Control2 address Wire.write((byte)0x11); // TI/TP:1(繰り返し割り込みモード),TIE:1(定周期割り込み時、Lレベルの割り込み信号を発生させる) Wire.endTransmission(); Wire.beginTransmission(RTC8564_SLAVE_ADRS); Wire.write((byte)0x0E); // Timer Control address Wire.write((byte)0x82); //countdown period to 1Hz Wire.write((byte)0x01); //interrupt every second Wire.endTransmission(); }interruptを受け取るピン番号を引数に取る。Arduino Unoでは2か3のはず。
こちらを参考に、RTCモジュールのピン3をD2かD3に繋げる。
3行目: currentRTCに自分を覚えさせる。interruptのハンドラ(interruptHandler())はグローバル関数しか渡せないので、処理の対象をcurrentRTCで覚える。だったらそもそもsingletonとして設計しろって話だが、そのうち配列で覚えるよ。
7-9行目: 渡されたinterruptピンを念のためINPUTモードにし、interruptHandler(後述)を電圧降下時のinterruptとして登録する。
以降: 1秒に一回interruptが呼ばれるように設定
次は、interruptのハンドラ:
void interruptHandler(){ //record millis() of current second.000 currentRTC-> lastSecUpdateMS =millis(); }
これが呼ばれたということは秒が変わったということなので、currentRTCで登録されたオブジェクトのlastSecUpdateMSに今のmillis()を格納する。
次に、RTCの最新時刻を取得するupdateTime() (旧available())
void RTC8564ms::updateTime(){ Wire.beginTransmission(RTC8564_SLAVE_ADRS); Wire.write((byte)0x02); // write reg addr 02 Wire.endTransmission(); Wire.requestFrom(RTC8564_SLAVE_ADRS, 7); for(int i=0; i<7; i++){ if(Wire.available()){ currentRTC->data[i] = Wire.read(); } } long current=millis(); if(current<lastSecUpdateMS) _ms= current; else _ms=millis()-lastSecUpdateMS; }↑prettifyでコード内に「<」があるとバグるのがとてもウザい。なんとかならんのですかね?
RTCから年〜秒情報を読み込む。
更に、今のmillis()から、現在秒の頭で記憶したmillis()を引いて、差分を現在時刻のミリ秒として格納。
millis()は数ヶ月?ぐらいでオーバーフローするので、オーバーフロー時は適当に処理する。誤差の範囲だ誤差の。
ms(), years(), などはそのまんまの実装。
RTCに時刻を設定するための関数setTimeも、大して難しいことはない。詳しくは下記添付参照。
ライブラリ
RTC8564ms [zip]
以上ファイルをダウンロードして、Arduinoのlibrariesフォルダに置く。
実行してみる
projects: Biotope: Arduinoとリアルタイムクロック -1: 定周期タイマー割り込み & スリープで公開されている回路図に基づいて組んで、以下のサンプルコードを動かしてみる:
#include <Wire.h> #include <RTC8564ms.h> RTC8564ms *rtc; void setup(){ Serial.begin(9600); rtc=new RTC8564ms(2); //initialize using interrupt pin 2 rtc->setTime(2011,12,3,25,10,30,20); } void loop(){ //update rtc rtc->updateTime(); //print! Serial.println(rtc->toString()); delay(10); }
実行;
![]() |
RTC8642ms実行結果 |
ちゃんと動いてるね。
まとめ
まとめ
- millis()を別管理してRTSと同じ簡便さでミリ秒も楽々管理出来るライブラリを作った
- interrupt中はmillisは止まるので、正直そこまで正確というわけではない。同じ秒のindexを管理するよりはマシってレベルだろうきっと。
- RTCへのクエリーはどれぐらいのスピードで回せるんだろう?
登録:
投稿 (Atom)