2015年11月30日月曜日

BL600 で RSSI の強度を上げる方法

概要

前回の記事で nrf51822 で RSSI の強度を上げる方法を紹介しました
この場合は例えば nRF51 DK ボード上で動かしていたり、USB ドングルを使って開発している場合にはいいのですが、BL600 等のサードパーティ製の製品上で動かす場合に有効になりませんでした
今回は BL600 上で動作する nRF51 系のアプリで RSSI を強くする方法を紹介します

環境

  • Windows7 64bit
  • nRF51822
  • nRF51 DK
  • nRF51 SDK 9.0.0
  • SoftDevice S130

設定方法

ずばり以下を設定する
自分は advertising_init メソッド内でコールしました

nrf_gpio_cfg_output(20);
nrf_gpio_pin_clear(20);

初めこれでできたときは「魔法とはこれか」と思ったくらいビックリしました
詳しいことは良くわからないのですが、どうやら nRF51 DK の P0.20 ピンが VDD 周りの制御をしているらしく、そこに信号を送らないようにすればいいとか、詳しい方ヘルプ、、、

参考サイト

2015年11月27日金曜日

nrf51822 で RSSI の強度を上げる方法

概要

アドバタイジング時に RSSI の強度を強くしたり弱くしたりすることで検知させたいデバイスの距離を操作することができます
nrf51822 で RSSI の強度を設定する方法を紹介します

環境

  • Windows7 64bit
  • nRF51822
  • nRF51 DK
  • nRF51 SDK 9.0.0

設定方法

適当な場所で以下をコールすれば OK です
自分は advertising_init 内でコールして問題ありませんでした

err_code = sd_ble_gap_tx_power_set(4);
APP_ERROR_CHECK(err_code);

sd_ble_gap_tx_power_set メソッドは ble_gap.h のヘッダファイルに含まれているのでない場合は include してください

設定できるパラメータは -40, -30, -20, -16, -12, -8, -4, 0, 4 だけです
これ以外を指定すると APP_ERROR_CHECK でエラーとなりアプリが停止します
試した感じだと -40 が弱く 4 が強い設定になります
-40 とかは本当に弱く 20 cm くらい離れると検知できません
4 は正確には計測していませんが、5m くらいは余裕でした

一度設定してからアプリ内で動的に変更することもできるようです

最後に

RSSI の強さが動的に変更できると具体的に何ができるか思いつきませんが、何かおもしろいことができるような気がします

参考サイト

2015年11月26日木曜日

RaspberryPi で無線 LAN のアクセスポイントを追加する方法

概要

過去に WiMax2 に接続する方法を紹介しました
WiMax2 が使えない状況が発生し iPhone のテザリングしかネットワークがなく、デザリングを新しい無線 LAN のアクセスポイントとして追加してみました

環境

  • Raspberry Pi Type B Single Board Computer 512MB
  • Raspbian 8.0 (Jessie)
  • Kernel Version 4.1.7+

手順

新規に network の定義を追加する

  • sudo cp /etc/wpa_supplicant/wpa_supplicant.conf{,.back}
  • sudo chmod 666 /etc/wpa_supplicant/wpa_supplicant.conf
  • sudo wpa_passphrase ssid ssid-password >> /etc/wpa_supplicant/wpa_supplicant.conf

ssid と ssid-password は今回は iPhone のテザリング情報を入力しました

追加した network 定義を編集する

  • sudo vim /etc/wpa_supplicant/wpa_supplicant.conf

追加した ssid の network の定義に以下を追加する

  • proto=WPA2
  • key_mgmt=WPA-PSK
  • pairwise=CCMP

記載したら保存して終了する

  • sudo chmod 600 /etc/wpa_supplicant/wpa_supplicant.conf

権限を戻しておく

ネットワークを再起動する

  • sudo systemctl restart networking

でしばらくするとテザリング用の NAT IP が iPhone からもらえると思います

最後に

既存の無線 LAN 設定が記載されている wpa_supplicant.conf に設定を追記するだけなので簡単でした

両方のネットワークにアクセスできる状況で、この設定ファイルを使うとどっちのネットワークを使うのか気になりました
優先度とかを定義することができるのか、単純にファイルの上位に記載されているネットワーク定義から評価していくのか、、、どうなんだろうか

試せる機会があったらやってみよう

2015年11月25日水曜日

nrf51822 でタイマーのクロック間隔を短くすることで起動時間を長く管理する方法

概要

前回 タイマーを使って起動時間を取得する方法を紹介しました
前回の問題点として管理できる時間が短いという点をあげました
今回はそれが解決でき、長い時間管理できるようになったので紹介します

環境

  • Windows7 64bit
  • nRF51822
  • nRF51 DK
  • nRF51 SDK 9.0.0
  • SoftDevice S130

実装方法

タイマーを使う方法は前回の記事を参照してください

まず前提として前回から判明したことが

  • 保存できるカウントの最大値は 24bit = 16, 777, 216 まで
  • 1 秒間のカウントで増加する値は 32, 768

であることがわかりました ( 参考 )

保存できるカウントを増やす方式は難しいため増加するカウントを減らすことで管理できる時間を増やせないか検討してみました

ずばり回答としては

#define APP_TIMER_PRESCALER 0

の値を増やすことです
この値を増やすことで影響するのが

APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_MAX_TIMERS, APP_TIMER_OP_QUEUE_SIZE, false);

の部分です
この初期化をしている第一引数で増加するカウントの 32, 768 を割り算しているようです
例えば APP_TIMER_PRESCALER を 16 とすると 1 秒間でカウントされる値は

32, 768 / 16 = 2, 048

になります
なので最大保存時間は

16, 777, 216 / 2, 048 = 8, 192 (sec) = 136 (min) = 2.27 (hour)

になります
一応この値が 32 でも正常に動作することは確認しています

カウントから時間 (秒) を取得する方法は

uint32_t time = p_ticks / (APP_TIMER_CLOCK_FREQ / APP_TIMER_PRESCALER);

で OK です

気になる点

では一体 APP_TIMER_PRESCALER の値はいくつまで設定できるのかと言うとおそらく 4,095 までいけるっぽいです ( かなり不確定、カウントの最大が 24 bit であることから逆算しているみたいです )
確かに 4,095 を設定しても問題なく動くことは確認しました

ただ、今度はタイマーを使っているバッテリーレベルの Characteristics が更新されなくなってしまいました
32 や 16 のときはほぼリアルタイムで read してもバッテリーレベルが更新されていたのですが 4, 095 を設定すると更新されなくなりました

詳しく調査していないので、予想ですがこの後タイマーを作成 (app_timer_create) してスタート (app_timer_start) すると思うのですが、スタートする際にタイマーのインターバルを決定する引数 ( BATTERY_LEVEL_MEAS_INTERVAL) がありこれが APP_TIMER_PRESCALER を使っているため、更新するインターバルの時間が伸びたんだと思います

なので、ちゃんとやるとしたら時間を取得するためだけのタイマーを作成、スタートして、そのポインタから時間を参照するようにしたほういいと思います
チュートリアル を見てもアプリごとに 10 個タイマーを持てるとあるので、そうするのがベターなんだと思います

Tips

わからないことは Nordic Developer Zone で質問してみましょう
基本英語です
もちろん過去ログは検索してから質問したほうがいいです
結構適当な英語でも頑張って解釈してくれるので、ちゃんした返事が返ってきます

2015年11月24日火曜日

nrf51822 でデバイスをスキャンして Macアドレスと RSSI を取得する方法

概要

nrf51822 に Central の機能を実装して BLE デバイスをスキャンしてみました
スキャンした際に対象デバイスの Mac アドレスと RSSI (受信信号強度) を取得してデバッグ出力してみます

環境

  • Windows7 64bit
  • nRF51822
  • nRF51 DK
  • nRF51 SDK 9.0.0
  • SoftDevice S130

実装方法

今回は Peripheral ではなく Central の機能を実装するので SoftDevice のバージョンは s120 or s130 が必要になります
なので、あらかじめ上記の SoftDevice を書き込んでおいてください
実装方法は SDK に含まれる Central のサンプルコードベースで説明します

スキャンできるように初期化する

まずスキャンの方法を設定します
サンプルコードでは基本的に main メソッド内で初期化用のメソッドをコールすることで初期化を行っています

スキャンの初期化の流れは ble_stack_init -> softdevice_ble_evt_handler_set -> ble_evt_dispatch -> on_ble_central_evt になります
簡単に説明するとスキャンを実行した際に発生するイベントを on_ble_central_evt メソッドでハンドリングする設定を行っています

このコールの流れは基本サンプルのままで OK です
これが設定されていればスキャンの基本の設定は完了です
次にハンドリングしたイベント内で実際に Macアドレスと RSSI を取得してみます

Macアドレスと RSSI を取得するロジックを追加

修正は on_ble_central_evt メソッドだけになります
このメソッドは発生したイベント ID を取得して switch 文でイベントを分岐しています

static void on_ble_central_evt(ble_evt_t * p_ble_evt) {
    uint32_t                err_code;
    const ble_gap_evt_t   * p_gap_evt = &p_ble_evt->evt.gap_evt;

    switch (p_ble_evt->header.evt_id) {
    case BLE_GAP_EVT_ADV_REPORT: {
            // ...
            break;
        }
    case BLE_GAP_EVT_TIMEOUT:
        // ...
        break;

    case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST:
        // ...
        break;

    case BLE_GAP_EVT_DISCONNECTED:
        // ...
        break;

    default:
        break;
    }
}

今回はこの中の BLE_GAP_EVT_ADV_REPORT の switch 文を修正します
Mac アドレスと RSSI は引数として渡ってきた ble_evt_t のポインタから取得します

取得方法は以下の通りです

ble_gap_addr_t pa = p_gap_evt->params.adv_report.peer_addr;
int8_t rssi = p_gap_evt->params.adv_report.rssi;
printf("Mac Address: %02x:%02x:%02x:%02x:%02x:%02x \r\n", pa.addr[5], pa.addr[4], pa.addr[3], pa.addr[2], pa.addr[1], pa.addr[0]);
printf("RSSI %d \r\n", rssi);

これをそのまま BLE_GAP_EVT_ADV_REPORT の switch 文中に記載すれば OK です
Mac アドレスは LSB (下位ビットから格納する方式) になっているので、添字の大きい方から参照します

ドットや矢印でいろいろと参照していますが流れとしては

  1. ble_evt_t から evt.gap_evt で GAP (General Access Profile) のイベントを取得
  2. イベントの params フィールドからパラメータを参照
  3. パラメータの adv_report フィールドからアドバタイジング情報を参照
  4. アドバタイジング情報の peer_addr フィールドから Mac アドレス情報を参照
  5. アドレス情報の addr[6] フィールドが Macアドレスが格納されている配列になっている

という感じです
RSSI は adv_report から直接数値が参照できます
この辺りはリファレンスを参照すると、この構造体のこのフィールドを参照しているという流れがわかると思います

スキャンを開始する

これもサンプルをそのまま使っているのであれば特に変更する箇所はありません
main メソッド内 scan_start というメソッドをコールしていれば Central のスキャンを開始することができます

int main(void) {
    uint32_t err_code;
    bool erase_bonds;

    // Some Initialize ...
    ble_stack_init();
    // Some Initialize ...

    // Some Initialize ...
    scan_start();
    // Some Initialize ...

    for (;; ) {
        power_manage();
    }
}

scan_start を辿ってみるとわかると思いますが結構いろいろな設定をしています
スキャンの間隔やホワイトリストを使って、信頼するデバイスだけスキャンするようにするとか、タイムアウトをどうするかなど設定できます
興味があれば、scan_start メソッドのサンプルとリファレンスを見ながらいろいろとパラメータチューニングしてみてください

コードが記載できたら Keil でビルドして nRFgo Studio でアプリケーションを焼きこんでみましょう
焼きこみが完了すれば自動的に nRF51 DK が BLE デバイスとなりスキャンを開始します

試す

アドバタイズしている BLE デバイスは結構街中に飛んでいるのでスキャンを開始すればデバイスが見つかるかもしれません
ない場合はスマホアプリで Peripheral になれるアプリがあるので、それを使ってみてください
自分は SensorTag CC2650 を使いました

デバッグは nRF51 DK を PC に USB で接続して TeraTerm でシリアルモニタをすればいいと思います
ボーレートは 38400 を設定してください

今回のサンプルは printf しているだけなので、デバイスが見つかればそのまま出力されると思います

最後に

コンシューマ向けの BLE デバイスは基本は Peripheral のみが実装されており、iPhone とか Android などのスマホが Central になっています
nrf51822 は Central にもなることでできるのでちょっとおもしろい実装ができます

nrf51822 には pstorage という仕組みもあってデバイス上にデータも保存できるので、スキャンした情報を保存しておくこともできます

pstorage の話もどっかでできればなぁと思っています
あと、サラッと書いたデバッグの方法とかも書いたほうがいいかなと思っています

2015年11月20日金曜日

CentOS7 + AWS で docker-swarm を試してみた

概要

docker-swarm は複数の docker-engine を 1 つの docker-engine として扱うことができるクラスタリングツールです
コンテナがいっぱいになってスケールしたいとき docker-engine をクラスタに追加することで簡単にコンテナをスケールすることができるようになります
今回は例のごとく Getting Started を試してみたので紹介します

環境

  • CentOS7 64bit
  • docker-machine 0.5.0
  • docker-engine 1.8.3

事前準備

docker-swarm は docker-machine の機能を使っているので事前に docker-machine をインストールしてください
http://kakakikikeke.blogspot.jp/2015/11/try-docker-machine-with-aws.html

クラスタをディスカバリするためのトークンを生成する

docker-swarm で生成するクラスタはトークンを使って、どのクラスタかを管理します
まずはトークンを作成するために 1 台マシンを構築します

  • docker-machine create --driver amazonec2 --amazonec2-access-key [Your Access Key] --amazonec2-secret-key [Your Secret Key] --amazonec2-vpc-id vpc-xxxxxxxx --amazonec2-region ap-northeast-1 --amazonec2-zone c token-machine

この辺のコマンドは前回の docker-machine の紹介で記載したコマンドと同じです
10 分くらいでインスタンスが立ち上げるので待ちましょう
作成できたら、マシンを確認後、環境変数を読み込みます

  • docker-machine ls
  • eval "$(docker-machine env token-machine)"

そしてこのマシン上で 1 つコンテナを立ち上げます
コンテナの元イメージになるのは DockerHub で公開されている swarm というイメージを使います

  • docker run swarm create

これを実行するとイメージのダウンロードが始まり、その後コンテナが起動され、以下のようにコンソールに出力されます

Unable to find image ‘swarm:latest’ locally
latest: Pulling from library/swarm
2bc79aec8ea0: Pull complete
dc2fb86a875a: Pull complete
435e648d0f23: Pull complete
e16042a92d05: Pull complete
045bd7b00b5b: Pull complete
3caea1253d76: Pull complete
2b4c55187a27: Pull complete
6b40fe7724bd: Pull complete
Digest: sha256:51a30269d3f3aaa04f744280e3c118aea032f6df85b49819aee29d379ac313b5
Status: Downloaded newer image for swarm:latest
6c56e07a671372421a6724ce79047d2f

この出力の最後の文字列「6c56e07a671372421a6724ce79047d2f」これをトークンとして使います

クラスタ内でのマスターノードを作成する

トークンが取得できたらクラスタを構築していきます
docker-swarm のクラスタの世界ではマスターと、それ以外のエージェントノードで構成されます
まずはマスターノードを作成する必要があります

  • docker-machine create --driver amazonec2 --amazonec2-access-key [Your Access Key] --amazonec2-secret-key [Your Secret Key] --amazonec2-vpc-id vpc-xxxxxxxx --amazonec2-region ap-northeast-1 --amazonec2-zone c --swarm --swarm-master --swarm-discovery token://6c56e07a671372421a6724ce79047d2f swarm-master

コマンドが長くなってきました
前半のドライバの指定やアクセスキーの指定は同じです
違うのは --swarm 以降のコマンドでこれを指定することでクラスタとして作成することができます
--swarm-master オプションを付けることでマスターとしてノードを立ち上げることができます
そして、先ほど作成したトークンを --swarm-discovery オプションを使って指定します

無事ノードが作成されれば完了です

エージェントノードを追加する

マスターノードができたらエージェントノードを追加していきます
クラスタをスケールさせたいときにはこのエージェントノードを追加していきます

  • docker-machine create --driver amazonec2 --amazonec2-access-key [Your Access Key] --amazonec2-secret-key [Your Secret Key] --amazonec2-vpc-id vpc-xxxxxxxx --amazonec2-region ap-northeast-1 --amazonec2-zone c --swarm --swarm-discovery token://6c56e07a671372421a6724ce79047d2f agent01

コマンドは先程のコマンドとほぼ同じです
--swarm-master の指定がないのと作成するノード名がことなるだけです
こんな感じで agent02 まで作成しましょう

作成できたノードを確認する

  • docker-machine ls
NAME          ACTIVE   DRIVER      STATE     URL                        SWARM
token-machine *        amazonec2   Running   tcp://xx.xx.xx.xx:2376    
swarm-master  -        amazonec2   Running   tcp://xx.xx.xx.xx:2376     swarm-master (master)
agent01       -        amazonec2   Running   tcp://xx.xx.xx.xx:2376     swarm-master
agent01       -        amazonec2   Running   tcp://xx.xx.xx.xx:2376     swarm-master

でノードの一覧を確認することができます
SWARMの欄にマスターノードの名前が記載されていることが確認できると思います
また、クラスタ内のマスターノードには (master) があると思います

docker-machine コマンドの他に docker-info コマンドでもクラスタの状況を確認することができます

クラスタ内にコンテナを作成する

まずは docker コマンドでこのコンテナを操作できるようにします

  • eval "$(docker-machine env --swarm swarm-master)"

env コマンドで環境を表示させ、eval で評価します
これで docker コマンドをコンテナ内で使うことができます
あとはいつも通り docker run すればマスターノードが適当なエージェントノード内にコンテナを作成してくれます

  • docker run hello-world
  • docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                     PORTS                                   NAMES
103e4ed46f78        hello-world         "/hello"                 2 minutes ago       Exited (0) 2 minutes ago                                           agent01/drunk_kalam

最後に

紹介は以上です

ノードを増やしてスケールさせたい場合は docker-machine create して、ノードを削除したい場合は docker-machine rm すれば OK です
docker-machine rm でマスターノードを指定するとクラスタがおかしくなるので注意してください

コンテナの数が数百や数千を超えるような場合には非常に便利な機能だと思いました
コンテナの数やコンテナのリソース消費を監視してキャパシティプランニングまでやってくれると非常に嬉しいなと思いました
いまマシンが足りないから自動で EC2 上にマシンを構築してクラスタに追加しましたとか
さすがに現状だとそこまではやってくれないっぽいです

2015年11月19日木曜日

Redis でバイナリファイルを保存する方法

概要

Redis で PNG 画像のようなバイナリファイルを保存する方法を紹介します
今回は特にプログラムから保存するのではなく、redis-cli を使ってやってみます

環境

  • Mac OS X 10.10.5
  • Redis 3.0.2

バイナリデータの保存

  • redis-cli -x HSET some_key image_binary <image.png

画像データを保存しています
HSET を使って保存しており some_key という key の image_binary というフィールドの値として画像を保存しています
画像情報はパスやファイル名を指定するのではなく、ファイルをリダイレクトで入力してあげます
-x を使うことで最後のパラメータを標準入力から受け取ることができるようになります

バイナリデータの取得

  • redis-cli --raw HGET some_key image_binary > image_new.png

取得する場合は HGET で key とフィールド名を指定します
オプションに --raw を指定する必要があります
これを指定することでマルチバイト文字 (バイナリ) を扱えるようになります
あとは結果を画像ファイルにリダイレクトしてあげれば OK です

取得した画像がちゃんと表示されるかプレビュー等で確認するといいと思います

参考サイト

2015年11月17日火曜日

nrf51822 で Real Time Clock を使って起動時間を取得する方法

概要

nrf51822 上で起動時間を取得するために RTC (RealTimeClock) の仕組みを使ってみました
RTC の値はデバイスの電源の ON/OFF でリセットされる値になります

環境

  • Windows7 64bit
  • nRF51822
  • nRF51 DK
  • nRF51 SDK 9.0.0

実装方法

nRF51 DK に含まれる App Timer (以下タイマー) という機能を使って実現します

nRF51 SDK に含まれているサンプルを見るといろいろなサンプルでこのタイマーを使っているので基本はそれをベースにすれば OK です
今回はバッテリーレベル用のタイマーを定義して、それを例に
流れを説明していきます

初期化

まず、タイマーを使うために APP_TIMER_INIT というマクロをコールする必要があります
サンプルではだいたいこんな感じで実装されていると思います

APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_MAX_TIMERS, APP_TIMER_OP_QUEUE_SIZE, false);

基本はこれで問題ないです

タイマーの生成

次にタイマーを生成します
生成するには app_timer_create をコールします

uint32_t err_code;
err_code = app_timer_create(&m_battery_timer_id, APP_TIMER_MODE_REPEATED, battery_level_meas_timeout_handler);
APP_ERROR_CHECK(err_code);
static app_timer_id_t m_battery_timer_id;

app_timer_id_t は typedef されている型で実体は uint32_t になります
この ID に対するタイマーを生成していることになります
また、 battery_level_meas_timeout_handler ですがこれは関数になっており、タイマーがタイムアウトしたときにコールされる関数を指定できます
この辺もサンプルを見ると流れが把握できると思いますが、この関数内でバッテリーレベルの再取得を実施し Characteristics の value の更新を行っています

タイマーが生成できたらタイマーをスタートします

タイマーを開始する

タイマーを開始するには app_timer_start をコールします

uint32_t err_code;
err_code = app_timer_start(m_battery_timer_id, BATTERY_LEVEL_MEAS_INTERVAL, NULL);
APP_ERROR_CHECK(err_code);

これをコールしたタイミングから RTC によるカウントが開始されます

現在のカウントを取得する

タイマーを開始したら、現在のカウントを取得してみます
現在のカウントを取得するには app_timer_cnt_get をコールします

uint32_t p_ticks;
app_timer_cnt_get(&p_ticks);
printf("%d \r\n", p_ticks);

こんな感じでカウントしている値を取得できます

ここでちょっとはまったのは app_timer_cnt_get の返り値を参照してもずっと 0 でした
リファレンスを見たのですが、この関数の返り値は正常に取得できたかのフラグを return しているだけなので常に 0 が返っていました
関数側では、受け取った引数のポインタに対して書き込みを行っているので、引数として渡した変数を参照する必要がありました

で実際にこの値を定期的に出力してみたのですが、値を見ると 1, 2, 3, … のような秒数を刻む値ではなく 3256, 6785, 125678, … のようにガンガン値が増えていました
ちょっとこの値に説明します

カウント値について

以下もしかすると、間違いがあるかもしれません

この値について目視でどの程度増えているのか計測してみたのですが、だいたい 30 秒で 1,000,000 カウント増えている感じでした
なので 1 秒間で約 33,000 ほど増えていることになります

何かそれっぽい値を定義している箇所がないか調べてみたのですが、APP_TIMER_CLOCK_FREQ というマクロが定義されておりこの値が 32768 になっていました
おそらくですが 1 秒間にこの APP_TIMER_CLOCK_FREQ の値だけ増加しており、app_timer_cnt_get ではそれが取得できているのだと思います
なので、時間を取得したいのであれば、取得した値を APP_TIMER_CLOCK_FREQ で割り算すればそれっぽい起動時間が取得できると思います

また、値の最大値なのですが、約 16, 800,000 くらいになるとまた 0 にリセットされてカウントが始まりました
( 16, 800, 000 / 33,000 = 510 (sec) = 8 min 30 sec )
なので何回リセットされたかどうかも管理しないとダメそうな感じです
最大値を伸ばす方法とリセットされた回数を取得できる方法があるかどうかは、すいません、調査しきれていません、、、

ちょっとこの辺が曖昧な記載なのは、そこまで深く調べていないので自信がないためです
間違いがや追加の情報あればご指摘いただけると助かります

最後に

とりあえず nrf51822 で起動時間っぽい値を取得できるようになりました
完全に使うためにはもう少し実装が必要そうですが、ベースとなる呼び出し方は理解できたと思います

10分くらいでリセットされるタイマーだとちょっと管理が大変なので、半日分くらいは管理できるようにしたいなと思っています

2015年11月16日月曜日

Jekyll に theme を適用する方法

概要

Jekyll のデザインには様々なテーマが公開されており、これを使って簡単にデザインをカスタマイズすることができます
今回はテーマを使って jekyll build する方法を紹介します

環境

  • Mac OS X 10.10.5
  • Jekyll 2.5.3

テーマを適用してみる

http://jekyllthemes.org/ から好きなテーマを選択してください
今回は Jekyll Now というテーマを使ってみます

  • mkdir -p jekyll/work
  • cd jekyll/work
  • git clone https://github.com/barryclark/jekyll-now.git
  • gem install jekyll-sitemap
  • cd jekyll-now
  • jekyll server

で起動まで実施します
途中サイトマップを表示するためのプラグインをインストールしています
jekyll server を実行すると localhost:4000 で LISTEN するのでブラウザでアクセスしてみましょう

今回のテーマだと以下のようなサイトが表示されると思います
jekyll-apply-theme.png

ちょっとカスタマイズする

名前を変更する

  • emacs jekyll/work/jekyll-now/_config.yml

name: Your Name

を編集して再度 jekyll server すれば変更できます

記事をポストする

  • cd jekyll/work/jekyll-now
  • cp _posts/2014-3-3-Hello-World.md _posts/2015-11-16-sample-post.md
  • emacs _posts/2015-11-16-sample-post.md

jekyll server を実行すれば (内容は特に変更しなくても) 記事が増えていることが確認できると思います
あとはこんな感じで markdown ファイルを増やしていけば OK です

ビルドする

サイトなどで公開するための HTML ファイルを生成します

  • cd jekyll/work/jekyll-now
  • jekyll server

_site というディレクトリ配下に HTML や CSS が作成されるのでそれをそのまま Web サーバの DocumentRoot に配置すれば OK です

最後に

既存の Jekyll に対して適用するやり方は今回紹介しませんでしたが、おそらく _posts 配下にある .md ファイルを一旦退避し、テーマをダウンロード後に _posts ファイルに移動すれば適用できるはずです
プラグインを使って記載されている markdown やレイアウトがある場合はプラグインの再インストールも必要になると思います

特にデザインを自分でゴリゴリ作成したいということでなければ、テーマをベースに作成するといいと思います
レイアウトや 404 ファイルなどサイトの公開に必要なファイルは一通りそろっている状態なので、これをベースにカスタマイズしたほうがいいと思います

自分で作成したテーマはもちろん jekyllthemes.org で公開することもできます

あと Jekyll 3.0 が 2015/10/26 に正式にリリースされましたが、 3.0 だともしかしたらエラーになるテーマがあるかもしれません

2015年11月12日木曜日

CentOS7 + AWS で docker-machine を試してみた

概要

docker-machine は仮想マシン上に docker-engine が動作する環境を構築することができるツールです
今回は CentOS7 上の docker-machine から AWS の EC2 インスタンス上に docker 環境を構築してみます

環境

  • CentOS7 64bit
  • docker-machine 0.5.0
  • docker-engine 1.8.3

docker-machine インストール

事前に docker-engine のインストールを行っておいてください

  • mkdir ~/mydocker.machine
  • cd ~/mydocker.machine
  • curl -L https://github.com/docker/machine/releases/download/v0.5.0/docker-machine_linux-amd64.zip >machine.zip
  • unzip machine.zip
  • rm machine.zip
  • mv docker-machine* /usr/local/bin

docker-machine -v でバージョンが表示されればインストール完了です

AWS 上での準備

API でもマネージメントコンソールでもどちらでも OK です

VPC およびサブネットの作成

マネージメントコンソールにログインしたら

サービス > VPC -> VPCウィザードの起動

と実行すれば VPC とそれに紐づくサブネットを一気に作成できます
create_vpc_and_subnet.png

VPC を作成したリージョンと VPCID をメモしておいてください
サブネットを作成したゾーンもメモしておいてください

API をコールすることになるので、アカウントが持つアクセスキーとシークレットキーを用意してください

docker-machine の実行

では、 AWS 上にインスタンスを作成し docker-engine が動く環境を構築します

  • docker-machine create --driver amazonec2 --amazonec2-access-key [Your Access Key] --amazonec2-secret-key [Your Secret Key] --amazonec2-vpc-id vpc-xxxxxxxx --amazonec2-region ap-northeast-1 --amazonec2-zone c aws01

入力しなければいけないのは [Your Access Key], [Your Secret Key], vpc-xxxxxxxx の部分です
VPC およびサブネットを作成したリージョンとゾーンが異なる場合は ap-northeast-1 と c の部分も書き換えてください

上記の場合は ap-northeast-1 リージョンにある vpc-xxxxxxxx 内のサブネットに aws01 というインスタンスを作成します
作成されるインスタンスのタイプは t2.micro になります

しばらく待っていると docker-engine がインストールされたインスタンスが起動します

Running pre-create checks…
Creating machine…
Waiting for machine to be running, this may take a few minutes…
Machine is running, waiting for SSH to be available…
Detecting operating system of created instance…
Provisioning created instance…
Copying certs to the local machine directory…
Copying certs to the remote machine…
Setting Docker configuration on the remote daemon…
To see how to connect Docker to this machine, run: docker-machine env aws01

AWS 上に作成した docker-engine を操作してみる

  • docker-machine ls

で作成したインスタンスの情報を取得できます
IP アドレスを取得するときに API をコールしているので API のコールに失敗するとエラーが表示されます

docker コマンドで AWS 上のインスタンスを操作できる準備をします

  • eval “$(docker-machine env aws01)”

を実行すると以降の docker コマンドの操作が AWS 上のインスタンスに対する操作になります
docker-machine env aws01 だけ実行するとわかりますが、いくつかの環境変数を export するコマンドが出力されます
それを eval しているだけです

例えば すでに CentOS 上で docker-engine が動作しておりイメージが存在しているのであれば eval したあとで docker images とかを実行してみると何もイメージが表示されないことが確認できると思います

  • docker run busybox echo hello world

超簡単なコンテナの実行です
DockerHub から busybox イメージをダウンロードして echo しているだけです
問題なく実行できると思います
終了後に docker ps -a で確認すると終了していることがわかると思います

これだと本当に AWS 上のインスタンスで実行されているかわからないので nginx を動かしてアクセスできるか確認してみます

  • docker run -d -p 8000:80 nginx

nginx のイメージを取得して起動します
インスタンスの 8000 番をコンテナの 80 番にフォーワードして -d でデタッチモードで起動します

  • curl $(docker-machine ip aws01):8000

で Nginx の「Welcome to Nginx」の HTML が返ってくることを確認してください
返ってこない場合は 8000 番がセキュリティグループで閉じられていると思います
docker-machine で作成したインスタンスには docker-machine というセキュリティグループが自動で作成され割り当てられるようで、これが 22 と 2376 しかデフォルトでは空いていませんでした
ポートを開放して再度実行して HTML が返ってくることを確認してください

  • docker-machine aws01 stop

使わなくなったら上記コマンドでインスタンスを停止することができます
再度使いたい場合は start で OK です

最後に

今回は AWS 上で試しましたが docker-machine には driver という概念があり、様々なクラウドサービスや仮想環境にアクセスできる driver が備わっています
https://docs.docker.com/machine/drivers/

今後もいろいろな driver が追加されると思います
どうしても追加してほしい driver があれば pull - req でもいいと思います

テストとかで試すために自分の環境に docker-engine をインストールすることはあると思いますが、プロダクションなどで複数のインスタンスに docker-engine をインストールする場合は docker-machine を使って構築すれば管理が楽になると思います

あとは、SWARM という欄が ls 実行時にあったので docker-swarm と連携して、複数クラウドサービス間で docker クラスタを組めたりする感じでしょうか
この辺りはまた次回にでも試せればと思います

トラブルシューティング

  • Error creating machine: Error with pre-create check: unable to find a subnet in the zone: us-east-1a
    デフォルトのリージョンは us-east-1a にインスタンスを作るみたいで、そこに VPC とサブネットがないと上記のエラーになります

  • Error creating machine: Error in driver during machine creation: Error launching instance: Problem with AWS API call: Non-200 API response: code=400 message=Your requested instance type (t2.micro) is not supported in your requested Availability Zone (ap-northeast-1a). Please retry your request by not specifying an Availability Zone or choosing ap-northeast-1b, ap-northeast-1c.
    デフォルトのインスタンスタイプは t2.micro のようでゾーンによっては t2.micro が推奨されないタイプになります
    その場合に上記のエラーが発生します
    インスタンスを作成するゾーンを変更するかインスタンスタイプを変更 (--amazonec2-instance-type) してあげれば OK です

  • Host already exists: “aws01”
    すでにインスタンスが作成されているため create コマンドが失敗しています
    実際に AWS 上にインスタンスは作成されていないみたいで、不整合が発生しているのでローカルの情報を削除してあげましょう

    docker-machine rm -f aws01

  • Error creating machine: Error with pre-create check: There is already a keypair with the name aws01. Please either remove that keypair or use a different machine name.
    キーペアがすでに作成されているためにエラーが発生しています
    マネージメントコンソールから EC2 -> キーペア -> aws01 を削除して再度実行してください

  • Error creating machine: Error with pre-create check: unable to find a subnet in the zone: ap-northeast-1c
    指定したゾーンにサブネットが存在しない場合に発生するエラーです
    マネージメントコンソールの VPC から該当のゾーンにサブネットを作成しましょう

参考サイト

2015年11月11日水曜日

nRF51822 の Advertise で Scan レスポンスパケットを設定する方法

概要

Scan レスポンスパケットは Advertising でスキャンした後にレスポンスとして Peripheral が Central に送信できるおまけパケットです
Advertising パケットは上限が 31 バイトになっておりその上限を超えて何かデータを送りたいときなどに使います
データの構造は Advertising パケットと同様になっています

環境

  • Windows7 64bit
  • nRF51822
  • nRF51 DK
  • nRF51 SDK 9.0.0

背景 (なぜ Scanパケットを設定したかったのか)

ちょっと長くなりますが背景を詳しく説明します

サンプルのせいにするわけではないですが nRF51 SDK に含まれている各種サンプルでは基本的に Scanパケットを設定していません
で、Central 側の実装を Python ベースの gattlib というライブラリを使って実装していたのですが、Advertising パケットをスキャンした際に DeviceName が含まれずに困っていました
具体的には DiscoveryService.discover というメソッドを使うと DeviceName が取得できない状況でした

切り分けのため TI 社が提供する SensorTag や iPhone で実装した Peripheral デバイスを使ってスキャンしてみたのですが、その場合はうまく DeviceName が取得できました
なので、nRF51822 上に実装しているアプリが悪そうだ、ということでいろいろ調べたところ Scan レスポンスパケットを設定してあげることで、nRF51822 でも DeviceName を取得することができるようになりました

更に余談になってしまうのですが、hcitool の lescan というコマンドを使っていると DeviceName が (unknown) と表示されることにも気付きました
unknown がちょくちょく出ていましたが、ちゃんと DeviceName が表示されることもあったので初めは無視していました
また、nRF51822 の場合でも SensorTag の場合でも unknown が表示されていたので「こんなもんなのか」と思っていたのですが、discover すると nRF51822 だけ DeviceName が取得できないのはおかしいということに気が付き詳しく調べてみたところ Scan レスポンスパケットという仕様にたどり着き設定してみたらうまくいった感じです

ということは今思うと SensorTag は Scan レスポンスパケットを設定しておりかつ、gattlib の DiscoveryService.discover は Advertising パケットの DeviceName を見ているわけではなく、Scan レスポンスパケットの DeviceNam を見ている ( のではと今になって予想しています、コードレベルまで見ていないので正解がどうかは不明です )

長くなりましたが、まとめると

  • gattlib の DiscoveryService.discover で DeviceName が取得したかった

ために設定した感じです

設定方法

前置きかなり長くなりましたが実装方法です
nRF51 SDK のサンプルでは多くの場合、 main メソッド内で各処理の初期化を行っています
その中の advertising_init というメソッドで Advertising パケットの設定をしておりそこを修正します

具体的なコードの全貌は以下のとおり

static void advertising_init(void) {
    uint32_t      err_code;
    ble_advdata_t advdata;
    ble_advdata_t rspdata;

    // Build advertising data struct to pass into @ref ble_advertising_init.
    memset(&advdata, 0, sizeof(advdata));
    memset(&rspdata, 0, sizeof(rspdata));

    advdata.name_type               = BLE_ADVDATA_FULL_NAME;
    advdata.include_appearance      = true;
    advdata.flags                   = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
    advdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]);
    advdata.uuids_complete.p_uuids  = m_adv_uuids;

    rspdata.name_type               = BLE_ADVDATA_FULL_NAME;

    ble_adv_modes_config_t options = {0};
    options.ble_adv_fast_enabled  = BLE_ADV_FAST_ENABLED;
    options.ble_adv_fast_interval = APP_ADV_INTERVAL;
    options.ble_adv_fast_timeout  = APP_ADV_TIMEOUT_IN_SECONDS;

    err_code = ble_advertising_init(&advdata, &rspdata, &options, on_adv_evt, NULL);
    APP_ERROR_CHECK(err_code);
}

ポイントは rspdata 変数を宣言して rspdata.name_type = BLE_ADVDATA_FULL_NAME; として DeviceName を設定するところです

冒頭でも説明していますが、Advertising パケットと Scan レスポンスパケットはデータ構造が同じです
なので、すでに宣言している advdata を使いたいところですがこれを使うとうまく動作しませんでした

また、 rspdata に DeviceName だけ表示するように設定していますが、これもポイントで他のパラメータも advdata と同じように設定したところ、これまたうまく動作しませんでした
( うまく動作しない明確な理由がわからない状態です、すいません )

なのでとりあえず上記のように、記載することで Scan レスポンスパケットを設定することができました

最後に

これで再度 hcitool lescan をすると nRF51822 で実装した BLE デバイスに unknown が表示されなくなっていることが確認できると思います
Advertising + Scan レスポンスパケット両方で DeviceName を設定するようにしたためです

ただ、他のデバイスを見るとほとんどのデバイスで unknown になることがあるので、おすすめ実装的にはやっぱりどっちかだけで DeviceName を送信するほうがいいのかもしれません
まぁ確かに同じデータを 2 回送るのであれば無駄といえば無駄ですからね
とは言え Central 側の実装も考慮しなければいけないと考えるととりあえず両方設定しておいたほうが無難といえば無難なのでしょうか

相変わらず BLE の実装は大変です

2015年11月10日火曜日

スタンドアロンになってしまった RaspberryPi を救う方法

概要

想定ケースとしては

  • RaspberryPi (RPi) は常に無線 LAN に接続しており他のマシンから SSH でログインして操作していた

という状況で突如無線 LAN が停止してログインできなくなったときに救うケースを考えてみます

環境

  • Raspberry Pi Type B Single Board Computer 512MB
  • Raspbian 8.0 (Jessie)

最終手段

いきなりですが、最終手段です
どうしても RPi を操作できる状況にできない場合は、ネットワークが復旧したあとで電源プラグを引っこ抜いて再起動するしかないと思います

電源を直接抜いてシャットダウンすると SD カードが破損して最悪 OS 起動しなくなったりデータが正確に保存されないなどのリスクがあります
自分は一度だけ OS が起動しなくなり SD カードをフォーマットしなおしたことがありますが、ほぼ遭遇したことはありません
なので「どうしても」というケースでは実施して問題ないと思います

今回は上記を最終手段として、それまでに救えるいくつかの方法を検討していきます

キーボードおよびディスプレイを使って救出する

おそらくこれが一番メジャーだと思います
キーボードしかない場合も想定して復旧方法を検討します

有線のキーボードおよびディスプレイに接続できる状況

この状況があれば一番救える確率が高いです
キーボードは USB でディスプレイは HDMI とします

この場合はまずそのままキーボードとディスプレイを RPi に接続します
で、キーボードから何かしらの信号を送れば HDMI 側にも信号が飛んで RPi の CUI が表示されればそのまま救出完了になります
( RPi の OS のバージョンが Raspbian Jessie だった場合はデフォルトが GUI なのでキーボードの Tab や Alt 十字キーを使ってターミナルを起動するなりして救う必要があります、キーボードが HHK で十字キーボードがないとか OS のキーボード配列の設定が違うとか問題に遭遇する可能性もありますが、そうなったら頑張るしかないです )

ですが、キーボードとディスプレイを接続して信号を送ってみたのにディスプレイ側に信号が来ないなんてことに遭遇すると思います
RPi は起動時にディスプレイが繋がっていれば HDMI の出力を ON にするのですが、HDMI が繋がっていない状態で電源を ON にすると HDMI の出力が行われません
( 自分の場合は上記に該当しており、デフォルト GUI だった OS を CUI の状態にしたら発生しました )
その場合は画面が見えない状態でキーボードで HDMI の出力を ON にするコマンドを実行しなければいけません
コマンドは以下の通り

  • tvservice -o
  • tvservice -p
  • fbset -depth 8
  • fbset -depth 24

簡単に説明するとディスプレイの出力を OFF -> ON して画面のフレームバッファの設定を 8 -> 24 に変更します
このコマンドを画面が真っ暗な状態で、想像しながらタイプする必要があります
間違ってタイプした場合は Ctrl + e -> Ctrl + u を駆使して一旦クリアした後で再度冷静にタイプしましょう
タイプが成功して HDMI への信号が ON になれば画面が表示されて救出完了になります

あとコマンドをいきなり実行できる状態で RPi が起動していればいいのですが、pi ユーザで一度ログインしないとダメな場合には、そこから想像しながらタイプする必要があるので若干難易度があがります

どうしても画面が表示されない場合は「sudo reboot」もありです
もしくは「sudo shutdown -h now」でシャットダウンして RPi 上の LED が点滅しないことを確認して電源を抜いてから再起動でも問題ないと思います

有線のキーボードはあるがディスプレイがない

これは、上記の通り想像しながらキーをタイプするしかないと思います
ディスプレイがないのでディスプレイに出力してもしょうがないのでこの場合は

  • sudo reboot

or

  • sudo shutdown -h now

のどちらかを頑張ってタイプして復旧させるしかないと思います
そしてこの場合は GUI だと終わります
さすがに GUI をキーボード Only で想像しながらタイプするのは無理があります

頑張ってタイプしても再起動しない、停止しないという場合は、キーボード自体の信号が送信されていない可能性があるかもしれません
例えば PPi を電池やモバイルバッテリーで動かしている場合に充電が足りずに RPi に十分な電圧が加わらず USB ポートが正常に動作しないなどが考えられます
RPi は通常 5V (家庭用の電源コンセント) の電圧がかかることを想定しています

ディスプレイはあるが無線キーボードしかない

例えば Bluetooth の無線キーボードだけある状況です
基本は有線と変わらず接続できたら停止 or 再起動コマンドを想像しながら発行するということしかできません

ただ、無線の場合は有線に比べて信号を送るまでの難易度があがります
まず RPi に Bluetooth レシーバが接続されていることが絶対条件です
これがないと終了です
レシーバがあり無線キーボードがアドバタイズできる状況であるならば救える可能性はあります

が、ここからもハードルが高いです
RPi の場合 Bluetooth キーボードと接続するにはキーボードとペアリングするためのコマンドを発行する必要があります
(参考 : RaspberryPi で Bluetooth キーボードを接続する方法, RaspberryPi の bluetoothctl で無線キーボードに接続 )
一度接続したキーボードは trust することで自動で再接続してくれるオプションがあるのですが、このオプションは RPi が起動する場合でないと使えません
なので RPi が起動中に Bluetooth キーボードが接続できる範囲にきても自動で接続してくれません

ではどうするか、ですが自分は以下のスクリプトを cron で回す設定を事前に行っています
bluetoothctl と expect で無線キーボードに定期的に接続するスクリプト

ここまで事前に用意できていて初めて無線キーボードが使えるようになります
有線に比べてかなりハードルが高いので、緊急時はできれば有線キーボードを準備してください

キーボードもディスプレイもない

これは相当厳しいです
最悪 PC があればなんとかなります (後述) が、この場合は電源 OFF をするしかないです

PC を持っている場合

一台 PC を持っている場合に救出できる方法がないか検討します

シリアル通信を使う

RPi の GPIO を使って RPi 上の信号を PC に表示します
ただ、シリアル通信をするのであれば PC 以外に以下の機材が必要になります

  • ジャンパケーブル
  • FTDI シリアル - USB 変換アダプタ
  • USB ケーブル

やり方や機材等の詳細はこちらを御覧ください
シリアル通信に必要な機材はこれ以外のパターンもたくさんあります
が、とりあえず PC だけでは無理です

そしてシリアル通信の最大の弱点は PC を停止した状態で配線しないと信号が受け取れない点にあります
・・・そう、起動している RPi だと結局シリアル信号をモニタすることができないのです

じゃあなんで紹介したんだとなりますが、1 つは電源での OFF -> ON 後にとりあえず正常に動作しているか確認したい場合に使えます
もう 1 つは実は起動した状態でシリアル通信できる方法があると誰かが教えてくれのではと、思ったからです
もしかしたら、あとで調べたらあっさり方法がわかるかもしれませんが

最後に

RPi は一度セットアップしてサーバとして動かすのであれば電源だけあれば OK で省スペースなのですが、いざぶっ壊れて対応しなければいけないときに、とたんにハードルと必要になる機材が増えるようなイメージがあります

しょうがないと言えば確かにしょうがないですが、もっとスマートな方法はないものだろうかと思いました

2015年11月9日月曜日

CentOS7 で docker-compose を試してみた

概要

docker-compose は複数のコンテナで構成されるアプリを管理するためのツールです
fig と言われていたツールがそのまま docker-compose になりました
今回は docker-compose の QuickStart を試してみたので紹介します

環境

  • CentOS7 64bit
  • docker-engine 1.8.3
  • docker-compose 1.4.2

docker-compose のインストール

  • VERSION_NUM=1.4.2
  • curl -L https://github.com/docker/compose/releases/download/VERSION_NUM/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
  • chmod +x /usr/local/bin/docker-compose
  • docker-compose version

でインストールします
インストールが完了したらバージョンが表示されることを確認してください

各種ビルド用のファイルの作成

アプリを構成するファイルを作成していきます

DockerFile の作成

  • mkdir ~/mydocker
  • cd ~/mydocker
  • touch DockerFile
FROM ruby:2.2.0
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev
RUN mkdir /myapp
WORKDIR /myapp
ADD Gemfile /myapp/Gemfile
RUN bundle install
ADD . /myapp

イメージは DokcerHub にある ruby というイメージの tag 2.2.0 を使います
他の最新版のバージョンもあるのでそれでもいいかもしれません

Gemfile の作成

  • cd ~/mydocker
  • touch Gemfile
source 'https://rubygems.org'
gem 'rails', '4.2.0'

単純に rails をインストールするだけの Gemfile です
DockerFile 内の ADD というコマンドで作成した Gemfile をコンテナ上に渡します

docker-compose.yml の作成

  • cd ~/mydocker
  • touch docker-compose.yml
db:
  image: postgres
web:
  build: .
  command: bundle exec rails s -p 3000 -b '0.0.0.0'
  volumes:
    - .:/myapp
  ports:
    - "3000:3000"
  links:
    - db

docker-compose.yml にアプリを構成するコンテナの定義を記載します
DB には postgres を指定します
ファイル内では環境変数の参照も行えるようです
その他の詳細はこちらのページを参照してください

web コンテナ上で動作する rails のサンプルアプリを作成する

  • cd ~/mydocker
  • docker-compose run web rails new . --force --database=postgresql --skip-bundle

run コマンドのあとに docker-compose.yml に記載したコンテナを指定します ( -> web )
そのあとでコンテナ上で実行するコマンドを記載します ( -> rails new . --force --database=postgresql --skip-bundle )
コンテナ上で実行されたコマンドの結果はローカルに保存されるのでこのアプリを使ってコンテナ上で動作させます

Gemfile の編集

サンプルアプリを作成した際に生成される Gemfile を編集します
今回はブラウザ上で動作するアプリを実行するための以下の行をコメントアウトします

gem 'therubyracer', platforms: :ruby

コメントアウトしたら保存しましょう

config/database.yml の編集

  • cd ~/mydocker
  • vim config/database.yml
development: &default
  adapter: postgresql
  encoding: unicode
  database: postgres
  pool: 5
  username: postgres
  password:
  host: db

test:
  <<: *default
  database: myapp_test

上記の設定になるようにローカルの config/database.yml を編集してください
デフォルトで作成される config/database.yml にはいろいろと記載されているので全部消してもいいですし、必要な部分だけ編集しても OK です

ビルドの実行

docker-compose 上で動作するイメージをビルドします

  • cd ~/mydocker
  • docker-compose build

初回ビルド時はいろいろとダウンロードする必要があるので時間がかかります
ビルドが完了したら docker images で新しいイメージが作成されていることを確認しましょう
今回の手順で実施すると mydocker_web というイメージが作成されていると思います

REPOSITORY                  TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
mydocker_web                latest              35147b5838ce        18 seconds ago      914.2 MB

コンテナ上でのアプリの起動

イメージが作成できたらアプリを起動してみましょう

  • cd ~/mydocker
  • docker-compose up

起動したらプロセスを確認してみます

  • docker-compose ps
     Name                   Command               State           Ports
--------------------------------------------------------------------------------
mydocker_db_1    /docker-entrypoint.sh postgres   Up      5432/tcp
mydocker_web_1   bundle exec rails s -p 300 ...   Up      0.0.0.0:3000->3000/tcp

State が Up になっていれば OK です

動作確認

この状態でブラウザで 3000 番にアクセスすると Rails のサンプル画面が表示されると思います

http://hostname:3000/

コンテナを停止させたい場合は

  • docker-compose stop

で OK です

紹介は以上です
次回は docker-compose の特徴的な機能の 1 つである scale を検証できればと思います

Tips

データベースが作成されているか確認してみる

  • docker exec -it mydocker_db_1 bash
  • su - postgres
  • psql -l
  • psql postgres

docker exec は作成したコンテナにログインすることができる便利なコマンドです
デバッグで重宝します
データベースがない場合はdocker-compose run web rake db:create で作成可能です

イメージが削除できない

Error response from daemon: Conflict, cannot delete 3e2dbcd4b881 because the running container 379975ee952b is using it, stop it and use -f to force

docker-compose で作成したイメージを削除しようとして発生しました
まだイメージを使ったコンテナが動作しているためイメージを削除できないというエラーのようです
docker ps -a で全コンテナを表示して該当するコンテナを削除しましょう
全コンテナを削除して問題ない場合は

  • docker rm $(docker ps -aq)

で全コンテナを削除してから、再度 docker rmi してみましょう

2015年11月8日日曜日

Eclipse + Astyle で C 言語のコードをフォーマットする

概要

Astyle という C や Java で使えるソースコードフォーマッタを Eclipse で使えるようにしてみました

環境

  • Mac OS X 10.10.5
  • Eclipse 4.4 Luna
  • Astyle Plugin 1.0.1

インストール

Eclipse を開き

Help -> Install New Software

を選択

Add を選択しプラグインを公開している URL を入力
http://astyleclipse.sourceforge.net/update

add_plugin_site_astyle.png

一覧に表示されたチェックし Next を選択

check_plugin_astyle.png

利用規約に同意してインストールを実施する
セキュリティ警告は OK にする
再起動を促されるので実施する

設定方法

コードフォーマットしたときにインストールした Astyle プラグインのフォーマットルールを使うように設定する

Eclipse -> 環境設定 -> Astyle

でスタイルを選択できるので好みのスタイルを選択し OK

choice_style_in_astyle.png

次に C/C++ のフォーマットの設定を Astyle のフォーマッタに変更する

Eclipse -> 環境設定 -> C/C++ -> Code Style -> Formatter

で Code Formatter の部分を「Astyle Plugin」に変更する

change_fomatter_to_astyle.png

これで設定は完了です
あとは C 言語のソースコードを編集しているときに Ctrl+Shift+f でフォーマットすることで Astyle のフォーマットが適用されます

2015年11月6日金曜日

nRF51822 + nRF51 DK を使って BLE デバイスの開発環境を構築

概要

nRF51822 とは NordicSemiconductor 社が提供する BLE モジュールです
nRF51822 には専用の開発用のボード (nRF51 DK) がありこれを使うことで BLE デバイスの開発を行うことができます
今回は開発環境の構築方法を紹介します

環境

  • Windows7 64bit
  • nRF51822
  • nRF51 DK
  • MicroUSB x 1

各種インストール

各種インストールの作業は Windows 上で行っていきます

アプリ焼きこみ用のツール nRFgo Studio のインストール

開発したアプリをモジュールに焼きこむためのツールです

  • https://www.nordicsemi.com/chi/node_176/2.4GHz-RF/nRFgo-Studio にアクセス
  • 「DOWNLOADS」タブを選択
  • nRFgo Studio-Win64 を選択しダウンロード
  • ダウンロードした nrfgostudio_win-64_1.21.0_installer.msi を実行しインストール
  • インストール中の Choose Setup Type は Typical を選択
  • ドライバをインストールする確認ダイアログが続けて表示されるのですべて OK にする
  • 続けて nRF Tools をインストールする旨が表示されるので続けてインストール
  • J-Link のドライバをインストール

で nRFgo Studio がインストールできます
同時に J-Link のドライバもインストールするのを忘れないようにしてください
2015/11/05 時点での最新版は 1.21.0 でした

開発用の IDE Keil のインストール

Keil という組み込み開発で使用する IDE をインストールします

  • https://www.keil.com/download/ にアクセス
  • 「Download」タブを選択
  • 「Product Downloads」を選択
  • 「MDK-ARM」を選択
  • ダウンロードするために個人情報を入力 (keil だけダウンロードに必要)
  • ダウンロードのページに遷移したら MDK517.EXE を選択しダウンロード
  • ダウンロードした MDK517.EXE を実行しインストール

で Keil の μVision という IDE がインストールできます
デフォルトの設定だと C ドライブ直下に C:\Keil_v5 というディレクトリ名でインストールされます
IDE を起動する場合は C:\Keil_v5\UV4\UV4.exe を実行してください
2015/11/05 時点での最新版は 5.17.0 でした

nRF51 SDK のインストール

開発に必要な SDK をインストールします

ダウンロードが完了したら解凍して適当な場所に配置すれば OK です
nRFgo Studio から参照します
zip をダウンロードする際に他の最新版があればそちらをダウンロードしても OK です
2015/11/05 時点での最新版は 9.0.0 でした

この作業は nRF Studio のインストール時に完了しています
最新版をインストールしたい場合にだけ実施してください

  • https://www.segger.com/jlink-software.html にアクセス
  • Software and documentation pack for Windows の最新版を Download
  • ダウンロードが完了したら zip を解凍し Setup_JLink_V502i.exe を実行しインストール
  • インストール中の「Install USB Driver for J-Link」にチェック

でドライバがインストールされるはずです
2015/11/05 時点での最新版は 502i でした

配線

開発ボードと Windows を接続していきます
開発ボードへの電源の供給は PC から行います

配線は非常に簡単で開発ボード側の MicroUSB と PC の USB ポートを接続すれば OK です
基本はこれだけで開発できます

他にはデバッグ用のシリアル通信や nRF51822 モジュールへの書き込みを行うための配線がありますが、とりあえず BLE デバイスを開発するだけであれば上記で十分です

配線が完了したら開発ボードの電源を ON にしましょう

サンプルの焼きこみ

では開発ボードにサンプルアプリを焼きこんでみましょう
今回は簡単な Peripheral アプリを焼きこんで、ちゃんとアドバタイズされるか確認してみます

配線を完了し開発ボードの電源が入っている状態で nRFgo Studio を起動します
起動したら左ペインの「Device Mangaer」に nRF51 development boards があり、その中に Segger … で始まるデバイスが認識されていることを確認してください
これが表示されない場合は開発ボードがうまく Windows 側に認識されていないので、ドライバのインストールを再度実施してください

SoftDevice の焼きこみ

Segger を選択した状態で右ペインに移動します
まずは SoftDevice を焼きこんでいきます
SoftDevice とは簡単にいうとミドルウェアのようなもので、開発するアプリはこの SoftDevice 上で動作します

右ペインの「Program SoftDevice」タグを選択します
そして「File to program」に SoftDevice を指定します
指定する SoftDevice はダウンロードした SDK に含まれています
例えば C ドライブ直下に SDK を配置したのであれば

C:\nRF51_SDK_9.0.0_2e23562\components\softdevice\s110\hex\s110_softdevice.hex

にあります
選択したら「Program」ボタンを押して焼きこみを開始します
ダイアログが表示され最終的に successfully になれば OK です

サンプルアプリのビルド

ここがちょっとだけ面倒です
サンプルアプリ用の .hex ファイルが SDK 内に同梱されておらずソースファイルから自分でビルドして作成する必要があります
まず Keil を開きましょう
開いたら SDK に同梱されているサンプルプロジェクトを開きます

Project -> Open Project

で以下を指定して開きます

C:\nRF51_SDK_9.0.0_2e23562\examples\ble_peripheral\ble_app_hrs\pca10028\s110\arm5_no_packs\ble_app_hrs_s110_pca10028.uvprojx

するとプロジェクトが開きます
今回は特にソースを修正する必要はないので開いたらいきなりビルドします

Project -> Build target

でビルドが始まります
プロジェクト内に存在する C のソールコードがコンパイルされ最終的に .hex が作成されれば OK です
.hex ファイルはarm5_no_packs\_build\nrf51422_xxac_s110.hex に作成されます

サンプルアプリの焼き込み

作成できたアプリを焼きこんでいきましょう
再度 nRFgo Studio に戻ります

今度は右ペインの「Program Application」タグを選択します
そして、FIle to program に先ほど作成した .hex ファイルを指定します

C:\nRF51_SDK_9.0.0_2e23562\examples\ble_peripheral\ble_app_hrs\pca10028\s110\arm5_no_packs\_build\nrf51422_xxac_s110.hex

選択したら「Program」を選択します
SoftDevice の書き込み同様ダイアログが表示され最終的に successfully になれば書き込み完了です

動作確認

今回は iPhone で確認してみます
スマホアプリに BLE を検知できるアプリがいくつかあるのでそれを使います

開発ボードの電源が入っている状態でアプリを立ち上げてみましょう
すると開発ボードに焼きこまれたアプリがBLEデバイスとして検知できると思います
今回の場合「Nordic_HRM」というデバイス名でアプリを書き込んでいるのでその名前で見つかると思います

最後に

紹介は以上です
今回 nRF51822 モジュールに直接書き込みはしませんでした
モジュールに書き込みを行いたい場合は Debug out という 10pin の I/F が開発ボードにあるので、ジャンパを使って nRF58122 が乗った別のボードと接続した状態で nRF Studio で Program すれば焼きこむことができると思います

あとは main.c なりソースの修正をしてビルドして再度 .hex ファイルを作成して焼き込めば開発できると思います
ただ、これだと print 文などをデバッグできないので作業効率が悪いです
やはり開発ボードとシリアル通信して print 文をデバッグした方がいいです
次回にでもシリアル通信の記事を紹介できればと思います

Tips

アプリを修正して Program してうまく動作しない場合は一旦「Erase all」してから再度 SoftDevice -> アプリの順番で書き込みを行ってみてください

2015年11月4日水曜日

CentOS7 で docker 1.8 を試してみた

概要

久しぶりに docker に触りました
バージョンアップもしていたので試したことをメモしておきます
これ をベースに進めていきます

環境

  • CentOS 7.1.1503 64bit
  • kernel 3.10.0-229.el7.x86_64
  • Docker 1.8.3 build f4bf5c7

インストールおよび docker デーモンの起動

以降の作業は root ユーザで実施しました

HelloWorld サンプルの実行

  • docker run hello-world

DockerHub で公開されている hello-world というイメージをダウンロードしてコンテナとして起動します
このサンプルはヘルプ的なものが表示されてすぐに終了します

インタラクティブモード

  • docker run -it ubuntu bash

ubuntu というイメージをダウンロードしてインタラクティブモードで bash を実行します
普通に SSH をしているように ubuntu 上でコマンドが実行できます
apt でパッケージのインストールも行えます
インタラクティブモードは exit 等で抜けない限り docker 上のプロセスとして存在します
exit 後はプロセスが終了します ( コンテナが削除されます )

特定のプログラムを実行するサンプル

  • docker run docker/whalesay cowsay boo

docker/whalesay というイメージをダウンロードして「cowsay boo」というコマンドを実行します
cowsay というコマンドは AA を作成し引数に渡された文字列をセリフとして出力するネタコマンドです
docker/whalesay イメージはすでに cowsay がインストールされているイメージなのでコンテナとして実行することができます
実行すると AA が表示されてコンテナが終了します

独自のイメージを生成してみる (Dockerfile 入門)

  • mkdir mydocker
  • cd mydocker
  • touch Dockerfile
  • vim Dockerfile
FROM docker/whalesay:latest
RUN apt-get -y update & apt-get install -y fortunes
CMD /usr/games/fortune -a | cowsay
  • docker build -t docker-whale .
  • docker images
  • docker run docker-whale

やっていることは単純で Dockerfile を作成して、そこに実行するコマンドを記載しているだけです
FROM, RUN, CMD は Dockerfile 内で使えるコマンドです
FROM は取得するイメージを指定し、RUN はイメージ作成時に実行されるコマンドで、CMD はコンテナ起動時に実行されるコマンドです
他のパラメータについてはこちらを参照してください

docker build の -t オプションで作成するイメージ名を指定します
build が完了したら docker images で作成できたイメージを確認しましょう

REPOSITORY                  TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
docker-whale                latest              421acc6431fe        About an hour ago   276.8 MB

あとは作成したイメージを指定して docker run します
fortune というコマンドを使って先ほどの cowsay に出力される吹き出しのセリフをランダムに変更しているだけです
コンテナを何度か起動してみるとセリフが毎回変わっていることが確認できると思います

作成した独自のイメージを DockerHub で公開する

  • docker tag 421acc6431fe kakakikikeke/docker-whale:latest
  • docker login –username=username –password=password –email=your-registed-email@sample.com
  • docker push kakakikikeke/docker-whale

まず tag で公開用のイメージをローカルに作成します
tag を付けるときは「ユーザ名/イメージ名」という命名規則で作成してください
最後にコロンでバージョン名を記載します

次に docker login コマンドで認証します
DockerHub に登録したユーザ名、パワワード、メールアドレスを使って認証します
認証に成功すると /root/.docker/config.json に認証用のファイルが生成されます

そして最後に push します
push に成功すると DockerHub のコンパネ上に自分のイメージが表示されるようになります
my_docker_images.png

公開した自分のイメージを使ってみる

  • docker rmi -f 421acc6431fe
  • docker pull kakakikikeke/docker-whale
  • docker run kakakikikeke/docker-whale

既存のローカルのイメージを削除して、DockerHub からイメージを pull してあとは run しているだけです
ダウンロードしたイメージでもコンテナが正常に動作していることが確認できると思います

最後に

紹介は以上です
「-it」オプションのインタラクティブモードは非常に便利な機能だなと思いました
Dockerfile を作るのが捗る気がします

Tips

CentOS 6 でも試してみたのですがエラーが発生し動きませんでした

  • CentOS 64bit 6.7
  • kernel 2.6.32-358.el6.x86_64
  • Docker 1.7.1

Error response from daemon cannot start container xxxxxxxxxx no such file or directory

CentOS の 6 系はそもそもサポート対象ではなくなったっぽいので納得と言えば納得ですが、まぁ仕方ないといったところでしょうか
古いバージョンの Docker なら動くかもしれないです
https://github.com/docker/docker/issues/14365

なんかすごいブーイングですが、押し通してる感じです

2015年11月2日月曜日

RaspberryPi + FTDI でシリアル通信をやってみた

概要

RaspberryPi に接続するのに SSH や HDMI などでディスプレイの表示ができないときに PC と RaspberryPi だけを使って接続することができます
シリアル通信という技術を使うことで実現することができるのでその方法を紹介します

環境

Mac へのドライバインストール

変換アダプタを Mac 上で使用できるようにするためにドライバをインストールします

http://www.ftdichip.com/Drivers/VCP/MacOSX/FTDIUSBSerialDriver_v2_3.dmg

をダウンロードしてポチポチやっていけばインストールできます
2015/10/30 時点でのドライバの最新版は v2_3 でしたので最新版が他にあればそちらをインストールするようにしてください

配線

まず完成した配線は以下の通りです
overview.jpg

ジャンパワイヤ (ジャンパ) が 3 本必要になります (Mac 側から電源を共有するのであれば更にもう一本ジャンパワイヤが必要になります)
以下配線の説明を簡単にしていきます

RaspberryPi 側の配線

まず、RaspberryPi 側の GPIO にジャンパ(メス)を接続します
GPIO の物理 PIN の番号でいうと 6番(GND), 8番(TX), 10番(RX) に接続します
3 本並んでいるのでわかりやすいと思います
rpi_to_ftdi.jpg

FTDI 側の配線

RaspberryPi(RPi) に配線したジャンパを FTDI のアダプタに接続します
まず、RPi 側の GND に接続したジャンパを FTDI の GND に接続します
アダプタに GPIO の番号が印字されているので GND のところに接続してください

次に RX, TX ですがここがちょっと気をつけるポイントです
RPi の TX に接続したジャンパは アダプタ側の RX に接続します
そして、RPi の RX に接続したジャンパは アダプタ側の TX に接続します
つまり、RX と TX がクロスすることになります
RPi 側のTX (送信) を FTDI 側で RX (受信) する感じです
ftdi_to_mac.jpg

Mac 側の接続

これはアダプタの USB 端子をそのまま PC に接続すればOKです
接続が完了したら以下のコマンドを実行して USB アダプタがちゃんと認識されているか確認してください

  • ls -ltr /dev/tty.*

自分の場合は以下の名前でアダプタが認識されていました

crw-rw-rw- 1 root wheel 18, 4 10 29 20:48 /dev/tty.usbserial-AI02RMKU

こんな感じの結果があれば OK です

screen コマンドでシリアル通信の準備をしておく

先に説明しておくべきでしたが、配線中は RaspberryPi の電源は OFF にしておいてください
ON の状態で実施してもシリアル通信のデータを Mac で受信することができません

USB のアダプタが認識できたら screen コマンドを使ってシリアル通信の準備をします
Mac 上でターミナルを起動します
以下のコマンドでシリアル通信を実現します

  • screen /dev/tty.usbserial-AI02RMKU 115200

最後の「115200」という数字はボーレートという値で RPi 側から送信されるボーレートの値が 115200 なのでそれに合わせる必要があります
とりあえず実行すると真っ暗な画面になりますが、そのまま待機しましょう

RaspberryPi の電源を ON にする

ここまで準備出来たら RaspberryPi の電源を ON にしましょう
今回はコンセントから直接電源を共有しているので、起動するには電源アダプタをコンセントに接続すれば OK です

すると screen で待機していたターミナル上に RaspberryPI の起動ログが流れていることが確認できると思います
起動が完了するとログインプロンプトが表示されるので、普通に Mac のキーボードを使ってログインすれば、RPi 上でコマンドを実行することが可能になります
raspberry_serial_console.png

最後に

紹介は以上です

Wi-Fi 環境があったり有線 LAN 環境があるのであれば SSH で接続することをおすすめします
理由としては機材を用意し配線する必要もないからです

シリアル通信を使うケースとしてはやはり緊急時等のデバッグかなと思います
RPi やネットワークに問題があり SSH できない場合やキーボードやモニタなどの機材が用意できない場合に PC さえあれば接続できるので便利です

今回は FTDI の変換アダプタを使いましたが USB とジャンパが一旦になっている専用のケーブルもあるのでそれを使ってもOKです
どちらにしろ最近の PC であれば USB に変換するのは必要だとは思いますが

2015年11月1日日曜日

RaspberryPi で Lチカをやってみた

概要

今更ながらやってみました
簡単に紹介します

環境

  • Raspberry Pi Type B Single Board Computer 512MB
  • 各種DIYキット
    • ブレッドボード
    • ジャンパ (オス - メス) 2 本
    • LED (緑色)

配線

完成図は以下の通りです
enter image description here

enter image description here

まず配線方法についてそれぞれ説明します
以下の作業は電源 ON でも OFF でもどちらでも OK です

RaspberryPi 側の配線

こちらは超簡単です
GPIO の論理 PIN 番号の 6 番(GND), 18番 (GPIO) にジャンパンのメスを接続します
※物理 PIN 番号だと 6 番, 12 番になります
あとはオス側はブレッドボードの同列に適当に差し込んでおけばとりあえず OK です
wiring_rpi.png

ブレッドボード側の配線

こっちが少しだけ大変です
wiring_bread_board.png

まず RaspberryPi (RPi) の GND の同列上に LED のマイナス側を刺します
LED には +/- がありプラスのほうが足が少し長いです
なので短い方を GND の列と合わせてブレッドボードに刺します

次に LED のプラス側の下に抵抗を刺します
今回用意した抵抗は 220 オームの抵抗 (色 : 赤赤茶金) を用意しました
200 から 300 オームくらいの抵抗であれば OK です
1Kオームくらいの抵抗をつなぐと抵抗が強すぎるせいで LED が点灯しないので注意してください

そして抵抗のもう片方の列上に RPi に接続されている GPIO から出いているジャンパを接続します

これで L チカのための配線自体は完了です

信号の送信

たぶんこの状態だと RPi の電源が入っていてもまだ LED は光っていないと思います
理由は GPIO 18 番にまだ電気が流れていないためでその制御を RPi 上でコマンドで制御します

まず GPIO 18 番を使えるようにします

  • sudo echo 18 > /sys/class/gpio/export

次に GPIO 18 番を信号の「出力」として使うことを設定します

  • sudo echo out > /sys/class/gpio/gpio18/direction

あとは、実際に信号を送信します

  • sudo echo 1 > /sys/class/gpio/gpio18/value

すると LED がピカっと光るとおもいます
最後の echo で 0 を送信すると LED が消灯します

最後に

基本はググれば L チカ関係のネタはたくさんでてくると思います

今回自分がはまったポイントは 2 つです

  • 抵抗の値が大きすぎて通電はしていたが LED が光らなかった
  • RPi 上でコマンドで制御する GPIO の番号は物理番号ではなく論理番号を使う

でした
どちらもかなり基本的なところでつまづきました
これを経験して感じたのは

  • 抵抗のオーム数は色からわかるようにしておくとよい
  • GPIO はある程度配置と役割を覚えておいたほうがよい

ということでした
次はセンサーやモーターを GPIO で制御してみたいです

おまけ: Pythonスクリプトで制御

https://github.com/kakakikikeke/python-pybluez-sample/commit/0e69f3a2f606630126b37f722fa185dc244c956e