おうちハック#2発表会でLTしてきた

2015/02/01におうちハック#2発表会というところでLTしてきました。

内容は、「電気やガスのスイッチを消したことを記録してくれるボットがいれば、心配になって、一度帰ったりしなくて良くなるんじゃないか。」というもの。

それを実現できそうな技術に当てはめて、いけそうな目処がついたのでLTしてきました。

FeliCaを使って消したことをチェックし、チェックしたことをSlackへ通知しています。

使った部品

今回は、初めてFeliCaWiFiモジュールを使ってみました。

どちらもライブラリがあり、意外と簡単に扱えました。

使ったライブラリ

Q & A

  • スマホでいけるんでは。
    • スマホにリーダー機能ついているのであればできそうです。
  • 実際使う?運用面倒じゃない?
    • このままだとやはり使いにくいと思っています。やっぱりカードを持ち歩く方が楽かなーと思います。

補足

  • やっぱりスイッチ自体に加工いれたくない?
    • 現状復帰が面倒なので、あまりそれはしたくないです。
  • 消えてるという状態になっているとは限らないよね?
    • それはとれてないです。
  • スイッチ自体にタッチセンサー付けるとか?
    • それなら実現できると思います。
    • ただ最近の電灯のスイッチは冪等性がない(1回押すたびにON/OFFが変わる)ので、結局上の補足の問題点は解決できないので、悩ましいです。
  • mbed単体でもSlack通知は可能では。
    • SSL通信ができれば可能そうではありました。
    • ON/OFFデータ自体は他の用途でも使えそうなので、温湿度計でも使っているfluentdで集めるのはありかなと。
  • fluent-plugin-slackが新形式のhookurlに対応していない。
    • fork辿って行くとすでに直している人がいるので、それを使わせてもらいました。

MFT2014に出展したmbedを使ったニコニコ新着動画表示器

この記事はmbed Advent Calendar 2014 - Adventarの18日目の記事です。

以前、作ったニコニコ新着動画表示器にサムネイル表示機能をつけて、MFT2014で展示してきました。

1. 全体の構成

大きな構成は変更しておらず、mbedからHerokuを経由してニコニコ新検索βAPIニコニコ大百科に書いてあった動画情報を取得するAPIへアクセスして、データを返しています。

2. Heroku上で動いているプログラム

GitHub - mia-0032/nico-category-recent-videos-for-mbed: ニコニコ新検索βの検索APIをラップしてカテゴリ別新着動画の取得をする(mbed用)

で公開しています。

以下の2つのAPIを作りました。

  1. カテゴリを指定すると新着動画を取得し、mbedで表示するために整形して、JSON形式で返すAPI
  2. 動画IDを指定するとその動画のサムネイルをbmp3に変換して返すAPI

mbedでjpegのデコードライブラリをいくつか試したのですが、画像によってはうまくいかないことがあったので、サーバー側ですべてbmp3に変換しています。

ビットマップ形式はデコードが必要なく、1バイトずつ読みこめば画像を表示することができるので、扱いが楽で良いです。

ついでにサーバー側でサムネイルサイズの違いを吸収して、すべて128*128で返すようにしており、mbed側で画像のサイズに合わせてオフセットをつけるといった処理を省きました。

3. mbed側の処理

サムネイル表示にはMARY-OB OLED基板を使いました。

mbedとの接続は以下のようにしています。

p5 <-> OLED_SDIN
p7 <-> OLED_SCK
p8 <-> OLED_CNS
p12 <-> OLED_RESN
p11 <-> OLED_VCC_ON

書いたプログラムは以下に公開しています。

mbed_recent_nicovideo_display_pub - display recentest video in niconico. | Mbed

Herokuのホスト名部分(SERVER_HOST)だけ変えれば動くと思います。

MARY-OB OLED基板用のライブラリとして MARMEX_OB基板OLEDライブラリ (MARMEX_OB_oled) | Mbed を使っています。

mbedのバージョンアップで、そのままだと動かないので、SPI_FREQUENCY = 16000000に変更して動かしています。

mbed側では以下のように処理を行っています。

  1. カテゴリ名を指定してHerokuにアクセスし新着動画の取得。
  2. JSONをパースし、動画ID、カテゴリ、タイトルを取得。
  3. 動画IDを指定してHerokuにアクセスして動画サムネイル画像を取得。
  4. 一度、mbedのストレージに画像を書き出す。
  5. 画像を読み出し、OLEDへ表示。
  6. タイトルなどをOLEDへ表示。

3と4についてはaccess_thumb_apiの関数で行っています。

bmpファイルは424Dから始まるので、ネットワークから取得したデータのその部分からローカルファイルに書き出しています。

5の部分についてはdisplay_bmpの関数で行っています。

bmp3は最初の54バイトはヘッダ情報になっているのでスキップして、それ以降のデータを表示しています(注:今回はあらかじめサーバー側でサイズなどを全部固定しているのでスキップして問題ないです)。

bmpファイルは画像の左下から右上の順にデータが並んでおり、それをそのままOLEDのドットに反映しているので、下から更新されていく感じになっています。

4. 現状の問題

  • 有機ELモジュール SEL10016B (文字を表示している方)の初期化がうまくいかない問題があります。
    • 電源投入直後は初期化処理がうまくいかないようで、一度、有機ELモジュールを抜いて、その後mbedをリセットをすると表示されるようになります。
      • 初期化処理のタイミングの問題かなとは思っています。
  • 長時間動作させるとフリーズします。
    • まだ原因不明です。
  • サムネイル表示処理(ダウンロードと表示)に数十秒かかっています。
    • ダウンロードしたファイルをストレージに書き込む部分で時間がかかっているようです。
    • できればもう少し高速化したいところです。

5. まとめ

  • サーバー側でだいぶ処理を挟んで楽をしました。
  • 使いたい部品についてmbed.orgで探すとたいてい誰かが作ったライブラリがあるのがいいです。

明日は@ssci_officialさんです。よろしくお願いします。

MFT2014に出展したmbedを使った蛍光表示管 温湿度気圧計

この記事はmbed Advent Calendar 2014 - Adventarの5日目の記事です。

以前作った蛍光表示管を使った温湿度気圧計にグラフ表示機能を追加してMakerFaireTokyo2014に展示してきました。

全体の構成図はこんな感じです。

グラフ表示の部分については、データの送信までをmbedでやって、残りはRaspberryPiでやっています。

mbedからイーサネット経由でHTTPでデータを送信して、それをRaspberryPi上のfluentdで受け取ります。

受け取ったデータはグラフ化ツールのfocuslightに送信され、focuslightにブラウザからアクセスすることで、温度・湿度・気圧の変化のグラフを見ることができるようになっています。

このあたりの仕組みはTesselで同じことをやったときのものを大体流用しています。

コードは以下で公開しています。

mbed_vfd_thermometer - thermometer, hygrometer and barometer. Using VFD … | Mbed

fluentdにHTTP経由でPOSTする部分を追加しています。

FluentLogger - FluentLogger: fluent-logger-mbed A structured log… | Mbedというライブラリが公開されているのですが、今回は検証時間がとれなかったので、HTTP経由でやっています。


実際にMFT2014の当日に測定した結果をスクショとってみました。

RaspberryPiをインターネットに接続していなかったので、時間がずれてしまっています。

グラフでみると1日目は6時間後、セットアップしたのが9時頃だったので15時くらいに最も温度が高くなっています。この時は湿度も高いです。

体感でもこの時間は会場が非常に暑く、上着を脱いだ記憶があります。その後、シャッターの閉まっていたドアが半分開放されて、非常に涼しくなった記憶があります。

2日目も同じく30℃くらいまで温度が上昇しているものの、湿度が高くはなく、暑すぎるという感じではありませんでした。

2日目はたしか最初からドアが開いていたと思うので、そのおかげかもしれません。


6日目はtw_hoehoeさんです。よろしくお願いします。

mbed Advent Calendar 2014 - Adventarは、特に14日の週が空いているので、ぜひ参加お願いします!複数書いても大丈夫です!

mbedからニコニコ新検索βAPIにアクセスして結果を表示

この記事はmbed Advent Calendar 2014 - Adventarの1日目の記事です。

以前、mbed祭り2014@夏の東銀座mbedからインターネット上のAPIへアクセスしてデータを表示というプレゼンをやりました。

そのときはニコニコ新検索βAPIからデータを取得する際に、herokuを経由して文字コードを変換&GETメソッドでアクセスできるようにして、OLEDに表示していました。

その後、使用したGraphicOLEDのライブラリがアッフデートされてUTF-8に対応していたので、今回はmbedから直接ニコニコ新検索βAPIへアクセスして表示してみます。

POSTメソッドでAPIにアクセスする参考になるかと思います。

最後はこんな感じになります。

0. mbedと有機ELモジュールおよびイーサネットコネクタの接続

有機ELモジュールについてはmbedからheroku上のデータを取得してOLEDに表示してみる - 工作とかプログラミングとかの記事と同じ接続なので、 そちらを参照ください。

前回と同じくイーサネット接続にはmbed LPC1768用イーサネット接続キット - スイッチサイエンスを使いました。

前回、ネットワークの接続がうまくいかないことがあったのですが、キットの3.3VとGNDをmbedに接続し忘れていたことが原因でした・・・

ちゃんと接続すると安定して動作するようになりました。

1. mbedからニコニコ新検索βAPIへアクセスする

実際のコードは mbed_nicovideo_search_api - ニコニコ新検索βAPIからデータを取得して有機ELに表示する。 | Mbed に公開しています。

コードの解説をしていきます。 コードはすべてmain.cppに書いてあるので、その解説になります。

1.1 イーサネットコネクタのLEDを光らせる

イーサネットコネクタには通信状態を示すLEDがついています。 そのLEDを光らせるコードです。

こちらのコードは mbed用イーサネット接続キットでメール送信を試す。: じぇーけーそふとのこーなー を使わせていただきました。ありがとうございます。

17-26行目:

// ethernet
DigitalIn lnk(P1_25);
DigitalIn spd(P1_26);
DigitalOut speed(p29);
DigitalOut link(p30);
 
void flip(void const *args) {
    speed = !spd;
    link = !lnk;
}

35-37行目:

    // ethernet led
    RtosTimer flipper(flip, osTimerPeriodic, NULL);
    flipper.start(50);

コードとしてはネットワークの接続状態が出力されているP1_25, P1_26のピンを50msごとにLEDの接続されているp29,p30へリダイレクトするようになっています。

1.2 mbedからニコニコ新検索βAPIへアクセスする

53-55行目:

    char post_data[256];
    sprintf(post_data, "{\"query\":\"%s\",\"service\":[\"video\"],\"search\":[\"tags\"],\"join\":[\"cmsid\",\"title\",\"start_time\"],\"from\":0,\"size\":1,\"sort_by\":\"start_time\",\"issuer\":\"apiguide\",\"reason\":\"ma10\"}", SEARCH_TAG.c_str());
    pc.printf("POST Data:\r\n%s\r\nLength:%d\r\n", post_data, strlen(post_data));

post_dataにはJSON形式の検索クエリが入っています。検索クエリのフォーマットについてはAPIリファレンスに書いてあるので、そちらを参照ください。

内容としてはmbedタグのついた動画を新着順にソートして新しいものから1件取得するというものになっています。

57-60行目:

    char http_cmd[1024];
    sprintf(http_cmd, "POST %s HTTP/1.1\r\nHost: %s:%d\r\nAccept: */*\r\nContent-Length: %d\r\nContent-Type: application/json\r\n\r\n%s\r\n\r\n", API_PATH.c_str(), API_HOST.c_str(), API_PORT, strlen(post_data), post_data);
    pc.printf("Request:\r\n%s\r\n", http_cmd);
    sock.send_all(http_cmd, sizeof(http_cmd)-1);

HTTPメソッドにPOSTを指定してリクエストを送る部分です。

POSTでは送るデータの長さをContent-Lengthヘッダーに指定する必要があります。

また送るデータの形式Content-Typeを指定する必要があります。今回はJSON形式なのでapplication/jsonを指定しています。

key=valueみたいな値(URLエンコード済み)とキーを指定する形式であれば、application/x-www-form-urlencodedを指定します。

76行目:

    response_body = response.substr((int)response.find("\r\n\r\n") + 1);

APIから受け取ったレスポンスからヘッダー部を取り除く処理です。

ヘッダーとボディは改行コード2つで分かれており、その部分で文字列を切り取っています。

1.3 レスポンスから動画タイトルの抽出

APIのレスポンスボディは以下のように4行のJSONから構成されています。

{"dqnid":"9c55fb01-42db-48c1-8ef5-8268b9fc04c7","type":"stats","values":[{"_rowid":0,"service":"video","total":52}]}
{"dqnid":"9c55fb01-42db-48c1-8ef5-8268b9fc04c7","endofstream":true,"type":"stats"}
{"dqnid":"9c55fb01-42db-48c1-8ef5-8268b9fc04c7","type":"hits","values":[{"_rowid":0,"cmsid":"sm24696784","start_time":"2014-10-15 12:54:14","title":"mbedプラットフォーム「うおーるぼっとBLE」"}]}
{"dqnid":"9c55fb01-42db-48c1-8ef5-8268b9fc04c7","endofstream":true,"type":"hits"}

3行目のvaluesの中に動画タイトルが含まれいるので、まず3行目以降を取り出します。

81-83行目:

    for(int i=0; i<3;i++){
        response_body = response_body.substr((int)response_body.find("\n{") + 1);
    }

その後、values内の[]で挟まれた部分を抽出します。

85-87行目:

    int start_pos = (int)response_body.find("[") + 1;
    int end_pos = (int)response_body.find("]");
    response_body = response_body.substr(start_pos, end_pos - start_pos);
  • (注): 動画タイトルなどの文字列に]が含まれているとうまくいかないので、その時はエスケープをちゃんと見るようにしないといけないです。

ここまでで以下のように動画のタイトルが含まれたJSON形式の文字列を抽出できます。

{"_rowid":0,"cmsid":"sm24696784","start_time":"2014-10-15 12:54:14","title":"mbedプラットフォーム「 うおーるぼっとBLE」"}

1.4 JSON形式の文字列のパース

あとはpicojsonというJSONパーサーを使って、titleの部分を抜き出して表示するだけです。

92-100行目:

    picojson::value v;
 
    const char *json = response_body.c_str();
    string err = picojson::parse(v, json, json + strlen(json));
    pc.printf("--> error %s\r\n", err.c_str());
 
    pc.printf("--> values %s\r\n", v.get("title").get<string>().c_str());
    oled.cls();
    oled.printf(v.get("title").get<string>().c_str());

picojson::parseメソッドでJSON形式の文字列をパースできます。

その中から特定のキー、例えばtitleの値を取りたいときはv.get("title")のように指定し、さらにメソッドをつなげてv.get("title").get<string>()のようにすると、titleの文字列(string型)を取得できます。

  • (注): 3行目をそのままpicojsonで読み込ませても動く気がするのですが、うまくいかなかったのでvalues部分だけ抽出してpicojsonでパースしています。

あとはOLEDに出力してあげれば最初の画像のように文字列を表示することができます。


まだ12月5日、7日、10日以降が空いているので、 mbed Advent Calendar 2014 - Adventarにぜひ参加してください。複数書いてもいいですよ!

12月2日は@en129さんです。よろしくお願いします。


関連エントリ

ログのURLをパースして指定した要素を抜き出すNorikraUDFを作った

f:id:mia_0032:20151112084622p:plain

URLをパースして指定した要素を抜き出してくれるUDF(splituri)と、GETパラメータを同じようにパースして指定したキーの値を抜き出してくれるUDF(splitquery)を作りました。

norikra-udf-uri_parser | RubyGems.org | your community gem host

github.com

なぜ作ったか?

流れてくるログに含まれるURLの中から特定のパスや、特定のGETパラメーターを取得したい要件があって、それを楽にするために作りました。

使い方

splituri(expression, string)

このUDFは基本的にはRubyURI.parseをラップしたようなUDFになっています。

第1引数にはURLまたはpathの文字列をとります。

第2引数には以下の文字列を指定できます。 scheme,userinfo,host,port,path,opaque,query,fragment

返り値は第1引数で指定したURI文字列の第2引数で指定した要素の部分の文字列になります。

クエリ例

pathフィールドには/hoge?foo=bar#topといった文字列が入っているとします。 以下にクエリその結果を返します。

SELECT
  splituri(path, 'scheme')   AS scheme,
  splituri(path, 'userinfo') AS userinfo,
  splituri(path, 'host')     AS host,
  splituri(path, 'port')     AS port,
  splituri(path, 'path')     AS path,
  splituri(path, 'opaque')   AS opaque,
  splituri(path, 'query')    AS query,
  splituri(path, 'fragment') AS fragment
FROM access_log
{
  "port":"",
  "host":"",
  "scheme":"",
  "query":"foo=bar",
  "opaque":"",
  "path":"/hoge",
  "userinfo":"",
  "fragment":"top"
}

URL形式の文字列を指定することもできます。 例えばrefererフィールドにhttp://example.com/hoge?foo=bar#topというURLが入っているとします。

SELECT
  splituri(referer, 'scheme')   AS scheme,
  splituri(referer, 'userinfo') AS userinfo,
  splituri(referer, 'host')     AS host,
  splituri(referer, 'port')     AS port,
  splituri(referer, 'path')     AS path,
  splituri(referer, 'opaque')   AS opaque,
  splituri(referer, 'query')    AS query,
  splituri(referer, 'fragment') AS fragment
FROM access_log

上記のクエリは以下の結果を返します。

{
  "port":"",
  "host":"example.com",
  "scheme":"http",
  "query":"foo=bar",
  "opaque":"",
  "path":"/hoge",
  "userinfo":"",
  "fragment":"top"
}

splitquery(expression, string)

GETパラメータなどのクエリ文字列(ex.key1=value1&key2=value2)の中から指定したキーの値を取得するUDFです。

確認したところURLエンコードされた文字列もデコードしてくれるようです。

第1引数には上記のクエリ文字列をとり、第2引数に値を取得したいキーを指定します。

クエリ例:

queryフィールドにfoo1=bar1&foo2=bar2&foo3=bar3という文字列が指定されているとします。

SELECT
  splitquery(query, 'foo1') AS foo1,
  splitquery(query, 'foo2') AS foo2,
  splitquery(query, 'foo3') AS foo3
FROM access_log

上記のクエリは以下の結果を返します。

{
  "foo3":"bar3",
  "foo2":"bar2",
  "foo1":"bar1"
}

配列でパラメータを渡すような場合(ex. foo[]=bar1&foo[]=bar2&foo[]=bar3)にも対応しています。

SELECT
  splitquery(query, 'foo[]') AS foo
FROM access_log

この場合は返り値が配列になる点に注意してください。

{
  "foo":[
    "bar1",
    "bar2",
    "bar3"
  ]
}

キーのみがついていて、値がない場合(ex. test&foo1=bar1&foo2=bar2test)には空文字を返すようになっています。

SELECT
  splitquery(query, 'test') AS test,
  splitquery(query, 'other') AS other
FROM access_log

存在しないキーについてはnullを返すようになっているため、存在するかを判定したいときはnullチェックをすればできると思います。

{
  "other":null,
  "test":""
}

splituriとsplitqueryの組み合わせ

もちろん入れ子にして使うこともでき、例えばpathフィールドに/hoge?foo=barという文字列が入っているとすると、

SELECT
  splitquery(splituri(path, 'query'), 'foo') AS val
FROM access_log

上記のクエリは以下の結果を返します。

{
  "val":"bar"
}

まとめ

  • Norikraでアクセスログの集計などを行う場合に便利かと思うので、よければ使ってください。

参考にしたもの

  • https://github.com/norikra/norikra-udf-mock
    • 初めてNorikraのUDFを書きましたが、これを見るだけで書けるくらいに手順が書いてあるので、非常に助かりました。ありがとうございます。

備考

  • splituriはログの中身によって文字列か配列かを返すようになっているため、逆に使いずらいかもしれないです。
    • 配列パラメータについては文字列か配列のどちらで返すか選べるようにしたほうがいいかもしれないと思っています。
  • 第2引数を指定せず、すべてハッシュで取得できるUDFもあると便利かもしれないです。

mbedで蛍光表示管を使った温湿度気圧計

mbedで蛍光表示管を使って温度・湿度・気圧を表示できるデバイスを作成しました。

f:id:mia_0032:20141115204225j:plain

この作品はMakerFaireTokyo2014に出展します。

実物見たい人は是非見に来てください。

製作について

1. 蛍光表示管のシールド作成

f:id:mia_0032:20141115204649j:plain

蛍光表示管の信号線をすべて1本1本mbedに接続すると、9個(7セグ+ドット+4の横棒)*4の36個も端子を使ってしまうので、そういう接続はせずに、ダイナミック点灯という方法を使います。

ダイナミック点灯は目の残像を利用した点灯方法です。 4本のうち光っているいるものは常に1本で、それを高速で切り替えることで、残像で全部が光ってみえます。

4本あるうちのどの蛍光表示管を光らせるかの接続4個とどの部分を光らせるか(上の9個)の13個の信号線だけで蛍光表示管を駆動できるので端子数が節約できて良いです。

蛍光表示管をダイナミック点灯するための回路は、デジットで売られている蛍光表示管のキットの回路を大体そのまま使わせてもらいました。

蛍光表示管は駆動するのに、最低でも12V以上の電圧が必要となります。なので、mbedの端子から出力できる3.3Vの電圧では足りないため、間にトランジスタを挟み、mbedの出力を別電源から与えた電圧に変換して蛍光表示管に与えています。

蛍光表示管を光らせるには電圧は12V以上の電圧が必要ですが、電流はそんなに流れません。

そこで蛍光表示管用の電源は、外部に別の電源を用意するのではなく、秋月の昇圧キットを使って、USBの5Vから昇圧して20Vを得ることで光らせることにしました。

なお、今回20Vとしているのは、ダイナミック点灯により実質明るさが1/4となってしまうため、電圧を上げてその分、1本あたりの明るさをあげています。

2. 使用したセンサー

を使いました。

どちらもI2C接続で接続でき、mbedの使用する端子の数を減らせます。 AM2321とLPS331は、LPS331のI2Cのアドレスを変更することで同時利用できます。

3. mbedのプログラム

mbedはLPC1768、いわゆる青mbedを使いました。 何だかんだで使いやすいmbedだと思います。

今回使用したライブラリは以下です。

ソースコードは以下で公開しています。

mbed_vfd_thermometer - thermometer, hygrometer and barometer. Using VFD … | Mbed

初めてタイマー割り込みを使ってみましたが、こんなに便利なものとは思ってなかったです。コードがすっきりするので見通しがよくなりますね。

下のような感じで表示されます。

温度の表示のときは末尾が「C」になります。

f:id:mia_0032:20141109210942j:plain

湿度表示のときは末尾が「P」になります。

f:id:mia_0032:20141109210950j:plain

気圧表示のときはの末尾なしか3桁のときは「h」が出るようになっています。

f:id:mia_0032:20141109210954j:plain

4. 外装の作成

2枚のアクリル板で挟むサンドイッチみたいな構造にします。

上側にセンサーや蛍光表示管やICなどが出っ張っているので、それを活かしたデザインにします。

まずはプロトタイプを紙で作成しました。

f:id:mia_0032:20141115200516j:plain

加工は、いつもどおりはざい屋にお願いしました。

現物合わせで調整したい基板の取り付け穴などは自分で加工しました。

f:id:mia_0032:20141115200459j:plain

仮組みしてみたときはこんな感じです。

f:id:mia_0032:20141115144820j:plain

できあがり

f:id:mia_0032:20141115204225j:plain

まとめと今後

  • メジャーなセンサーはmbed.orgにライブラリをつくってくれている人がいるのでありがたいです。
  • RTOSはサンプルプログラムがわかりやすいので、サンプルを実行しながら説明を読むと、理解しやすかったです。
  • Ethernetとかの部分はまだ作りかけです。

RaspberryPiでfluentdを立ち上げる

RaspberryPiにデータ収集して可視化する環境の構築をする。

今回はfluentdのデーモン化まで。

0. 使うもの

  • RaspberryPi
    • OS: RASPBIAN
  • Supervisor
    • 各種アプリケーションのデーモン化のために使う。
  • Fluentd
    • データ収集アプリケーション。

1. 準備

1.1 RaspberryPiのメモリを空ける

自分の持っているRaspberryPiは古いタイプでメモリが256MBしかない。

いくつか常駐のプロセスをたちあげたいので、できるだけメモリの空き容量は増やしておく。

以下のページを参考にメモリ空き容量を増やした。

Raspberry Pi 使えるメモリー量を増やすチューニング | Act as Professional

1.2 rbenvのインストール

システムのrubyはバージョンが古めなので、新しいバージョンにするついでにrbenvで複数のバージョンを同居できるようにしておく。

インストール方法は以下を参照した。

rbenv のインストール (Linux Mint) - Qiita

rubyのインストールには数時間かかった・・・

2. fluentdのインストールと設定

2.1 fluentdのインストール

$ gem install fluentd --no-ri --no-rdoc

依存パッケージも自動的にインストールされる。

2.2 fluentd用のOS設定

2.2.1 時刻の設定とNTPの設定

時刻が日本時間になっていない場合、設定画面から設定する。

$ date
2014年 10月 26日 日曜日 11:28:25 UTC
# 最後がJSTになっていたら必要なし。UTCなど他のものであれば日本時間に直す。
$ sudo raspi-config 

4.Internationalisation OptionsI2 Change Timezoneアジア東京 で日本時間に設定できる。

NTPの設定については以下のページを参照した。

Raspberry Piの設定【NTPデーモンの設定】 - Aldebaranな人のブログ

2.2.2 ファイルディスクリプタの設定

http://docs.fluentd.org/ja/articles/before-installを参考にファイルディスクリプタの最大値を上げておく。

2.2.3 ポートの開放

fluentdのin_forwardプラグインで受けるポート(24224)を開ける。

基本的にはRaspberry pi セットアップその9 iptablesの設定 | Keep no way, keep on screamingを参照して行った。

fluentd用に/etc/iptables/rules.v4を編集して以下を追加している。

# Allows forward connections for fluentd
-A INPUT -p tcp -m state --state NEW --dport 24224 -j ACCEPT
-A INPUT -p udp -m state --state NEW --dport 24224 -j ACCEPT

2.3 fluentdのconfの作成と起動

/home/pi/fluent/fluent.confを作成し、以下のように記述する。

<source>
  type forward
  port 24224
  bind 0.0.0.0
</source>

<match **>
  type stdout
</match>

この設定でfluentdに送られてきたデータは標準出力に出力されるようになる。

試しに起動してみる。

$ fluentd -c /home/pi/fluent/fluent.conf -v &

以下のようなコマンドをうつとログが流れる。

$ echo '{"json":"message"}' | fluent-cat debug.test

2014-10-26 21:30:06 +0900 debug.test: {"json":"message"}と流れてきたら成功。

手元のMacにもfluentd-catがインストールされていれば、以下のコマンドをうつとログが流れる。

echo '{"json":"message"}' | ./fluent-cat -h <RaspberryPiのIP> -p 24224 mac.test

上と同じく2014-10-26 21:48:13 +0900 mac.test: {"json":"message"}と流れれば成功。

3. Supervisorを使ったデーモン化

3.1 Supervisorのインストール

pipでインストールすることもできるが、apt-getで入れた方がsupervisor自身の管理までやってくれるので楽。

$ sudo apt-get install supervisor

3.2 fluentdのSupervisorの設定ファイルの作成

/etc/supervisor/conf.d/fluentd.confを作成し、以下のように記載する。

[program:fluent]
command=/home/pi/.rbenv/shims/fluentd -c /home/pi/fluent/fluent.conf
stdout_logfile_maxbytes=1MB
stderr_logfile_maxbytes=1MB
stdout_logfile=/var/log/fluent/%(program_name)s.log
stderr_logfile=/var/log/fluent/%(program_name)s_error.log
autorestart=true
autostart=true
user=pi

以下のコマンドを実行するとfluentdがデーモン化される。

$ sudo supervisorctl reread
$ sudo supervisorctl add fluent

ここまででfluentdの立ち上げまで終わり。

関連エントリ

mbed祭り2014@夏の東銀座 で「mbedで作るニコニコ新着動画表示器」の発表をした

第10回mbed祭り2014@夏の東銀座の20分枠で発表してきました。

発表した内容

タイトルは「mbedで作るニコニコ新着動画表示器」。

内容は、以下の2つの記事をまとめて、あとはWebAPIを叩く時に必要になる知識の部分を追加した感じです。

スライドは以下にアップロードしていますのでよければどうぞ。

自分の展示

当日は自席の上で作った物の展示もしていました。

何人かから話しかけていただいて、いくつか質問もらったり、アドバイスもらったりしたのでメモ。

  • Heroku使わなくても良くない?
    • mbedでやろうと思えば全部できると思います。ただサーバーサイド入れ替えれば何でも表示できるのは強いかなーと。
  • Herokuってお金かかるの?
    • 1アプリで無料時間があるものの、ずっと使うとお金かかるので、家のRasPiとかに移したほうがいいかも。
  • RasPiだったらすぐに作れそう。
    • RasPiは電源入れたり抜いたりするのが面倒なので、できればマイコンボードで作りたかった。
  • サムネイルほしい。レトロな感じでドット絵風とか。
    • 確かにそれはほしいと思った。次回の改良時には入れたい。

当日のまとめ

生放送もタイムシフト試聴できる(2014/09/06(土) 23:59:59まで)ので、ぜひとも。

注:一般会員で事前にタイムシフト予約していない場合は見れないです・・・

感想

  • 意外と今回初めてきたという人が多かった。新しい層に広がっているのは良いと思う。
  • 前回参加した時は抽選会でフリスケ黒mbedが当たり、今回はフリスケ青mbedがあたった。
    • フリスケに縁があるのかもしれない。
    • 何か作らねば。
  • IoTとかM2Mの話はよく出てきたので、やはり最近の流行りな感じはした。
  • プレゼンするのは楽しかったので、ネタ作ってまた次回もやりたい。

関連エントリ

mia-0032.hatenablog.jp

mia-0032.hatenablog.jp

mbedとニコニコ検索APIで新着動画表示器を作った

前回の記事で作成した、mbedでheroku上のデータを有機ELモジュールに表示するというデバイスの続きです。

今回は、heroku上のアプリケーションからニコニコ新検索βのAPI(以下、ニコニコ検索API)を叩いて、カテゴリごとの新着動画を取得して表示できるようにします。

全体の構成

mbed <-> heroku <-> ニコニコ検索API

上記のようにmbedからheroku上のアプリケーションへアクセスし、さらにそのアプリケーションからニコニコ検索APIを叩くという構成です。

herokuを挟まずにmbedから直接ニコニコ検索APIを叩くという方法もできると思いますが、文字コード変換やJSONのパースなど、面倒なことが多そうだったので、こういう構成にしています。

  • herokuでやっていること

    1. ニコニコ検索APIを適切なパラメータで叩いてデータを取得する。
    2. 取得したデータのパース。
    3. 表示する形式に加工して出力。
  • mbedでやっていること

    1. heroku上のアプリケーションへアクセスしデータの取得。
    2. 取得したデータを有機ELモジュールへ表示。

heroku上のアプリケーションの作成

heroku上のアプリケーションでやることは先ほど述べた以下の3つの処理です。

  1. ニコニコ検索APIを適切なパラメータで叩いてデータを取得する。
  2. 取得したJSONデータのパース。
  3. 表示する形式に加工して出力。

1については、APIガイドを参照してもらうのが早いです。

例えば以下のようなリクエストボディを指定してAPIへPOSTすると、レスポンスが返ってきます。

リクエストボディ例:

{
  "query" : "ニコニコ技術部",
  "service" : ["video"],
  "search" : ["tags"],
  "join" : ["cmsid", "title", "start_time"],
  "from" : 0,
  "size" : 1,
  "sort_by" : "start_time",
  "order"  : "desc",
  "issuer" : "apiguide",
  "reason" : "mbed"
}

レスポンス例:

{"dqnid":"0de8aa15-90ba-47d2-a61c-7da950bbe3bc","type":"stats","values":[{"_rowid":0,"service":"video","total":29260}]}
{"dqnid":"0de8aa15-90ba-47d2-a61c-7da950bbe3bc","endofstream":true,"type":"stats"}
{"dqnid":"0de8aa15-90ba-47d2-a61c-7da950bbe3bc","type":"hits","values":[{"_rowid":0,"cmsid":"sm24113085","start_time":"2014-07-29 11:13:21","title":"【物理エンジン】 骨付きSoftBodyによる挙動制御"}]}
{"dqnid":"0de8aa15-90ba-47d2-a61c-7da950bbe3bc","endofstream":true,"type":"hits"}

他のカテゴリの新着動画を検索するときは、上記のリクエストボディ例のニコニコ技術部の部分を各カテゴリタグに変えてリクエストすればOKです。

2については、レスポンス例を見ると3行目に表示に必要な動画情報が入っていることがわかります。 その3行目のvaluesのキーの中に配列が入っており、その各要素が1つの動画情報になっています。

今回は最新の1つが取れればいいので、配列の要素は1つだけです。 複数取得した場合は、この配列の中に複数要素が入ることになります。

3については、動画情報の中のcmsidtitle、検索の際に指定したカテゴリタグを使って以下のような形式に加工します。

sm24113085|ニコニコ技術部|【物理エンジン】 骨付きSoftBodyによる挙動制御

カテゴリタグは表示領域の関係から半角カタカナにしています。

また、有機ELモジュールのライブラリはShift-JISのみの対応となるので、カテゴリタグとタイトルについては文字コードをShift-JISへ変更しておく必要があります。

さらにタイトルには、HTMLエンティティ(&amp;など)が含まれるため、これをデコードする処理が必要になります。

以上の処理を入れてheroku上で動くようにしたコードは以下のリポジトリに公開しています。

GitHub - mia-0032/nico-category-recent-videos-for-mbed: ニコニコ新検索βの検索APIをラップしてカテゴリ別新着動画の取得をする(mbed用)

mbedのプログラム

mbedのプラグラムは前回の記事からいくつか変更を行っています。

大きな変更としては、heroku上のアプリケーションにアクセスするときに、カテゴリ名を指定できるようにしました。 8秒ごとに次のカテゴリに切り替わるようにしています。

他にも有機ELモジュールで表示できる文字数に文字列を制限したり、いくつかの定数の切り出しなどの変更を行っています。

インポートしているライブラリは前回の記事と同じく以下のライブラリです。

またmbedと有機ELモジュールの接続も前回と同じ接続です。

有機ELモジュール <-> mbed

1(VDD) <-> VOUT

2(VSS) <-> GND

4(RS) <-> p24

6(E) <-> p26

11(DB4) <-> p27

12(DB5) <-> p28

13(DB6) <-> p21

14(DB7) <-> p22

書き込んでいるコードは以下に記載しています。

ニコニコ動画新着動画表示器 · GitHub

your-app.herokuapp.comの部分は自分のサーバーに書き換えて使ってください。

mbedに書き込むと、以下のようにカテゴリごとの新着動画が表示されます。 8秒ごとに次のカテゴリになり、また一周すると最初のカテゴリに戻ります。

f:id:mia_0032:20140728001404j:plain

f:id:mia_0032:20140728001436j:plain

最初、mbedのループ処理の中でEthernetの初期化〜クローズしていたらうまく動かなくて、だいぶ悩みました。 ループの外に出してやると、うまく動くようになりました。 原因はよくわかっていません。

感想

有機ELモジュールの色がとても良いです。キャラクタ液晶のフォントのレトロ感も相まって、雰囲気の良いものができました。

もう少し拡張しようかと思っていましたが、このデバイスはこれでシンプルかつコンパクトにまとまったので、ケースに入れようと思っています。

関連エントリ

mbedからheroku上のデータを取得してOLEDに表示してみる

mbedからheroku上に作成したWebアプリケーションのデータを取得してグラフィック有機ELモジュールに表示するということをやってみました。

mbedとは

ARM社が開発しているラピッドプロトタイピング用のマイコンボードです。 同じようなものにArduinoがあります。

Arduinoと比較すると、

  • ブラウザ上で開発できる
  • コードやライブラリなどの公開・共有ができるhttps://mbed.org/
  • 全体的にスペックが高め
  • イーサネットの物理層がチップに載っているのでコネクタをつけるだけでネットワークに接続できる
  • 一部の機種ではアナログ出力(PWMではなく)が使える

といった特徴があります。

特にネットワークにつなぎやすいというのは大きな特徴で、Arduinoだと別途イーサネットシールドを買わなければならず、結局、費用が高くついてしまいます。

mbedはマイコンボード自体はArduinoより価格が高いですが、ネットワークにつなぐ時にはコネクタを用意すればいいだけなのでトータルコストでは安くなります。

というわけで、mbedを今回は使って進めました。

heroku上にWebアプリケーションを作成する

今回はmbedの方のシステムを検証したかったので、herokuのGetting Started with Herokuの通りに進めて Hello, world を表示するだけのアプリケーションにしました。

次の記事で、Webアプリケーションの方は本格的に作成します。

mbedでネットワーク上のデータを取得する

mbedのRD-, RD+, TD-, TD+をイーサネットコネクタに接続してネットワークに接続できるようにします。

最初にmbed_officialのTCPSocketのサンプルコードを動かしてみました。

なお、依存関係のある以下の3つのライブラリは先にインポートしておきます。

mbedに書き込んでリセットボタンを押してしばらく待ちます。 シリアル出力をコンソールで見ると以下のようになって正常に動いていることを確認できます。

IP Address is 192.168.0.1
                         Received 299 chars from server:
                                                        HTTP/1.1 200 OK
Server: nginx/1.1.19
Date: Tue, 15 Jul 2014 16:10:28 GMT
Content-Type: text/plain
Connection: close
Last-Modified: Fri, 27 Jul 2012 13:30:34 GMT
Cache-Control: max-age=36000
Expires: Wed, 16 Jul 2014 02:10:28 GMT
Vary: Accept-Encoding
X-Mystery-Header: 894274989
X-be: web2
          Received 57 chars from server:
                                        _prod_sjc
X-Varnish: 894274989
Age: 0

Hello world!

次に先ほど作成したheroku上のアプリケーションに接続するため以下の部分を書き換えます。 your_appの部分は自分の作ったアプリケーション名です。

11〜13行目:

    sock.connect("your_app.herokuapp.com", 80);

    char http_cmd[] = "GET / HTTP/1.1\r\nHost: your_app.herokuapp.com\r\nConnection: close\r\n\r\n";

ホスト名の書き換えの他に、HTTPのプロトコルを1.1にして、2つリクエストヘッダーを追加しています。

herokuは自分が試した限りではHTTP1.0のプロトコルでは接続できないようで、HTTP1.1を指定する必要があるようでした。

余談ですが、ここが原因であることを突き止めるまでに作業の大半の時間がかかりました・・・

HostはHTTP1.1では必須の項目です。

Connectionは指定しないとkeep-aliveが指定され接続がタイムアウトするまで次に処理が進みません。 今回はすぐに接続を切ってしまって大丈夫なのでcloseを指定します。

この書き換えを行って再度シリアル出力をコンソールから見ると、以下のようになり正常にデータを取得できていることがわかります。

IP Address is 192.168.0.1
                         Received 194 chars from server:
                                                        HTTP/1.1 200 OK
Content-Type: text/html;charset=utf-8
Date: Tue, 15 Jul 2014 16:25:58 GMT
Server: WEBrick/1.3.1 (Ruby/2.0.0/2014-05-08)
Content-Length: 12
Connection: Close

Hello, world

有機ELモジュールに取得したデータを表示する

使った有機ELモジュールはこちらです。

今回使った有機ELモジュールはGraphicOLEDというライブラリですでに動作実績があるので、このライブラリを使います。

このライブラリには美咲フォントという日本語フォントが同梱されているため、日本語も表示することができます。

まず有機ELモジュールをmbedに以下のように接続します。

有機ELモジュール <-> mbed

1(VDD) <-> VOUT

2(VSS) <-> GND

4(RS) <-> p24

6(E) <-> p26

11(DB4) <-> p27

12(DB5) <-> p28

13(DB6) <-> p21

14(DB7) <-> p22

以下のライブラリをインポートします。

mbedに書き込むプログラムを以下のように変更します。

#include "mbed.h"
#include "EthernetInterface.h"
#include "GraphicOLED.h"
#include <string>

//有機ELモジュールのインスタンスを生成
GraphicOLED oled(p24, p26, p27, p28, p21, p22);

int main() {
    // ネットワークに接続する
    EthernetInterface eth;
    eth.init(); //Use DHCP
    eth.connect();
    printf("IP Address is %s\n", eth.getIPAddress());
    
    // アプリケーションへアクセス
    TCPSocketConnection sock;
    sock.connect("your_app.herokuapp.com", 80);
    
    char http_cmd[] = "GET / HTTP/1.1\r\nHost: your_app.herokuapp.com\r\nConnection: close\r\n\r\n";
    sock.send_all(http_cmd, sizeof(http_cmd)-1);
    
    // レスポンスの取得
    char buffer[300];
    int ret;
    while (true) {
        ret = sock.receive(buffer, sizeof(buffer)-1);
        if (ret <= 0)
            break;
        buffer[ret] = '\0';
        printf("Received %d chars from server:\n%s\n", ret, buffer);
    }
      
    sock.close();
    eth.disconnect();

    // レスポンスのボディ部を取得するためにヘッダー部は取り除く    
    string response(buffer);
    string response_body;
    response_body = response.substr((int)response.find("\r\n\r\n") + 1);

    // 有機ELモジュールに出力
    oled.cls();
    oled.printf(response_body.c_str());
    
    while(1) {}
}

先ほどのサンプルプログラムからの大きな変更点はGraphicOLEDを使うようになったことと、Webアプリケーションのレスポンスからボディ部を取得する処理を追加したことです。

レスポンスのヘッダー部とボディ部は\r\n\r\nで区切られていますので、そこから最後までを取得するとボディ部だけを抽出することができます。

以下は有機ELモジュールに出力が成功した写真です。

f:id:mia_0032:20140713004208j:plain

次の記事ではWebアプリケーション部分をもう少し豪華にして、いろいろとOLEDに表示できるようにします。

関連エントリ

RaspberryPiにGrowthForecastをインストールする

やりたいこと

mbedで温度を取得して、それをRaspberryPiに送る。 RaspberryPi側ではそのデータを蓄積してグラフ化する。

センサーデータを集めて利用するという、最近流行りのIoT(Internet of Things : モノのインターネット)の基本の一部をやってみる。

今回はRaspberryPiに可視化ツールのGrowthForecastを入れるまで。

RaspberryPiのセットアップ作業

この記事で使ったGrowthForecastを使ってデータの蓄積とグラフ化をする。

最初にRaspberryPi自体の更新。

# パッケージの更新
$ sudo apt-get update
$ sudo apt-get upgrade
# ファームウェアの更新
$ sudo rpi-update

GrowthForecastのセットアップ

必要なパッケージはRaspbianの標準で入っているので、インストールを省略。

cpanmのインストールから。

$ cpan
# CPANの自動設定
$ sudo curl -L http://cpanmin.us | perl - --sudo App::cpanminus
$ cpanm -n GrowthForecast

とりあえず起動してみるがエラーで動かない。

Can't locate Plack/Loader.pm in @INC (...省略...) at ./growthforecast.pl line 13.
BEGIN failed--compilation aborted at ./growthforecast.pl line 13.

こちらの解決策を参照して~.bashrcにPerlのパスを通す。

GrowthForecast用のディレクトリを作る。

$ sudo mkdir -p -m 777 /data/growthforecast

起動。

$ growthforecast.pl --data-dir /data/growthforecast

PCなりからhttp://RasPiのIP:5125でアクセスできればOK。

関連エントリ

GrowthForecastを使ってみる

GrowthForecastがグラフの出力に便利そうだったのでCentOS 6.5上でインストールして実際に動かしてみる。

0. cpan, cpanmのインストール

初期状態ではCentOSには入っていなかったのでyumでインストールする。

sudo yum install perl-CPAN
curl -L http://cpanmin.us | perl - --sudo App::cpanminus

1. GrowthForecastのインストール

GrowthForecastのInstalling and Bootingにしたがってインストール。

2. GrowthForecastの起動

growthforecast.pl --data-dir <data_directory>

で、起動します。

デフォルトではhttp://localhost:5125で起動するようになっているので、ブラウザからそのURLでアクセスできる。

3. 適当なデータを送って表示してみる

以下のようなプログラムを書いて、ランダムな数値を1分ごとに送って表示させてみた。

  • サービス名:test_service
  • セクション名:test_section
  • グラフ名:test_graph

growthforecast_test.rb

#! ruby -EUTF-8
# -*- mode:ruby; coding:utf-8 -*-

require 'uri'
require 'net/http'

while true
  i = rand(100)

  url = URI.parse('http://localhost:5125/api/test_service/test_section/test_graph')
  res = Net::HTTP.post_form(url, {'number' => i})
  puts res.body

  sleep(60)
end

ruby growthforecast_test.rbで実行してしばらく経ったあとのスクリーンショット

f:id:mia_0032:20140417140145p:plain

WindowsでJenkins経由のPythonのユニットテストをやってみる

ローカルのWindows上でもJenkinsが動かせたら、いろいろと実験しやすいなと思ってgithubからリポジトリをcloneしてPythonユニットテストが通るまでやってみる。

0. JDKのインストール

OracleからJDK1.7系をダウンロードしてインストール。

インストールするディレクトリはスペースを含まないディレクトリにしておいたほうが無難 (例:C:\Java\jdk1.7.0)。

1. Jenkinsのインストール

http://jenkins-ci.org/からWindows版をダウンロードして解凍。

中のmsiファイルを実行してインストール。 JDKと同じくスペースが入らないディレクトリにしておいたほうが無難そう(例:C:\Jenkins)。

デフォルトでは http://localhost:8080/ にアクセスするとJenkinsのダッシュボードにアクセスできる。

2. Pythonユニットテスト環境を作る

以下の記事を参照してpipのインストールまで行う。

ソースコードは以下の記事のものを使うのでmockをインストールしておく。

> pip install mock

以下のパッケージのインストールを行う。

> pip install nose
> pip install unittest-xml-reporting
> pip install coverage

3. Jenkinsの設定

3.1. gitとCoberturaプラグインの導入

  1. 「Jenkinsの管理」
  2. プラグインの管理」
  3. Git Plugin, Cobertura Pluginを選択してインストール

3.2. Jenkins用のSSH公開鍵を作成

JenkinsはデフォルトではLocal Systemユーザーで実行されるようなので、そのユーザー用に鍵を作る。

> cd C:/Windows/SysWOW64/config/systemprofile/.ssh
> ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/c/Users/【ユーザー名】/.ssh/id_rsa): ./【秘密鍵ファイル名】

できた【秘密鍵ファイル名】.pubの中身をgithubSSH Keysに登録しておく。

3.3. ジョブの作成

3.3.1. githubからソースコードを落とすところまで
  1. 「新しいジョブの作成」
  2. プロジェクト名を入力して、フリースタイル・プロジェクトのビルドを選択
  3. ソースコード管理 → Git → Repositories → Repository URLに自分のGithubリポジトリを入力。 git@github.com:mia-0032/python-test.git

  4. Credentialsの横のAddからKind「SSHユーザー名と秘密鍵秘密鍵「Jenkinsマスター上の~/.sshから」を選択。

ここまでで「ビルドを実行」するとワークスペース以下にファイルが落ちてきているはず。

3.3.2. テストの実行結果とカバレッジの出力まで

ビルド → ビルド手順の追加 → Windowsバッチコマンドの実行に以下の記述を追加。

(Jenkinsの実行ユーザーで【Pythonのインストールディレクトリ】\ScriptsにPathを通してあること。)

nosetests test/ -v --with-coverage --with-xunit
coverage xml

ビルド後の処理 → ビルド後の処理の追加 → JUnitテスト結果の集計 → テスト結果XMLnosetests.xml と入力。

同じく ビルド後の処理の追加 → Cobertura カバレッジ・レポートの集計 → Cobertura XMLレポート パターン → coverage.xml と入力。

ビルドの実行

上記の手順で「ビルドを実行」すれば、テストが成功して以下の用にグラフが表示されます。

f:id:mia_0032:20140413124017p:plain

という感じで完了。 いろいろと試行錯誤していたら時間かかった・・・。

マルチタッチパネルの製作(その2:Arduinoのライブラリを使う)

↑でやったMPR121を使う方法の他にArduinoCapSenceというライブラリを利用した静電容量センサーも実験してみました。

作ってみる

CapSenceのページにあるように送信ピンと受信ピンの間に抵抗を挟み、受信ピン側にセンサーとなる銅線を接続します。

こんな感じでさくさくっと。 上の抵抗から順番に、1MΩ、2MΩ、3MΩ、3.9MΩ、5.1MΩで実験しました。

Arduinoに書き込むプログラムはCapSenceのサンプルコードをそのまま使いました。

試してみる

1MΩでは、指が直接触れないと出力に変化はなかったです。

だいたい3MΩあたりから、触れなくても値に変化が出てきます。 5.1MΩで、触れなくても結構出力の数値が変わるのでしきい値を適当に決めれば、判定できそうな感じではありました。

数値のばらつきがかなり大きいので、ソフトウェアの処理で誤判定をなくす工夫(サンプル数を上げる、N回の平均を取る、一定時間内にM回のしきい値超えがある)は必要そうです。

CapSenceによれば、並列にコンデンサを仕込むだけで、数値が安定するそうなので、それも試してみるのはありかなーと。

配線が動いただけでもだいぶ数値が変わってしまうので、ちゃんと固定してから再度しきい値を決めたりしないといけない感じです。

サンプリング速度は5.1MΩのときで3~4ms程度だったので、銅線が25本あるときは100msで全部スキャンできると思います。 だいたい10fpsくらいのサンプリング速度ですかねー。

まとめ

MPR121を使った方法のほうが精度は高そうです。

配線が動いたときなど大きく値が変化するときはオートでキャリブレーションが必要ですが、そのあたりの判定ロジックとかを考えると中々大変そうな感じがします。

簡単なタッチボタンであればArduino単体で問題なさそうです。

特に電極に直接触れることができるときは、数値差が桁が違うレベルで大きいので、しきい値を大きめにとるだけで、簡単に判定できると思います。

関連エントリ

マルチタッチパネルの製作(その1:MPR121を使う)

「あの楽器」のマルチタッチ化に向けて少し工作を開始しました。

タッチパネルのプロトタイプを作成する

「あの楽器」で使うには、タッチパネルの下に液晶なりLEDマトリックスなりの表示装置がいるので、電極として銅箔テープなどは使えず、細い銅線か透明電極が必要になります。

アクリル板を加工して、細い銅線をX軸・Y軸に並行に並べるという設計で、とりあえず作っていきます。

アクリル板の端に穴を空けていき、タップでネジ穴を切ります。

こんな感じになりました。

MPR121を使ってみる

まずはスイッチサイエンスさんで取り扱いのあるMPR121搭載の静電タッチセンサーモジュールArduinoを使って実験してみました。

Arduinoソースコードは以下のページのコードをそのまま使いました。 http://bildr.org/2011/05/mpr121_arduino/

データシートと比べながらソースコードを読んでみると、mpr121.h内の以下の定数を変更することで感度を調整できるようです。

#define TOU_THRESH   0x06
#define REL_THRESH   0x0A

TOU_THRESHがタッチと判定するときのしきい値で、REL_THRESHが離したと判定するときのしきい値です。

これらの数値を小さくすると感度が上がり、反応しやすくなります。 ただちょっとのことで反応してしまうので、そこは調整して適当な数値に決めます。

TOU_THRESHを0x02まで下げるとセンサーピンに直接触れなくても、ソケットの黒い部分に指を当てるだけで反応するようになりました。

データシートを見ると、

Typically the touch threshold is a little bigger than the release threshold to touch debounce and hysteresis.

と書いてあるので、TOU_THRESHREL_THRESHよりも少しだけ大きな値にするといいみたいです。 となると、上のサンプルコードと矛盾しているのですが・・・"a little"なので、そこまで大きな影響はなさそうです。

他の設定項目を調べていると、上記のサンプルコードでは変更されていないですが、Debounce Register (0x5B)というものがあり、これは指定した回数反応したときだけタッチ・リリースとしてみなすという設定項目のようです。 ここの回数を増やすと誤反応は減りそうです。

あとはADDRピンがデフォルトでGNDに接続されていますが、ここをVCC、SDA、SCLにつなぎ替えることで、I2Cのアドレスを変更することができるようです。

このMPR121は、専用ICだけあって誤反応が少なく扱いやすいのですが、指が接触しない場合はしきい値をだいぶ下げてやらないとあまり反応しないようです。

しきい値を0x02まで下げても1mmくらいの厚みまでしか反応しない感じです(電極が大きさと間に挟まる空気の厚みが変わればもう少し反応する厚みは大きくなるのかも)。 どちらにせよ、細い銅線ではちょっと間隔が空きすぎて難しそうです。

電極について

透明電極なんて手に入らないよなーと思っていたら、なんとデジットで取り扱いがありました。(デジットBlog:いろんな可能性を秘めている!?透明導電フィルムが入荷!)

ブログを見る感じではアルコールで導電膜をはがせるようなので、MPR121のデータシートにあるような千鳥模様の電極配置もがんばれば作れるのかなーと思っていますが、手作業でそういう模様を作るのは難しそうなので、どうしたものかなーと考え中です・・・。

静電容量タッチパネルの設計についてしらべていると、 Microchip 堅牢なタッチセンシングの設計手法というPDFを見つけました。 通常のスイッチとのノイズの違いや、カバーの厚みや材質・接着剤の種類など細かく書いてあり、非常に参考になります。

  • 誘電率の高いガラスのほうがアクリル板よりもカバーには向いている。
  • 15mm*15mmのセンサーではカバーの厚み3mm以下にしたほうがいい。
  • カバーと電極の間に空気をできるだけ挟まない。 ことが重要そうです。

まとめ

MPR121を使ってX軸Y軸の座標をとるには、さらに工夫が必要そうです。

特に電極の工夫は結構必要そうです。

関連エントリ

©2023 みや All rights reserved.