Myo日記

長嶋 洋一

(一部 leap motion日記かも)

(一部 Propeller/mbed日記かも)

(一部 「知覚コロキウム」報告)


2015年2月15日(日)

5ヶ月前、CQ出版の編集者からのメイルで始まった去年の9月26日からの mbed日記(1) 、10月27日からの mbed日記(2) を経て、11月17日からの mbed日記(3) が12月23日に終了し、このCQ出版「インターフェース」誌2015年4月号「生体情報の信号処理」特集記事が刊行されるまであと10日である。ここから話はスタートするが、タイトルの「Myo」に辿り着くのは、かなり後になりそうである。

執筆依頼打診から3ヶ月、去年の12月23日に提出した原稿はその後、上のような変遷(補足・修正・校正)を経て最終的な記事となったが、実はこの日記を書いている時点で、どんな紙面であるか不明である(^_^;)。 最近は原稿執筆も電子化されていて、過去のような「著者最終校正」など、無いのである。 25年以上も昔、かつて「インターフェース」に連載や特集を書いていた頃には、宅急便で「紙」が行き来したり、急ぎの場合にはFAXであったが、今では編集者からの質問にメイルで回答しつつ補足記事を添付メイルで送ったり(上図の「補足」というディレクトリ)、下校がCQからPDFで送られてくるとプリントに赤を入れてスキャナで取り込んでZIPにまとめてサーバに上げてURLをメイルしたり(上図の「校正」というディレクトリ)、と全てが電子的にサクサクと進むのであった。

僕は自分の予定を常に 世界に公開  していて、学生などはこれを見て空いたところにアポを入れてくるが、この予定表は「今後の予定」を日々刻々と加筆しつつ、過去になった瞬間にどんどん消して上書きしていくので、ここから「自分の過去」を振り返ることはまったく出来ない(^_^;)。 そこで mbed日記(3) が終ってから今日までの約2ヶ月を思い出すというのは至難の業であるが、 この記録研究室ページ から、飛び飛びながら思い出すことが出来る。

CQ関係では、紙面に入り切らない情報をまとめて、ついでにこれまでの筋電関係の情報を全て整理してまとめたページとして このページ を作って公開した。 その後、CQの編集者の側で原稿作成(僕の原稿を切り貼りして再配置)している期間には、補足として Maxの解説 をまとめたり(結局、紙面に入らなかったのでWebに上げた(^_^;))、依頼に応じて補足記事を追加した。 その間、M2のリュジュンヒー君の修了制作作品「POMPOM」 が完成したり、準ゼミの藤石さんと MOSS で遊んだり、ゼミの土佐谷さんの 卒制を支援 したりして、学期末のメディア造形学科 卒業制作 最終合評(4回生) と 総合演習I 最終合評(3回生) があった。

その合間にCQから「開発した筋電センサを使っている<絵>が欲しい」と依頼されて、藤石さんに協力してもらって ビデオ記録 したり、研究費の旅費枠を使い切って断念していたのを一転、このCQの原稿料を充当・自費出張することにして参加申し込みした3月上旬の情報処理学会・音楽情報科学研究会/エンタテインメントコンピューティング研究会の発表論文 を執筆して学会に送ったり、 メディアデザインウイーク があったり、「サウンドデザイン演習」の 最終合評 があったりした。 (他にもこの間に、センター試験監督2日間、某論文52pages62MB[pdf]執筆とプレゼン、某国際会議論文応募2件、某インスタレーション作品展示発表、大学院入試面接官などもあり)

そんな中、筋電ネタでもう25年以上の付き合いである、コラボレータの照岡さんと記事に関してメイルをやりとりしていると、2月3日に「その後の筋電グッズですが、ご存知かもですが、8ch筋電によるコントローラ「MYO」が出ました」というメイルが届いた。 mbed日記(1) の後半では、最近の筋電システムの事例として「BITalino」と「e-Health」の2つを紹介していた。 これはCQの原稿としてもかなり書いたが、全て紙面では却下されてしまった(^_^;)。 そしてもう一つ、去年から話題となっていたのが、この「Gesture Control Armband」、 Myo なのである。 もちろんこれは知っていたが、199ドルの予約購入受け付けがいつまでたっても始まらないので、放置していたのである。 これが遂に完成したらしく、予約していた照岡さんはさっそくバラして解析したというのである。

早速輸入して(photo1)、1chの蓋を剥いてみました。内部はphoto2の通りで、チップが小さくて
全回路までは追えてないのですが、4個入りのオペアンプを使ってることから、添付の回路図(kairozu)
のような回路で、ほぼ間違いないと思います。
#AD627の方が高性能です(^^)/
その後、8chの筋電アナログ信号を1ブロックに導き、流行りのBTLEでPCに転送していますが、
ADのサンプリングレートなど詳細は不明です。
#でも、8chで$199ならば確かに安いですね。

・・・さすがである(^_^)。 まだ研究費(旅費枠以外)に余裕があったので、とりあえず駄目モトで、SUACの出入り業者(商社)に、このMyoを2台、発注するメイルを出したが、まぁ今期のうちに入ることは期待していなかった。 ところがなんと即答で業者からメイルがあり、他の企業から依頼されて予約していたMyoが1個だけなら手元にあり、もう1個については3ヶ月か半年かかるが・・・という事だった。 ただし事前購入のプレミアで、価格は199ドルのMyoが46000円だという(^_^;)。 そこで迷わず「では1個だけ、今あるものを購入します」と返信すると、翌日、2月4日にはMyoが 研究室に届いてしまった

さっそく遊んでみたいが、2月に入っていよいよ、 このように  CQの記事の第1校が続々と届いて、 校正作業 に追われたり、さらに依頼されて、今度はたった一人で 追加ビデオ記録 を撮ったりしたが、その合間に、とりあえず Myoのサイト から Developerのページ に行き、ここの Downloadページ から最新のMyoファームウェアを落としてインストールして動作を確認すると、さらに Unofficial Tools というソソラレル場所を発見していくつかのデモ/ツールを落として、またまた藤石さんを誘って Myoとleap motionのテスト などをやってしまった。 leap motionは購入してから9ヶ月ほど放置していたが、昨年末に新しいMacBookAir(Yosemite)を買ったので、ようやく動かすことが出来た。 既に赤松さんのMaxオブジェクトが公開されていて、これはもうびしばし使える事を確認した。 その後さらに 怒濤の校正作業 が続き、合間には 9作品の記録を追加 したり、 1回生の映像作品パーティ があったり、と追われて、Myoが1106の机上にあるのになかなか手を出せない日々が続いたのである。

2015年2月16日(月)

そして新しい週となった2月16日である。上に「2月15日」とあるのは実際には今朝から全て書いて、ここからいよいよMyo日記なのであるが、午前には 卒展オープニング があったので、実質的には午後だけの時間である。 明日の火曜日は午前から会議の4連発(;_;)に時間を取られてほとんど何も出来ず、水曜日から土曜日までは「初めての宮古島」を含む、毎年恒例の沖縄行き(^_^)であり、続きは来週になってしまう。 それまで忘れないように整理しておこう、というのが、ここで慌てて「Myo日記」をまとめた理由なのである。

Myoの Unofficial Tools のページの上のリストから、「使えそう」なものを探す、というのが最初の作業となった。 ここで「使える」というのはもちろん、「Maxで使える」ことを意味する。 去年の Max日記は、 Part2Part3Part4 まで、半年ちょっとで終っていた。 すっかり忘れていたが、いちばん最後にはjitterでネットワーク経由の動画伝送までやっていたようである(^_^;)。 leap motionもようやくMac OSX 10.10ということで使えたが、こちらはもう赤松さんのMaxオブジェクトでの動作を確認したので完了である。(^_^)

ただし、せっかく新しいMacBookAir(Yosemite)なのに、まだMax6.1.9である。 実は、SUACは2016年春から全学のコンピュータを一新するので、そこでようやく「Max7」が使えるのだが、なんとMax7ではこれまでのChallenge/Response方式のオフライン・インストールが出来ない、と判明したのだ。 SUACの情報系工房に新しく入れるコンピュータにMax7を入れるのに、SUACネットのproxyサーバをオンライン認証のプロトコルが通らない、という問題があり、これは去年からCycling'74の担当者とやりとりしているが、まだ解決していない。

既にメイルのやりとりは49本、実験用に提供されたパッチをMax7で走らせてテストするYosemiteのスクリーンショットPNGも17枚になるが、このところ10日以上、先方のMax7プログラム改訂を待っているところなのである。 既にダウンロードしているMax7をモバイルWiFiルータとか出張先のホテル(インターネット素通し)でオンライン購入するのは簡単なのだが、この1106の新しいMacBookAir(Yosemite)は、1年後のSUAC導入作業のためのシミュレーションとして、あくまでSUACネット内からproxyを経由してインストール検証したいので、Max6.1.9を別途に入れてまで、ひたすら「待って」いるのだ。



まずは、このHTMLを書いているお仕事Mac miniの横にMacBookAir3号機(Yosemite)を並べて、スクリーンショット転送用にFile共有サーバを走らせて、上のようにセッティングである。 Myoのポイントは、筋電・9軸センサ情報・ホストからの振動情報の転送にBLEを使っているところで、それとMacのBluetoothで通信するのではなく、専用のUSBドングル(青い頭の小さいやつ)がBluetooth-USBインターフェース(と正規購入Myo認証?)を兼ねている。 もし認証が無いのであれば、おいおい赤松さんのBluetooth-Maxオブジェクトが登場することだろう。

Myoの内蔵バッテリの充電は普通のUSB電源ケーブルであり、これで充電中はUSBコネクタの近くのLEDが橙色になり、満タン充電で緑色になる。 上の写真のように、このUSB充電ケーブルを抜くと自動でMyoは動作状態(Bluetooth接続待機)になって、中央の青いマークが点滅する。 つまり、「充電しつつ動作させる」という事が出来ないので、常にバッテリ残量が気になり、Computer Musicの「楽器」としてはちょっと心配(バッテリ切れ)が残ることになる。 Downloadページ にあった「Myo Firmware 1.1.755 (Jan 15, 2015)」のインストールはmbedのNucleoF401REとまったく同じで、このUSBケーブルをMacに繋ぐと出現してマウントされるディスクイメージに、ダウンロードしたHEXをドラッグ&ドロップするだけで完了した。

Downloadページ にある、上の「Myo Connect for Mac 0.8.1 (Jan 15, 2015)」というのが、この専用のUSBドングルを経由してMyoと通信するインターフェースになっていて、 Unofficial Tools は全て、基本的にこの「Myo Connect」と通信することでMyoを活用するためのTool群を構成している。 「Myo Connect」は単にMyoと通信するだけでなく、以下のように「CARIBRATION」メニューから画面の指示に従って、「グー」「パー」「手首曲げ」「手首反らし」「脱力」の5ポーズを設定すると、Myoに学習したパターン認識のパラメータを送信して、以降はMyoから筋電センサの生データだけでなく、5種類のポーズ情報を受けとることも出来るようになる。 指定された「2分間」、ベルトを付けて待っていると(OKになると自動でMyoからバイブが来る)、この5ポーズについてはほぼ確実に区別して認識できる。 以下のYouTube動画は、 Myoとleap motionのテスト のものとほぼ同じだが、こちらはちゃんと2分間以上たっていたので、ジェスチャ認識はとても良好である。

YouTube

さて、 Unofficial Tools の中で「Maxと繋ぐ」とすれば、名前からの直感で、およそ以下の候補がある。

そこでまずは、 Myo-OSCMyOSC とをいろいろと調べてみた。 しかしこれはXcodeのためのSDKライブラリであり、ちょっと距離があるので、あえなく断念バーグとなった(^_^;)。

次の候補はJavascriptである。 これまでMaxであまりやってこなかったが、ちょうど去年、 Max日記(3) でFirmataとmaxuinoをやって、その中でJavascriptで記述されたmaxuinoオブジェクトと遊んだので、「MaxオブジェクトをJavascriptで記述」に抵抗が無くなっていたのである。 そこでまずは、上のように MyoJS というのを試すことにして、「これが必要だ」という「myodaemon」というデーモンサーバをインストールして起動してみると、メニューにあるVisualizerはなかなかに優れたものだった。

そして上のように、この「myodaemon」を呼び出すサンプルHTMLでは、筋電で3次元直方体がぐりぐり回ったり、リアルタイムにセンサ情報を表示しつつ、ボタンをクリックするとMyoのバイブを呼び出すことが出来た。 ところがこれをMaxの「js」オブジェクトにコピペして動かそうとすると、あれこれ色々とやってみたものの、どうしてもerrorが出て、つまりは使うことが出来なかった。残念。(^_^;)

そこで次にトライしたのは、「myodaemon」のようなサーバを使うこともなく、何故かJavascriptで記述したHTMLだけで、上のサンプルのようにちゃんと筋電グラフや9軸グラフをリアルタイムに描画してくれる、という myo.js である。 これはどうやら、「myodaemon」に相当するサーバとして、「WebSockets」を使うものらしい。 ここから、あれこれWebで検索して実験したわけだが、こちらも結論としては、Maxの「js」オブジェクトにコピペして動かそうとすると、あれこれ色々とやってみたものの、どうしてもerrorが出て、つまりは使うことが出来なかった。残念。(^_^;)

そして、 Downloadページ にある「Mac SDK OS X 0.8.1 (Jan 15, 2015)」は、もろXcodeでCでグリグリと書くためのものだが、その中にサンプルとしてMyoとの簡単なインターフェース・バイナリがあった。 上はこれを起動した様子で、可能性としては、これをUnixプロセスとしてMaxから呼ぶことも出来そうであるが、欲しい情報を獲得するためのインターフェースを作るとなると、結局のところ、Xcodeできちんとガリガリとやる必要があるのだった。(^_^;)

そこでUnixシェルも断念バーグして、最後に挑戦したのが myo-processing である。 サンプルの Processingプログラム を走らせてみると、上のようにちゃんと8チャンネルの筋電信号が表示された。 ここまでは、 Myoとleap motionのテスト のいちばん下にあるYouTube動画でやった事であり、新しいのはここから先である。

MyoとProcessingが繋がったとして、ここからMaxとどう繋ぐか・・・というのが「壁」となる筈なのだが、どっこい、既に僕にとって「MaxとProcessing(とSuperCollider)とは、OSCで連携するお友達」だったのだ(^_^)。 3年半前に、 Processing日記(4)SuperCollider日記(6) のあたりでやっていた事を、まずは発掘した。 思い出しのスタートラインは、 udptest_07 というMaxパッチとProcessingスケッチである。 これらは更にSuperColliderとOSC連携しているが、それは無視しても大丈夫である。

そして最初の実験として成功したのが、上の Myo_Max_01 である。 ここではまだ何も判っていないので(^_^;)、とりあえず「udptest_07」と「サンプル」をそのまま合体させているが、ちゃんとOSCを経由して筋電情報がリアルタイムにMaxに引き渡された。

こうなれば、少しずつ改造して、不要なものをカットして、欲しいものを加えて・・・という改造大会である(^_^)。 上の Myo_Max_02 では、Processingサンプルがやっていた、「-127〜+127を0〜50にマッピングして描画」などというのを除去して、ナマの筋電情報を「-127〜+127」のフルスケールで送ることが出来た。

さらに続けて、上の Myo_Max_03 では、見た目はあまり変化がないようで、サンプルにあった「synchronized」という謎のやつをカットして、馴染みのある記述で筋電情報をハンドリング出来ることを確認できた。

そして最後の Myo_Max_04 では、Webの情報として載っていないにも関わらず、手探りであれこれ探して、なんとMaxの側からOSC経由、Processing経由でMyoに対して「短いバイブ」を命令して、任意にMyoを振動させる事が出来た、という例である。 ここまでが、あれこれの合間に進めてきたことであり、とりあえずインターフェースの壁はほぼ突破できたので、leap motionとともに、Myoも新しい「楽器」として、いかようにもMaxで料理していける・・・というスタートラインに到達したのだ。(^_^)

明日は会議で潰れて、あとは今週は沖縄で充電してくるので、メイルを読むのにMacは持参するもののMyoは持っていかない。 このページも、せっかくCQ「インターフェース」でオリジナル筋電センサをmbedで作った、という記事が出るので、リンクせず25日の出版日までは公開しないでおく事にしよう。 そして来月、音楽情報科学研究会とエンタテインメントコンピューティング研究会でも、 このページ をさりげに宣伝することになるので、その後ででも、リンクを繋いで公開しつつ、このページの続きを進めていくことにしよう。 ただし、いくつか面白そうなセンサを残った研究費で発注しているので、そちらが面白くなると、この日記はたった2日で放置されて「終了」となるかもしれない。(^_^;)

2015年2月23日(月)

上の日記からちょうど1週間が経過してしまったが、この期間、2月17日(火)には後述の照岡さんの「Myo解析」メイルが届いたり、大学院入試判定教授会など、会議会議会議が続いた。 そして2月18日(水)〜2月21日(土)には、毎年恒例、今回が17回目の 沖縄行き があり、初めての宮古島などを堪能した。 帰宅してみると、自宅には2つの郵便物が届いており、一つは4月のタイガース甲子園ライトスタンド巨人戦のチケット(^_^)、そしてもう一つはCQ出版部からの「もうじき刷り上がったインターフェース誌を送るので、デバッグ情報を2/28までにヨロシク」との連絡だった。 12時間爆睡で回復後、昨日の2月22日(日)には、2/19宮古島mixi突発カラオフ7時間19曲に続いて、mixiカラオフ6時間22曲を走破した。 そして今日の午前には、卒展の機材返却などがあり、ようやく 沖縄行き の写真とYouTubeをWebに上げて、午後イチで医者に行って薬をもらってきたところである。

沖縄に行っている間に届いたメイルとしては、CQ出版の担当者から「Interface4月号読者と編集部との交流会」という「オフ会のお誘い」というメイルが届いたが、これに出るには1泊2日が必要なので、ちょっと回答留保である。 この返信で、ちょうど届いた以下をお知らせしておいた。

ところで、以下のニュースがありました。
http://japan.cnet.com/news/service/35060542/
「Apple Watch」、健康関連機能の搭載を断念の可能性--センサの問題で

> Apple Watchで心拍数、血圧、ストレスレベルをモニタリングできるようにする計画が中止
> になったという。センサの動作があまりにも一貫せず、同社の望む結果が得られないため
> だという。4年間にもわたる研究、開発、試験にもかかわらず、バンドの締め付け具合、皮膚
> 水分量の変化、装着者の腕の毛深さといった変数の補正が難しすぎることが明らかになった。 

・・・まぁ、当然のことです。(^_^;)
天下のAppleでも生体センシングに難儀している、という事では、
超小コラムとして紹介してもいいネタですが、まぁ間に合わないでしょうか。

また、今年の日本時間学会(山口)の大会日程がアナウンスされたが、なんと、日本音楽知覚認知学会(札幌)と完全にカブッた6月6・7日である。 困った困った。 そして、今年のSketchingの開催地と日程がアナウンスされたが、日程は7月30日〜8月2日という、まさに前期末の佳境の時期である(^_^;)。 場所はアリゾナ州Tusconから1時間ほどの Biosphere 2 という、「synthetic space habitat and research facility」であり、Tusconと言えば 世界最大の飛行機墓地 があり、ここも見物しよう・・・と言う。 ちょうど「メディア造形総合演習II」で担当する学生がいない年であるが、最終合評の欠席はなかなか悩ましいところである。

今週は、明日は午前に医者2件ハシゴで検査と薬を受けとると午後は大学入構禁止であり、水曜日と木曜日はいよいよメインの前期入試である。 またまた鉛筆デッサン実技試験監督、230分立ちっぱなしに挑戦である。 そして金曜日の晩にも某カラオフがあり、土日の準備を経て、その翌週には月・火と甲府に情報処理学会ダブル(MUS+EC)研究会に発表参加、木曜から日曜まで、今度は大分での知覚コロキウムに発表参加である。 なかなかMyoと遊べないのだが、両方とも筋電ネタの発表をするので、出来ればMyoを持参してチラ見せしたいところである。(^_^;)

・・・ということでようやく、照岡さんからの「Myo解析」メイルの話に到達した。 「結論から申しますと(回路図までは追えてないのですが)、120MHzのARMを使ってるので、結構処理は高性能ですね。でもどうもBLE(Bluetooth Low Energy)で、律速がかかっている感じがします」というのは、僕の印象とまったく同じである。 まず、Myoのバラし方については、以下のYouTubeに上がっていたという、

Thalmic Labs Myo teardown

そして、筋電ユニットは、8つの電極ボックスに全て同じ、以下のようなもの(フラットケーブルのパターンだけ別)が入っている。 使われてるチップ(OPアンプ)は、ST Microelectronicsで"VA1814"と読めるものの、メーカのサイトに該当製品は無い。 ただしチップのピン配置が典型的な4個1パックなので、おそらく単純なRailtoRailのOPアンプで、一般的な3個のOPアンプを使った差動増幅回路だ、という見立てである。

筋電センサ電極は、基板直付けのステンレス電極、電源は±の二電源で、うち0V(GND)が、中央の電極につながっている。 ただし上下の測定電極は、OPアンプに直結されておらず、コンデンサを経由してつながっているという。 8つのユニットのうち中央の3つが少し大きめで、そのうち両端の二つにあるのは、上のYouTube動画にある通り、リチウムイオンバッテリー(3.7V 260mAh)である。 中央部分のメインユニットには、超小型コネクタから8つのアナログ筋電信号が入って来る。 このメインユニットの主な使用チップは以下である。

そして、ここからは個人的感想という事で、「ハードのスペックとしては、まずまず」、「個人的には初段差動アンプはOPアンプではなく、  AD627とかINA333を使って欲しかった」、「長嶋・動画レポの通り、標準のアプリはちょっとしょぼい」、「生波形の方も、少し遅延が気になる」、「改造は途中の極小コネクタからアナログ信号をとってきてmbedでADというのが一番気持ち良さそうだがコネクタの入手が困難そう」、「それよか、もともとのminiBiomuseのmbed化(Wifi化)の方が良さそう」という、これまた僕の印象とまるで同じ結論となった。 こうなると、Myoは改造対象としてでなく、普通のインターフェースとして「そこそこ遊ぶ」という程度の付き合いになりそうである。

そして午後、遂に上のようにCQ出版から、明後日2/25に発売される「インターフェース」が届いた(^_^)。 さっそく このように Webに上げた。 来月号の巻末「でばっぐ」で訂正するほどのミスは無かったが、102ページ右段の最後から6行目に、突然に「USBオーディオ治具」という単語が出てきていた。 これは校正の途中までは、解説の原稿が生きていたのに、最終的に消えた(^_^;)ものである。 仕方ないので、 このページ に補足をあれこれ追加した。 「Max」の解説とか、せっかく書いた「BITalino」「e-Health」の原稿もそのまま置いた。 これでようやく、今回の執筆も終了である。

2015年2月26日(木)

昨日の前期入試1日目では、新しくデザイン学部デザイン学科としてスタートする新入生になるために、実技試験4.0倍、数学試験7.8倍に向かって多数の受験生がやってきた。 18人全員が揃った試験室での鉛筆デッサン実技試験監督、230分立ちっぱなし(毎年恒例、心の中で受験生を応援する私的な儀式)を無事にこなしたが、その実技選択の受験生は今日は2日目、「発想表現」に挑戦している。 これまでいつも2日監督をしていた僕は、珍しく監督業務から外れて、邪魔の入らない日となった。 ただし後期入試(15.9倍)では、鉛筆デッサン実技試験が4時間になって290分立ちっぱなし、続けてその後21人の面接試験、というハードな1日が待っている。

こんな時期でないと出来ないので、昨日の午後から今日の午前までかけて、卒展図録に付録のDVDからメディア造形学科学生作品をムービーとして取り込んでMP4に圧縮したり、上のように教材用ムービーHDDとその2つのバックアップに整理格納したりしているうちに、午前は終ってしまった。 3個のHDDの中身は同じ筈なのに、微妙に容量とかファイル数が違っているのは「誤差」である(^_^;)。
また、CQ出版の編集者に依頼されて、 こんなイベント に、手弁当で参加することになったが、「せっかくなので、まったく誌面に無いデモをしたいと思います。誌面にある事はYouTubeにも上げてあるので、その用意はしません。さらにAdvancedな話題を提供したいと思います」と伝えてOKをもらったので、ここはMyoの出番だろう。

実は沖縄・宮古にMyoを持っていかなかったものの、空港などの待ち時間に、ちょっとだけMaxプログラミングの補足を実験していた。 2月16日の日記の最後の Myo_Max_04 では、Myoから送られてくるBluetoothパケットのうち、筋電情報しか表示していないが、ここに加速度・ジャイロ・地軸方向の9時センサ情報も重畳させるには、データパケット長が異なるメッセージの先頭文字列で分岐させる必要があり、単純な「zl」オブジェクト1個では出来ないな・・・と止まっていたのである。 それを上のように、メッセージの先頭文字列を比較して、いったんメッセージオブジェクトに溜めたものを再度叩く、という「list_parse.maxpat」を実験して作っていたところからの再開である。

2時間ほどあれこれ試行錯誤して、初めて触れるProcessingの「PVector」というやつもなんとか解読して、上のように全ての情報をMyoから受けとってOSCで送るProcessingスケッチと、対応したMaxパッチ Myo_Max_05 が完成した。 表示されているMyo情報は、

であり、筋電・加速度・ジャイロを「+127〜-127」の範囲に、方向を「0〜256」の範囲に表示するように、それぞれ適当にProcessing内でスケーリングしている。 この筋電情報は生の筋電信号であるが、ここに「インターフェース」誌の記事に書いたような、全波整流、移動平均を盛り込めば、奇麗な8チャンネル筋電エンペロープが得られる。 せっかくなのでこれは着手せずに、 このイベント の講演デモの場で、アドリブでプログラミングしてみる、というアイデアを思い付いた(^_^;)。 Maxはライブのプロトタイピングにこそ最大の能力を発揮するので、「Max紹介」としては格好の題材である。

2015年2月27日(金)

色々と充実した2月もぼちぼち終わり、これで2015年も1/6を消化した事になるが、新学期まで、3月が色々と「仕込み」の季節である。 来週は2日間と4日間(3日半)の出張が予定されていて、さらに今日の晩には少数精鋭mixi水面下カラオフという楽しみな企画が待っているので、あまり巨大なお仕事に着手しにくいタイミングである。 そこでまず、CQの原稿とともに去年11月あたりから突っ走ってくる中で、「暇があったら片付けよう」と棚上げしていた事項を棚卸ししてみる事にした。 すると、ザッと簡単に挙げても上のようにたくさんある事に気付いて、慌てて このページ にまとめた。 「やるべき事」を可視化して、公開して、自分にプレッシャーをかける、というのはいつもの事である。 Myoについては昨日の日記でとりあえずの区切りまで到達したので、以下、自分の整理も兼ねて簡単に確認しておこう。

上のleap motionについては、 Myoとleap motionのテスト のところで、赤松さんのMaxオブジェクトを確認して、一応は「使える」モノとなったのだが、残念ながらこれだとleap motionを1個しか使えない。 1個のleap motionで両手の10指をセンシング出来るのでOK、と言えばそれまでだが、認識範囲が半径30〜40cmの半球内、という小ささが不満であり、やはり「空間に多数のleap motionを配置したい」のである。 そのためには、ホストPCでは1対1接続となるので、何らかのマイコンでleap motionを処理して、それら多数のマイコンからの情報をホスト(Max)に収集したい、というのが、この「宿題」なのである。 ネットでちょっと検索しても、「leap motionとRaspberry Pi」、「leap motionとArduino」などのリンクが多数、存在している。 「leap motionとRaspberry Pi」であればOSCでほぼ見えているが、「leap motionとArduino」については、どうやら「node.js」と「Johnny Five」と「firmata」を使うらしい。 ちなみに、検索していたら leap motionを分解してみた というページもあった。これも面白い(^_^;)。 とりあえず、「leap motionとArduino」を攻略するために、 これこれこれ のリンクをここに記しておこう。

上の、ごろごろたくさんあるのは、Felicaのあれこれである。 これまで、学生の インスタレーション作品 (「はやくスシになりたい」「おはなしパネル」等)に何度も活躍してきたRFIDのメーカは、あまりポピュラーなところではなかった。 また、RFIDリーダとの通信をAKI-H8が行って、その番号を4ビットディジタルにエンコードしてGainerに与える、というやや冗長なシステムとしてきた。 これを、せっかくなのでスイカやイコカやトイカで有名なFelicaに置き換える、というテーマを意識して、写真のようにリーダ/ライタと多種多数のFelicaタグを購入したのは、もう数ヶ月前になる。 Arduinoを使ってfirmata化するか、Propellerにするか、はたまたmbedでNucleoF401REを使うか、まだ未定であるが、これも時間のある時にやっておきたい懸案事項なのだ。 技術的にはあまり新規なことが無い(やれば出来るだろうと判っている)ので、いつも後回しになっているFelicaである。

上は先日、今期の最後の研究費を使い切る際に、10個仕入れてみた「PAWセンサ」というもので、シンプルというかちょっとショボい(^_^;)ものの、立派に「tactile sensor」なのである。 中身には2個のLEDと2個のフォトトランジスタがあり、異なる場所にあるLEDを選択して点灯させると、フォトトランジスタはそれぞれの場所での受光量を電圧として出力する、というもので、ポイントはこの全体がウレタン(スポンジ)で覆われている事である。 つまり、ウレタンをうにょうにょと押しつぶすと、密度が増えて受光量が減る、という変化から、このピンクのウレタンをうりうりと押す触覚的ニュアンスを検出できるというのだ。 「触らない楽器」シリーズの後には「触りまくる楽器」をやってみたかったので、これも楽しみである。

上にあるのは、ちょうどMyoにもほぼ同じものが入っているらしい、今期の最後の研究費で5個仕入れてみた「9軸センサ」である。 9軸というのは、3次元加速度、3次元角加速度(ジャイロ)、3次元の地軸方向、という3種類を一気にセンシングするものであり、スマホなどに内蔵されることで小型軽量廉価化が進展したものである。 これはホストインターフェースが「I2C」であるが、これまでI2Cは未経験なので、楽しい「未知の領域」である。 実は、 新楽器「GHI2014」 に使った超音波センサが、ホストインターフェースとして「I2Cまたはシリアル」の2種に相応していたのだが、この時に手抜きをしてシリアルを使ったので、まだI2Cが未体験なのだった(^_^;)。 こちらのセンサはI2C専用なので、いよいよ逃げずにI2Cをやっておくと、これまで購入して使っていなかったA/Dチップ(I2Cタイプ/Raspberry Pi用)も使えるようになるので、一挙両得である。

そして残ったのは、上のいろいろな論文/文献のお勉強である。 「Seth論文」とは これ のことで、いま勉強中の「内受容感覚」テーマのキーとなる論文である。 これに関連して、「心理学評論」という文献からオンライン購入した2本の論文「寺澤悠理・梅田 聡, 内受容感覚と感情をつなぐ心理・神経メカニズム」「大平英樹, 感情的意思決定を支える脳と身体の機能的関連」もまた、2読3読、と勉強中なのだ。 1月には、来週に発表参加する「知覚コロキウム」に関連して知った「基礎心理学会」の学会誌「基礎心理学研究」バックナンパから選んで27冊を購入したが、まだ2/3程度しか目を通していない。残り9冊を、来週の出張出発までに眺めるのも必須なのである。 そして分厚い本は、ソマティック・マーカー仮説と言えばダマシオ、という アントニオ・ダマシオ氏 の3部作、「デカルトの誤り 情動、理性、人間の脳」・「無意識の脳 自己意識の脳」・「よみがえるスピノザ 感じる脳 情動と感情の脳科学」も、ようやく3冊目である。 もちろん、 ダマシオ批判 があるのも承知の上で、しかしとりあえずはこれを整理してから「その先」に行きたいのである。

そして午後になり、 これこれこれ を眺めるところから、leap motionを再開した。 これ はどうやら、leap motionとArduinoを繋ぐ王道のようで、まずはleap motionコントローラのセッティングで「WebSocketをON」にする、とある。 そういえばWebSocketとNode.jsの組み合わせは、Myoにトライした最初の頃にやっていたが、MaxのjsオブジェクトがNode.jsと相性が悪くて断念していた。 今回はMaxでなくArduinoなので、話は別である。
・・・しかしここで気付いたが、WebSocketと繋がったサーバは、PCの内部で走っているのであり、ArduinoはこれとNode.jsを介して通信しているが、決してスタンドアロンでは無かった。 これは他の2件も基本的に同様で、つまり、「Arduinoは外部I/Fとしてランプを点灯させたりロボットアームを動かすために使う」もので、USBでもBluetoothでも、要はそこにPC(サーバ)が必要なのだった。 これでは赤松さんのオブジェクトと同じで、PCあたり1個のleap motionしか使えない。 こうなれば、解決策としてはRaspberry Piという事になる。 そこで調べてみると、 これ とか これ とか これ とか これ とか、色々と出て来た。 ただし問題は、Raspberry Piは Raspberry Pi 日記 として進めた、2013年5月14日〜2013年9月1日まででストップしていて、いまや完全に忘却の彼方にある、という事なのである。(^_^;)

これまで、ネットで何か調べて出てくれば、たいていそれを追いかけて(追試)、先人が到達したところまで追いつくことが出来たが、なんと検索で出て来た これこれこれこれ をザッと読んでみて判明したのは、 「leap motionとRaspberry Pi」は無理っぽい 、という事だった(^_^;)。 正式にサポートされておらず、どうやらRaspberry Piの512MBというメモリが小さ過ぎて、要するにRaspberry PiでもWebSocketサーバを走らせてleap motionと通信するには非力らしい。 もう少し強力な奴なら・・・という話題も発展することなくストップしていた。 これでは、当然だが単体での「leap motionとArduino」など、最初から不可能である。 いいところスマホで、あとは普通に最近のPCがleap motionを繋ぐ標準プラットフォームだとすれば、マイコン単体では手に負えないのだろうか。

 

そこで初心に戻って、 leap motionのDeveloperページ に行ってみると、上のように、SDKで対応しているのは以下の6つの環境だった。

Unityがあるので藤石さんが喜びそうだが(^_^;)、僕はUnityはActionScriptと同じぐらい、忌避してきたのである。 うーむ困った。 しかし、ここでの「Java」というのがProcessingでなく「素のJava」であるとすれば、ちょっと手を出しにくくなる。 そこで「leap motion Processing」で検索すると、 これ とか これ とか これ とか これ とか これ とか これ とか とか、色々と出て来た。 まだ脈がありそうである(^_^;)。
・・・そしてここから、上記のリンクをそれぞれ辿ってみたところ、ライブラリが不足して叱られたり単なる情報ページだったりした中で、最初の ここ だけが以下のように、無事に環境インストールから3種類のサンプル実行まで上手くいった。 何より素晴らしいのは、このProcessingスケッチは、leap motionから提供されている「leap motionコントローラ」を起動しなくても動く、というところで、つまり、(WebSocketサーバのような?)面倒なルートを使っていないのである。(^_^)

サンブル(1) basic

 

import de.voidplus.leapmotion.*;

LeapMotion leap;

void setup() {
  size(800, 500, OPENGL);
  background(255);
  // ...
  leap = new LeapMotion(this);
}

void draw() {
  background(255);
  // ...
  int fps = leap.getFrameRate();

  // ========= HANDS =========

  for (Hand hand : leap.getHands ()) {

    // ----- BASICS -----

    int     hand_id          = hand.getId();
    PVector hand_position    = hand.getPosition();
    PVector hand_stabilized  = hand.getStabilizedPosition();
    PVector hand_direction   = hand.getDirection();
    PVector hand_dynamics    = hand.getDynamics();
    float   hand_roll        = hand.getRoll();
    float   hand_pitch       = hand.getPitch();
    float   hand_yaw         = hand.getYaw();
    boolean hand_is_left     = hand.isLeft();
    boolean hand_is_right    = hand.isRight();
    float   hand_grab        = hand.getGrabStrength();
    float   hand_pinch       = hand.getPinchStrength();
    float   hand_time        = hand.getTimeVisible();
    PVector sphere_position  = hand.getSpherePosition();
    float   sphere_radius    = hand.getSphereRadius();

    // ----- SPECIFIC FINGER -----

    Finger  finger_thumb     = hand.getThumb();
    // or                      hand.getFinger("thumb");
    // or                      hand.getFinger(0);

    Finger  finger_index     = hand.getIndexFinger();
    // or                      hand.getFinger("index");
    // or                      hand.getFinger(1);

    Finger  finger_middle    = hand.getMiddleFinger();
    // or                      hand.getFinger("middle");
    // or                      hand.getFinger(2);

    Finger  finger_ring      = hand.getRingFinger();
    // or                      hand.getFinger("ring");
    // or                      hand.getFinger(3);

    Finger  finger_pink      = hand.getPinkyFinger();
    // or                      hand.getFinger("pinky");
    // or                      hand.getFinger(4);        

    // ----- DRAWING -----

    hand.draw();
    // hand.drawSphere();

    // ========= ARM =========

    if (hand.hasArm()) {
      Arm     arm               = hand.getArm();
      float   arm_width         = arm.getWidth();
      PVector arm_wrist_pos     = arm.getWristPosition();
      PVector arm_elbow_pos     = arm.getElbowPosition();
    }

    // ========= FINGERS =========

    for (Finger finger : hand.getFingers()) {
      // Alternatives:
      // hand.getOutstrechtedFingers();
      // hand.getOutstrechtedFingersByAngle();

      // ----- BASICS -----

      int     finger_id         = finger.getId();
      PVector finger_position   = finger.getPosition();
      PVector finger_stabilized = finger.getStabilizedPosition();
      PVector finger_velocity   = finger.getVelocity();
      PVector finger_direction  = finger.getDirection();
      float   finger_time       = finger.getTimeVisible();

      // ----- SPECIFIC FINGER -----

      switch(finger.getType()) {
      case 0:
        // System.out.println("thumb");
        break;
      case 1:
        // System.out.println("index");
        break;
      case 2:
        // System.out.println("middle");
        break;
      case 3:
        // System.out.println("ring");
        break;
      case 4:
        // System.out.println("pinky");
        break;
      }

      // ----- SPECIFIC BONE -----

      Bone    bone_distal       = finger.getDistalBone();
      // or                       finger.get("distal");
      // or                       finger.getBone(0);

      Bone    bone_intermediate = finger.getIntermediateBone();
      // or                       finger.get("intermediate");
      // or                       finger.getBone(1);

      Bone    bone_proximal     = finger.getProximalBone();
      // or                       finger.get("proximal");
      // or                       finger.getBone(2);

      Bone    bone_metacarpal   = finger.getMetacarpalBone();
      // or                       finger.get("metacarpal");
      // or                       finger.getBone(3);

      // ----- DRAWING -----

      // finger.draw(); // = drawLines()+drawJoints()
      // finger.drawLines();
      // finger.drawJoints();

      // ----- TOUCH EMULATION -----

      int     touch_zone        = finger.getTouchZone();
      float   touch_distance    = finger.getTouchDistance();

      switch(touch_zone) {
      case -1: // None
        break;
      case 0: // Hovering
        // println("Hovering (#"+finger_id+"): "+touch_distance);
        break;
      case 1: // Touching
        // println("Touching (#"+finger_id+")");
        break;
      }
    }

    // ========= TOOLS =========

    for (Tool tool : hand.getTools ()) {

      // ----- BASICS -----

      int     tool_id           = tool.getId();
      PVector tool_position     = tool.getPosition();
      PVector tool_stabilized   = tool.getStabilizedPosition();
      PVector tool_velocity     = tool.getVelocity();
      PVector tool_direction    = tool.getDirection();
      float   tool_time         = tool.getTimeVisible();

      // ----- DRAWING -----

      // tool.draw();

      // ----- TOUCH EMULATION -----

      int     touch_zone        = tool.getTouchZone();
      float   touch_distance    = tool.getTouchDistance();

      switch(touch_zone) {
      case -1: // None
        break;
      case 0: // Hovering
        // println("Hovering (#"+tool_id+"): "+touch_distance);
        break;
      case 1: // Touching
        // println("Touching (#"+tool_id+")");
        break;
      }
    }
  }

  // ========= DEVICES =========

  for (Device device : leap.getDevices ()) {
    float device_horizontal_view_angle = device.getHorizontalViewAngle();
    float device_verical_view_angle = device.getVerticalViewAngle();
    float device_range = device.getRange();
  }
}

// ========= CALLBACKS =========

void leapOnInit() {
  // println("Leap Motion Init");
}
void leapOnConnect() {
  // println("Leap Motion Connect");
}
void leapOnFrame() {
  // println("Leap Motion Frame");
}
void leapOnDisconnect() {
  // println("Leap Motion Disconnect");
}
void leapOnExit() {
  // println("Leap Motion Exit");
}

サンブル(2) gestures

import de.voidplus.leapmotion.*;

LeapMotion leap;

void setup(){
  size(800, 500, OPENGL);
  background(255);
  // ...
    
  leap = new LeapMotion(this).withGestures();
  // leap = new LeapMotion(this).withGestures("circle, swipe, screen_tap, key_tap");
  // leap = new LeapMotion(this).withGestures("swipe"); // Leap detects only swipe gestures.
}

void draw(){
  background(255);
  // ...
}

// ----- SWIPE GESTURE -----

void leapOnSwipeGesture(SwipeGesture g, int state){
  int     id               = g.getId();
  Finger  finger           = g.getFinger();
  PVector position         = g.getPosition();
  PVector position_start   = g.getStartPosition();
  PVector direction        = g.getDirection();
  float   speed            = g.getSpeed();
  long    duration         = g.getDuration();
  float   duration_seconds = g.getDurationInSeconds();

  switch(state){
    case 1:  // Start
      break;
    case 2: // Update
      break;
    case 3: // Stop
      println("SwipeGesture: "+id);
      break;
  }
}

// ----- CIRCLE GESTURE -----

void leapOnCircleGesture(CircleGesture g, int state){
  int     id               = g.getId();
  Finger  finger           = g.getFinger();
  PVector position_center  = g.getCenter();
  float   radius           = g.getRadius();
  float   progress         = g.getProgress();
  long    duration         = g.getDuration();
  float   duration_seconds = g.getDurationInSeconds();
  int     direction        = g.getDirection();

  switch(state){
    case 1:  // Start
      break;
    case 2: // Update
      break;
    case 3: // Stop
      println("CircleGesture: "+id);
      break;
  }
  
  switch(direction){
    case 0: // Anticlockwise/Left gesture
      break;
    case 1: // Clockwise/Right gesture
      break;
  }
}

// ----- SCREEN TAP GESTURE -----

void leapOnScreenTapGesture(ScreenTapGesture g){
  int     id               = g.getId();
  Finger  finger           = g.getFinger();
  PVector position         = g.getPosition();
  PVector direction        = g.getDirection();
  long    duration         = g.getDuration();
  float   duration_seconds = g.getDurationInSeconds();

  println("ScreenTapGesture: "+id);
}

// ----- KEY TAP GESTURE -----

void leapOnKeyTapGesture(KeyTapGesture g){
  int     id               = g.getId();
  Finger  finger           = g.getFinger();
  PVector position         = g.getPosition();
  PVector direction        = g.getDirection();
  long    duration         = g.getDuration();
  float   duration_seconds = g.getDurationInSeconds();
  
  println("KeyTapGesture: "+id);
}

サンブル(3) camera_images

import de.voidplus.leapmotion.*;

LeapMotion leap;

void setup(){
  size(640, 480, OPENGL);
  background(255);  
  leap = new LeapMotion(this);
}

void draw(){
  background(255);
  
  // ========= CAMERA IMAGES =========
  
  if (leap.hasImages()) {
    for (Image camera : leap.getImages()) {
      if (camera.isLeft()) {
        // left camera
        image(camera, 0, 0);
      } else {
        // right camera
        image(camera, 0, camera.getHeight());
      }
    }
  }  
}
3つ目などはもの凄いシンプルなProcessingスケッチなのに、なんとウインドウ内にleap motionの2個の画像センサからのリアルタイム画像が表示された(^_^)。 これはもう少し、掘り下げてみる価値がありそうである。 これを使えば、Myoと同様に、赤松さんのMaxオブジェクトを使わずに、leap motion〜Processing〜OSC〜Maxというルートが確立することになる。 別々にでなく、MyoのProcessingスケッチに合体すると、そこそこスマートになるかもしれない。

2015年3月1日(日)

金曜日の晩に9時間ほどのマラソン24曲を堪能し、土曜日は休養日、そしてこの日は明日からの学会発表2件のプレゼン作成のために研究室に出て来た。 まず最初に、フト気になったので確認したのは、「赤松さんのleap motionオブジェクトもまた、leap motionコントローラを起動しなくても動く」という事実だった。 Processingで最後に調べたツールがleap motionコントローラを不要としていたので、駄目モトで確認したのだが、さすが赤松さん、パッチには「leap motionコントローラを起動してね」と書いてあるものの、起動しなくてもちゃんとleap motionの情報を受けとっていた。 こうなれば、ProcessingからOSC経由で受けとる必要性がほとんど無いことになる。(^_^)

   

そして午前中から午後にまで跨がって、上のような 音情研EC研 の、両方のプレゼンをKeynoteで完成できた。 写真ばっかりだが、さらに見せたい動画がたくさんあるので、もうこれで十分である(^_^;)。 さらに午後には、半分ほど残っていたダマシオ3部作の最後、 「よみがえるスピノザ 感じる脳 情動と感情の脳科学」 と、合わせてプリントしていた ダマシオ批判 とを読破したが、なんだかなぁ・・・という読後感である(^_^;)。 まぁ、読んだ文献に対して100%完璧に同意・賛同・共鳴するのでは「宗教」になってしまうので、アウフヘーベンのためには突っ込みどころがあった方が良いのかもしれない。

2015年3月4日(水)

初めての甲府で、無事に2日間の 情報処理学会・音楽情報科学研究会/エンタテインメントコンピューティング研究会 に参加してきたが、会場では謎のトラブルにずっと悩まされた。 MyoとやりとりするProcessingスケッチと、これとOSCで通信するMaxパッチまでを作って、これでさりげにMyoをはめてプレゼンするぞ・・・と勇んで出かけたのに、なんと会場に着いて内職でテストしてみるとエラーが出て、以下のような現象に悩まされたのである。 結局、Processing+MaxでのMyoデモを断念バーグして、プレゼンの冒頭(ちょうどセッションの最初だったので)でさりげに、Myoデーモンを使わないJavaScript版のデモをスクリーンに出す、という形で終ってしまった。

 

しかしこれでは、月末にあるCQ出版の読者交流会でも困ってしまう・・・と、甲府から静岡に向かう特急「ふじかわ」に乗り込んだところで、駄目モトでモバイルWiFiルータを繋いで、元のライブラリを仮にリネームして、再度、 myo-processing を一式、ダウンロードして、ライブラリ以下をそっくりそのまま、置き換えてみた。 すると、何事も無かったように正常に戻って、問題は解決してしまった。 どうやら、過去にパスの先にあるmyoライブラリをロードしたところでProcessingを異常終了した事あたりをきっかけに、このmyoライブラリが他プロセスに読み込まれたまま解放されない・・・というような、いわゆるdirtyなゾンビ化してしまったらしい。 とりあえずこれが解決して、安心して帰宅できた。

2015年3月5日(木)

この部分はいつものようにセントレアのラウンジで打っているが、今日は夕方に博多に飛んで前泊である。 明日から、いよいよ本年度最後の出張(ただし全額自費(;_;))、知覚コロキウムである。 フォトレポートは、 初めての日田 を参照されたい。 e-wingの車内の「Free Wifi Hamamatsu」が全然使えないよ、と遠鉄に電話していたのだが、今日は改良されたのか、ちゃんと繋がったのは収穫である。 ただし、バスの車内ではそうそうパソコン画面を見ていられないので(^_^;)、これは帰途に向けた朗報というところだ。

 

ラウンジでは、ちょっとした懸案を試してみた。 その第一はMyoの内臓バッテリの消耗であり、もう一つはMyoの8チャンネル電極の配置である。 一昨日の甲府の研究会の会場でほぼ満タンに充電して、帰途の甲府駅でチラッと動作確認をした時に使って以来、約マル2日が経過しているが、USB充電プラグを抜かれたMyoはずっと、センターモジュール上の青色LEDの模様がゆっくり点滅を続けていた。 そして今、新たにMyoコネクトとMaxとProcessingを起動してみると、ちゃんと動いた。 まぁバッテリがまだ新品ということもあるが、とりあえずは、まずまずである。(^_^)

そして次に、8チャンネルの筋電センサ電極を少しだけ浮かせて信号が消えるチャンネルから、電極番号の対応を確認してみた結果が、上のようになった。 これで、ほぼ反対側の電極ペアは見当がつくが、センターブロック(CPU+Bletooth)とその両隣(パッテリ×2)はちょっと幅が広いので、注意が必要である。 CQの読者交流会の場でMaxプログラミングをして「全波整流+移動平均」を組み込む、という構想だったが、明日からのコロキウムでの発表と絡めて、ちょっと実験してみるとすると、これはサッサと作ってしまいたくなってきた(^_^;)。

そしてラウンジを出て、セキュリティチェックを通ってゲートに行ったところで、サクサクと上のように、手慣れた「全波整流+移動平均」を作ってしまった。 たぶんこれで動くと思うが、まぁそれは大分に行ってからである。 明日の学会が朝イチで、浜松からは間に合わないので今夜の前泊となったが、馴染みの博多であり、行き先は既にネットでチェックしているので、今夜はホテルでプログラミングする事もなく、博多の某所で熱唱なのである。(*^o^*)

2015年3月6日(金)

今回は浜松〜セントレアにe-wing、セントレア〜福岡空港がフライト、そして博多〜日田が高速バス、ということで、なんと「乗り鉄」の僕が列車に乗ったのは、往路の福岡空港→博多駅の地下鉄たった2駅だけ(帰途は日田〜福岡空港直行)、となった。これはかなり珍しい。 そして前夜は真面目に24時にホテルに戻って、この日は6時起床、いよいよ知覚コロキウムの会場、大分県・日田温泉の「かんぽの宿」に出発した。 ホテル至近の博多駅バスターミナルから出た、日田行きの高速バスはまたまた僕一人の貸し切りで、その後、天神と空港で数人が乗っただけだった。 到着した日田バスターミナルはかんぽの宿の送迎バスが待っているJR日田駅前で、なんとも快適に到着した。

昼食に美味しい「筍釜飯」をいただいた後で、セッション前の会場で昨日のMaxパッチを走らせてみると、さっそくバグが発覚した(^_^;)。 そして絶対値計算のために2乗した後に抜けていた「sqrt」を追加して、無事に上のように筋電信号も「全波整流+移動平均」が完成した。 さらに、Myoに対して「1」を送ると「長いバイブ」となったが、「0」を送ると「短いバイブ」になる事も確認できた(・・・と思っていたが、後でこれは勘違いであると判明(^_^;))。 こうなると、可能であれば明日の発表でチラ見せしたくなってきた。

 

さて、自腹でまで参加した学会なので、あれこれ全てお勉強、ここからはセッション中にメモメモ大会である。 以下が、今回の全体プログラムである。 整理打ち込みして気付いたが、なんと口頭発表は1人30分もあった。 準備したプレゼンは20分を想定していたので、これはいきなりピンチである(^_^;)。

第1日, 2015年3月6日, 金曜日
12:00 受け付け開始
13:25-13:30 開会あいさつ
13:30-14:30 口頭発表セッション 1(日本語)
14:40-17:30 ポスター発表セッション
18:00-20:00 夕食および自由時間
20:10-21:00 ポスター発表セッションの続き
21:30- フクロウ・セッション(二次会)

第2日, 2015年3月7日, 土曜日
7:00-8:30 朝食
8:40-9:40 口頭発表セッション 2(日本語)
9:50-10:50 口頭発表セッション 3(英語)
11:00-12:00 口頭発表セッション 4(英語)
12:00-13:20 昼食
13:25-17:45 国際五感シンポジウム
17:45-17:55 集合写真撮影
18:00-20:00 夕食および自由時間
20:10-21:00 デモンストレーション・セッション
21:30- フクロウ・セッション(二次会)

第3日,2015年3月8日,日曜日
7:00-9:00 朝食
9:30-11:00 口頭発表セッション 5(日本語)
11:30-12:30 昼食
12:40 送迎バス出発
13:30-15:30 ガイド付き見学ツアー

最初の発表は「素材質感知覚の種間比較, 平松千尋(九州大学大学院芸術工学研究院),藤田和生(京都大学大学院文学研究科) キーワード:質感知覚,種間比較,オマキザル」で、生物の知覚は進化により洗練されてきた、という立場から、ヒトだけでなくサルについて心理実験を行って(これは言葉が使えないのでかなり大変)、サルとヒトとを比較しよう、それによってよりヒトを理解しよう、というものであった。 さすがの「基礎心理学会」である。 被験猿実験に使えるようにサルを訓練するのにまず何年もかかる、というのは凄い世界だ。 サルとヒトの成人でなく、サルと乳児の比較、というのも重要かもしれない。

次は「触覚変化盲探索課題における視覚障害と探索方略の影響, 太田慧(東京工業大学大学院理工学研究科),板本周平(東京工業大学工学部),坂尻正次 (筑波技術大学保健科学部),和氣典二(神奈川大学マルチモーダル研究所),葭田貴子(東京工業大学機械物理工学専攻) キーワード:能動触,探索課題,ワーキングメモリ,Change blindness」である。 東工大というのは、触覚ディスプレイからの展開なのだ、と納得できた。 最初に「裏返して見ないように」とサンプルが配られたが、これは見たら一発なのに、触覚ではまったく判らなかった。 ここで出てきた「 Change Blindness 」(変化を検出するサーチに関する視点)という概念は、今後ちょっとチェックしてみたい。 また、心理学実験に協力してもらう視覚障害者には「先天盲」「早期失明者」「後天盲」「ロービジョン」と分類される、と知った。 緑内障の僕は右眼だけだとロービジョンである。

 

その後はポスターセッションである。 考えてみれば、まったく新しい(音知学会で知っている人は少しいるものの)アウェイの学会での初めての発表なので、このポスターにすれば良かった・・・と後悔してももう遅い。 自費参加を決心して申し込みした時にどんなハイ状態だったのか覚えていないが、(立派な発表が並んでいる)口頭発表、それもわざわざ「日本語」でなく「英語」セッションで申し込むとは、無謀にも程がある(^_^;)。 幸いに時間がたっぷり確保されているので、ポスター巡りをそこそこに、プレゼン増補に注力することにして、以下のように見て回った。

「マルチスペクトルイメージングによる匂いの可視化計測, 吉岡大貴,劉傳軍,林健司(九州大学) キーワード:匂い,マルチスペクトルイメージング,蛍光」は、なんと「匂いの可視化」である。これは凄い。

「皮膚感覚による自己運動知覚(1):直線運動と振動の比較, 村田佳代子(首都大学東京),小松英海(慶應義塾大学),石原正規(首都大学東京),増田直衛(慶應義塾大学) キーワード:皮膚感覚,自己運動知覚,直線運動,振動」 と、 「皮膚感覚による自己運動知覚(2):直線運動方向と風の方向の一致・不一致, 小松英海(慶應義塾大学),村田佳代子(首都大学東京),増田直衛(慶應義塾大学) キーワード:皮膚感覚,自己運動知覚,直線運動,方向」 は、椅子に座った被験者(目をつぶる)を移動させて、そこに風を当てるとどうなるか・・・というものだった。

「主観的な緊張がベクションを強める, 妹尾武治(九州大学高等研究院/応用知覚科学研究センター),小川将樹(九州大学) キーワード:緊張,ストレス,ベクション」 はともかく、 「幻覚と幻聴を反復経頭蓋磁気刺激法によって制御する挑戦的研究, 妹尾武治(九州大学高等研究院/応用知覚科学研究センター) キーワード:幻覚,幻聴,rTMS,脳」 は凄い研究だった。 自作の「LED強烈点滅メガネ」をかけてクラクラ模様の幻視を作り、そこにrTMSという強力磁気発生器を頭のそこかしこに当てて、幻視が消える場所を探そう・・・というものだった(^_^;)。 倫理委員会でさんざん絞られて、被験者は教員とポスドク、つまり研究者本人だけしか頼めない(^_^;)、という究極のキワモノであった。

「指差しによる標的位置の伝達:方向原点の分析, 草野勉(東京海洋大学),相田紗織(東京海洋大学・日本学術振興会),下野孝一(東京海洋大学) キーワード:ポインティング,サイクロプスの眼,視方向」 と、 「ワーキングメモリに保持された内容によって注意制御に与える影響は異なる, 川島朋也,松本絵理子(神戸大学大学院国際文化学研究科) キーワード:視覚的注意,ワーキングメモリ,認知制御」 と、 「記銘時の感覚モダリティの違いが閉眼効果に与える影響, 内山朋美(九州大学大学院人間環境学府),光藤宏行(九州大学大学院人間環境学研究院) キーワード:閉眼効果,想起,感覚モダリティ」 は、およそ「読めた」研究だった。

「食事による心拍数の増減が精神テンポと知覚時間に与える影響の検討, 佐々木春香,槇野那美,蘭悠久(島根大学法文学部) キーワード:心拍数,知覚時間,精神テンポ」 は、「腹が減っていると時間的な余裕が減少する」という当たり前のことを当たり前に検証した。

「音系列における調性の知覚, 銭花亮祐(九州大学大学院芸術工学府) キーワード:調性,プローブ音法」 は、「ダイアトニックスケールは人類共通のもの」という普通に当たり前の事をなぞっていた。

そして、 「Pattern perception brought by a transient switch of high-speed flicker stimuli, Yutaka NAKAJIMA and Yutaka SAKAGUCHI (Univ. Electro-Communications) Keywords: temporal processing, flicker perception, high-speed projector」 と、 「The molecular mechanisms involved in taste modifying effect of gymnemic acids examined by sweet-sensor, Keisuke SANEMATSU (Sect. Oral Neurosci., Grad. Sch. Dent. Sci., Kyushu Univ.), Keiko YASUMATSU (TAOS and Sect. Oral Neurosci., Grad. Sch. Dent. Sci., Kyushu Univ.), Noriatsu SHIGEMURA (Sect. Oral Neurosci., Grad. Sch. Dent. Sci., Kyushu Univ.), and Yuzo NINOMIYA (Sect. Oral Neurosci., Grad. Sch. Dent. Sci., and TAOS, Kyushu Univ.) Keywords: sweet-sensor, TAS1R2/TAS1R3, gymnemic acid」 と、 「A variation of the method of constant stimuli and its performance evaluation, Ken-ichi SAWAI (Kyushu Univ.), Yoshiyuki SATO (Univ. Electro-Communications), Kazuyuki AIHARA (Univ. Tokyo), and Yoshitaka NAKAJIMA (Kyushu Univ.) Keywords: psychometric function, method of constant stimuli, perceptual bimodal distribu- tion」 と、 「Perceptual roles of power-fluctuation factors in Japanese speech, Takuya KISHIDA (Grad. Sch. Design, Kyushu Univ.), Yoshitaka NAKAJIMA, Kazuo UEDA, and Gerard B. REMIJN (Dept. Human Sci./ReCAPS, Kyushu Univ.) Keywords: speech perception, cepstrum analysis, origin shifting factor analysis」 は、英語ということで閉口した。(^_^;)

そしてここからしばし、プレゼンを改訂して、さらにKeynote'09でエクスポート出来ることも確認したが、まだポスターセッション時間は1時間も残っている16:30だった。 その後、夕食時間が18:00〜20:00とあるが、いくらモタモタと飲みつつ食べても1時間にはならないし、その後に再度のポスターセッションが約1時間(温泉に入ればもうセッションルームには来ないのでは??)、というのも強烈に冗長である。 その後に「フクロウセッション」という謎の2次会が企画されているが、ほとんど知らないアウェーの身では、まだ自分の発表をしていないので躊躇する。 つまりは、ここから時間が膨大にある、と気付いた。 こうなれば、ここはMyoプログラミング・タイムだろう。

第4世代の筋電センサ「Megachips」では、Wiiリモコンの手首ベルトをイメージして、円周上に8電極、つまり4チャンネルだけの筋電センサで、その代わり、Max/MSPのFFTで50バンド/channel、計200バンドのリアルタイム・パターン認識を実現した。 そして今、CQのために作ったmbed版の筋電センサは電極に不満があるが、ここで登場したMyoは綺麗でスマートな8チャンネルである。 さらにCQの原稿で、リサジュー認識という手法を提案したが、これは単なる2チャンネル版だったので、「手首を反らす」「手首を屈曲」という違いしか認識できなかった。 そこて思いついたのは、Myoの8チャンネルをFFTでなく、4ペアのリサジューパラメータとして、第4世代の時に近い認識が出来ないか・・・という事なのである。 8チャンネルのペアリングについては、「向かい側とのペア」「隣接チャンネル同士」という2種類を是非、試してみたい。 これはうまく行けば、ちょうど6月の音知学会(札幌)に発表できるカモ・・・という可能性まで見えてきた。(^_^)

今回は会場の「かんぼの宿」はネットが全滅、と予告されていたので、今日の午後からモバイルWiFiルータの「1 day利用」を3日、連続する予定であり、その分、どこにいてもネットは快適である。 MyoのMaxパッチに適用するための材料として、 mbed日記(3) を探索する中で、肝心のindex.htmlにバグを2つ、発見した(^_^;)。 そして遂に、欲しかったブツとして、 CQに出した原稿 と、 Maxのリサジュー実験パッチ をゲットした。 これで準備は完了である。

 

ここで夕食となり美味しい料理に美味しいビールと焼酎をいただいた。 その後、ポスターセッションの時間に部屋に篭って約30分、一気に以下のように、思いついた事を実現してしまった(^_^)。 8チャンネルの筋電情報に対して、「隣接チャンネル同士」(中央左側の4段)・「向かい側とのペア」(中央右側の4段)という2種類のリサジュー認識結果は、確かに異なっているので、この計8トラックの情報をリアルタイムパターン認識に使える可能性が浮かんできた。

そして時間は21:45、「夜のセッション」の時間となった。 これは気持ち良く、飲むことが出来そうである。(^_^)

2015年3月7日(土)

おそらくまたまた24時あたりに就寝した筈なのにいつものように6時前に起床した、知覚コロキウム2日目である。 午前の最初のセッションの1件目、 「Odor visualization: Smell by eyes, Chuanjun LIU (Grad. Sch. Inf. Sci. Elect. Eng., Kyushu Univ.), Hirotaka YOSHIOKA and Kenshi HAYASHI (Kyushu Univ.) Keywords: olfactory, visualization, odor sensor」 は、匂いセンサの可視化の報告である。 「匂い」には40万種類もあるらしい(^_^;)。 五感のセンシングについての紹介によれば、味覚は基本的な5種(Sour, Sweet, Salty, Bitter, Umami)から構成されるという。 匂いセンシングとしては、「種類」「強度」「空間的分布」をそれぞれ検出する必要がある。

次の 「逆遠近錯視に線遠近法が及ぼす効果, 鈴木公洋(太成学院大学) キーワード:逆遠近錯視,線遠近法,奥行き」 の発表の冒頭、「久しぶりの知コロ(ちころ)で・・・」という言い方で、知覚コロキウムがチコロである、と知った(^_^;)。 午後の五感シンポジウムの基調講演のTOKO先生が素晴らしい・・・というイントロが長かった。 3Dの環境世界を2Dの網膜像にして、それを再び3Dの知覚世界にする、という領域の研究で、視覚の知覚に関する初心者向け解説は有益だった。

そしていよいよ次が、自分の 「Somatic Marker Feedback in Electromyogram Control, Yoichi NAGASHIMA (Shizuoka Univ. Art and Culture) Keywords: somatic marker, electromyogram, pattern recognition」 である。 無事になんとか このプレゼン で発表を終えたが、昨夜作ったMaxパッチが最後の10分間をばっちり埋めて(引き付けて)くれて、大いに助かった。(^_^)

次の 「Fabrication of taste sensor as a science teaching material, Xiao WU (Grad. Sch. Inf. Sci. Elect. Eng., Kyushu Univ.), YusukeTAHARA, Kiyoshi TOKO, and Hisao KURIYAKI (Fac. Inf. Sci. Elect. Eng., Kyushu Univ.) Keywords: taste sensor, selectivity, science class」 は、味覚センサを作る、というサイエンス教育の話題だった。 九大は聴覚だけでなく、味覚・嗅覚に研究を特化させていて、さらにこれを教育にも活用している、というのはさすがである。

次のセッションも英語の口頭発表である。 考えてみると、たぶん午後の国際五感シンポシウムも英語なので、今日は英語の日なのだった。 「Discrimination of Indonesian herbal medicines by using electronic nose based on array of metal oxide semiconductor gas sensors, chemometrics and gc/ms analysis, Fajar HARDOYONO (Dept. Phys., Gadjah Mada Univ., and Dept. Edu., Stat. Inst. Islamic Studies), Bambang Heru ISWANTO (Dept. Phys., Jakarta Stat. Univ.), Kuwat TRIYANA (Dept. Phys. Gadjah Mada Univ. and Instr. Develop. Div., Interdiscip. Halal Res. Gr., Univ. Gadjah Mada), Chuanjun LIU, and Kenshi HAYASHI (Dept. Elect., Grad. Sch. Inf. Sci. Elect. Eng., Kyushu Univ.) Keywords: Indonesian herbals, electronic nose, GC/MS」 という発表はインドネシアの研究者で、インドネシアに多いハーブ(香辛料だけでなく薬/飲料/サプリとして普及)の「E-nose」の話題だった。 具体的には、ginger, galangal, turmeric, zedoary, greater galangal, patchouli, and wild gingerについて計測した。 ただし大学に高額な計測器材が無いので、それぞれ複数の成分に異なった反応を持つ多種のガスセンサを組み合わせて、その計測出力をニューラルネットに食わせて分析する、というもので、なんか好感が持てた。

次の 「The occurrence of the time-shrinking illusion: Comparison between auditory, visual, and tactile modalities, Emi HASUO (Kyushu Univ./Jap. Soc. Prom. Sci.) Keywords: time perception, modalities, assimilation」 は、中島先生の時間縮小錯覚ネタが、遂にマルチモーダル(視覚・聴覚・触覚)になってきたようである。 ただし発表を聞いてみると、3種類の感覚チャンネルでそれぞれ時間縮小錯覚を実験して、その似ているところと違いを述べただけで、組み合わせているわけではない・・・と質問したら、ちゃんと組み合わせた実験も準備していて、ムービーがサッと出てきた。 英語もペラペラだし、やっぱり、さすがである(^_^)。 触覚の実験で、手の甲に刺激を与えるよりも、顔を刺激する方がいい(ニューロンが短いので反応が早い)、というコメントも有意義だった。

 

そして昼食後、いよいよ午後は英語漬け、「国際五感シンポジウム(13:25-17:45)」である。 イントロの中島先生によると、こちらは「1st」ということで、これまでの知コロからいよいよInternational Symposiumに発展してきたようである。 かつて音知研が1st ICMPCを京都で開催して、後に音知学会になったこと、幕張でIWECが開催されて、それが後にECやICECに発展したことを思い出した。 以下、ここからは基調講演が2件、全体紹介講演が4件、と充実していて、メモは断片的になるが仕方ない。

最初の 「Keynote Lecture 1. Biochemical sensors for senses of taste and smell, Kiyoshi TOKO (Grad. Sch. Inf. Sci. Elect. Eng., and TAOS, Kyushu Univ.) Keywords: taste sensor, electronic nose, food scores」 は、1980年代に世界で初めて「味センサ」を研究開発したToKo先生のサーベイで、色々と収穫があった。 「TasteはVirtualである」というのは名言。 テレビにたくさん出ていて、膨大なプレゼンの中にはそのビデオが多数、登場した。

次の 「Keynote Lecture 2. What does abnormal perception tell us about normal perception? , Stuart ANSTIS (Dept. Psych., Univ. California, San Diego)」 は 「1. Illusions of motion」として「Footsteps illusion」と「Flying bugs illusion」と「Flash-grab illusion」と、 「2. Adaptation and aftereffects」 についてサーベイしてくれた。 運動視も色々と面白そうである。 コントラストが高い方がエネルギーが大きいと知覚される。 反転画像を繰り返した残像錯覚は面白い(^_^)。 運動図形の背景を運動させると錯覚する。 ローカル運動とグローバル運動とで交互に感覚が移動する。 「Motion Illusions」は検索して調べるべし。 中心視と周辺視。 縦長の長方形を12時から時計周りclockwiseで6時まで回転させ、そこから反時計周りcounterwiseで戻る、という往復CGを作るべし。 絶対に「まっすぐ立つ」と見えない。(^_^;)

ここから休憩時間に5分ほどで、さっそく上のセッションの最後の運動錯覚をMaxで作ってみた。 これ である。

そして次は、 「Overview 1. Interaction between taste and odor sensation Kenshi HAYASHI (Grad. Sch. Inf. Sci. Elect. Eng., and TAOS, Kyushu Univ.) Keywords: multimodal, olfaction, gustation」 ということで、九大の得意な、味覚と嗅覚の相互作用である。 この文脈では嗅覚の対象はsmellでなくodorというらしい。 匂いや香りが味に影響するというのは確かで、夜のセッションのためにバランタイン・ウイスキーを差し入れてくれた。 このあたり、視覚の錯覚はプレゼンでばんばんデモ出来るが、匂いは出来ないのが辛いところなのかな(^_^;)。 「Salty odor」というのも面白い。 「醤油は塩辛さを変える」というガイジンの研究はなかなか日本人には出来ないかも。 「Hot/Cool」→熱さと辛さを感じる受容体は同じ、冷たさとミントのスーッとするのを感じる状態も同じ。 動物の嗅覚は外部にだけ向いているが、人間の嗅覚は食べた後で食道からも回り込んでくるので、食べ物の味に香りが大きく影響する。 化学物質が匂いの原因ではなく、脳で知覚されたもの匂いとなる。 Odorはそれ単体でなく、他の情報/感覚を補強する。

次は、 「Overview 2. Human haptic perception, Tetsu MIYAOKA (Shizuoka Inst. Sci. Tech.) Keywords: haptic perception, mechanoreceptors, tactile illusion」 静岡理工大の宮岡先生の「触覚サーベイ」であった。 僕は筋電とピリピリばかりやっているが、考えてみれば、皮膚の構造、その下の組織、そして多種な触覚レセプタ(4種類あるらしい)、そして脳に至る神経ネットワークについて、これまであまりに未知だった・・・と痛感した。 さらに振動tactileも色々と面白そうである。 振動触覚を実験しようとすると、接触面積、振動強度、振動周波数といきなり3次元になるのだ。 2点を弁別する分解能も、身体の場所に応じてだいぶ変わる。 テクスチャの触覚分解能は100ミクロン・・・これも凄い。 触っただけではわからなくても、ちょっと動かしたらわかるというのも凄い。 4種類のセンサ「SA I」「SA II」「FA I」「FA II」がそれぞれ別の出力を出すことでテクスチャを認識する。 「ラフさ」は対象物体表面のparticleの大きさ(最小1ミクロン未満)で知覚する。 晩のデモセッションでは「触覚の錯覚」をやってくれるそうである。(^_^)

次の 「Overview 3. Neural Dynamics of visuo-tactile integration related to subjective feeling, Noriaki KANAYAMA (Hiroshima Univ.) Keywords: visuo-tactile integration, EEG, body representation」 は、主観的感情? 自己意識? について、脳科学の立場からの解説である。 乳児が「自己」を意識していく(ビデオ画面の中の自分を自分と判る)のは2歳〜3歳あたり。 マネキンと自分の顔をモーフィングして(ラバーハンド錯覚のように触って)どこで自分と判るか、という実験。 頭の移動をトラッキングしてHMD内の顔が動く場合と動かない場合(どれが自分か)を比較。 脳波のN170とN250が自分と他人の識別に対応している。 RHI - 視覚情報と触覚情報を組み合わせると錯覚する。 視覚+触覚で自己意識が高まるとガンマ波の脳波が出る。

最後の 「Overview 4. About time processing and processing time in the auditory and visual modality, Gerard B. REMIJN (Dept. Human Sci./ReCAPS, Kyushu Univ.) Keywords: time perception, sound, vision」 は視覚と聴覚のモダリティでtime processingとprocessing timeについて、というもの。 左右の耳に到達するサウンドの0.7msecの違いから空間的定位を知覚する。 フラッシュから24msec遅れたサウンドを同時と知覚する。 フラッシュから67msec遅れたサウンドは「別のこと」と知覚する。 錯覚のデモmovieを見て違いが判る参加者が多い・・・さすが知覚コロキウム(^_^)。 視覚よりも聴覚の反応の方が速いのは、寝ている時でもサウンドで危険を知覚する必要がある・・・という進化的理由。 話している時のリップシンクに比べてハンマーの音の方が早く対応する。 クロス移動する2物体が衝突する瞬間に音が出ると反発して見えて、遅れて音がすると通過して見える。

 

・・・そして「集合写真撮影」と「夕食」を経て「デモンストレーション・セッション」になった。 当初予定では、 「Several examples of tactile illusion, Tetsu MIYAOKA (Shizuoka Inst. Sci. Tech.)」と「Taste sensor, Yusuke TAHARA and Rui YATABE (Grad. Sch. Inf. Sci. Elect. Eng., and TAOS, Kyushu Univ.)」と「The effect of gymnemic acids on taste and the recovery by γ-cyclodextrin, Keiko YASUMATSU (Div. Sensory Physiol., TAOS, Kyushu University), Keisuke SANE- MATSU (Sect. Oral Neurosci., Grad. Sch. Dent. Sci., Kyushu Univ.), and Yuzo NINOMIYA (Sect. Oral Neurosci., Grad. Sch. Dent. Sci., and TAOS, Kyushu Univ.)」と「Auditory Grammar in music: Demonstrations, Yoshitaka NAKAJIMA (Dept. Human Sci./ReCAPS, Kyushu Univ.), Takayuki SASAKI (Dept. Psych. Behavioral Sci., Miyagi Gakuin Women’s Univ.), Kazuo UEDA, and Gerard B. REMIJN (Dept. Human Sci./ReCAPS, Kyushu Univ.)」と「Demonstrations of the perceptual roles of power-fluctuation factors in Japanese and English speech, Takuya KISHIDA (Grad. Sch. Design, Kyushu Univ.)」であったが、早めに夕食会場から部屋に戻って、なんと30分間で、Myoを使ってサウンドを鳴らす、という Maxパッチ をアドリブで作って、上のように飛び入りデモをやってしまった(^_^;)(^_^;)。

 

・・・そしてここまで加筆して、飲み続けて「フクロウ・セッション(二次会) Owl Session (21:30-)」に突入して、嵐のような2日目が終わった。

2015年3月8日(日)

前夜は25:30頃に部屋に戻って寝たが、またも起床は6時過ぎだった。 体内時計はちょっとのことでは崩れないようだ。 セッション部屋の学生によれば、終わったのは午前3時らしい(^_^;)。 今日はSUACは点検のために停電するので、メイルもチェックする必要が無くて、気楽である。

そして最終日、日本語の口頭発表が3件である。 セッション前に、昨日の時間錯覚デモを再現する Maxパッチ を10分ほどで作った。 最初の 「感情喚起が有効視野に及ぼす影響, 増田奈央子(久留米大学大学院心理学研究科) キーワード:感情価,覚醒度,有効視野」 は、タイトルの通りで、感情価と覚醒度が有効視野に及ぼす影響について視覚実験によって検討を行ったものである。 この手の研究でいつも思うのは、提示する画像をどう選んでいるかである。

次の 「他者の視線知覚における空間の幾何学的構造, 森将輝(慶應義塾大学大学院),渡辺 利夫(慶應義塾大学) キーワード:視線知覚, 空間知覚,アフィン変換」 では、ヒトの「目」が他の動物よりもコントラストが強く、コミュニケーションに活用するよう進化してきたというのが、まず面白い。 進化的な視点が常に重要になりそうだ。

「MOT課題における両眼視差定義オブジェクトの奥行き位置効果, 金谷英俊(愛知淑徳大学人間情報学部) キーワード:MOT 課題,両眼視差,図と地」 MOT = Multiple Object Tracking。 なかなか面白かった。

そしてここから昼食、その後日田駅に行って荷物をパスターミナルのコインロッカーに入れて、日田散策ツアーがあった。 フォトレポートは、 初めての日田 を参照されたい。 また、フォトレポートには自分が写っていないが、後日、上田先生の撮った写真が公開された中で、僕がどこかに写っているのは以下である。

2015年3月10日(火)

昨日は有休で某マラソン34曲、そして次のマラソンも予約した(^_^;)。 先週までの学会3連チャンの記録を ここ に加筆して、いよいよ「次」である。 案内が届いていたSketching2015は、まだ確定しないもののフライトを調べた範囲では、なんとか前期最終の「メディア造形総合演習II」の最終合評の翌日に出発すれば、時差の関係で間に合いそうだ、という事で参加費を支払った。 そして6月の第1週末にバッティングしていた、時間学会(山口)と音知学会(札幌)の2択については後者を選択し、、今回の筋電ネタと内受容感覚を組み合わせたタイトル「内受容感覚コントローラとしての筋電楽器〜癒し系エンタテインメントのために〜」と、アブストラクト「外受容感覚(五感)に加えて最近注目されている内受容感覚と情動/感情と脳内プロセスモデルの関係について、筋電楽器のジェスチャ認識研究で発見した無意識下のリラックス効果の適用を検討し、癒し系エンタテインメントの可能性について考察した」で、えいやっと発表申し込み、ホテル予約、フライトチケット購入まで完了させてしまった(^_^;)。 これで、何が何でも研究を進めなければならないところに自分を追い込んだ。 さらに気合いで、ネットからもう1台、 Myo を1個、購入手配した。 いつ届くか、楽しみである。

2015年3月11日(水)

翌日に今シーズン最後の後期入試を控えたこの日は何も予定がなく、電子情報通信学会の色々な研究会開催予定を調べていて発見した、6月の新潟での「福祉/音声/聴覚/パターン認識メディア理解一般」研究会での発表に向けて、Myo絡みのアイデアを思い付いて着手することにした。 既に2010年に これこれこれ で発表していた研究のMax/MSPパッチを改造して、FFTでなくリサジュー解析によって、Myoで出来る限りのパターン認識をやってみよう、という挑戦である。 うまく行ったら、こちらの研究発表も申し込んでみる、という作戦である。 そして、今年の「エンタテインメントコンピューティング2015」は9月末に札幌、という情報も発見、これは音知学会に続いてまたまた札幌を目指す気になった。こちらはまだ申し込み期限まで余裕がある。

さらに、今年のFITはいつもの9月上旬でなく「中旬」である、というアナウンスが届いた。 会場は愛媛大学である。 9月の教授会を欠席することになるものの、いつもの上旬だとアルスエレクトロニカとバッティングするので参加できなかったFITにも行ける可能性が出て来た。 ・・・そして午後いっぱい、「数年前に作った自分のMaxプログラムを解読しつつ改訂する」、という苦難の作業に直面したが、結局、解決しないままこの日が終った(^_^;)。 明日は後期入試、監督者要項によれば朝8時に集合して4時間の実技監督、さらに多数の面接があり、終了は17時過ぎである。

2015年3月13日(金)

昨日の後期入試のデザイン学部デザイン学科(この新入生より、これまでの生産造形学科とメディア造形学科と空間造形学科を合体させたデザイン学科となる再編の新体制に突入)入試の、出願時点での倍率は16倍(定員12人に対して応募191人)であった。 鉛筆デッサン4時間の試験室に入ってみると、18人の部屋に16人の受験生が来て、つまりこの中で合格するのはたった1人、という倍率である。 いつものように、試験4時間プラス事前入室、計280分をまったく座らず、立ち続けるという苦行(によって心の中で受験生を応援する、という自分だけの儀式)を無事に達成した。 9時〜13時のこの実技試験に続いて、午後には面接があり、当初予定の21人より減った13人の面接を終えるとクタクタになったが、これで今シーズンの入試も終わりである。

そして帰宅すると、CQ出版からの封筒が届いていた。 上のように、遂に「インターフェース」特集記事の原稿料の通知である(^o^)。 だいぶ昔に「トランジスタ技術」と「インターフェース」に執筆していた頃に比べて、ちょっと1ページあたりの原稿料が高くなっていたのは、以下のようにWeb版などについての再利用を許諾しているからなのだ、とこの通知で知った。

「原稿料624,400円」に喜んではいられない。源泉徴収63,751円が引かれて振り込まれるのは560,649円だが、この2割、つまり約112,000円を、来年3月の確定申告で税金として取られる(^_^;)。 さらに、今回の甲府と日田の2回の出張は、SUAC研究費の旅費枠をほぼ使い切っていたので、超過分を自費で行く、という事でこの原稿料を当てにして我が家の家計から「借りて」いたので、それも奥さんに返さないといけない。 忘れないように自分のためのメモとして端数を捨てて整理したのが以下である。(^_^;)

収入
	原稿料 560,600円

支出
	翌年度確定申告税金 112,000円
	甲府 17,500円
		交通費 20,000円
		宿泊費 15,000円
		研究費旅費残額 -17,500円
	日田 24,500円
		(宿泊費 27,000円 自己費用負担済)
		参加費 -5,000円 (研究費から出る)
		博多ホテル 6,500円
		フライト 14,000円(片道分はマイルから支出)
		e-wing 5,800円
		博多-日田高速バス 3,200円
	計 154,000円 → 奥さん(家計)へ

差し引き 406,600円  → 自分カードへ(^_^)

ということで、約40万円が今回のCQ・筋電記事の実収入ということになったが、これはもともと当初のイメージよりちょっとだけ多く、気合いのカラオケマラソンにおよそ20回ほど行ける、というだけでも嬉しい。 頑張った甲斐があるし、この筋電ネタは2015年の研究の中核を成すものに発展させる可能性もあるのだ。 そのためにも、一昨日やりかけて止まっていた、Myo+リサジュー解析による筋電パターン認識を実現していかねば。 昨日の4時間のデッサン実技試験監督の間、何もメモを取らないで頭の中だけではあるが、あれこれ検討していた内容を反映させていこう。

・・・そして苦闘すること5時間、過去に作ったMaxパッチの主要部分をかなり全面的に書き換えつつ、遂に完成してしまった(^_^)。 FFTなど使わなくても、2電極の配置パターンを4種類それぞれ8チャンネル電極、計32チャンネル・パラメータでのリアルタイム・リサジュー解析によるパターン認識は、過去に200バンドFFTで4チャンネル筋電センサに対して実現したものよりも高性能である事が判明した。 これはもう、6月の音知学会には予稿集論文が書けるレベル、はっきりとした進展である(^_^)。 どうしてどうして、Myoもなかなかやるものだ。

2015年3月14日(土)

久しぶりに平穏な週末である。 これから予定が入るにしても、常に世界に公開している スケジュール を見てみると、とりあえず今日の段階で、今週を入れて5週連続で、土日に予定がまったく入っていない。 その後はいつものあらえっさっさであるが、何か予定を入れたくなり、ちょっと水面下で工作を開始した(^_^;)。

研究室に出てみると、いくつものメイルや情報が届いていた。 オンライン注文したMyoは、発送するので来週には「5 business dayで届く」とのこと。 先月、SUAC出入り業者に注文した時には「いま手元にある1台は46,000円で出せるが次は3ヶ月以上かかる」と言われたが、翌月にはオンライン199ドル(+送料20ドル)で1週間で買えるのだった。 そしてさっそく、Fedexから届いたメイルによれば、上のように既にカリフォルニアから集荷して、日本の浜松に向けて発送していて、到着は19日の18時だという。 凄い時代である。(^_^)

さらに、Sketching2015について、主催者のMike Kuniavskyからのメイルが届いた。 参加申し込みの際に質問していたのは、Sketching2015会場の Biosphere 2 に行くための空港は「Tuscon」と「Phoenix Sky Harbor」の2つがあるが、上のようにクルマ(つまりタクシー(^_^;))で1時間とか2時間半とかの距離であり、試しに調べたフライトだと、近いTusconは深夜着・早朝発でタクシー一択である、ということなのだ。 Mikeからのメイルは以下のようなものだった。

Several of you have asked about transportation to Biosphere 2 and around there. 
Tuscon is the closest airport. It's about an hour's drive. Phoenix Sky Harbor is a 
larger airport, but it's about 2.5 hours away in a car.

To my knowledge there's very little public transportation in Tuscon (there's a bus 
system, but I don't know if it goes out to Biosphere 2 and do you really want to 
figure out how to transfer between busses in 100-degree weather?), so if you're 
looking for a ride to Biosphere 2, please let us know and we'll try to arrange it or 
provide a guide.

そう、真夏のネバダ州は「華氏100度」、つまり摂氏38度という暑さなのだ(^_^;)。 仕方ないので、上記のフライトスケジュール案を知らせて、アドバイスを求めた。 これまでの 海外渡航経験 から、深夜24時に空港に到着してタクシーでホテルに向かうのも、出発のために朝4時にホテルにタクシーを呼んで空港に向かうのも慣れっこではあるが、なるべく通常の時間帯にしたいのだ。 質問メイルに対して、向こう(カリフォルニア)はまだ深夜でMikeは起きていたのか、30分ほどで「スタッフに調査を頼んだので来週火曜日までに知らせるよ」と即答メイルが届いた。 即刻「OK, Thanks !!」と返信した。 ・・・いい時代である。(^_^)

さらにネットニュースを巡回していると、上のような「PlayWatch」をタカラトミーが出す、というのを知り、速攻でオンライン注文した。 iPhoneも携帯もスマホも持たない僕にとって、AppleWatchは何もソソラレないのでスルーしていたが、これはAppleWatchよりもクールだ(^_^)。 6歳以上の子供が、これで写真や動画を撮ったり録音したりゲームをするのだという。 僕が子供の頃(半世紀前)には、スーパージェッターが「流星号」を呼び出す腕時計型の通信端末「タイムストッパー」(時間も止められる !!)に憧れたものだが、その時代にも、まさか静止画や動画が自在に撮れる機材がこんなに小さくなるという発想は無かった。なんという時代だぁ。(^_^;)

そして午後までかけて、昨日の筋電認識システムのちょっとした改良(移動平均を20段→40段にして、さらに生の筋電信号と、全波整流+移動平均処理後の筋電情報を表示するウインドウの追加)を思い付いていたのでバージョンを上げて実験し、さらにジェスチャー認識の性能が向上したのを確認した。 Myoが提供しているジェスチャー認識は、脱力を入れて5パターンであるが、ここでは全29ジェスチャーの中で、けっこういい感じで10ポーズほどは良好に再現できる。 その模様を、とりあえずは自分一人しかいないので写真に撮ったのが これ である。 これはいつものように記録動画を撮ってYouTubeに上げたいので、アカペラ1回生に打診したところ、七海ちゃんと花波ちゃんが水曜日の午前に研究室に来てくれる事になった。 これで準備万端である。(^_^)

ここで、まだ時間があったので、この筋電ネタでの学会発表について作戦を検討した。 新年度(4月以降)で、現在確定している国際会議はSketching2015(ネバダ)、3/20の採択結果待ちなのがNIME2015(ルイジアナ)である。 国内では、時間学会と重なっている日本音楽知覚認知学会2015年度春季研究発表会(札幌)は既に発表申し込みを完了していて、あと可能性として候補にあるのが、以下の4つである。

音学シンポジウムはポスター発表のみ募集で、デモりたい身としてはちょっと物足りないのと、チュートリアル部門でmbedネタで応募したNIME2015の採択/不採択によって、旅費の残額がだいぶ変わることがあり、なかなか決めかねているのである。 ・・・とここまで書いたところで、なんと某SNSのローカルコミュで「突発カラオケオフ」の話が勃発した(*^o^*)。 これは天の声だ、とばかりに食い付いて、あたふたと大学から浜松駅に向かうことにした。 あとは明日である。

2015年3月16日(月)

この日は午後に翌日の卒業式のリハーサルがあるだけ、というお仕事日で、ぼちぼち音知学会の予稿を書いていたところに、 ゼミの卒業生の金子冴子さんが研究室にやってきた。 的場先生に依頼されての特別講義で、今日一日、後輩に仕事ぶりを紹介するのだという。 彼女は、入りたかった サン宝石 という会社に就職して、上にあるようなWebページなどもほとんど全てを作っていて、社長も一目置いているという(^_^)。 最近では製品紹介動画をYouTubeに置いていて、 この動画 に登場するのは彼女本人であり、ナレーションもボイスチェンジャーを使って自分でやっているという。 素晴らしい。(^_^)

そして昼前にちょっと買い物に出て「観葉植物用の土」を仕入れて、以下のように1106研究室の主役を交代した。 詳しい解説は 葉から芽 としてまとめた。 南国の植物なのに、浜松の軒先の寒風に耐えた強い奴である。 どうなるか、楽しみに眺めていこう、

そして、午後には講堂での卒業式リハーサル(今回は大学院デザイン研究科の呼名を担当)に1時間ほど出たりする合間に、音知学会の予稿をかなりの気合いで書き進めた。 原稿は最大6ページだが、一気に3ページほど出来てしまい、まだまだ書きたい事があるので、執筆後半にはいかにカットするか・・・に悩みそうである。 その後は今度はお仕事パソコンの前でウトウト・・・である。 1月末から耳鼻科で処方してもらっている花粉症の薬は、松竹梅の「竹」を飲み続けているが、午後に猛烈に眠くなって生産性が低下するのが玉にきず、しかし仕方ない。(^_^;)

2015年3月18日(水)

昨日は 卒業式 だった。 そして今日の午前には、七海ちゃんと花波ちゃんに手伝ってもらって Myoによるジェスチャ認識デモ の記録を撮って、 YouTube にも上げた。 午後には、的場先生が久世さん夫妻を呼んで開催しているというArduinoワークショップの、電子制御機器制作室のコンピュータ環境設定の手伝いをした。 これで1日が終った。(^_^;)

2015年3月20日(金)

今年の花粉症はかなり酷く、昨日の午前中にはいつもの耳鼻科に行き、いつもと違う強い薬をもらった。 ちょっとワークショップは覗けそうもなくパス、絶不調である(^_^;)。 そして午後にかけて、音知学会での発表予稿の「とりあえず5ページ半バージョン」を書いてプリントした。 これはすぐに送らず、ちょっと寝かせて修正していく方針である。

さらに、6月の新潟での電子情報通信学会PMRU研究会への発表参加を、気合いで申し込みしてしまった。 会場の「新潟大学駅南キャンパス[ときめいと]」というのは、調べてみるとなんと「新潟駅南口から徒歩3分」とあった。 これは楽勝である。 木・金の開催で「福祉情報工学」・「音声」・「聴覚」・「パターン認識・メディア理解」の4研究会の共催ということは中身満載だろう、という事で、とりあえず1日目の午後か2日目の午前の発表希望、としたが、翌日が土曜日なのでゆっくり後泊することにして、新潟駅前でなく、敢えて新潟最大の繁華街、古町のホテルを予約した。(^_^;)

・・・そして今日になった。 薬がそこそこ効いて(ステロイドなので本格的に効いてくるにはあと1-2日)、耳管炎のような症状は多少は楽になった。 昨夜は音知学会発表予稿仮プリントを見直してから寝たが、寝ている間にも思考は進むもので、なんとも遠大なストーリーと研究の作戦が朧げに浮かんできた。 今日は午後に業者打ち合わせと教授会があるので、午前中はここに没頭である。 そして晩には自宅にMyoが届く(Fedexのページで確認済み)ので、明日には「ダブルMyo」のテストである。 明日にはおそらく、NIME2015の結果通知も届くので、これでおよそ今年前半の概要が見えてくることになる。

・・・と作業していると、Cycling'74からのメイルが届いた。 まだ解決していなかった、新しいMax7のインストール問題で、対応を考えると言っていたので「どうなってる?」と投げかけてみたら、ほぼ即答で返ってきて、準備は出来ていたようである。 プロキシサーバを経由してオンラインオーソライズするために、Max7のPreferencesに「URL」を追加した、新しい「Max7.0.2」をダウンロードして試してみると、上のように進展があって、ユーザ登録までは出来たが、肝心のオーソライズ・トークンをコピペしたのに叱られてしまった(^_^;)。 あと一歩、というところだ。

・・・そしてちょうどお昼前に、音知学会の発表予稿が完成してしまった。 これ である(当日まではマル秘)。 一読するとなんのこっちゃ(^_^;)というpaperになったが、どうしてどうして、これまでの勉強と考察の成果がぎっしり凝縮されているのである。 原稿提出締め切りまであと1ヶ月もあるが、もうこれでOKということで発送し、受領まで確認した(^_^)。 一つ進んだ、というのは、嬉しい情動を喚起するのだ。 ただし体調はイマイチで、咳が出て鼻声である。風邪でなければいいのだが・・・。

2015年3月21日(土)

この日は、前夜にFedex(国内は日通)から届いた2台目のMyoを以下のように研究室に持っていって、大きな目標は「同時に2台のMyoを使えるか」のテストである。

Myoサイトの Downloadページ に行ってみると、ファームウェアが「Myo Firmware 1.2.955 (Mar 5, 2015)」になっていた。 そこでこれをまず落として、mbedのNucleoF401REとまったく同じように、Myoと繋いだUSBケーブルをMacに繋ぐと出現してマウントされるディスクイメージに、ダウンロードしたHEXをドラッグ&ドロップして、2個のMyoとも最新にした。 この作業だけは、Yosemiteでなくお仕事Mac(10.6.8)上でもちゃんと出来る。

さらに Downloadページ のMyo Connectも対応するように「Myo Connect for Mac 0.9.1 (Mar 11, 2015) 」となっていたので、これも落として、YosemiteのMacBookAir内に上書きインストールした。 実験すべき事はたくさんあるので、順に落ち着いてチェックである。 まずは新旧のMyoをとりあえず明示的に区別するために、これまで使って来たMyo1を左手に、新しく届いMyo2を右手に嵌めることとして、それぞれのUSBドングルも「左手用(Myo1)」と「右手用(Myo2)」ときちんと区別することにした。 まず、左手にMyo1を付けて、USBドングル「左手用(Myo1)」を経由して最新のMyo Connectを起動して接続すると、これまでとまったく同様に接続できた。 この確認からである。

次に、上の状態からMyo2を右手にはめてみると、左手のMyo1がバイブした。 ただしこれは、左手を使ったアーティファクトによるものか、通信が確立している左手のMyo1系と違うBluetoothが来たためなのかは不明である。 とりあえずこの状態でも、左手の通信は良好である。 そこで次に、両腕にMyoを付けた状態で、いったんMyo Connectを終了させてから、再起動してみた。 すると、USBドングル「左手用(Myo1)」だけが挿さっていることもあり、Armband Managerは左手のMyo1とだけ普通に接続した。

そこでいよいよ、USBハブにさらにUSBドングル「右手用(Myo2)」も挿して、Myo Connectを終了させてから、再起動してみた。 すると、画面は左手だけしか出なかったが、「+」というボタンを押すと、2番目のMyoが登場して、無事に上のように、ちゃんと2個のMyoは個別に通信が成り立つことが確認できた。 「+」ボタンを試しに押すと下のように、さらにマークが現れた(しかし存在しないので何も出来ない)ので、見たところでは同時に4個か5個のMyoまで、Myo Connectは対応しそうである。

そこで両方のMyoと通信している状態で、Myo Daemonのビジュアライザを起動してみると、両方のMyoからの情報を交互に受けているらしく、3次元表示している立方体は痙攣したように動いた(^_^;)。 つまり、Myo Daemonは標準では「1個のMyo」にしか対応していないのであるろう。 ただしMyo Connectが複数のMyoに対応するということは、その識別IDを操作できれば、同時使用は可能な筈だ。

そして最後のチェックとして、Myo Connectを終了させてから、右手のMyo2を取り外して充電状態にして(Bluetooth通信が自動的に止まり認識されなくなる)、USBハブからUSBドングル「左手用(Myo1)」を抜いた。 つまり、左手のMyo1と、USBドングル「右手用(Myo2)」とで通信できるかどうかのいじわるテスト(ペアリングされているか)である。 結果は、Myo ConnectのArmband Manager画面には、これまでに登録されている2個のMyoが現れていて、しかし停止させたMyo2とは通信できないまま(接続をトライし続けているのでdisconnectした)、そしてMyo1の方では何事もなく通信できた。 つまり、USBドングルには個体識別情報は無いのだ。

そしてさらにひらめいて、この状態で、つまりUSBドングルが1個の状態で、再度右手にMyo2を嵌めてみると、ちゃんとMyo ConnectのArmband Managerは両方を区別して通信できた。 要するに、MyoはBluetoothクライアントだが、USBドングルは1個で複数のMyoと通信できてしまうのだった(^_^)。 これで全体像が見えたので、以下のように2個のMyoに「Left」と「Right」と命名しなおした。

・・・しかしここからが、本当の五里霧中の富士樹海である(^_^;)。 Myo ConnectのArmband Managerは、2つのMyoをちゃんと区別して認識した。 そしてMaxパッチを改訂して、OSCのポートを7000と7001のダブルに用意してみると、試しのProcessingスケッチから区別してアクセスできる事を確認した。 つまり最後の壁は、ProcessingでどのようにMyoの情報を区別して取得するか、である。

ここでMyoサイトの ユーザフォーラム に行って、試しに「multiple Myo」で検索してみると、 How many Myos on one dongle? には「3個まで使えたよ」などと書かれている(^_^;)。 ここで改めて ユーザフォーラム の先頭にある、最新で最古の開発者の Myo Developer FAQ (Read this first!) を見てみると、なんと 「Can two Myo armbands be used simultaneously?」 という質問に、明快に 「Yes, the Myo SDK will officially support the simultaneous use of two Myo armbands, with one on each arm. 」 と答えている。 つまり、2個使いは出来るのである。

そこでとりあえず、MyoとProcessingのライブラリから Myo.javaCollector.java を発掘し、さらにMyo SDKの奥底を探して、ずばりのタイトルの multiple-myos.cpp というのを探し出した。 しかし、ここからは牛歩である。 なんせProcessingもJavaも中途半端に忘却の彼方、それも十分に極めていない世界なので、手探りの試行錯誤しかない。 multiple-myos.cpp から「onPair()」という宣言をして、データとしては一気にまとめて受けとって後で分配するらしい・・・と判ったものの、Processingエラーが起きないように記述する方法が見当たらない。 これぞ「未知なるプログラミングの迷宮」、そう簡単には脱出できない、苦しい楽しい世界なのだ(^_^;)。 ここで一歩も進まなくなり、この日が終ったが、解決の道筋はまったく見えない。

2015年3月22日(日)

この日は1時間ほどあれこれ調べたが、追加で DeviceListener.cpp をさらに拾ったぐらいで、他にまったく進展ナシ。 この壁は高いのだ。(^_^;)

2015年3月25日(水)

上の日記から3日が経過したが、Myoについて言えば、まったく何も進展していない(^_^;)。 いよいよ新学期が近付いてきて、なんせデザイン学部は開学以来の3学科体制だったのが合体してこの新入生からデザイン学科100人(実際は約120人)となり、そのための準備とかのあれこれが大変なのである。 そのあたりに忙殺されているうちに、Myoに取り組む時間がまとまって取れず・・・という日々である。 その分、新学期、あるいはその翌年のSUAC全学コンピュータ一新、に向けての準備が進んでいるのだ。

昨日は有休で、アカペラの新2回生の4人と9時間マラソンカラオケを十分に堪能して終わった。 そして今朝になって遂に、英語メイルが65本ほど行き来していた、Cycling'74とのやりとりに大きな進展があった。 SUACのproxyサーバがあるために、Max7がオーソライズ(インストール)出来ない、という1年後にとても困る状況が、ようやく解決しそうである。 既に1106のYosemiteのMacBookAirと、さらになんともう1台のOSX10.7のMacBookAirに入れたMax7が、試行的なものであるがオーソライズされてトライアル版(30日限定、正規版と同様にパッチの保存も可能)となった。 さすがのCycling'74、Max7のバージョンを上げて改良して、proxyサーバを経由してもオンライン登録が出来るようにしてくれたが、まだ一部に未解明の問題も残っている。 そしてなんと、別に主としてアカデミックサイトへのオーソライズ手法として、新しいもの(keyfile)を作って、僕はその実験に協力して確認したわけだが、「出来た」ところなのだ。 今後も仕様は代わり得るのでここでは詳細は書かないが、とりあえず、よかった。(^_^)

さらにNIME2015からメイルが届き、Tutorialのproposalとして出したpaper(←このような扱いには本質的に無理があるのだが)に対してrejectの通知が来た。 これはまぁ、もし通ってしまったら休講とかあれこれ何とかしよう、と思っていたものなので、40%ほどは想定内である。 これで今年の海外出張については、「Sketching2015」(米国ネバダ州)がまず確定して、あとはdefaultであれば9月上旬のArs Electronicaである。 サイト に行ってみると、上のように今年のフェスティバルが「9月3日から9月7日まで」と告知されていた。 海外渡航歴 を見てみると、これまで過去に9回、リンツのArs Electronicaに行っているが、他の予定と絡めずそれだけ、というのはたった2回であり、たいていは何かと絡めて一緒にリンツにまで行っている。 そこで今回も、アルスの日程が確定したところで、ここに隣接してついでに行ける会議とかフェスティバルは無いか・・・とまずは探すことにした。

また、今年後半の会議案内メイルを整理していると、シンガポールで 2nd International Symposium on Sound and Interactivity という、そそられるタイトルの隔年開催(といってもこれが2度目)の国際シンポジウムを発見した。 シンガポールは シドニー(NIME2010) 行きで経由しただけでなく、2003年には学生2人も同行して ICMC2003 で行っていたところである。 ちょっとあまりに暑い時期ではあるが、建物のエアコンは良好だろうし、なにせ大人な国なので、これもいいかもしれない。 何より、まだ応募期限まで時間が十分にあるし、こちらのネタも十分にあるのだ。 さすがに8月19日〜23日というこの会議から連続してリンツには向かえないので、ここは悩ましい「二択」である。

朝に届いていたもう1本のメイルは、僕の EC2009 のチュートリアル受講者としてロシアから参加して知り合いになり、後には僕が SYNC2010 のコンテスト審査員・レクチャー講師・新作初演作曲家として招待されるきっかけとなった、研究者・Denis Perevalov氏からのものである。 OpenFrameWorksの本を出し、アーティストとののコラボレーションでインスタレーション作品の実現にも活躍している彼の最新作は これ である。 素晴らしい(^_^)。
さらに朝からメイル数本が行き来して、まだここには書けない、4月からの新プロジェクトも準備が大きく進展した・ 実はこれは新年度、さらにもしかするとその次あたりまで続く大ネタであり、状況によってはシンガポールとリンツを両方とも可能にしてしまう破壊力を持っているのだが、ここには書けない。(^_^;)
春休み期間に東京でインターンシップをしている藤石さんからのメイルもあり、4月初旬にMyoやleap motionについての相談で研究室に来るアポが入った。 出来れば、それまでに「ダブルMyo」の道筋をつけてみたいが、これは何とも言えない(^_^;)。
ここまであれこれ(実際にはさらに今後に向けた調べと仕込みをあれこれ画策(^_^;))して、最終的に5月の「音学シンポジウム」はポスターセッション以外の企画情報がまったく無いことを理由にポスター応募を断念バーグして、帰宅まで残り2時間を切ったので、ダブルMyoトライを明日に頑張ろう、と決めた。 残り時間は、いよいよ最後まで残っていたダマシオ4部作の最後の1冊「Self comes to Mind」の残りを読み進めた。 だいぶ見えて来たが、ダマシオのモデルを頭に日々を過ごすとしっくり来るところも少なくないが、かといってダマシオに騙されてはいけないところ(^_^;)もあるのだ。

2015年3月26日(木)

僕はいつも自分の予定をWebに上げて世界に公開しているが(^_^;)、以下のようになんと、今日から4日間は奇跡の「空白」である。 こんな事はおそらく1年間に1度あるかないかの事であり、これはまさに「ダブルMyoに挑戦せよ」という天の声である。 朝イチでCycling'74から届いたメイルに関係して午前中あれこれ動き回ったものの、ここは基本的に没頭モードである。

まずは。適当に実験していたProcessingスケッチとMaxパッチを改めて「doubleMyo_01」として整理した。 ここではバイブだけでなく、Maxからのコマンドで「myo.withEMG()」と「myo.withoutEMG()」とを切り替えて送り、必ず出ている9軸センサの情報に対して、同時にEMG情報を送ったり止めたり出来る事を確認した。

そして、2個のMyoを充電状態(これだとBluetooth通信をしない)状態から、まず左手Myo(1)だけ腕に取り付けると、上のように、Myo(1)だけ通信接続して、Myo(2)はBluetoothを探しに行かない状態となった。 そして次に、右手Myo(2)も腕に着けると、以下のように、両方のBluetooth通信が同時に確立した。

ここで、両方のMyoとArmband Managerが通信しつつ、Processingスケッチは1個のMyoに対応した状態のまま、Maxパッチの画面を良く見てみると、下のように、9軸センサのグラフは、2つのMyoからの情報が一緒に入っていて、細かくヒゲのようになっている。 一方、EMG情報の方は、MaxからのコマンドでON/OFFできるが、片方のMyoだけの情報しか出て来ない。 ここから、Armband Managerで2つのMyoの「connect」と「disconnect」をあれこれ試してみたが、両方OFFから最初に繋がった方、というわけでもなく、常に右手のMyoだけだった。 昨日は左手のMyoだけだったような記憶があるが、いずれにしても、9軸センサの情報と、EMG情報とでは、伝送プロトコルの構造が基本的に異なるようであり、対応は切り分けて考える必要がありそうだ。

ここから午後は、MacBookAirのデスクトップには、Armband ManagerとProcessingスケッチとMaxパッチ、さらに Myo.javaCollector.javamultiple-myos.cppDeviceListener.cpp とをJeditで広げて、あれこれひたすら試行錯誤の実験である。 右手Myo(2)と左手Myo(1)のどちらを掴むか、というルールについては、Armband Managerでの個々の「connect」・「disconnect」とProcessingパッチの起動・終了を組み合わせた結果、 「Processingスケッチが起動する直前にArmband Managerで認識されている方のMyo」である、と判明した。 Processingが走る時にMyoを宣言して設定する、その時に生きているMyoが対象となるようだ。

・・・そして15時を過ぎたところで。今日の挑戦は終了とした。続きは明日。 午前、午後にそれぞれ2時間も集中すれば、もう限界である。 Myoの圧迫の圧力は低いとはいえ、腕の電極の跡は1時間以上は残る。 ハンダ付けなどの単純作業で朝から晩まで連続、というのはあるが、この手の作業は集中が命であり、昨夜のようにまた今夜も攻略のアイデアが浮かぶことを期待しつつ、オシマイである。 残りの時間はまたまた、騙シオ、もとい(^_^;)ダマシオ本で過ごすことにして、夕方には遂に読破した。

この読書の時間を使って、お仕事Mac miniを、遂に10.6から10.7 Lionに上げてしまった(^_^;)。 実はMax7のあれこれに絡んで、Yosemiteの新しいMacBookAirだけでなく、あと2台あった10.6のMacBookAirを一足先に10.7にしていて、それを何度か出張に持参して、それほど問題がない、と確認していたのである。 そこで今日は午前中から午後にかけて、並行して研究室の2台のMacBookも10.6から10.7にしていて、せっかくなので最後のIntel Macであるお仕事用miniも・・・という事なのだ。

これで1106研究室のMacのうちIntel Macは9台とも全て、10.7以上となった。 PowerPCのMacは7台とも全て10.4.9であり、あと1台だけclassic(Mac OS9)が生き残っている。 マルチメディア室のMacはあと1年間、10.6.8のままなのでちょっとズレてくるが、ここは辛抱である。 ちなみに1106研究室にあるWindowsは、95と98が各1台(^_^;)、そしてXPが3台であるが、まともに立ち上がるのは1台しかない。 先日、電子制御機器制作室でのワークショップの手伝いで「Windows8」というのに触れたが、どうして皆んな、あんなに死ぬほど遅いコンピュータを好き好んで使っているのか、理解できなかった。(^_^;)

ただしこのupdateには副作用もあった。 お仕事Mac miniに繋いでいたスキャナのドライバやStuffIt!などいくつかのソフトが使えなくなってしまい、泣く泣く削除した。 CANONのサイトに取りに行ってみると、10.7に対応の予定が無いという古い機種と判明、これは新学期になったらまずは、研究室のお仕事用スキャナを購入しなければならなくなった(^_^;)。 もしかしてプリンタも? ・・・と慌ててテストしたが、プリンタは互換で動いてくれた。やれやれである。

2015年3月27日(金)

「何もない4日間」の2日目である。 まずは、昨日までに10.7に上げてMax7を入れた(TRIALなので1ヶ月で使えなくなる)Macの残り3台、既にXcodeのために10.7に上げていた3台のMac miniの「見ざる」「言わざる」「聞かざる」も、 このように updateとともにMax7を入れた。 まさに単純作業であるが、これで午前の3時間近くかかってしまった。

そして昨日、メイルをやりとりした、 EC2009 で知り合い、後に僕の SYNC2010 ツアーでご一緒した、研究者・Denis Perevalov氏からのメイルが届いた。 下の写真の左端が彼であり、中央はずっとご一緒した、世界的に有名な作曲家のJon Appleton氏、そして右はSYNC2010の会場となったコンセルバトアールで活動する作曲家のTatiana Komarova女史である。 実は昨日のメイル(SUAC学生の新しいインスタレーション作品をロシアの学生に紹介するので教えて、というリクエストに回答)の最後にチラッと書いていた事に、彼は熱烈に食い付いてきてくれたのである。(^_^)

これは Max6日記(1) の最初、2月13日での記述を発端とする。 去年の2014年というのは、 Sabbatical 2004 から10年後であった(下の写真はその中でアムステルダムのSTEIMで行ったLecture/Workshopの模様)。 SUACの教員学外研修制度は10年に一度の権利であり、ようやく2014年に再びチャンスが来たのである。 ここからあれこれ調べて このような 世界一周の旅程を立てて、応募した。 しかし4月1日の記述にあるように、 この計画 は消滅した。 知らなかったのだが、学外研修の予算枠が一人分だったのだ(^_^;)。 そして今年、2015年については、諸々の理由により、最初から応募しなかったのである。

そこで次といえば2016年である。 ブラジルでのオリンピックの年なので、南米はちょっと無理っぽいが、考えてみれば Sabbatical 2004 の最中にも、たしかシドニーオリンピックが開催されていて、ホテルのテレビで見たような記憶がある。 そこでチラッとDenisに、「夏のロシアに、ワークショップとかで行く可能性」について、軽く打診してみたのだ。 すると彼から来たのは、以下のような「熱い」申し出だった。

Dear Prof. Yoichi,

*** Your performance and videos describing your instrument is awesome!

*** Considering your attending to Yekaterinburgin the summer 2016:
I think it's a great idea!
Summer in our city is nice. Sometimes we had fast jumps of temperature (+40C dry at one 
day and +18C with rain at the next day), but sure, it is more comfortable for you than our winter.

*Lecture Workshop* : 
Currently many people in my city is involved and interested in media/physical computing/
performances/experimental music.
So indeed, your Lecture Workshop should attend many people.
There are several institutions which I think is appropriate for workshop:

 1)   Ural branch of National Centre for Contemporary Arts 
	(http://www.ncca.ru/main?filial=5)

 2)  Ekaterinburg's Academy of Modern Arts  
	(http://еаси.екатеринбург.рф/)
(They have students for designing/programming things which we are interested. I receive invitation 
from them to give them lection course in autumn 2015, so I explore this institution soon.)

3) Ural State Academy of Architecture and Arts  
	(http://www.usaaa.ru/)
- I had give them couple of lections in this month, and see that they could be a platform for your Workshop too.

(Currently, I think Ural Conservatory is not to be a good platform for Workshop.)

*Resident program*: 
in our city I know two organizations holding this:
 - Ural branch of National Centre for Contemporary Arts
 - "Cultural Transit" foundation (http://www.cultt.ru/abouteng)

*Festival and Conference*:
I think we could organize a Festival by ourselves, or may be attend some Festival/Conference in Moscow / St Peterburg.

*** Thanks so much for links on your students works! It's just great, and we will discuss them on my lection.

素晴らしい(^_^)。 このところの世界中の国際関係と同様に、日本とロシアもなんかギクシャクしているが、どうしてどうして、行ってみれば人々は素晴らしい、いい国であり、さすがの大国、実に文化的なのである。 ただしロシア大使館でビザを取ったり、宿泊するホテルからの招待状まで全て事前に準備しないと渡航できなくて、まだまだ「近くて遠い国」なのである。 2010年にはマイナス15度(下の写真)を初めて体験したが、夏のYekaterinburgは素晴らしいらしい。 このロシアツアーを中心として、2016年の夏に2度目(ラストチャンス)の海外ツアーを計画するには、行き先のinvitationを打診・手配するためには、もう今年から動いていなければならないのだ。

・・・ここで午後になり、いよいよ「ダブルMyo」への挑戦を再開した。 昨夜、フト目覚めた時に思い付いたテストは今回はたった1種類だったが、これはアッサリと駄目と判明して、またまた暗中模索となった。 そしてまたまた、 これこれこれこれ を眺めて沈思黙考すること1時間、ようやく少し「読めて」きた。 onPair()というのはMyoに対して発行するコマンドではなくて、Armband Managerが接続されているMyoが1個から2個になった時にイベントとして起こすメソッドなのだった。 気付いてみれば当然で、MyoもArmband Managerも、「2個にするぞ」というようなコマンドをホストから受けとることは無く、あくまで現象としてMyoがたまたま1個から2個に増えたのをArmband Managerが察知した時に、受動的に発生するのだ。

これを確認するために、Myoイベントのキーワードとして「PAIR」と「UNPAIR」を「EMG」等に加えて並べてMaxに送るようにProcessingスケッチを変更してみると、とりあえず見事に、Myoの「connect」と「disconnect」に対応して、Max側でその状態を表示できるようになった。 上は1個だけ接続されてもう1個が接続されていない状態、下は2個目も接続した状態であり、Maxの画面に「0 0 0」と「1 2 3」として表示されている。 これは大いなる進展である(^_^)。 この状態をキープするために、これを「doubleMyo_02」として固定し、コピーした「doubleMyo_03」として続けることにした。

Processingのスケッチは、起動する時にArmband Managerを呼びに行き、Myoと接続されていないと最大10秒、待機して、それでも発見できないとエラー終了する。 いったんProcessingのスケッチが起動してしまえぱ、その後に接続されるMyoが増えても減っても、ゼロになってもずっと監視を続けている、というのも明らかになってきた。 これで次に必要なのは、1個→2個となった時のonPair()イベントから、2個のMyoを区別して呼び出すための情報の獲得である。 なお実験として駄目だったものも記録しておくと、 DeviceListener.cpp にあった以下から、同様に「CONNECTED」と「DISCONNECTED」も抽出してMaxに送ってみたが、これは「PAIR」「UNPAIR」と情報がかぶっていて、加えて有効な情報が得られるわけでもないと判断して、また消した。

class DeviceListener {
public:
    virtual ~DeviceListener() {}

    /// Called when a Myo has been paired.
    /// @param myo The Myo for this event.
    /// @param timestamp The timestamp of the event. Timestamps are 64 bit unsigned integers that correspond to a number
    /// of microseconds since some (unspecified) period in time. Timestamps are monotonically non-decreasing.
    /// @param firmwareVersion The firmware version of \a myo.
    virtual void onPair(Myo* myo, uint64_t timestamp, FirmwareVersion firmwareVersion) {}

    /// Called when a Myo has been unpaired.
    /// @param myo The Myo for this event.
    /// @param timestamp The timestamp of the event. Timestamps are 64 bit unsigned integers that correspond to a number
    /// of microseconds since some (unspecified) period in time. Timestamps are monotonically non-decreasing.
    virtual void onUnpair(Myo* myo, uint64_t timestamp) {}

    /// Called when a paired Myo has been connected.
    /// @param myo The Myo for this event.
    /// @param timestamp The timestamp of the event. Timestamps are 64 bit unsigned integers that correspond to a number
    /// of microseconds since some (unspecified) period in time. Timestamps are monotonically non-decreasing.
    /// @param firmwareVersion The firmware version of \a myo.
    virtual void onConnect(Myo* myo, uint64_t timestamp, FirmwareVersion firmwareVersion) {}

    /// Called when a paired Myo has been disconnected.
    /// @param myo The Myo for this event.
    /// @param timestamp The timestamp of the event. Timestamps are 64 bit unsigned integers that correspond to a number
    /// of microseconds since some (unspecified) period in time. Timestamps are monotonically non-decreasing.
    virtual void onDisconnect(Myo* myo, uint64_t timestamp) {}
};

「読書百遍」と言うが、確かに、何度も何度も これこれこれこれ を眺めていると、判らないなりにも滲み出てくるように何かが判ってくるものである。 午後の集中も3時間となって、今日はここでおしまい、とした。 また明日に挑戦である。 春休みならではの超余裕であるが、新学期が始まればこんな時間はふっ飛んでしまう。 そのメリハリもまた、いいのだ。(^_^)

2015年3月28日(土)

「何もない4日間」の3日目である。 我が家のマンションを出たところにある桜はこの1週間、というより数日で一気に開花から3分咲き、5分咲き、そしてもう今日はほぼ満開である。 天気もいいし「お花見」シーズンの週末であるが、どっこいこちらは花粉症、ちっともソソラレない(;_;)。 「桜」については、かつて2004年の3月末から4月上旬に、奈良と京都の2つの国際会議に参加しつつ、合間に大阪・吉野・滋賀にまで足を延ばして各地の名所の桜を 堪能しまくった事 があり、この写真を眺めるだけで十分である。

そして懸案の「ダブルMyo」であるが、昨夜はいろいろと頭に浮かんで整理できてきた。 昨日の夕方に、みっちりと MyoのDeveloperサイトで「multiple」「Myo」で検索、ヒットした68件 を読んでいたのが、寝ている間に脳内で整理されてきたようである。 個別に引用しないが、ここでは約半数、30件ぐらいは僕と同じように「2個のMyoを使うには?」という質問が出ていた。 誰でも考えることは同じである(^_^;)。 そして、およそ以下のような感じであった。

ここで問題となるのは、SDKというのはつまりCであり、2個のMyoの識別に、その構造体のポインタを使っているところである。 これはおそらく、Javascriptなどのスクリプト系でも、そしてProcessingつまりはJavaでも、積極的に隠蔽している「陰」にある情報であり、使えない「手」(低水準のアクセス)なのである。 一読しては見あたらなかったが、「スクリプト系で駄目」であるなら、ProcessingつまりはJavaでも駄目である可能性がかなり高い。 つまり、一昨日からやっている挑戦(ProcessingでダブルMyoを識別)は、無駄骨となるのだ(^_^;)。 そこで改めて MyoのDeveloperサイトDownloadページ から行く Unofficial Tools and Bindings に立ち戻ることになった。 このリストを作っているのは、まさに「2個のMyoは使えるよ」と回答している、開発者本人なのである。 リスト末尾のタイムスタンプは「Last edit: March 16, 2015 10:29 AM」となっていて、ここは日々、新しい情報が集まる、ホットな場のようだ。

ここで、2月16日に書いた作業を再追跡ということになったが、さすがにここまでの道のりがあるので、今回は驚くほどスムースに進んだ。 まずは、 Unofficial Tools and Bindings から、 Myo-OSC をダウンロードした。 よく読んでみると、ちゃんとMac OSX用のバイナリが付いているのである。 そのまま実行してみると、下のように「Connect to Myo Armband !」とメッセージがあり、OSCのdefaultのポート番号が7777だというので、Maxパッチを変更してみると、あっさりと「Orientation」「Gyro」「Accel」の9軸センサの情報がゲット出来てしまった(^_^)。

ただし、EMGは出て来ない。 defaultではEMGはOFFなので、Processingのスケッチからも「ON」を送っていたのだが、このMyo-OSCはMyoの情報をOSCに垂れ流しに送るものなので、コマンドが送れない。 そこでMyo Daemonを起動して、そのsettingからEMGのONを送ってみたが、Myo DaemonのVisualizerで確認できるものの、こちらからは出てこなかった。 また、2個目のMyoを接続してみると、9軸センサの表示がギザギザになり、つまり両方のMyoからの情報が到着Bluetoothパケットごとに混ざった状態となった。 これでは「ダブルMyo」も期待できそうもない(^_^;)。 結局、 Myo-OSC というのは、1個のMyoで9軸センサ情報だけを取得する場合にのみ、ProcessingナシでMaxから「使える」と判明した。

次に、 Unofficial Tools and Bindings から、 MyOSC という これ をダウンロードした。 こちらはBATファイルとかが並んでいて、基本式に邪悪なWindows臭がプンプンしているが(^_^;)、とりあえず「MyOSC.dmg」というMac用のインストーラがあったので、とりあえずバイナリを走らせて様子を見よう、とインストールした。 するとインストーラが、「adobeのサイトに行き、Adube AIRの最新版を落としてインストールする必要がある」と言ってきた。 今度はadobeかぁ、まさに邪悪のオンパレードである(^_^;)。 しかし乗りかかった船なのでこれを入れて、今度はターミナルから走らせるコンソールアプリでない、単独のアプリケーションとしての「MyOSC」が出来た。

これを起動すると、上のように画面内になんとも怪しいものがいくつも出現してきて、とりあえず適当に「+」を押すと、なんだか6000番、6001番、・・・とどんどん多数のMyoと接続しているかのようなインジケータが出現してきた。 とても怪しい(^_^;)。 そして、 試しにMaxパッチでポート6000番を受けても、どうも何も起きていないので、ここで改めて「README.md」を読むと、Macのインストールに関しては「Mac : Install using the MyOSC.dmg in the "installers" folder. You might need to copy "myo.framework" from the official Myo SDK from Thalmic into the "~/Library/Frameworks" folder of your computer.」 と書かれていた。 そこで「myo.framework」を、言われるままに「/Library/Frameworks」に加えてみた。

すると上のように、まずは全画面を覆うグレー(わずかに下が透けて見える)と、そこに今度は左側の円が接続しているMyoに対応してぐりぐり回る、というものになった。 どうやら左がArmband Managerとの通信モニタで、右側でこの情報を送るOSCポートを設定する、というようなものらしい。 Max画面にはMyoの数に対応して6000番と6001番のそれぞれで情報が届くのだが、しかし残念なことに、9軸センサの情報は左右どちらかの同じものである。 こうなると、適当にやらずにキチンと「README.md」を読む必要がある(^_^;)。 以下が、「README.md」のうち、インストールとWindowsの情報とポーズの設定をカットした、関係しそうなところである。

MyOSC
=====
## How it works
MyOSC is OSC Bridge made with Adobe AIR that let users easily send data from one or multiple Myos to one or multiple targets, with an easy interface.
MyOSC can also receive vibrate OSC messages from applications to make the connected myo vibrate

### Usage
When installed, application should open full screen.
- Hit "Escape" to hide it.

- Left Click on a Myo Feedback node to see more informations
- Right Click on a Myo Feedback node to offset the Yaw. The compensation assumes that your arm is pointing forward when calibrating.

- When registering from the target software : send an OSC Message to "/myosc/register" on port 9000, 
	with 3 arguments (string, string, int) : connectionID (arbitrary) / host (your IP) / port (to receive OSC Messages)
- To unregister, just send "/myosc/unregister" on port 9000, with 1 argument (string) : connectionID (the one used to register)
- To send a vibrate message, send "/myosc/vibrate"
 - 0 argument = vibrate all myos with default duration 0 (= SHORT)
 - 1 argument INTEGER = vibrate all myos with set duration (0 = SHORT, 1=MEDIUM, 2=LONG)
 - 1 argument STRING = vibrate specific myo (argument is Mac Address of the myo) with default duration 0
 - 2 arguments STRING INT = vibrate specific myo with set duration

### Features
- Connect with multiple Myos
- Live creation / removal of OSC targets
- Orientation, Pose, Gyroscope and Accelerometer data providing
- Per target data filtering (enabled pose / orientation sending)
- One Click Saving / Loading presets
- OSC target registration (the target application can send an OSC Message to register into the bridge)
- Vibrate Myo via OSC, by ID or all at once
- Easy absolute yaw calibration

こちらは、ポート9000番を使って、任意のアプリを登録したりバイブレーションを送れる、という。 しかし最後の「Features」を読んでみると、駄目じゃん(;_;) と判明してしまった。 複数のMyoと接続できるよ、と言っているこのMyOSCはなんと、筋電は伝えないのだった。 9軸センサをいくら両腕から送れたとしても、Myoというのは筋電センサの筈である。 筋電情報を送らないMyOSCは、残念ながら「使えない」のだ。 これで振出しに戻った。 Processingを使わなくてもOSCに出せる・・・と思っていた期待は潰えて、やはり進めてきたProcessingの方法しか残っていない。 もちろん、せっかく全てのMacが10.7になったので、Xcodeを入れてガリガリとやる、という選択肢は最初から最後まで残っているのだが、これは避けたいというこだわりがある(^_^;)。 だいぶ面白い実験が出来たので、進展ではなかったが自分の理解としてMyoがさらに身近になったところで、今日はオシマイである。

2015年3月29日(日)

「何もない4日間」の最終日である。 明日は有休で、朝からつくばに行き、久しぶりに母親の顔を見に行っててついでに一緒に桜を見て(生きてるうちが親孝行)、夕方には東京に戻って、CQ出版の「インターフェース読者との集い」という謎な場に行く予定である。 それでもう3月も終るので、とりあえず「ダブルMyo」への挑戦も、この日が最終日である。
まずは、例によって昨夜に浮かんだ着想からである。 昨日、 Unofficial Tools and Bindings を眺めた時に、それ以前には無かった BLE specification of the Myo armband というのが最下段に加わっていたのを思い出した。 これはつまり、MyoのBluetooth情報の詳細について、秘密にせず公開している、という事である。 ということは、直接Bluetoothをやりとりして、つまりArmband Managerを経由しないでMyoとやりとりできないか、という可能性もあるのだ。 さっそく これ をダウンロードした。 すると、「myohw.h」というCヘッダファイルに、以下のように全ての情報が並んでいた(一部カット)。 さすがオープンソース文化、素晴らしい(^_^)。

#pragma once
#include <stdint.h>

#define MYO_SERVICE_INFO_UUID { 0x42, 0x48, 0x12, 0x4a, 0x7f, 0x2c, 0x48, 0x47, 0xb9, 0xde, 0x04, 0xa9, 0x01, 0x00, 0x06, 0xd5 }
static const uint8_t kMyoServiceInfoUuid[] = MYO_SERVICE_INFO_UUID;

/// The number of EMG sensors that a Myo has.
static const int myohw_num_emg_sensors = 8;

/// @defgroup myo_hardware Myo Hardware Data Structures
/// These types and enumerations describe the format of data sent to and from a Myo device using Bluetooth Low Energy.
/// All values are big-endian.

/// The following enum lists the 16bit short UUIDs of Myo services and characteristics. To construct a full 128bit
/// UUID, replace the two 0x00 hex bytes of MYO_SERVICE_BASE_UUID with a short UUID from myohw_standard_services. 
/// The byte sequence of MYO_SERVICE_BASE_UUID is in network order. Keep this in mind when doing the replacement.
/// For example, the full service UUID for GCControlService would be d5060001-a904-deb9-4748-2c7f4a124842. 
#define MYO_SERVICE_BASE_UUID { 0x42, 0x48, 0x12, 0x4a, 0x7f, 0x2c, 0x48, 0x47, 0xb9, 0xde, 0x04, 0xa9, 0x00, 0x00, 0x06, 0xd5 }

typedef enum {
    ControlService                = 0x0001, ///< Myo info service
    MyoInfoCharacteristic         = 0x0101, ///< Serial number for this Myo and various parameters which
                                            ///< are specific to this firmware. Read-only attribute. 
                                            ///< See myohw_fw_info_t.
    FirmwareVersionCharacteristic = 0x0201, ///< Current firmware version. Read-only characteristic.
                                            ///< See myohw_fw_version_t.
    CommandCharacteristic         = 0x0401, ///< Issue commands to the Myo. Write-only characteristic.
                                            ///< See myohw_command_t.
    ImuDataService                = 0x0002, ///< IMU service
    IMUDataCharacteristic         = 0x0402, ///< See myohw_imu_data_t. Notify-only characteristic.
    MotionEventCharacteristic     = 0x0a02, ///< Motion event data. Indicate-only characteristic.
    ClassifierService             = 0x0003, ///< Classifier event service.
    ClassifierEventCharacteristic = 0x0103, ///< Classifier event data. Indicate-only characteristic. See myohw_pose_t.
    EmgDataService                = 0x0005, ///< Raw EMG data service.
    EmgData0Characteristic        = 0x0105, ///< Raw EMG data. Notify-only characteristic.
    EmgData1Characteristic        = 0x0205, ///< Raw EMG data. Notify-only characteristic.
    EmgData2Characteristic        = 0x0305, ///< Raw EMG data. Notify-only characteristic.
    EmgData3Characteristic        = 0x0405, ///< Raw EMG data. Notify-only characteristic.
} myohw_services;

// Standard Bluetooth device services.
typedef enum{
    BatteryService                = 0x180f, ///< Battery service
    BatteryLevelCharacteristic    = 0x2a19, ///< Current battery level information. Read/notify characteristic.
    DeviceName                    = 0x2a00, ///< Device name data. Read/write characteristic.
} myohw_standard_services;

/// Supported poses.
typedef enum {
    myohw_pose_rest           = 0x0000,
    myohw_pose_fist           = 0x0001,
    myohw_pose_wave_in        = 0x0002,
    myohw_pose_wave_out       = 0x0003,
    myohw_pose_fingers_spread = 0x0004,
    myohw_pose_double_tap     = 0x0005,
    myohw_pose_unknown        = 0xffff
} myohw_pose_t;

/// Various parameters that may affect the behaviour of this Myo armband.
/// The Myo library reads this attribute when a connection is established.
/// Value layout for the myohw_att_handle_fw_info attribute.
typedef struct MYOHW_PACKED
{
    uint8_t serial_number[6];        ///< Unique serial number of this Myo.
    uint16_t unlock_pose;            ///< Pose that should be interpreted as the unlock pose. See myohw_pose_t.
    uint8_t active_classifier_type;  ///< Whether Myo is currently using a built-in or a custom classifier.
                                     ///< See myohw_classifier_model_type_t.
    uint8_t active_classifier_index; ///< Index of the classifier that is currently active.
    uint8_t has_custom_classifier;   ///< Whether Myo contains a valid custom classifier. 1 if it does, otherwise 0.
    uint8_t stream_indicating;       ///< Set if the Myo uses BLE indicates to stream data, for reliable capture.
    uint8_t sku;                     ///< SKU value of the device. See myohw_sku_t
    uint8_t reserved[7];             ///< Reserved for future use; populated with zeros.
} myohw_fw_info_t;
MYOHW_STATIC_ASSERT_SIZED(myohw_fw_info_t, 20);

#define MYOHW_FIRMWARE_VERSION_MAJOR 1
#define MYOHW_FIRMWARE_VERSION_MINOR 2
static const uint16_t myohw_firmware_version_major = MYOHW_FIRMWARE_VERSION_MAJOR;
static const uint16_t myohw_firmware_version_minor = MYOHW_FIRMWARE_VERSION_MINOR;

/// Kinds of commands.
typedef enum {
    myohw_command_set_mode               = 0x01, ///< Set EMG and IMU modes. See myohw_command_set_mode_t.
    myohw_command_set_mode_custom        = 0x02, ///< Set EMG and IMU modes with custom parameters.
                                                 ///< See myohw_command_set_mode_custom_t.
    myohw_command_vibrate                = 0x03, ///< Vibrate. See myohw_command_vibrate_t.
    myohw_command_deep_sleep             = 0x04, ///< Put Myo into deep sleep. See myohw_command_deep_sleep_t.
    myohw_command_vibrate2               = 0x07, ///< Extended vibrate. See myohw_command_vibrate2_t.
    myohw_command_set_sleep_mode         = 0x09, ///< Set sleep mode. See myohw_command_set_sleep_mode_t.
    myohw_command_unlock                 = 0x0a, ///< Unlock Myo. See myohw_command_unlock_t.
    myohw_command_user_action            = 0x0b, ///< Notify user that an action has been recognized / confirmed.
                                                 ///< See myohw_command_user_action_t.
} myohw_command_t;

/// Header that every command begins with.
typedef struct MYOHW_PACKED {
    uint8_t command;        ///< Command to send. See myohw_command_t.
    uint8_t payload_size;   ///< Number of bytes in payload.
} myohw_command_header_t;
MYOHW_STATIC_ASSERT_SIZED(myohw_command_header_t, 2);

/// EMG modes.
typedef enum {
    myohw_emg_mode_none         = 0x00, ///< Do not send EMG data.
    myohw_emg_mode_send_emg     = 0x02, ///< Send filtered EMG data.
    myohw_emg_mode_send_emg_raw = 0x03, ///< Send raw (unfiltered) EMG data.
} myohw_emg_mode_t;

/// IMU modes.
typedef enum {
    myohw_imu_mode_none        = 0x00, ///< Do not send IMU data or events.
    myohw_imu_mode_send_data   = 0x01, ///< Send IMU data streams (accelerometer, gyroscope, and orientation).
    myohw_imu_mode_send_events = 0x02, ///< Send motion events detected by the IMU (e.g. taps).
    myohw_imu_mode_send_all    = 0x03, ///< Send both IMU data streams and motion events.
    myohw_imu_mode_send_raw    = 0x04, ///< Send raw IMU data streams.
} myohw_imu_mode_t;

/// Classifier modes.
typedef enum {
    myohw_classifier_mode_disabled = 0x00, ///< Disable and reset the internal state of the onboard classifier.
    myohw_classifier_mode_enabled  = 0x01, ///< Send classifier events (poses and arm events).
} myohw_classifier_mode_t;

/// Command to set EMG and IMU modes.
typedef struct MYOHW_PACKED {
    myohw_command_header_t header; ///< command == myohw_command_set_mode. payload_size = 3.
    uint8_t emg_mode;              ///< EMG sensor mode. See myohw_emg_mode_t.
    uint8_t imu_mode;              ///< IMU mode. See myohw_imu_mode_t.
    uint8_t classifier_mode;       ///< Classifier mode. See myohw_classifier_mode_t.
} myohw_command_set_mode_t;
MYOHW_STATIC_ASSERT_SIZED(myohw_command_set_mode_t, 5);

/// Kinds of vibrations.
typedef enum {
    myohw_vibration_none   = 0x00, ///< Do not vibrate.
    myohw_vibration_short  = 0x01, ///< Vibrate for a short amount of time.
    myohw_vibration_medium = 0x02, ///< Vibrate for a medium amount of time.
    myohw_vibration_long   = 0x03, ///< Vibrate for a long amount of time.
} myohw_vibration_type_t;

/// Vibration command.
typedef struct MYOHW_PACKED {
    myohw_command_header_t header; ///< command == myohw_command_vibrate. payload_size == 1.
    uint8_t type;                  ///< See myohw_vibration_type_t.
} myohw_command_vibrate_t;
MYOHW_STATIC_ASSERT_SIZED(myohw_command_vibrate_t, 3);

/// Deep sleep command.
typedef struct MYOHW_PACKED {
    myohw_command_header_t header; ///< command == myohw_command_deep_sleep. payload_size == 0.
} myohw_command_deep_sleep_t;
MYOHW_STATIC_ASSERT_SIZED(myohw_command_deep_sleep_t, 2);

/// Extended vibration command.
#define MYOHW_COMMAND_VIBRATE2_STEPS 6
typedef struct MYOHW_PACKED {
    myohw_command_header_t header; ///< command == myohw_command_vibrate2. payload_size == 18.
    struct MYOHW_PACKED {
        uint16_t duration;         ///< duration (in ms) of the vibration
        uint8_t strength;          ///< strength of vibration (0 - motor off, 255 - full speed)
    } steps[MYOHW_COMMAND_VIBRATE2_STEPS];
} myohw_command_vibrate2_t;
MYOHW_STATIC_ASSERT_SIZED(myohw_command_vibrate2_t, 20);

/// Sleep modes.
typedef enum {
    myohw_sleep_mode_normal      = 0, ///< Normal sleep mode; Myo will sleep after a period of inactivity.
    myohw_sleep_mode_never_sleep = 1, ///< Never go to sleep.
} myohw_sleep_mode_t;

/// Set sleep mode command.
typedef struct MYOHW_PACKED {
    myohw_command_header_t header; ///< command == myohw_command_set_sleep_mode. payload_size == 1.
    uint8_t sleep_mode;            ///< Sleep mode. See myohw_sleep_mode_t.
} myohw_command_set_sleep_mode_t;
MYOHW_STATIC_ASSERT_SIZED(myohw_command_set_sleep_mode_t, 3);

/// Unlock types.
typedef enum {
    myohw_unlock_lock  = 0x00, ///< Re-lock immediately.
    myohw_unlock_timed = 0x01, ///< Unlock now and re-lock after a fixed timeout.
    myohw_unlock_hold  = 0x02, ///< Unlock now and remain unlocked until a lock command is received.
} myohw_unlock_type_t;

/// Unlock Myo command.
/// Can also be used to force Myo to re-lock.
typedef struct MYOHW_PACKED {
    myohw_command_header_t header; ///< command == myohw_command_unlock. payload_size == 1.
    uint8_t type;                  ///< Unlock type. See myohw_unlock_type_t.
} myohw_command_unlock_t;
MYOHW_STATIC_ASSERT_SIZED(myohw_command_unlock_t, 3);

/// User action types.
typedef enum {
    myohw_user_action_single = 0, ///< User did a single, discrete action, such as pausing a video.
} myohw_user_action_type_t;

/// User action command.
typedef struct MYOHW_PACKED {
    myohw_command_header_t header; ///< command == myohw_command_user_action. payload_size == 1.
    uint8_t type;                  ///< Type of user action that occurred. See myohw_user_action_type_t.
} myohw_command_user_action_t;
MYOHW_STATIC_ASSERT_SIZED(myohw_command_user_action_t, 3);

/// Classifier model types
typedef enum {
    myohw_classifier_model_builtin = 0, ///< Model built into the classifier package.
    myohw_classifier_model_custom  = 1  ///< Model based on personalized user data.
} myohw_classifier_model_type_t;

/// Integrated motion data.
typedef struct MYOHW_PACKED {
    /// Orientation data, represented as a unit quaternion. Values are multiplied by MYOHW_ORIENTATION_SCALE.
    struct MYOHW_PACKED {
        int16_t w, x, y, z;
    } orientation;
    int16_t accelerometer[3]; ///< Accelerometer data. In units of g. Range of + -16.
                              ///< Values are multiplied by MYOHW_ACCELEROMETER_SCALE.
    int16_t gyroscope[3];     ///< Gyroscope data. In units of deg/s. Range of + -2000.
                              ///< Values are multiplied by MYOHW_GYROSCOPE_SCALE.
} myohw_imu_data_t;
MYOHW_STATIC_ASSERT_SIZED(myohw_imu_data_t, 20);

/// Default IMU sample rate in Hz.
#define MYOHW_DEFAULT_IMU_SAMPLE_RATE 50

/// Scale values for unpacking IMU data
#define MYOHW_ORIENTATION_SCALE   16384.0f ///< See myohw_imu_data_t::orientation
#define MYOHW_ACCELEROMETER_SCALE 2048.0f  ///< See myohw_imu_data_t::accelerometer
#define MYOHW_GYROSCOPE_SCALE     16.0f    ///< See myohw_imu_data_t::gyroscope

/// Types of motion events.
typedef enum {
    myohw_motion_event_tap = 0x00,
} myohw_motion_event_type_t;

/// Motion event data received in a myohw_att_handle_motion_event attribute.
typedef struct MYOHW_PACKED {
    uint8_t type; /// Type type of motion event that occurred. See myohw_motion_event_type_t.
    /// Event-specific data.
    union MYOHW_PACKED {
        /// For myohw_motion_event_tap events.
        struct MYOHW_PACKED {
            uint8_t tap_direction;
            uint8_t tap_count;
        };
    };
} myohw_motion_event_t;
MYOHW_STATIC_ASSERT_SIZED(myohw_motion_event_t, 3);

/// Types of classifier events.
typedef enum {
    myohw_classifier_event_arm_synced   = 0x01,
    myohw_classifier_event_arm_unsynced = 0x02,
    myohw_classifier_event_pose         = 0x03,
    myohw_classifier_event_unlocked     = 0x04,
    myohw_classifier_event_locked       = 0x05,
    myohw_classifier_event_sync_failed  = 0x06,
} myohw_classifier_event_type_t;

/// Enumeration identifying a right arm or left arm.
typedef enum {
    myohw_arm_right   = 0x01,
    myohw_arm_left    = 0x02,
    myohw_arm_unknown = 0xff
} myohw_arm_t;

/// Possible directions for Myo's +x axis relative to a user's arm.
typedef enum {
    myohw_x_direction_toward_wrist = 0x01,
    myohw_x_direction_toward_elbow = 0x02,
    myohw_x_direction_unknown      = 0xff
} myohw_x_direction_t;

/// Possible outcomes when the user attempts a sync gesture.
typedef enum {
    myohw_sync_failed_too_hard = 0x01, ///< Sync gesture was performed too hard.
} myohw_sync_result_t;

/// Classifier event data received in a myohw_att_handle_classifier_event attribute.
typedef struct MYOHW_PACKED {
    uint8_t type; ///< See myohw_classifier_event_type_t
    /// Event-specific data
    union MYOHW_PACKED {
        /// For myohw_classifier_event_arm_synced events.
        struct MYOHW_PACKED {
            uint8_t arm; ///< See myohw_arm_t
            uint8_t x_direction; ///< See myohw_x_direction_t
        };
        /// For myohw_classifier_event_pose events.
        uint16_t pose; ///< See myohw_pose_t
        /// For myohw_classifier_event_sync_failed events.
        uint8_t sync_result; ///< See myohw_sync_result_t.
    };
} myohw_classifier_event_t;
MYOHW_STATIC_ASSERT_SIZED(myohw_classifier_event_t, 3);

/// The rate that EMG events are streamed over Bluetooth.
#define MYOHW_EMG_DEFAULT_STREAMING_RATE 200

/// Raw EMG data received in a myohw_att_handle_emg_data_# attribute.
/// Value layout for myohw_att_handle_emg_data_#.
typedef struct MYOHW_PACKED {
    int8_t sample1[8];       ///< 1st sample of EMG data.
    int8_t sample2[8];       ///< 2nd sample of EMG data.
} myohw_emg_data_t;
MYOHW_STATIC_ASSERT_SIZED(myohw_emg_data_t, 16);

「Deep Sleep Mode」とか、拡張のバイブレーション・コマンドだと振動の持続時間まで設定できるとか、なかなか詳細である。 このように、ハードウェアとファームウェアをオリジナルに開発した場合には、コマンドとかプロトコルを自由に決めて「これだよ。ちゃんと解釈してね」とドキュメント化するのが、とても楽しいのを思い出した。 かつて某楽器メーカで音源LSIとかPC拡張音源システムを開発した時には、自分が端から端まで設計したLSIや回路やCPUファームウェアなので、LSI内部のレジスタマップからCPUインターフェース、ホストPCとのインターフェース定義まで、全て自由に決めていいのだった。 そこに、こだわりの直交性とかをいかに美しく盛り込むか、というのがエンジニアとしての美学だった。
CPUで言えばインテルに比べてモトローラ(6800→6805→6809→68000)はかなりアーキテクチャが美しいが、それよりロックウェルの6502の美しさは段違いだった。 CPUが非力な時代にファミリーコンピュータが出現したのは、何より6502というCPUの美しさに依存している。 僕はこの美しさを最大限に活用して、音源LSI内に6502コアを入れた、コンパクトで超強力な音源LSIを設計できた経験に、今でも感謝している。 そして現代で言えば、究極的に、むしろ変態的にまでアーキテクチャの美しさを社長自身が追求して設計、実現してしまったCPUこそ、 Propeller なのである。(^_^)

そして思い出したのが、上のように、Maxの「serial」オブジェクトは、これまでにmaxuinoとかXBeeとかでさんざん活用してきているが、考えてみればBluetoothもその仕様として持っている、という事である。 これなら、MyoからのBluetoothをMaxのserialオブジェクトで受けて、低水準の情報解析からしこしこと記述していけば、出来そうな気がする。 何より、上記のようにMyoのBluetoothプロトコルは全て公開されているので、Microsoftのような「見えない」「怪しい」部分が無いのは嬉しい。 そこでさっそく、Myoを充電状態から外して腕に着けて、つまりはBluetooth接続を求めているだろう状態にして、MacのBluetoothツールで、デバイスとして探してみた。 ・・・しかし下のように、いくら待ってもデバイスが現れなかった(;_;)。 Wiiリモコンとかではサッと出て来たが、あれはWiiリモコンのボタンを押してペアリングを求めたからだった。 Myoでは、いちばん最初に「BluetoothのUSBドングルの近くに持っていって、タップする」というおまじないがあったが、それをしても駄目だった。

・・・結局、Bluetoothをじかに取得する、というアイデアは、肝心のMyoがBluetoothデバイスとして「見えない」ので、またまた断念バーグとなった。 こうなると、いよいよ残されたのは、昨日までの実験から、Processing(つまりJava)でSDKのようにArmband ManagerからMyoの情報を個別に取得できるか・・・という、可能性はあまり高くない悪あがきしか残っていない。 前述のように「Myo2個使いが出来るよ」、というSDKというのはつまりCであり、2個のMyoの識別に、その構造体のポインタを使っている。 しかし、たしかJavaには構造体って無かった気がする(^_^;)。 そこで、Cで出来てProcessing(Java)で出来るかどうか、ということなので、まずはYAHOOで「Java 構造体」で検索して出て来た、 これ とか これ とか これ とか これ とか これ とか これ とか これ とか これ とかを眺めることから始めた。 すると、これらはほぼ、同じような事を言っている、と判ったが、まぁ当たり前である(^_^;)。
攻略の対象となる「multiple-myos.cpp」は以下である。

#include <iostream>
#include <stdexcept>
#include <vector>
#include <myo/myo.hpp>

class PrintMyoEvents : public myo::DeviceListener {
public:
	// Every time Myo Connect successfully pairs with a Myo armband, this function will be called.
	// You can rely on the following rules:
	// - onPair() will only be called once for each Myo device
	// - no other events will occur involving a given Myo device before onPair() is called with it
	// If you need to do some kind of per-Myo preparation before handling events, you can safely do it in onPair().
	void onPair(myo::Myo* myo, uint64_t timestamp, myo::FirmwareVersion firmwareVersion)
	{
		// Print out the MAC address of the armband we paired with.
		// The pointer address we get for a Myo is unique - in other words, it's safe to compare two Myo pointers to
		// see if they're referring to the same Myo.
		// Add the Myo pointer to our list of known Myo devices. This list is used to implement identifyMyo() below so
		// that we can give each Myo a nice short identifier.
		knownMyos.push_back(myo);

		// Now that we've added it to our list, get our short ID for it and print it out.
		std::cout << "Paired with " << identifyMyo(myo) << "." << std::endl;
	}

	void onPose(myo::Myo* myo, uint64_t timestamp, myo::Pose pose)
	{
		std::cout << "Myo " << identifyMyo(myo) << " switched to pose " << pose.toString() << "." << std::endl;
	}

	void onConnect(myo::Myo* myo, uint64_t timestamp, myo::FirmwareVersion firmwareVersion)
	{
		std::cout << "Myo " << identifyMyo(myo) << " has connected." << std::endl;
	}

	void onDisconnect(myo::Myo* myo, uint64_t timestamp)
	{
		std::cout << "Myo " << identifyMyo(myo) << " has disconnected." << std::endl;
	}

	// This is a utility function implemented for this sample that maps a myo::Myo* to a unique ID starting at 1.
	// It does so by looking for the Myo pointer in knownMyos, which onPair() adds each Myo into as it is paired.
	size_t identifyMyo(myo::Myo* myo) {
		// Walk through the list of Myo devices that we've seen pairing events for.
		for (size_t i = 0; i < knownMyos.size(); ++i) {
			// If two Myo pointers compare equal, they refer to the same Myo device.
			if (knownMyos[i] == myo) {
				return i + 1;
			}
		}
		return 0;
	}

	// We store each Myo pointer that we pair with in this list, so that we can keep track of the order we've seen
	// each Myo and give it a unique short identifier (see onPair() and identifyMyo() above).
	std::vector<myo::Myo*> knownMyos;
};

int main(int argc, char** argv)
{
	try {
		myo::Hub hub("com.example.multiple-myos");

		// Instantiate the PrintMyoEvents class we defined above, and attach it as a listener to our Hub.
		PrintMyoEvents printer;
		hub.addListener(&printer);

		while (1) {
			// Process events for 10 milliseconds at a time.
			hub.run(10);
			}
	} catch (const std::exception& e) {
		std::cerr << "Error: " << e.what() << std::endl;
		std::cerr << "Press enter to continue.";
		std::cin.ignore();
		return 1;
	}
}

また、ここでincludeされている「myo.hpp」は以下である。

#pragma once

#include <myo/libmyo.h>

namespace myo {

/// Represents a Myo device with a specific MAC address.
/// This class can not be instantiated directly; instead, use Hub to get access to a Myo.
/// There is only one Myo instance corresponding to each device; thus, if the addresses of two Myo instances compare
/// equal, they refer to the same device.
class Myo {
public:
    /// Types of vibration supported by the Myo.
    enum VibrationType {
        vibrationShort  = libmyo_vibration_short,
        vibrationMedium = libmyo_vibration_medium,
        vibrationLong   = libmyo_vibration_long
    };

    /// Vibrate the Myo.
    void vibrate(VibrationType type);

    /// Request the RSSI of the Myo. An onRssi event will likely be generated with the value of the RSSI.
    /// @see DeviceListener::onRssi()
    void requestRssi() const;

    /// Unlock types supported by Myo.
    enum UnlockType {
        unlockTimed = libmyo_unlock_timed,
        unlockHold  = libmyo_unlock_hold
    };

    /// Unlock the Myo.
    /// Myo will remain unlocked for a short amount of time, after which it will automatically lock again.
    /// If Myo was locked, an onUnlock event will be generated.
    void unlock(UnlockType type);

    /// Force the Myo to lock immediately.
    /// If Myo was unlocked, an onLock event will be generated.
    void lock();

    /// Notify the Myo that a user action was recognized.
    /// Will cause Myo to vibrate.
    void notifyUserAction();

    /// Valid EMG streaming modes for a Myo.
    enum StreamEmgType {
        streamEmgDisabled = libmyo_stream_emg_disabled,
        streamEmgEnabled = libmyo_stream_emg_enabled
    };

    /// Sets the EMG streaming mode for a Myo.
    void setStreamEmg(StreamEmgType type);

    /// @cond MYO_INTERNALS

    /// Return the internal libmyo object corresponding to this device.
    libmyo_myo_t libmyoObject() const;

    /// @endcond

private:
    Myo(libmyo_myo_t myo);
    ~Myo();

    libmyo_myo_t _myo;

    // Not implemented.
    Myo(const Myo&);
    Myo& operator=(const Myo&);

    friend class Hub;
};

} // namespace myo

#include "impl/Myo_impl.hpp"

まずCの動作が理解できないとJava版について検討できないので、ここで上の2つから、2個目のMyoがArmband Managerに認識された時の流れを追いかけてみた。 まず受動的に呼ばれるomPair()の該当部分は以下である。

	void onPair(myo::Myo* myo, uint64_t timestamp, myo::FirmwareVersion firmwareVersion)
	{
		knownMyos.push_back(myo);
		std::cout << "Paired with " << identifyMyo(myo) << "." << std::endl;
	}

そして、「myo::Myo*」がそれぞれのMyoに対応して持っているID番号(1,2,...)を取得する、というサンプルの該当部分は以下である。

	size_t identifyMyo(myo::Myo* myo) {
		for (size_t i = 0; i < knownMyos.size(); ++i) {
			if (knownMyos[i] == myo) {
				return i + 1;
			}
		}
		return 0;
	}

そして、「knownMyos」にそれぞれのMyoポインタを格納するというのが以下である。

std::vector<myo::Myo*> knownMyos;

ここらが、 Myo.javaCollector.java とを置き換えたもので表現できるのか・・・ということである。 とりあえず、これらのバックアップを確保した上で、Processingでインポートされる筈の、 ここ にある以下の2つのJavaプログラムを変更したらどうなるか、から実験してみた。

そして結論はアッサリと出た。 駄目であった(^_^;)。 ここに置かれているのは単なるライブラリのソースであり、実際はきっちりコンパイルされて以下に置かれているのだった。

つまり、「src」の中のJavaソースをいくら変えようが、消そうが、何も変わらないのである。 以下のように、JavaソースをHTMLで奇麗に見せる「reference」ディレクトリと同じだったのである。 これは、至極、当然である。

というわけで、「ダブルMyo」についてのアタックは、午後2時あたりに、とりあえず全滅した。 ただし、いろいろ実験したり回り道したりして、収穫も少なくなかったので、まずまず有意義な4日間だった、という事にしよう。 ここからは、明日の朝イチで浜松駅に向かうので、Myoその他を忘れないようにカバンを出したりして準備である。 この「Myo日記」の最後には、CQ出版でのイベントについて簡単に報告するとして、翌日、東京から朝帰りするともう3月31日である。 新学期になればあれこれ忙殺されるので、そこらでこの「Myo日記」も、いったん完結となるだろう。

2015年3月31日(火)

3月も最終日、いよいよ新学期・新年度の直前である。 ここは、昨日のCQ出版・オフ会で池袋泊して、朝帰り(^_^;)で東京から浜松に帰る新幹線の中で書いている。 昨日の様子をここにまとめて、この「Myo日記」もこれで終わりとしよう。 昨日の朝、大学から浜松駅に向かうバスに乗り、サークルKの交差点の赤信号でバスが停止していると、目の前には下のような、SUACの角の桜が満開であった。 幸先良いスタートである。

新幹線で東京へ、そして秋葉原へ。 やはり、秋葉原は普通ではなかった。 駅の構内に、コナンの教室があったり、ガチャポンが並んでいた(^_^;)。

そして、つくばエキスプレスでつくばへ。久しぶりに母親と食事。

東京に戻り、巣鴨のCQ出版に行って、インターフェース読者のオフ会に参加。 なかなか凄い人たちがやって来て、30数人というのは最多だったらしい。

・・・と写真をここにまとめたが、実はこの日の朝、研究室に出て出発する前に、Maxのプログラミングついて思いついた改良をして、つくばから秋葉原に帰るつくばエキスプレスの車内で、Maxパッチの改良に成功し、対応してProcessingのスケッチもかなりスッキリ改定できたのである。 それをここにメモすることで、無事に「Myo日記」も完了ということである。

上のMaxパッチ(部分)は、MyoからBluetoothを受け取ってMaxにOSCで送るProcessingスケッチと対応した、MaxでのOSC受信(解釈)部分である。 ProcessingからのOSCパケットは、先頭に「EMG」とか「accel」とかのキーワードがあり、ここにデータが続く、というメッセージとして受け取る。 僕はこれを、まず「zl nth 1」で先頭キーワードを抽出して、それを「zl compare」でいちいちキーワードと比較して番号を出し、入力メッセージを貯めていたバッファから出力する「gate」の振り分けに使っていた。 馬鹿正直というのは、こういうのを言う(^_^;)。

しかしMaxには「route」オブジェクトというのがある(昔は無かったが途中で出現した)、というのを、赤松さんのWii用オブジェクトを調べた時に発見したのである。 これを使うと、上のようにシンプルに、キーワードに対応して続くメッセージを振り分けて出力してくれるのだった。 これはたしか、leap motion用の赤松さんオブジェクトのサンプルにもあったのを、後で思い出した(^_^;)。 これに対応して、Processingの方もスッキリする方法を思いついて、Maxとセットで改定した。 ここまでのProcessingスケッチは以下だった。

import de.voidplus.myo.*;
import oscP5.*;
import netP5.*;

OscP5 oscP5;
NetAddress myBroadcastLocation;
Myo myo;
int received_0 = 0;
int received_1 = 0;

void setup() {
	myo = new Myo(this);
	myo.withEmg();
	oscP5 = new OscP5(this,8000);
	myBroadcastLocation = new NetAddress("127.0.0.1",7000);
}

void draw() {
}

void oscEvent(OscMessage theOscMessage) {
	received_0 = theOscMessage.get(0).intValue();
	received_1 = theOscMessage.get(1).intValue();
	if (received_0 == 1) {
		myo.vibrate(1);
	}
}

void myoOn(Myo.Event event, Myo myo, long timestamp) {
	switch(event) {
 		case EMG:
			OscMessage myOscMessage1 = new OscMessage("EMG");
			int[] data1 = myo.getEmg();
			for(int i = 0; i<data1.length; i++){
				myOscMessage1.add(data1[i]);
			}
			oscP5.send(myOscMessage1, myBroadcastLocation);
			break;
		case GYROSCOPE:
			OscMessage myOscMessage2 = new OscMessage("Gyro");
			PVector data2 = myo.getGyroscope();
			myOscMessage2.add(data2.x/8.0);
			myOscMessage2.add(data2.y/8.0);
			myOscMessage2.add(data2.z/8.0);
			oscP5.send(myOscMessage2, myBroadcastLocation);
			break;
		case ACCELEROMETER:
			OscMessage myOscMessage3 = new OscMessage("Accel");
			PVector data3 = myo.getAccelerometer();
			myOscMessage3.add(data3.x*40);
			myOscMessage3.add(data3.y*40);
			myOscMessage3.add(data3.z*40);
			oscP5.send(myOscMessage3, myBroadcastLocation);
			break;
		case ORIENTATION:
			OscMessage myOscMessage4 = new OscMessage("Orient");
			PVector data4 = myo.getOrientation();
			myOscMessage4.add(data4.x*14);
			myOscMessage4.add(data4.y*14);
			myOscMessage4.add(data4.z*14);
			oscP5.send(myOscMessage4, myBroadcastLocation);
			break;
	}
}

これが、以下のようになったのである。 これまた、改定としては美しいもので、満足なのだ。(^_^)

import de.voidplus.myo.*;
import oscP5.*;
import netP5.*;

OscP5 oscP5;
NetAddress myBroadcastLocation;
Myo myo;
int received_data;

void setup() {
	myo = new Myo(this);
	myo.withEmg();
	oscP5 = new OscP5(this,8000);
	myBroadcastLocation = new NetAddress("127.0.0.1",7000);
}

void draw() {
}

void oscEvent(OscMessage theOscMessage) {
	received_data = theOscMessage.get(0).intValue();
	switch(received_data) {
		case 0:
		myo.withoutEmg();
		break;
	case 1:
		myo.withEmg();
		break;
	case 4:
		myo.vibrate(3);
		break;
	}
}

void myoOn(Myo.Event event, Myo myo, long timestamp) {
	int events = 0;
	OscMessage myOscMessage = new OscMessage("NULL");
	switch(event) {
		case EMG:
			myOscMessage.add("EMG");
			int[] data1 = myo.getEmg();
			for(int i = 0; i<data1.length; i++){
				myOscMessage.add(data1[i]);
			}
			events = 1;
			break;
		case GYROSCOPE:
 			myOscMessage.add("Gyro");
			PVector data2 = myo.getGyroscope();
			myOscMessage.add(data2.x/8.0);
			myOscMessage.add(data2.y/8.0);
			myOscMessage.add(data2.z/8.0);
			events = 1;
			break;
		case ACCELEROMETER:
			myOscMessage.add("Accel");
			PVector data3 = myo.getAccelerometer();
			myOscMessage.add(data3.x*40);
			myOscMessage.add(data3.y*40);
			myOscMessage.add(data3.z*40);
			events = 1;
			break;
		case ORIENTATION:
			myOscMessage.add("Orient");
			PVector data4 = myo.getOrientation();
			myOscMessage.add(data4.x*14);
			myOscMessage.add(data4.y*14);
			myOscMessage.add(data4.z*14);
			events = 1;
 			break;
	}
	if(events > 0){
		oscP5.send(myOscMessage, myBroadcastLocation);
	}
}

この最後のProcessingスケッチから、もう一押しで「ダブルMyo」に挑戦したくなるようなアイデアも浮かんでいるのだが、これはたぶん、しばらくして思い出したら、という事になりそうである(^_^;)。 ここで静岡駅まで来た。あと20分で浜松に着き、バスで大学に行って、このデータをWebにFTPすると、無事に「Myo日記」はオシマイだろう。

なお、来年あたりに向けて、海外演奏ツアーに「楽器」としてMyoを持参するか、それともmbedかPropellerで新しいオリジナル筋電楽器を作るか、はまだ未定である。 というのも、Myoは充電中はそれに専念しているのでいいが、充電を終えると、defaultでメインボックス上のブルーのマークがゆっくり明滅して、ひたすらUSBドングルとBluetooth接続を求め続けるのである(^_^;)。 これは、飛行機に乗る場合にはかなり厄介で、スマホ等のように「機内モード」が無いのだ。 SDKのドキュメントのどこかに、「Deep Sleep」というコマンドがあったので、あれを与えるとたぶん沈黙するのだろうが、Processing、つまりJavaからこれが出来るかどうかも不明である。 ここが解決しないと、ちょっと飛行機に持ち込みにくいのだ。 実際には、大分の知覚コロキウムでセントレアと博多空港を往復する間にも、機内で僕のキャリーバック内のMyoはずっとBluetoothを出していた(^_^;)のだが、海外に持っていって取り上げられたら困るのである。

大学に戻ると、もう自由創造工房の前の桜は散り始めていた。

→ 話はここに続く