工作とかオーディオとか | 測定で作る自作スピーカー製作記

測定とシミュレーションで作る、自作スピーカー設計・製作記

Seeed Wio 3GからSORACOM Harvestに加速度データを送信して可視化

この記事はSeeed UG Advent Calendar 2018の14日目の記事です。

f:id:mia_0032:20181213135521j:plain
Seeed Wio 3G

概要

Seeed Wio 3GからSORACOM Harvestにデータを送って可視化してみます。

Seeed Wio 3GはSIMを挿すことで3G回線でインターネットに接続できるマイコンボードです。Arduino IDEで開発できるので手軽にIoTデバイスを作成することができます。 またGroveというセンサーなどが簡単に接続できるモジュールに対応しており、はんだ付け無しでいろいろな機能を実現できます。

SORACOM Harvestはデータの蓄積・可視化を行えるサービスです。デバイスにSORACOMのSIMを組み合わせることで利用できます。

今回はマイコンボードSeeed Wio 3GにSORACOMのSIMカードを挿し、Groveの加速度センサーの値をSORACOM Harvestに送ってみます。

Arduino IDEの設定

Wiki/setup-ja.md at master · SeeedJP/Wiki · GitHub を参照してWio 3Gの開発環境を構築します。

Harvestの利用設定

SORACOM Harvest でデバイスのデータをクラウドで収集・取得・可視化する | Getting Started | SORACOM Developers を参照してSIMグループおよびHarvestの開始手続きを行います。

Groveモジュールの接続とライブラリの読み込み

Wio 3GのI2CコネクタにGrove 3-Axis Digital Accelerometer(±1.5g)を接続します。

f:id:mia_0032:20181213151436j:plain
Wio 3GにGrove加速度センサーを取り付け

加速度センサーのライブラリとして GitHub - Seeed-Studio/Accelerometer_MMA7660: Seeed 3-Axis Digital Accelerometer(±1.5g) library を使いたいのですが、Wio 3GではWireクラスがWireI2Cになっていたりして、そのままでは使えません。

forkしてWio 3Gに対応したものを GitHub - mia-0032/Accelerometer_MMA7660_Wio_3G: Seeed 3-Axis Digital Accelerometer(±1.5g) library に置いていますのでZipでダウンロードして、ArduinoIDEにライブラリをインクルードしてください。

コードの書き込み

以下のコードをWio 3Gに書き込みます。Harvestのサンプルコードに加速度センサーの読み込み処理をつけたコードになってます。

可視化されたデータを見る

Wio 3Gを起動してしばらく立つとHarvestにデータが貯まっていきます。Harvestに送信されたデータは SORACOMのコンソール→SIM管理→SIMを選択→データを確認 という手順で見れます。

f:id:mia_0032:20181213172241p:plain
harvest

センサーを動かすと出力される値が動けば成功です。定期的に振ると上のようなグラフになります。

製作上でハマったところ

  • 通常のArduinoのクラス名とは異なるクラスが使われているのでそのままでは動かないライブラリもある。
  • しばらく経つとHarvestへの書き込みが止まってしまう。
    • これは原因がわかっていない。

まとめ

SORACOMのマネージドサービスのHarvestを使ってお手軽にセンサーデータの可視化ができました。

Wio 3Gは3G回線が使えるので、SIMだけ挿せばネットワークにつながる*1のが楽で良いですね。

*1:SIMが挿せるボードは未発売です。今回は販売前の製品をお借りすることができました。

mbed Device Connectorへデータを送ってみる

mbed FRDM-K64Fを使ってmbed Device Connectorを試しました。

f:id:mia_0032:20170221111232p:plain

今回は公式で公開されているサンプルを動かしてみました。

github.com

ビルド手順

1. import します。

$ mbed import mbed-os-example-client
$ cd mbed-os-example-client

2. Ethernetをつかってネットワークに接続するように設定します。

$ cat << EOS > configs/mbed_app.json
"network-interface": {
    "help": "options are ETHERNET,WIFI,MESH_LOWPAN_ND,MESH_THREAD.",
    "value": "ETHERNET"
}
EOS

3. 認証情報の設定

https://connector.mbed.com/#credentials から取得した認証情報で security.h を上書きします。

4. mbedへ書き込み

$ mbed compile --toolchain GCC_ARM --target K64F
$ cp .build/K64F/GCC_ARM/mbed-os-example-client.bin /Volumes/MBED

書き込みが終わったらresetボタンを押して、プログラムを実行します。

動作の確認

バイスが認識されているかの確認

https://connector.mbed.com/#homeで確認すると、デバイスが1つぶら下がっていることとデータが送られていることがわかります。

f:id:mia_0032:20170221105728p:plain

https://connector.mbed.com/#endpointsからはデバイスのendpointに使われる名前(secure.hに記載されているMBED_ENDPOINT_NAMEの値)を確認することができます。

f:id:mia_0032:20170221105350p:plain

データの確認

https://connector.mbed.com/#consoleから送られているデータのサンプルを見ることができます。

SW2を押した回数が3200/0/5501へ送られているようなので以下のように設定します。

f:id:mia_0032:20170221111944p:plain

TEST API ボタンを押すと以下のような結果が返ってきます。

f:id:mia_0032:20170221112238p:plain

payloadというキーに送信されたデータがBase64エンコードされた状態で入っています。 その下にBase64 decoded payloadというのが表示されており、これがデコードされた結果です。 ここでは35という値がスイッチを押した回数になります。

mbed CLIでのコンパイルを楽にするシェルスクリプト

はじめに

この記事はmbed Advent Calendar 2016の6日目の記事です。

mbed CLIがリリースされ、ローカル環境でのコンパイルが楽になりました。 しかし、コンパイルするときにボードを設定したり、コンパイルされたファイルが結構深い階層にあったりと、何度も手作業で繰り返すのは結構面倒です。 そこで一発でボードを自動的に判定し、mbedへのコピーまでやってくれるスクリプトを作ったので紹介します。

mbed CLI自体のインストールについては、既に日本語の記事がまとまっていますので、以下をご覧ください。

mbed CLI (コマンドライン・インタフェース)を Mac OS X で使ってみる | mbed

作ったスクリプト

#!/bin/bash

set -eu

PROGRAM_NAME=$(basename `pwd`)
MBED_DETECT=$(mbed detect | grep Detected | sed 's/,//g' | head -n 1)

if [ -z "${MBED_DETECT}" ];then
    echo "[info] No mbed boards are found."
    exit 1;
fi

TARGET=$(echo ${MBED_DETECT} | cut -d' ' -f3)
MBED_VOLUME=$(echo ${MBED_DETECT} | cut -d' ' -f7)

echo "[info] Target:"${TARGET}", Volume:"${MBED_VOLUME}

TOOL_CHAIN="GCC_ARM"

mbed compile --toolchain ${TOOL_CHAIN} --target ${TARGET}

BUILD_PATH=$(echo "BUILD/"${TARGET}"/"${TOOL_CHAIN}"/"${PROGRAM_NAME}".bin")
cp ${BUILD_PATH} ${MBED_VOLUME}/
echo "[info] Success to copy from "${BUILD_PATH}" to "${MBED_VOLUME}

適当な名前(compile.shなど)で保存し、$ bash compile.shとするか実行権限をつけて直接スクリプトを叩けば実行されます。

手元のLPC1768で試して動くことを確認しましたが、それ以外のボードでは未検証です。動かない場合は教えてください。

なおMacでしか動かないと思います(Linuxは動くかもですが)。

やっていること

mbed detectでターゲットとコピー先のボリュームを取得し、mbed compileで生成されたbinファイルをコピーしています。

mbed newmbed importするとディレクトリ名がbinファイルのファイル名となるので、それも利用しています。

複数のmbedがPCに接続されている場合はmbed detectで先頭になる1台に対してコピーが行われます。

mbed OS 5でのイベント処理(mbed events libraryの使い方)

はじめに

この記事はmbed Advent Calendar 2016の4日目の記事です。

mbed OS 5でイベント駆動なプログラムを書くためのライブラリ mbed-events-library の使い方を紹介します。 なお、ドキュメントに書いてあるコードは古いのか正常に動かないところがあったので、GithubのREADMEを参照して検証しました。

mbed-events-libraryが追加されたことで、従来の RtosTimer はdeprecated*1となったようです。

動かしてみる

青mbed(LPC1768)を使って実験しました。 p18 にPullUpでタクトスイッチをつけています。

1. 即実行されるイベント

EventQueueインスタンスを作成し、callメソッドを呼び出すことで即実行されるイベントを追加することができます。

dispatch メソッドを実行するとイベントループが廻り続けるため、最後に while(true) といった記述は必要ありません。

サンプルコードと実際の動作

#include "mbed.h"

DigitalOut led1(LED1);
InterruptIn sw1(p18);

// イベントキューを作成する
EventQueue queue;

// LEDのON/OFFを切り替える関数
void toggle_led() {
    led1 = !led1;
}

// タクトスイッチが押されたときに実行される関数
void pushed() {
    // 即実行されるイベント
    queue.call(&toggle_led);
}

int main() {
    // スイッチピンをPullUpにする
    sw1.mode(PullUp);

    // タクトスイッチが押されたときの割り込み処理
    sw1.fall(&pushed);

    // イベントループが廻り続ける
    queue.dispatch();
}

動作させたのが以下の動画です。スイッチを押すとLEDがON/OFFします。

f:id:mia_0032:20161203210614g:plain

2. 指定時間後に実行されるイベント

EventQueueインスタンスに対して call_in メソッドを呼び出すことで 指定ミリ秒後に実行されるイベントを作成することができます。

サンプルコードと実際の動作

先ほどのコードに queue.call_in(2000, &toggle_led); を追加し、ボタンを押してから2000ミリ秒(2秒)後に消える処理を追加しました。

#include "mbed.h"

DigitalOut led1(LED1);
InterruptIn sw1(p18);

// イベントキューを作成する
EventQueue queue;

// LEDのON/OFFを切り替える関数
void toggle_led() {
    led1 = !led1;
}

// タクトスイッチが押されたときに実行される関数
void pushed() {
    // 即実行されるイベント
    queue.call(&toggle_led);
    // 2000ms後に実行されるイベント
    queue.call_in(2000, &toggle_led);
}

int main() {
    // スイッチピンをPullUpにする
    sw1.mode(PullUp);

    // タクトスイッチが押されたときの割り込み処理
    sw1.fall(&pushed);

    // イベントループが廻り続ける
    queue.dispatch();
}

動作させたのが以下のようになります。スイッチを押すとLEDがONし、2秒後にOFFになります。

f:id:mia_0032:20161203210632g:plain

なお、ON/OFFするイベントをひたすらキューに積んでいる形になるため、連打するとON/OFFの順番は崩れます・・・

3. 指定時間ごとに定期実行されるイベント

EventQueueインスタンスに対して call_every メソッドを呼び出すことで 指定ミリ秒ごとに実行されるイベントを作成することができます。

サンプルコードと実際の動作

先ほどのコードからスイッチの処理を取り除き、call_every で1秒ごとに実行されるイベントを追加したものになります。

#include "mbed.h"

DigitalOut led1(LED1);

// イベントキューを作成する
EventQueue queue;

// LEDのON/OFFを切り替える関数
void toggle_led() {
    led1 = !led1;
}

int main() {
    // 1000msごとに定期実行するイベント
    queue.call_every(1000, &toggle_led);

    // イベントループが廻り続ける
    queue.dispatch();
}

動作させると以下のように、1秒ごとにLEDのON/OFFを繰り返します。

f:id:mia_0032:20161203210643g:plain

おわりに

今回のコードは以下のリポジトリに公開しています。 mbed import してお使いください。

github.com

以前、mbed OSのTechnical Preview版のときはMINARと呼ばれるイベントスケジューラーがあり、それを検証したことがありました。

そのときは結構な行数のコードが必要だったのですが、mbed-events-library は非常に簡潔なで直感的なコードで同様のことが実現できるようになったようです。

どんどん進化していますね。

MicroPythonでmicro:bit互換のchibi:bitを動かす

f:id:mia_0032:20160820155544p:plain

chibi:bitはスイッチサイエンスから発売されているmicro:bit互換のマイコンボードです。

micro:bitはmbed enableなのでC++(mbed)でも開発できますし、JavaScriptやBlockEditor, MicroPythonでも開発することができます。

WebIDEを使うと、非常に簡単にコードを動かすことができます。 コンパイルされたhexファイルをダウンロードできるので、hexファイルを通常のmbedと同じようにディスクへ書き込めば動きます。

しかしWebIDEではなくローカルPCで開発したいという人もいると思います。 そこで、この記事ではローカルPCでMicroPythonのコードをビルドしてchibi:bitで動かす手順を紹介します。

1. ローカルで開発できる環境を作る

Pythonのバージョンは 2.7.12 でやりました。OSXでの手順になります。

$ python --version
Python 2.7.12

Pythonで書かれたコードをhexファイルにコンパイルして書き込んでくれるuFlashというパッケージをインストールします。

$ pip install uflash

ビルドにはyottaも必要そうなのでインストールします*1

$ brew install cmake ninja arm-none-eabi-gcc
$ pip install yotta

2. HelloWorld.py

以下のコードを HelloWorld.py として保存します。

from microbit import *
display.scroll("Hello, Python World!")

chibi:bitへ書き込みます。

$ uflash HelloWorld.py /Volumes/MBED

3. 動作確認

MBEDデバイスが取り外されれば書き込みが完了した合図なので、あとはリセットボタンを押すだけです。

f:id:mia_0032:20160820155043g:plain

ちゃんと表示されました!

*1:特に依存しているようには見えないものの、インストールされていない状態だとhexファイルが書き込まれませんでした

IoT縛りの勉強会! IoTLT vol.3 でLTしてきた

2015/05/13 に開催されたIoT縛りの勉強会! IoTLT vol.3で「Tesselで作るコメントお知らせはちゅね」について話してきました。

スライドは以下です。

機能や仕組みは 以下の記事の「コメント新着お知らせ はちゅね」と同じです。

前のときはブレッドボードで組んだ状態で、ほんとにざっと組んだ感じでした。

今回はケースにいれて、基板もちゃんと配線しています。

手直しするだけで、GWが終わってしまい、新機能は追加できませんでした。

その分、スライドの方に、時間をかけたのでわかりやすくなっていると思います。

勉強会の感想

事例紹介がいくつかあり、どれも興味深いものでした。 個人的には、ねろさんの「IoTでいうところのIよりの知識でTする」の本棚の事例が楽しそうでした。

どちらかというとソフトウェアよりな発表が多かったです。 ハードウェア系の人の話ももっと聞きたかった感じがありました。

自分の発表については、何人か懇親会でTesselについて質問をもらったり、話せたりしたので、興味はもってもらえたかなと。

懇親会で、Web系の人にハードウェアに興味をもってもらうには、どうすればよいかといった話題まで話せたので、個人的にはすごく楽しい時間でした。

第4回は渋谷の21cafeで開催されるそう(http://iotlt.connpass.com/event/15005/)です。ぜひともまた行こうと思います。

関連エントリ

Tessel で作るコメント新着お知らせ はちゅね

社内でLTしたときに、作ったものです。

指定した動画を定期的にポーリングして、コメントがついていたら、前回チェックした時からの差分値だけネギを振る はちゅねミクです。

ニコニコ大百科に書いてあったAPIを使っています。

動画

Tesselで作るコメントお知らせ はちゅね from mia_0032 on Vimeo.

解説スライド

コード

GitHub - mia-0032/tessel-nicovideo-negifuri-counter: check my uploaded videos in niconico and notice to me by negifuri if my video commented

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さんです。よろしくお願いします。


関連エントリ

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とかの部分はまだ作りかけです。

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に表示できるようにします。

関連エントリ

マルチタッチパネルの製作(その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単体で問題なさそうです。

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

関連エントリ

©2023 みや All rights reserved.