漆黒な技術メモ

管理人が必要に応じて自分のメモを好き勝手に投下するたまり場的ブログ

【ちょっと技術的なことAdventCalender】 hackU実装振り返り-1. mbed×websocket-

この記事はちょっと技術的なことAdventCalenderの21日目です。 いよいよ最後も見えてきました。自分の担当分はこれを含めてあと4回です。

今日は、前回お話ししたhack Uで苦労したことにうちの1つをつらつら書いていこうと思います。

mbed × Webscoketは難しい

今回の残業防止IoT座布団では、座布団側のマイコンにmbedというARMマイコンを、サーバ側にnode.jsを利用しました。 この業界だと今流行りのマイコンは圧倒的にArduinoで、普通ならそっちを使うんですが、今回はチームメンバーが研究室でmbedを使っていること、 僕も昔に少し触れたことがあることから、mbedを採用しました。

で、mbedにもいくらかwebsoket関係のライブラリはあり、その中にはSocket.IOのラッパも存在したので、「これで問題なくSocket.IOを使ったwebSocketが使えるだろう」… って考えてた僕が馬鹿でした。 そのSokcet.IOのライブラリはどうもうまく動きませんでした。 パケットとライブラリ実装を確認すると、ライブラリのLast Commit Date が2012年になっており、そのころからSocket.IOの仕様が大きく変わってしまったため通信ができませんでした。 恐らくやるとしたらSocket.IOの仕様とライブラリの実装を読みくだきながらアレンジする必要があると思ったので、断念しました… 他にもWebsocketという名前そのままのライブラリがありました。しかしこれも最終コミットが2011年とまあまあ古い状態でした。ただRFC準拠実装みたいなので、何とかなるかなあと思い、サーバ(node.js)側でsocket.IO以外のライブラリを検討しました。

実装

結果node.js側で用意したのはwsというパッケージです。 インストールは $npm install ws で普通にインストールできます。 mbed側は先ほどお話ししたWebscoketライブラリを利用します。 フルソースは後日gitにアップするんで、一番要になる部分の実装だけ抜き出して…

mbed側

#include "mbed.h"
#include "Websocket.h"
#include "EthernetNetIf.h"

void init(char * hostAndPort){
    eth = new EthernetNetIf();
    EthernetErr ethErr = eth->setup();
    if (ethErr) {
        printf("\r\nERROR %d in setup.\r\n", ethErr);
    }
    printf("hostandport %s\n", hostAndPort);
    
    ws = new Websocket(hostAndPort, eth);
    printf("websock init\n");
}
    
bool connect(){
    printf("connecting...");
    int failcount=0;
    
    while(! ws->connect()) {
        failcount++;
        if(failcount>10){
            printf("cannot connect failed.\n");
            return false;
        }
        printf("cannot connect websocket, retrying...\n");
        wait(2);
    }
     return true;
}

int mess_send(char * msg){
    ws->send(msg);
    printf("data send\n");
    return 1;
} 

int mess_recv(char * msg){
    if (ws->read(msg)) {
        return 1;
    }else{
        return -1;
    }
}

int main() {
    init("ws://www.example.jp");
    printf("connect start\n");
    connect();
    printf("connect");

    char msg[64];
    while(1) {
        Net::poll();
        mess_send("hello");

        int ret = mess_recv(msg);
        if(ret)
            printf("recv: %s\n",msg);
        
        Net::poll();
    }
}

サーバ側

var wss = require('ws').Server;
var mport = 12020;
var ws_Mbed = new wss({ port: 12020 });

ws_Mbed.on('connection', function (ws) {
    wsm_groval = ws;
    countor = 0;
    console.log("connect from mbed");

    ws.on('message', function (message) {
        console.log('received:'+ message);
        var type;
    });
});

こんな感じで実装すればmbedでもwebsocketで通信できます!!

欠点

ただ、このmbedライブラリは大きな欠点を抱えています。イーサネットのライブラリに古いライブラリであるErthernetIFライブラリを利用しています。 現在はErthenetInterfaceというライブラリを利用するのが普通です。 古いErtherNetIFライブラリには大きな欠点があります。それはmbedのRTOS(非同期処理)ライブラリとすこぶる相性が悪いということです。 我々は新しいイーサネットライブラリへの付け替えにチームメンバが挑んでくれましたが、残念ながらうまくいきませんでした。
というわけで、たまたまmbedが2台あった我々は、mbed2台で通信側、センサ側と分け、2台のmbedをジャンパ線で直結してなんとか乗り切ろうという発想に至りました。
次回はそこでの苦労をお話ししたいと思います。

追記

mbed側のライブラリにWebSocketClientというライブラリがありました。こちらはErthenetInterfaceをライブラリに使っていたので、こちらを使えば次回に書くような苦労はしなくてもよかったのかもしれません。。。

【ちょっと技術的なことAdventCalender】Hack U(ハッカソンイベント)に参加してきました

この記事はちょっと技術的なことAdventCalenderの19日目です。
今日は日曜日に参加したHack U 2016 大阪会場 Student Hackathon - Yahoo! JAPANについてお話ししようと思います。 hacku.yahoo.co.jp

Hack Uとは

Hack U(ハック・ユー)は、限られた期間の中で、学生がプロダクトを自ら企画・開発・発表するイベントです。ものづくりの楽しさを体現できるよい機会となるよう、ヤフーの現役社員が学生のみなさんを全力でサポートいたします。

(公式サイトより)
まあすなわち、学生限定の相当大規模なハッカソンイベントと言ったところです。
今回のテーマは「自動○○」となっています。とはいうものの、何かプログラムを作ると大抵は何かを自動化しているので、結構何でもありの色彩が強い大会ではあります。
勿論優秀賞など、賞もありますが、残念ながら今回自分たちはじゅしょいうすることができませんでした。

自分たちの作ったもの

今回自分たちは、ネタに走りに行く気満々で「ブラックな人たちを助けよう」というお題目(当然このお題目の決め方もノリ)で、「残業防止座布団:‡漆黒からの解放‡」という作品をつくりました。
座布団の中に圧力センサ、加速度センサを埋め込み、長時間座っていることや貧乏ゆすりを検出して離席を促す作品です。 f:id:igbt3116redtrain:20161220052620j:plain この座布団の中にセンサとスピーカを仕込ませてあります。一見するとただの座布団(というかクッション)ですが
f:id:igbt3116redtrain:20161220052844j:plain 座面下にマイコン(mbed)、背もたれにバッテリーと通信モジュールを付加してあります(椅子は会場のモノです)
これらを利用して、

  • 離席を促すべき時に音楽を鳴らす機能
  • イライラ度可視化
  • 着席などのイベント発生に合わせたツイッターへの投稿機能
  • 可視化画面からの座布団の動作制御

を行っています。
f:id:igbt3116redtrain:20161220053343p:plain
この作品の主目的からは外れるためあまり注目はされませんでしたが、「webブラウザからの座布団動作」ができるようになっています。
自分はここに一番こだわりを持っていました。両方向のIoTを何とか形にしてみたかったからです。

利用した技術と自分の担当範囲

アーキテクチャ図にするとだいたいこんな感じです。 f:id:igbt3116redtrain:20161220055101p:plainバイス、マイコン、データベース、比較的新し目の通信規格&サーバ実行環境、可視化、他システムとの連携などIoTエコシステムと言われそうな部分を一通り実装しました。
(本当はAndroid連携をやりたかったのだけど実装に使える時間の確保ができませんでした…)
自分はデバイスを少しと、マイコンの通信部分、サーバサイド処理を担当しました。

次以降の記事の話

今回HackUの作品について書くのはここまでにしておいて、次回以降はこの実装で苦労した部分のことを自分のメモを兼ねて何回かに分け書いていきたいと思います。
またアドベントカレンダー期間が終わるころまでに今回のソースをgithub上に公開したいと思っています。
それでは!

【ちょっと技術的なことAdventCalender】改行区切りのログ出力をExcelとかで使えるようにCSVに変形するPythonスクリプト

この記事はちょっと技術的なことAdventCalenderの15日目です。
気づいたらもう折り返しを過ぎていますね…

プログラムを実行したときのログ出力

って、大体こんな感じで出力するようにプログラム組んでいる方が大半だと思います。

time : 10:00
power : on
value : 1

time : 10:10
power : off
value : 0

time : 10:20
power : on
value : 2

...

まあ実装上この形式で書くのが一番楽ですし、ログとして書く分には何も問題ないのですが… ある時、このログをExcelなどで集計しなくてはならない…!!なんてことになったら、この形式でやるのは超面倒ですね…

time,power,value
10:00,on,1
10:10,off,0
10:20,on,2

とかにできるのが一番理想です。
と、そんなことを実際にしなくてはならない場面に遭遇してしまったので、スクリプトを書きました

実際に作ったpythonスクリプト

引数でファイル名を指定します。空白行をCSVの行の分け目と認識するようにしています。
また、カラムはブロックごとに異なっても(途中から"Battery"カラムが増えたり、消えたり) 大丈夫なようになっています

#coding: utf-8
import sys

if len(sys.argv) < 2:
    print "usage filename"
    sys.exit(1)
filename = sys.argv[1]

f=open(filename)
lines=f.readlines()
valueText=""
columnTitles=[]
textBuf={}
for line in lines:
    if '\n' in line[0]:
        for col in columnTitles:
            if col in textBuf:
                valueText += textBuf[col]+","
            valueText+=","
        valueText += "\n"
        textBuf.clear()
    else:
        sptline=line.replace("\n","").split(":",1)
        if sptline[0] not in columnTitles:
            columnTitles.append(sptline[0])
        textBuf[sptline[0]] = sptline[1]

for col in columnTitles:
    print col+"," ,
print ""
print valueText ,

これを使って

$ python parser.py log.log > log.csv

とかやれば、変形できます。

実行結果

こんな感じです

$ cat status.log
time:2016/12/11 23:32:32
SSID:gp30
Mode:MultiShot
SubMode:TimeLapse
Recoding:True
Num. of taken:268
Num. of remaining:11794
SDcard:True
Battery:3

time:2016/12/11 23:40:25
SSID:gp29
Mode:MultiShot
SubMode:TimeLapse
Recoding:True
Recode:test
Num. of taken:278
Num. of remaining:11794
SDcard:True
Battery:3

$ python genlogparser.py status.log
time, SSID, Mode, SubMode, Recoding, Num. of taken, Num. of remaining, SDcard, Battery, Recode,
2016/12/11 23:32:32,gp30,MultiShot,TimeLapse,True,268,11794,True,3,
2016/12/11 23:40:25,gp29,MultiShot,TimeLapse,True,278,11794,True,3,test,

今日はここまで、それでは!!

【ちょっと技術的なことAdventCalender】自分がよく忘れがちなシェルスクリプトの文法&定型句まとめ

この記事はちょっと技術的なことAdventCalenderの13日目です。

このブログでもシェル関係のお話を取り上げることがそこそこ多いことからもわかるに、管理人はサーバ管理に研究にと、比較的多くの機械でシェルスクリプトを書いています。
が、シェルスクリプト歴は正直1年にも満たず、まだまだいろいろ覚えきれていないことが多い駆け出しシェルエンジニアです。
そこで今回は、「自分がよく使うにも関わらずよく忘れがちなシェルスクリプトの文法&定型句」をまとめてここに書いておきたいと思います。

現在時刻を任意のフォーマットで取得

どちらかというとdateコマンドの使い方ですね…

#!/bin/sh
echo `date '+%Y/%m/%d %H:%M:%S'` #2016/12/13 12:00:54

任意のコマンドの引数に変数を入れて実行、結果を変数へ

#!/bin/sh
var="value"
ret=`command ${var}

ファイルの絶対パスを分割し、ファイル名、ディレクトリ名、最下部のディレクトリ名だけ抽出する

fullPath="/home/user/document/file.txt"

fileName=`basename ${fullPath}` # => file.txt
dirName=`dirname ${fullPath}` # => /home/user/document
lastDirName=`${dirName%/*}` # ==> document

10回ループ

#!/bin/sh
for i in `seq 1 10`
do
    echo "$i times"
done

コマンドライン引数からファイル名を参照し、1行ずつ処理

#!/bin/sh
filename=$1
cat $filename | while read line
do
    ehco $line
done

今日はここまで

【ちょっと技術的なことAdventCalender】サーバのHDDをSSDに変えるのに苦労した話

この記事はちょっと技術的なことAdventCalenderの11日目です。

つい先日、研究室内のとあるサーバのHDDをSSDにして高速化しよう!というお話が上がり、サバ管を兼ねている自分が、その交換を行うことになりました。
研究室にはディスクの中身をハードウェア的にコピーするための機械があったので、適当にHDDとSSDをガチョンガチョン挿して動かせば終るだろうと思っていたのですが…大間違いでした。
ちなみに対象のサーバはRAIDが組んであるため、コピーするディスクは2枚になります。 そして購入の都合上、TrancendとSAMSUNGSSDを1枚ずつ購入したのですが、何故か同じ方法でできない…
ということで、自分の格闘記録を今後のために残しておきます。

共通

始めにGpartedをインストール

$ sudo apt-get install gparted

Trancend SSD

UbuntuSSDを接続し、Gpartedで1つパーティションを作成
File systemはcleardにする

その後、コピー用スタンドにHDDとSSDを接続し、コピーボタンを押す。

SAMSUNG SSD

UbuntuSSDとHDDを接続する。
SSDに何かパーティションができている場合は、Gpartedでパーティションを削除 その後、ddコマンドを用いて全てコピー

# /dev/sdbがコピー元、/dev/sdcがコピー先とする
$ sudo dd if=/dev/sdb of=/dev/sdc bs=512

進捗状況を見る場合、別のターミナルより以下を打ち込む

# nは進捗を表示する間隔(秒)
sudo watch -n 60 "pkill -USR1 dd"

ここまでこれば、SSDを接続し起動して、fdiscやcat /proc/mdstatなどでRAIDの状態を確認すれば完了です。
今日はここまで

【ちょっと技術的なことAdventCalender】ラズパイで接続先のwi-fiを切り替えるスクリプトを作った

この記事はちょっと技術的なことAdventCalenderの9日目です。
また多少遅刻してますがご愛嬌という事で

今日は、半年前ぐらいに研究で必要になったちょっとしたスクリプトをここに紹介しようと思います。
毎日テーマとなる題材がブレブレだけど、それがこのブログの趣旨なので…

他の方がそういうシチュエーションに遭遇するかわからないけど、自分が「接続するwi-fi親機を定期的に切り替える」という処理をラズパイに実装しなければならなかったので、
同じような人がいらっしゃれば手助けになれば、と思います。
結構突貫工事で作ったので、動作保証(特にラズパイ以外のLinux)はできないですが、参考程度にお使いください。

#/!bin/sh
#/!sbin/

ssid=$1
pass=$2

rm wpabuf.conf
for line in `wpa_passphrase ${ssid} ${pass}` 
do
    echo "$line" >> wpabuf.conf
done

sed -i -e "1i ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev" wpabuf.conf
sed -i -e "2i update_config=1" wpabuf.conf
sed -i -e "7i key_mgmt=WPA-PSK" wpabuf.conf
sed -i -e "8i proto=WPA2" wpabuf.conf
sed -i -e "9i pairwise=CCMP" wpabuf.conf
sed -i -e "10i group=CCMP" wpabuf.conf
sed -i -e "11i priority=2" wpabuf.conf

mv wpabuf.conf /etc/wpa_supplicant/wpa_supplicant.conf
/etc/init.d/networking reload
iwconfig wlan0

それでは

【ちょっと技術的なことAdventCalender】 Chainer Playgroundを少しだけ触ってみた

この記事はちょっと技術的なことAdventCalenderの7日目です。
7日目といいつつ書くのが遅くなってしまい日付を跨いじゃってますが、そこは大目に見てください…

さて、最近IT業界ではディープラーニングだのAIだの、機械学習系の話題がものすごく流行っていると思います。
筆者の所属する大学の研究室でも、機械学習を積極的にやっており、その分野で論文を書いている人もいます。(自分は機械学習とは異なる分野で研究しているのですが…)
で、そんな流行りものである機械学習ではそれを行うためのフレームワークなども出てきております。
そのような流れの中で、ひとつ気になるニュースがあったので今日はそれをピックアップしようと思います。
深層学習をウェブブラウザ上で学習できる「Chainer Playground」の無償公開について

そもそもChainerとは

先ほどお話しした、機械学習フレームワークの一つです。このフレームワークは日本の会社であるPreferred Networks(通称 PFN)が作成したフレームワークです。
Chainerの特徴はこんな感じらしいです。

In contrast, Chainer adopts a “Define-by-Run” scheme, i.e., the network is defined on-the-fly via the actual forward computation. More precisely, Chainer stores the history of computation instead of programming logic. This strategy enables to fully leverage the power of programming logic in Python. For example, Chainer does not need any magic to introduce conditionals and loops into the network definitions. The Define-by-Run scheme is the core concept of Chainer. We will show in this tutorial how to define networks dynamically.

http://docs.chainer.org/en/stable/tutorial/basic.htmlより引用

まあ英語で専門的なこと言われても何言っているかわかりませんね(読める人は読んでください)。
PFNの中の人のブログやSlideShareを見ると、要するにほかのフレームワークは"Define-and-Run"形式で、「ディープラーニングで使うネットワーク構造の構築」と「実際に構築した構造にデータを流して処理する」部分が別々の実装として書かなければならないのに対し、Chainerは"Define-by-Run"形式で構築と処理を一度に書けてしまうため、比較的簡単にニューラルネットワークの構造をかける点が特徴だそうです。(間違っていたらすいません)
ちなみに他に有名なライブラリとしてはGoogleのTensorFlowやカリフォルニア大学バークレー校の研究チームが開発したCaffeなどがあるようです。

Chainer Playgroundとは

Chainer Playgroundでは深層学習とChainerの基礎を実際のプログラミングを通しながら学べます。Chainer Playgroundを利用するにあたって必要なのはウェブブラウザのみで、PythonやChainerのインストールも必要ありません。ブラウザでChainer Playgroundに接続するだけですぐに学習を始められます。

深層学習をウェブブラウザ上で学習できる「Chainer Playground」の無償公開についてより引用

次は日本語でよかったです。まあ上に書いてある説明でだいたいは終わっていて、Chainerを使った機械学習の基礎をwebブラウザ上で簡単に学べるサイトになっています。Ubuntuを用意して環境構築してやっと…とかしいなくても機械学習を体感的に学ぶことができるみたいです。
ただしまだベータ版なので内容は完全版ではないみたいです。

少しだけ触ってみた

画面はこんな感じみたいです。 f:id:igbt3116redtrain:20161208030919p:plain
左側に説明、右側にエディタと実行結果が表示され、テキストを読みながら実行することができます。

早速管理人もやってみました。
最初は機械学習でいう「学習対象のモデル」とは何ぞやというところから入るわけですが…まあ数学チックな話がガンガン出てきます…結構本気で読む必要があり、理解するのにもなかなかの時間がかかります。そりゃあこんだけ難しいことをこなすデータサイエンティストは引く手あまたなわけだ…
ちなみに僕のような数学よくわかってない、プログラムガッツリやっていましたという人はおそらく「次元」って言葉で一気に混乱すると思います(実際しました)。100次元とかそういう字句がたくさん出てきますが、これは100次元「配列」のことではなく、100次元「ベクトル」のことですね。数学的なベクトルです。(x,y,z)みたいなアレです。そこを間違えるとコードを見ても???ってなるので気をつけてください。
そのあとは目的関数を定義して最適化することで、機械学習の基礎を学ぶみたいですが、この先は管理人も勉強中です…

機械学習にちょっと興味があるよって方、ぜひ試してみてはいかがでしょうか…!!