自己紹介
- 名前
- 加納 聖大
- 会社
- NCデザイン&コンサルティング株式会社
- やってること
-
- Webアプリ
- インフラ構築、運用
- 趣味
-
- PCゲーム
- 自宅サーバー
- いろんな技術で遊んでみること
Twitter: @karuru6225
自己紹介
- 名前
- 十川 亮平
- 会社
- NCデザイン&コンサルティング株式会社
- やってること
-
- AppPotというバックエンドサービスのプロダクトマネージャ
- 今回のデモではサーバーサイドを担当しています
Twitter: @rsogo
Twitter: @app_pot
NCDCの紹介
伊勢丹百貨店さま「MyIsetan、My三越」
その他事例
AppPotとは
AppPotのアーキテクチャ
IoTやAIの事例
某建設会社さま
建設機器のデータを自動でクラウドにアップ。
管理書類を自動でつくる。改ざんや、入力ミスの防止。
研究テーマとして、施工の結果がOKなのかNGなのかをDeep Learningで判定しようとしている。
IoTや機械学習で会社のルールや業務を変える
- 曖昧になっていたものが見えるようになる。
- これまでより多くの品質検査NGがでるようになるかも知れない・・・。現場のマネージャは結構悩んでいる
- 一方、今まで分からなかったので過剰に余裕を持っていたものを最適化
これらの案件から言えること1
業務フロー(UXと言っても良い)に着目して、業務フローを改善するパターン
- これまで人が入力していた業務を、Thingが勝手に連携してくれる
- 人が考えてやっていた業務を、MLが勝手にやってくれる
これらの案件から言えること2
これまではできなかったことを物量とCPUパワーでなんとかして実現する
ミニ四駆デモの構成
サーバー側をもっと詳しく(AppPot IoT)
いろんなIaaSや、オンプレミスで動作するようなミドルウェア選定をしています。
- ActiveMQ: MQTTを受信する
- Javaプログラム: 端末認証、端末の記録
- Kafka: メッセージをトピックとしてPublish
- Fluentd:
- Kafka Consumer: Kafkaからのメッセージ取得
- fluent-plugin-mysql
- MySQL: 今回は。実際はなんでもいい。
はじまり
飲みながら話をしたときのアイデア
- (ミニ四駆の)バッテリー残量を見る
- 電圧測ればいける?
-
F1の実況中継みたいな、加速度計があったらかっこいい?
- 加速度計
- ラップ数、ラップタイム
- ジャイロで一周したことを測る?
- コースに黒いテープを貼り付けて、そこを通過したら一周とする?
- フォトリフレクタの電圧をバッテリ残量のための電圧計で測ればいいか。
- モーターの温度とか測りたい
- 温度計
マイコンボードの選定
目的は、弊社製品の AppPot IoT のアピールだったので、以下のような条件を満たすマイコンが必要だった。
- インターネットに繋げられ、データの送信ができる
- センサーの情報取得できる
- ミニ四駆に載せられる
- (できれば)Node.jsでI2C通信でセンサーデータを取得できる
マイコンボードの比較
ボード名 | インターネット | ミニ四駆に載る? | Node.js |
---|---|---|---|
Arduino | △ 1 | ◯ | × |
Raspberry Pi | ◯ | △ | ◯ |
IntelEdison | ◯ | ◯ | ◯ |
部品購入 (10/7)
- Intel Edison Breakout Board Kit
- MPU-6050搭載 三軸加速度三軸ジャイロセンサモジュール
- ADS1015搭載 12BitADC 4CH 可変ゲインアンプ付き
- LiPo 燃料ゲージ
- QRE1113 フォトリフレクタ・モジュール
- TMP007 非接触温度センサ
- リチウムイオン電池900mAh
センサーからのデータ取得
各種センサーとの通信はI2C通信で行い、
得られたデータを色々処理すると、各種センサーのデータが得られる。
各種センサーは固有のアドレスを持っており、読み書きに先立って、対象のアドレスをi2c通信経路に送出する。
動かしてみる
早速各種ハンダ付けし、回路をブレッドボードで組み立て
Raspberry Piの方のコードを改造し動かしてみる
・・・が、Intel EdisonではNode.jsのI2Cライブラリが動かない
→ どうやらEdisonでは、mraaというライブラリで、各種通信を行うらしい。
mraaをインストー・・・
ビルドでコケてできない。
いろいろ調べた所、Edisonに入っている
ファームウェア(Linuxディストリ:Edison Yocto)の
バージョンが古いせいだった。
→ Yoctoを最新版に
ファームウェアのアップデート
J3にUSB MicroBを接続(シリアル接続)
J16にもUSB MicroBを接続(充電&その他接続)
iot-devkit-prof-dev-image-edison-20160606.zip をダウンロード&解凍
$ sudo brew install dfu-util coreutils gnu-getopt
$ cd iot-devkit-prof-dev-image-edison-20160606
$ sudo cu -s 115200 -l /dev/cu.usbserial-A502OQ0D
$ sudo ./flashall.sh
Bluetoothテザリングの設定
- 展示会場で使うことを踏まえ、Wifiでなく、Bluetoothデザリングをする
Bluetoothのペアリング
$ systemctl start connman
$ systemctl enable connman
$ rfkill unblock bluetooth
$ bluetoothctl
[bluetooth]# scan on
[bluetooth]# discoverable on
[bluetooth]# devices
[bluetooth]# pair AB:CD:EF:01:23:45
[bluetooth]# exit
接続&自動接続の設定
$ connmanctl
[connmanctl]# services
[connmanctl]# connect bluetooth_5fed432cba10_abcdef012345
[connmanctl]# config bluetooth_5fed432cba10_abcdef012345 autoconnect yes
[connmanctl]# exit
$ reboot
全体の構成
ここからのミニ四駆に乗せるまでの流れ
Node.jsのインストール
while(うまく動くまで) {
・ ブレッドボードで回路を試作,修正
・ JavaScriptのコード作成
}
走行テスト
ブレッドボードで試作
基本的には、どの機器も電源と、I2C通信用の2つの回路を繋げるだけ。
JavaScript
せっかくなので、babel & webpack & gulpを使ったナウでヤングな環境で作る
const webpack = require('webpack');
const env = process.env.NODE_ENV;
const webpackConfig = {
entry: {
index: './src/index.js'
},
output: {
filename: '[name].js',
libraryTarget: 'umd'
},
resolve: {
extensions: ['', '.js']
},
plugins: [],
target: 'node',
externals: [
/^(?!^\.\/)/,
/config\.js/
],
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
'presets':['es2015']
}
},
{ // ここ重要。mraaのバイナリを読むために必要
test: /\.node$/,
loader: 'node-loader'
}
]
},
node: {
fs: 'empty'
}
};
if(env == 'production'){
webpackConfig['plugins'].push(
new webpack.optimize.UglifyJsPlugin({
compress: { warnings: false }
})
);
}else{
webpackConfig['devtool'] = '#source-map';
}
module.exports = webpackConfig;
const gulp = require('gulp');
const plumber = require('gulp-plumber');
const watch = require('gulp-watch');
const del = require('del');
const webpack = require('webpack-stream');
const webpackConfig = require('./webpack.config.js');
const distDir = './dist/';
gulp.task('clean-js', ()=>{
return del([
distDir + '**/*'
]);
});
gulp.task('copy-js', ['clean-js'], ()=>{
return gulp.src([
'./src/config.js'
])
.pipe(plumber())
.pipe(gulp.dest(distDir))
});
gulp.task('compile', ['copy-js'], ()=>{
return gulp.src([
'./src/**/*.js'
])
.pipe(plumber())
.pipe(webpack(webpackConfig))
.pipe(gulp.dest(distDir));
});
gulp.task('build', ['compile']);
gulp.task('watch', ['build'], ()=>{
watch([
'./src/**/*.js'
], ()=>{
gulp.start('compile');
});
});
C言語やArduionのコードは落ちているが、JavaScriptのコードなんてどこ探しても全然ない!
→ 各センサーのデータシート(加速度計)や、C言語、Arduinoのサンプルコードを見つつ実装していく。
センサーデータの読み書き
各種センサーはレジスタを持っていて、設定や測定結果が格納されている。
大まかには以下のような手順でセンサーデータを得る
- 設定のレジスタに設定を書き込む
- 測定結果のレジスタから生データを取り出す
- データシートの記述に従い、生データを加工して測定データを算出する
JavaScriptのデータ型
ローレベルなデータを扱うとやはりデータの型が必要になってくる
→ Bufferを使う。
const raw = this._i2c.readBytes(0x3b, 14);
return {
ax: new Buffer([raw[0], raw[1]] ).readInt16BE(0) * this._accelMagni + this._e.ax,
ay: new Buffer([raw[2], raw[3]] ).readInt16BE(0) * this._accelMagni + this._e.ay,
az: new Buffer([raw[4], raw[5]] ).readInt16BE(0) * this._accelMagni + this._e.az,
gx: new Buffer([raw[8], raw[9]] ).readInt16BE(0) * this._gyroMagni + this._e.gx,
gy: new Buffer([raw[10], raw[11]]).readInt16BE(0) * this._gyroMagni + this._e.gy,
gz: new Buffer([raw[12], raw[13]]).readInt16BE(0) * this._gyroMagni + this._e.gz
};
実装
ここまでである程度動作するコード、回路が完成したので、
ブレッドボードの回路を参考にユニバーサル基板に色々はんだ付け
走行テスト (10/21 12:0016:31 〜 18:30)
実際にコースで走らせ、パーツの配置を直したり、回路を修正したり、コードを直したり・・・
何かが悪い?
走行テスト動かしてみる
→ うまく動いたり動かなかったり・・・
いくら見直してもコードも合ってそうだし、センサーはこわれてないと思う?
回路も最低限のもので検証し、合ってるはず・・・
EdisonのIO
EdisonのI2C通信を含む、外部接続は、1.8V基準になっており、
外部機器は3.3vで動作させている
→ 電圧が合ってない
EdisonのI2C通信の設定を変更し、対応。
プルプルプル
I2C通信再び
- I2C通信では、通信経路をプルアップすることが規格で定められている(電圧は決まってない)。
- Edison側、センサー側両方でプルアップがされていた。
→ Edisonの設定は、デフォルトpullupで、pullup、pulldown、nopullの設定が可能。
→ I2Cのポートの設定を pullup -> nopullへ
echo "nopull" > /sys/kernel/debug/gpio_debug/gpio27/current_pullmode # i2c-6 scl
echo "nopull" > /sys/kernel/debug/gpio_debug/gpio28/current_pullmode # i2c-6 sda
まさか?の故障
2代目回路
電池の電圧を測るセンサーと、加速度計が同時に動作させられなかったので、
フォトリフレクタの結果を取得するために コンパレーター を導入。
フォトリフレクタ?
ラップ数やラップタイムを取得するために購入したセンサー
センサーから赤外線が出ており、反射光の強さに応じて、出力される電圧が変化する。
コンパレーター?
2つの電圧を比較して、一方の方が大きかったら、電源電圧。小さかったら0vを出力する素子。
コンパレーター
2代目では、片方に半固定抵抗2の出力を入力し、もう片方にフォトリフレクタの出力を入力。
フォトリフレクタのデータを取得
コンパレーターからはデジタルな出力が得られるので、それをGPIOに入力。
(反射光が一定以上になったら、0になる)
GPIOの結果をmraaで取得し、ラップのカウントを送信。
GPIOの変化から、一周したと判断したら、その時刻を送信。
2代目回路の設計。
1代目はブレッドボードの試作を目で見て、行き当たりばったりで配線をしていた。
2回目走行テスト (10/24 18:30 〜 23:00)
2代目回路も無事完成し、走行テストをしつつ、半固定抵抗の抵抗値や、コード中の各種パラメーターを調整。
ようやく通して動いた!
展示会場でテスト (10/25 15:00 〜 )
バッテリーのコネクタが緩む、などの問題も発生したが、なんとか展示にこぎつけた。
コードの説明
コードはgithubのリポジトリで公開しています。
MQTTとは
MQTTとは、小さなメッセージを非同期でやりとりするための所謂メッセージ・キューの仕組みの一つ。
軽量なプロトコルでさまざまな機器で対応できるのが特徴。
MQTTブローカーの比較
Fluentdを使って任意の分析基盤にデータ連携
機器から取得した生データから、ビジネス的に意味のある値を得る必要がある。
RedShiftやHadoopのようなBigData系の分析基盤に流し込んでもいいし、
機械学習系の基盤に流し込むこともできる。
例えば・・・
荷物を収集する車から積載量や位置情報を収集する。
分析基盤で、積載量がある一定の条件を超えたら、位置情報や荷物の量から時間や料金が最適になるトラックを呼んで、持っていってもらう。
サーバー側をもっと詳しく(バックエンドサービスAppPot)
- JavaScript SDK
- ユーザー認証
- Databaseのテーブル作成とデータアクセス
PushやFile APIなどさまざまな機能がありますが、今回使っているのはこれだけ。
まとめ。
- Web系エンジニアでも、なんとかIoTっぽいことができる(ハード含めて)
- IoTのPoCするときでも、自分たちでなんとか作れる!
- ミニ四駆IoTくらいのものなら、2週間半(実業務をしながら)で、作れる!
3代目
依頼を受け、3代目の回路を設計&製作中。
Eagleというソフトウェアを使用し、回路設計。
P板.com にプリント基板を発注中。
購入品目リスト
スイッチサイエンス
- Intel Edison Breakout Board Kit
- MPU-6050搭載 三軸加速度三軸ジャイロセンサモジュール
- ADS1015搭載 12BitADC 4CH 可変ゲインアンプ付き
- LiPo 燃料ゲージ
- QRE1113 フォトリフレクタ・モジュール
- TMP007 非接触温度センサ
- リチウムイオン電池900mAh
秋月電子通商
- 2回路入コンパレータ NJM2903D (5個入)1パック
- 半固定ボリューム 3362P 10kΩ
- ロープロファイルピンヘッダ 2×14(28P) 9.54mm
- ロープロファイルピンソケット (低メス) 2×14 (28P) 5.0mm
-
Arduino YÚN miniというものならネットもNode.jsもOKだったらしい ↩
-
抵抗値を調節して、電源電圧〜0Vの間の任意の電圧を出力できるもの ↩