FTDI FT2232C用のudevルール
FTDIのFT2232C (Dual RS-232)というUSBシリアルを接続した際に、他のデバイスと識別できるよう、/dev/
以下にシンボリックリンクを作成するudevのルールです。
通常のUSBデバイスならば、Vendor IdとProduct Idを指定すれば良いのですが、FT2232Cは2つのシリアルポートが存在するため、少し工夫が必要です。
環境
- Ubuntu 14.04
USBデバイスとして認識していることを確認
lsusb
コマンドを実行して、 ベンダーIDとプロダクトIDが0403
, 6010
なるデバイスが存在することを確認します。
$ lsusb | grep "0403:6010" Bus XXX Device XXX: ID 0403:6010 Future Technology Devices International, Ltd FT2232C Dual USB-UART/FIFO IC
udevルールの作成
99-ft2232c.rules
というファイルを以下の内容で作成します。
# udev rule for FT2232C (Dual USB-UART/FIFO IC) ACTION=="add", SUBSYSTEMS=="usb", ATTRS{interface}=="Dual RS232", SYMLINK+="ft2232c-%s{bInterfaceNumber}"
作成したファイルを /etc/udev/rules.d/
以下にコピーします。
$ sudo cp 99-ft2232c.rules /etc/udev/rules.d/
シンボリックリンクが貼られたことを確認
USBケーブルを抜き差しすると、 /dev/ft2232c-00
, /dev/ft2232c-01
として、2つのシリアルポートが認識されていることが確認できます。
$ ls -al /dev/ | grep USB lrwxrwxrwx 1 root root 7 7月 25 18:48 ft2232c-00 -> ttyUSB0 lrwxrwxrwx 1 root root 7 7月 25 18:48 ft2232c-01 -> ttyUSB1 crw-rw-rw- 1 root dialout 188, 0 7月 25 14:07 ttyUSB0 crw-rw---- 1 root dialout 188, 1 7月 25 18:53 ttyUSB1
参考URL
ROS Pythonでオイラー角とクォータニオンの相互変換
ROSでオイラー角とクォータニオンを変換するには、tfパッケージの関数を利用すれば良いのですが、 単体の関数として使うには少々使いづらいので、簡単なラッパー関数を作りました。
オイラー角からクォータニオンへの変換
import tf from geometry_msgs.msg import Quaternion def euler_to_quaternion(euler): """Convert Euler Angles to Quaternion euler: geometry_msgs/Vector3 quaternion: geometry_msgs/Quaternion """ q = tf.transformations.quaternion_from_euler(euler.x, euler.y, euler.z) return Quaternion(x=q[0], y=q[1], z=q[2], w=q[3])
実行例
>>> import math >>> euler_to_quaternion(Vector3(0.0, 0.0, 0.0)) x: 0.0 y: 0.0 z: 0.0 w: 1.0 >>> euler_to_quarternion(Vector3(0.0, 0.0, math.pi / 2.0)) x: 0.0 y: 0.0 z: 0.707106781187 w: 0.707106781187
クォータニオンからオイラー角への変換
import tf from geometry_msgs.msg import Vector3 def quaternion_to_euler(quaternion): """Convert Quaternion to Euler Angles quarternion: geometry_msgs/Quaternion euler: geometry_msgs/Vector3 """ e = tf.transformations.euler_from_quaternion((quaternion.x, quaternion.y, quaternion.z, quaternion.w)) return Vector3(x=e[0], y=e[1], z=e[2])
実行例
>>> quaternion_to_euler(Quaternion(0.0, 0.0, 0.0, 1.0)) x: 0.0 y: -0.0 z: 0.0 >>> quaternion_to_euler(Quaternion(0.0, 0.0, 0.7071, 0.7071)) x: 0.0 y: -0.0 z: 1.57079632679
参考URL
ROS Pythonにおけるuint8[]の扱い方
ROSでuint8[]
型を利用しているトピックをPythonで使う場合にハマった点です。
環境
- Ubuntu 14.04
- ROS Indigo
rospyにおけるuint8[]
型の扱い
ROSのメッセージ型に関するリファレンスを参照すると、uint8[]
型について以下のような記述があります。
uint8 has special meaning in Python. uint8[] is treated as a Python bytes so that it is compatible with other byte-oriented APIs in Python.
rospy treats
uint8[]
data as a bytes, which is the Python representation for byte data. In Python 2, this is the same as str.
Pythonでは、ROSのuint8[]
型がbytes型(Python 2系ではstr型)として扱われるらしく、これは時に厄介な問題を引き起こします。
発生した問題
とあるセンサー群の測定値を測定するメッセージ型を以下のように定義しました。
foo_package/msg/FooSensor.msg
uint8[] value
そして、以下のようなシンプルなPublisherとSubscriberを作成しました。
publisher.py
import rospy from foo_package.msg import FooSensor def publish(): publisher = rospy.Publisher('/foo', FooSensor, queue_size=1) value = FooSensor(value=[100, 110, 120]) r = rospy.Rate(1.0) while not rospy.is_shutdown(): publisher.publish(value) r.sleep() publish()
subscriber.py
import rospy from foo_package.msg import FooSensor def callback(data): rospy.loginfo(data) rospy.loginfo(data.value) def subscribe(): rospy.Subscribe('/foo', FooSensor, callback) rospy.spin() subscribe()
publisher.py
, subscriber.py
を実行すると、以下のような2つのINFOレベルのログが出力されます。
- [INFO] [WallTime: 1461145922.975544] value: [100, 110, 120]
- [INFO] [WallTime: 1461145941.678116] dnx
data
自体を出力すると、valueにint型の数値が入っているのが確認できるのですが、data.value
を出力するとdnx
という文字列が出力されてしまい、配列の要素をint型として利用することが出来ません。
対処方法
対処方法はあまり根本的なものではないのですが、valueの各要素のASCIIコードが本来のintの値なので、ord
関数で変換してあげることでint型の配列を得ることが出来ます。
def callback(data): int_array = [ord(n) for n in data.value] rospy.logwarn(int_array)
再度実行すると[100, 110, 120]
という配列が出力されます。
ただし、この処理は直感的でなく、uint8[]
型以外に対してはエラーを返すため、あまりオススメできません。出来れば、メッセージ型の定義部分でuint16[]
等を利用することで回避するのが好ましいと思われます。
参考URL
BitBucketとWerckerでウェブサイトを自動デプロイ
タイトルの通り。BitBucketとWerckerとFTP(lftp)で静的なウェブサイトを自動デプロイする方法です。
ちなみにBitBucketとWerckerを使っているのは、プライベートリポジトリを無料で使えるから。
BitBucketの設定
- Gitのリポジトリを作って、ウェブサイトのファイルをコミットしておきます
Werckerの設定
Applicationの作成
- 画面上部のCreateからApplicationを追加します。
- Choose a repositoryでは、先ほど作成したBitBucketのリポジトリを選択します。
- Ownerの設定は自分のアカウントか、共有で管理するならばOrganizationを選択します。
- Configure accessは、recommendedの設定をそのまま利用すれば大丈夫です。
デプロイ設定
アプリケーションを作成したら、SettingsのTargetsから、デプロイターゲットの設定をします。
- Deploy target nameには適当な名前を設定します。
- Auto deployにチェックを入れておくと、ビルド成功時に自動でデプロイが行われます
- また、デプロイ対象となるブランチ名(通常はmaster)を入力します。
環境変数の設定
SettingsのEnvironmental Variablesに以下のKey, Valueのペアを登録しておきます。
FTP_SERVER_URL
: サーバのURL(ftp.example.comなど)FTP_USERNAME
: FTPのユーザ名(Protectedを推奨)FTP_PASSWORD
: FTPのパスワード(Protectedを推奨)
環境変数をProtectedにしておくと管理画面等で変数の内容が表示されないので、パスワード等の情報は必ずProtectedにしておくことを推奨します。
wercker.ymlの追加
リポジトリのルートにwercker.yml
として、以下のファイルを追加します。
# This references a standard debian container from the # Docker Hub https://registry.hub.docker.com/_/debian/ # Read more about containers on our dev center # http://devcenter.wercker.com/docs/containers/index.html box: debian # This is the build pipeline. Pipelines are the core of wercker # Read more about pipelines on our dev center # http://devcenter.wercker.com/docs/pipelines/index.html build: # Steps make up the actions in your pipeline # Read more about steps on our dev center: # http://devcenter.wercker.com/docs/steps/index.html steps: - script: name: echo code: | echo "Build finished!" deploy: steps: - install-packages: packages: lftp - script: name: upload files via FTP code: | lftp -u ${FTP_USERNAME},${FTP_PASSWORD} -e "set ssl:verify-certificate no;mirror -Rev -X wercker.yml アップロード元(リポジトリ)のディレクトリ/. アップロード先(サーバ)のディレクトリ/." ${FTP_SERVER_URL}
上記の設定ファイルによって、リモートリポジトリへのpush時にWerckerで以下の内容が実行されます。
- ビルドとデプロイを行うための、debianのboxを作成
- ビルド時に
echo "Build finished!"
を実行 - デプロイ時にlftpをインストール
- lftpコマンドでリポジトリ内のファイルをサーバへミラーリングアップロード(ただしwercker.ymlはアップロードしない)
デプロイの実行
上記の設定が済んだら変更内容をcommitし、リモートリポジトリのmasterブランチへpushを行います。
ビルドやデプロイに失敗するとWerckerからメール通知が来るので、エラーメッセージを読んで適宜修正を行います。
slackへの通知
wercker.yml
に以下の行を追加すると、デプロイ(もしくはビルド)時にslackへ通知を飛ばすことができます。
after-steps: - slack-notifier: url: $SLACK_WEBHOOK_URL username: Wercker
slack側で事前にIncoming WebhookのURLを取得し、Werckerの環境変数にSLACK_WEBHOOK_URL
として当該URLを登録しておくことでslackに通知が飛びます。
参考URL
ニューラルネットで声から体調を推定するシステムを作りました
IDCフロンティア主催のIoTと健康をテーマにしたハッカソン、サバフェス 2016で Healthy Voice Netというシステムを作ったので紹介します。大雑把に言うと、ニューラルネットワークを用いて声色を分類することで、声から体調が分かるシステムです。
プレゼンテーション
デモ動画
ソースコード
概要
Healthy Voice Netは、体調による声色の違いをニューラルネットワークを使って学習させることで、声から体調を推定できるシステムです。
見た目はこんな感じ。
ニューラルネットの学習
データの用意
体調の良い時、寝不足の時、風邪気味の時の声をたくさん録音しておきます。今回は「おはよう」という決め打ちの文言を、それぞれ約30回ずつ録音したファイル(wav, mono, 16bit, 44.1kHz)を用意しました。データ数は多ければ多いほど良いと思いますし、ノイズへの耐性を強くするために、様々な環境で録音するほうが好ましいです。
音声の前処理
前処理として、録音した音声ファイルをFFTにかけ、さらに音量を正規化します。これは、体調の良し悪しが音声のスペクトルに現れるという仮定のもと、波形の違いをニューラルネットに学習させるためです。音声の録音にはPyAudioを、FFT変換にはscipyをそれぞれ利用しています。
ニューラルネットの構成
ニューラルネットは、4層の全結合のものを利用しています。
- 入力層: 20000次元 (1Hz〜20kHzの各周波数の音量に対応)
- 中間層1: 100次元
- 中間層2: 20次元
- 出力層: 3次元 (良好、寝不足、風邪気味の各体調に対応)
ニューラルネットの生成、学習にはChainerを利用しました。
学習の実行
約100個の音声ファイルに対して60世代ほど学習をさせました。学習にかかる時間はCPUを利用しても10分程度です。学習データが少ないためか、かなり過学習になる傾向があり、50〜60世代くらいまでは精度が上がっていくのですが、逆にそこから先はテストデータに対する精度が落ちてしまいました。本来ならば現在の100倍〜1000倍くらいの学習データが必要だと思います。
体調の推定
システムの構築
システムの構築には以下のデバイスを利用しました。
- Raspberry Pi2 Model B
- サンワサプライ USBマイクロホン MM-MCU01BK
- タクトスイッチ 1個
- LED 3個
- 1kΩ抵抗 3個
- LCD 1個
- ブレッドボード・ジャンパワイヤ
LEDとスイッチは以下のように配線しています。
LCDの表示方法については以下の記事を参照してください。
上記のようにデバイスを構成して、Raspberry Piでpythonのスクリプトを動かすと、デモ動画のように動作します。
推定精度
ノイズの少ない環境においては、僕の3つの声色はかなり高い精度で推定できました。特に寝不足風の声に関しては、かなり声色に癖があったためか、ほぼ100%の確率で正しく推定できています。一方で、ノイズに対する対策を一切行っていないので、周辺の雑音が多い環境では普通の声が風邪気味と推定される確率が高かったです。
クラウドとの連携
ブラウザでの結果確認
今回のハッカソンがIDCフロンティア主催のサーバーフェスタということで、IDCFクラウドを利用してデータの表示や他のシステムとの連携を行っています。
推定された体調や録音された音声は、以下のページからブラウザ上で確認可能です。
- Healthy Voice Net (2016年4月末くらいまではアクセス可能)
上記のページでは単に結果を見られるだけでなく、ページ内のフォームで正しい体調を指定することで、ニューラルネットの学習用データが追加され、推定精度を高めることができます。ページの表示にはdjangoを利用しています。
myThingsとの連携
myThingsのIDCFクラウドチャンネルを利用することで、体調が推定された際に、myThingsからGmailやSlackなどのサービスへ通知を飛ばすことが出来ます。面倒なのかと思いきや、環境構築用のスクリプトが用意されていたので、ものの1時間程度でスマホにプッシュ通知を飛ばすことができました。しかも、クーポンを利用すると半年くらい無料でサーバが利用できるので超オススメです。
さいごに
本システムを持って乗り込んだサバフェスですが、なんとIDCF賞をいただくことができました。叙々苑で美味しい焼き肉食べてきます!
参加賞としてRaspberry Piやセンサー、microSDカード等を提供してくださった主催者、スポンサーの皆様、色々とお話をさせていただいた参加者の皆様、どうもありがとうございました!
サバフェスは本当に素敵なイベントです!次回以降も是非参加したいと思います!