TECH PLAY

アプトポッド

アプトポッド の技術ブログ

248

答え:トラベルルーターを使うと、手持ちのPC・スマホのWebブラウザからポチポチするだけで設定を変えられる!! 先端技術調査グループの南波です。 aptpod Advent Calendar 2019 の7日目はちょっとした便利ガジェットのお話です。 背景 1日目 、 2日目 でも紹介あったように、先端技術調査グループでは「自社技術・製品と世の中の技術・製品(機械学習、AWS Robomakerなど)を組み合わせ、新たな気付きをもたらすようなデモを作る」こともミッションの1つとして取り組んでいます。 デモの多くは展示会駆動開発(TDD 😎)で作られるため、 1日目 のTurtlebot3内蔵のもの、 2日目 のWebカメラのUSB接続先など、ラズパイを使う場合は展示会会場に引かれたLANに有線で接続するだけ、という前提で社内での動作検証等も行うことができます。 課題 まずは展示会をターゲットに作るのですが、bizdevチームから「この前のデモ、次の訪問打ち合わせに持ってきたいんだけどできるかな?ネットワークはモバイルルーターあればいい?」と2次利用依頼されることもあり、この場合は接続先の情報に合わせてラズパイを設定することになります。 ラズパイの無線ネットワーク接続の設定を変更するとき、基本的には ディスプレイ/キーボードを直接刺して編集する 手元のPCと同じネットワークに繋ぎ、sshで入って編集する のどちらかを行うことになるかと思います。 環境の整った社内で実施する場合はこれで問題ないのですが、「持って行ったモバイルルーターが調子が悪いので、お客様がお持ちのゲスト用無線LANなどの別のネットワークに変更したい」といった事情が発生した場合に苦しくなります。 解決策 トラベルルーターを使います。トラベルルーターは名前の通り、 小型軽量 ホテルなどに敷設された有線LANを、イーサネットの口のない手持ちのスマホ・ラップトップから利用できる といった特徴を備えたいわゆる無線ルーターです。さらに(今回検証に利用したBuffaloの機種では「ワイヤレスワンモード」という名前の) ホテルなどに敷設された無線LANを、イーサネットの口のある手持ちのデバイスから利用できる という機能もあり、「小型軽量」という特徴と合わせて今回の課題の解決にぴったりハマりました。 動作検証 ① Buffaloの WMR-433W2 を購入 ② 電源を入れ、手持ちのPCから筐体裏の情報(SSID / Password)に従い接続 ③ ウェブブラウザから 192.168.13.1 にアクセスし、動作モードおよびWAN側の設定を実施 トラベルルータ設定画面-1 トラベルルータ設定画面-2 トラベルルータ設定画面-3 ④ 手持ちのPCからインターネットに接続できていることを確認 🎉 ⑤ ラズパイとトラベルルーターを接続 イーサネットで有線接続、または $sudo raspi-config 等から無線の設定を入力して接続 ⑥ ラズパイからインターネットに接続できていることを確認 🎉 上記で一度動作確認できれば、以降は ② ~ ④ の手順だけを行うだけで、ラズパイから任意のネットワークを利用することができるようになります。 まとめ aptpod Advent Calendar 2019 7日目はラズパイの出先利用をちょっと便利にするデバイスのご紹介でした。 1つ懸念としては、「あくまで1,2個のデバイスを短時間接続する」目的での利用を想定した選択のため、「より多くのデバイスを長時間連続で」といったケースではまた別の選択が必要になるかもしれません。今後その課題に直面した際にはまたなにか記事にできればと思います💪
アバター
aptpod Advent Calendar 2019 6日目担当のエンベデッドチーム 久保田です。 仕事で関わることの多い自動車関連の技術について、少しお話させていただこうと思います。 intdash Automotive Pro は、自動車産業における車両CAN(Controller Area Network)データのデータロギング、データ管理、可視化・解析などのワークフローをクラウドシステムをベースにワンストップで実現するSaaSソリューションです。 このソリューションで車両CANを扱っていますが、CANの拡張型プロトコルであるCAN FD (CAN with Flexible Data rate)についてはご存じない方もいらっしゃるのではないでしょうか。 CAN FDについて調べると、ハードウェア仕様の話から始まる難しい記事ばかりです。 そこで、ソフトウェアエンジニア目線でCAN FDについてまとめてみました。 CAN FDについて、ざっくり知りたい方向けです。 CAN (Controller Area Network) CAN FDの話の前に、CANをおさらいしておきます。 CANとは、ドイツのBosch社が開発したシリアル通信プロトコルです。 OSI参照モデルの物理層・データリンク層・トランスポート層にあたります。 ライン型バス 複数のノード接続によるネットワークを構成するため、CANはライン型バスを採用しています。 転送速度 転送速度の最大は 1 Mbpsです。 フレーム バスに流れる信号は5つのFieldで構成されています。 フレーム機能 フィールド名 説明 Arbitration field 通信調停 Control field 通信制御 Data field 転送データ CRC field 誤り検出 Acknowledge field 受信完了通知 フレーム構成 ID (標準ID:11 bits, 拡張ID:29 bits) データ長(DLC) データ (最大 8 bytes) マルチマスター方式 バスに空きがある場合、ライン型バスに接続された全てのノードはフレームを送信できます。 ノードはライン型バスに接続された全てのノードにフレームを送信できます。 ( ブロードキャスト ) フレームを受信した場合は全てのノードが受信完了を通知できます。( ACK ) CSMA/CA方式バスアクセス バスに早くアクセスしたノードがフレームを送信できます。 また、同時に複数のノードがフレームを送信開始した場合、優先順位の高いID (ID番号の小さい方) が送信できます。 CAN FD(CAN with Flexible Data-Rate) CAN FDとは、CANプロトコル仕様を拡張し、従来のCANよりも通信速度の高速化と送受信データの大容量化に対応可能な通信プロトコルです。 従来のCANと物理層、システム構成がほぼ同等 物理層のコントローラ、トランシーバはCAN FD対応必要 IDは「標準フォーマット(11ビットID)」と「拡張フォーマット(29ビットID)」の2種類 (従来と同等) データ長は 最大 64 bytes (従来は最大 8 bytes) 通信ボーレートは最大 1 Mbps (従来と同等) データ部分の転送速度が可変で 通信ボーレートの1 Mpbs以上 が可能 (従来は通信ボーレートと同等) CAN FD種類 non-ISO CAN FD (The original Bosch CAN FD) ISO CAN FD (CRC強化による堅牢性改善) CAN FDフレーム構成 ID (標準ID:11 bits, 拡張ID:29 bits) データ長(DLC) データ ( 最大 64 bytes ) CAN FDデータ長 (bytes) フレームに指定されたDLCによりデータ長が指定できます。 CANが最大 8 bytesに対して、CAN FDは最大64 bytesです。 DLC 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 CAN 0 1 2 3 4 5 6 7 8 8 8 8 8 8 8 8 CAN FD 0 1 2 3 4 5 6 7 8 12 16 20 24 32 48 64 通信速度 通信調停を行うnominal(arbitration)ビットレートとデータを転送するdataビットレートとを異なるビットレートに設定が可能です。 nominalビットレートは最大 1 Mbpsですが、 例えば、dataビットレートは制御用途では 2 Mbps、診断・リプログラミング用途では 5 Mbpsで使用されます。 通信パフォーマンス 種類 CAN転送速度(kbps) Data転送速度(Mbps) 送信フレーム数(/sec) CANデータ長(bytes) busload(%) CAN 500 - 4000 8 99 CAN FD 500 2 4000 8 46 CAN FD 500 2 4000 32 99 通信速度の高速化と送受信データの大容量化により、データ転送効率が改善されています CANノードとCAN FDノードの混在 CANノードとCAN FDノードが同一バス上に混在可能です。 ただし、CANノードはCAN FDフレームを受信できません。 送信フレーム CANノード受信 CAN FDノード受信 CAN フレーム OK OK CAN FD フレーム Error OK まとめ CAN FDについて、おわかりいただけましたでしょうか。 Linuxでは、SocketCanと呼ばれるsubsystemにてCAN FDがサポートされていますので CAN FD対応トランシーバを簡単に接続することができます。 実際に動作させて、CAN FDの優位性を確認してみてください。 参考 CAN in Automation (CiA): CAN FD - The basic idea SocketCAN - Controller Area Network — The Linux Kernel documentation
アバター
本ブログへいらっしゃったみなさま、初めまして。 aptpod Advent Calendar 2019 5日目担当のsetoです。入社4ヶ月(2019/12/05現在)で、機械学習系の案件や自社プロダクト付加価値向上のための技術調査に従事してます。社内メンバーの技術領域が多彩で刺激を受けながらお仕事しています。 本記事では、エッジデバイスに採用したJetson Nanoの出力結果とクラウド推論に採用したAmazon SageMakerのエンドポイントの出力結果が同じにならない問題に遭遇し、解決するのに苦労した話です。 この記事を要約しますと、"読み込んだ画像のピクセル値が環境が違うと同じにならない"という検証すればすぐわかる問題に自分の思い込みのせいでなかなかたどり着けなかったという経験談を書いております。 取り組みの背景 弊社が開発を進めているシステムは、ディープラーニングの推論をクラウドとエッジデバイスの別々の環境でおこなっています。推論結果の一貫性を保つため同じ入力で同じ結果が出力できるように調査と対応を行うのが取り組みの背景です。 具体的には、クラウドの推論にAmazon SageMakerでApache MXNetを使用した機能を利用し、エッジ側はAmazon SageMaker NeoとNeo-AI-DLRを利用しました。この取り組みのゴールはこれらの異なるフレームワークから出力される推論結果を一致させることです。 使用しているフレームワーク Amazon SageMaker クラウド側の推論は Amazon SageMaker (以下、SageMaker)を活用しています。本テックブログの 2日目のキシダさん も同じフレームワークを活用しており、こちらの記事もご覧いただけると理解が深まると思います。本ブログでは、 SageMaker上でApache MXNetを動作させる枠組み を用いたものを利用しています。 Apache MXNet (以下、mxnet)は,ディープラーニングのフレームワークの一つです。 Amazon SageMaker Neo エッジ側の推論は Amazon SageMaker Neo (以下、SageMaker Neo)とSagMaker NeoでコンパイルしたモデルをJetson Nanoで動作させるランタイム Neo-AI-DLR (以下、dlr)を活用しています。本ブログでエッジ側で動作させる場合は、これらのフレームワークを活用して動作させていることになります。 調査の詳細 今回、調査した推論機能のパイプラインは下図のとおりです、特殊なことはなにもしていません。 図1. 推論処理パイプライン 調査をおこなう際にSageMakerのエンドポイントを立て続けて検証することはコストが高かったため、同一の結果がでることを確認したGPU付きのローカルマシンを代わりに使用しました。 調査の流れは、 推論処理の一致確認(計算が複雑で一致が難しいと判断したためはじめに対応) 前処理の結果の一致確認(1.よりは簡易であると考え2番目に対応) 画像の読み込みの一致確認(予想外の対応) という項目を行いました. 3. は予想しておらず、 2. が問題だという思い込みが苦労した大きい要因でもあります。調査に思い込みは厳禁であることを溶かした時間で学びました😇 推論処理の一致確認の詳細 この調査のゴールは、入力データを同じにすればエンドポイントで利用しているmxnetとエッジ側のdlrの推論結果の一致を確認することです。手続きとして以下の2段階の分けて確認を行いました。 全て1にした配列を入力して出力結果が一致するかを確認(一様な入力で一致するのか) 0.0~1.0までのランダムな数字で出力結果が一致するかを確認(多様な入力で一致するのか) この検証の際は、並列計算の加算が多く行われているため全ての数字の一致は望めないため、 1e-5 の桁まで数値が同じであれば一致しているとしました。これらの調査の結果、クラウド側のSageMakerの推論結果とエッジ側のdlrを用いた推論結果は一致することがわかりました。つまり、 推論に入力する前処理済みのデータが一致していない ことがわかりました。 前処理の結果の一致確認の詳細 この調査のゴールは、同じ実装を使った前処理の出力結果の一致を確認することです。前処理は、どのデバイスでもだいたいpipで入れることができる、pillow(6.1.0)ライブラリを使って実装しました。 図1. から前処理はリサイズとクロップをおこなう処理となります。前処理は、画像でみると 図2. のように変形処理を施していきます。 図2.前処理のイメージ図 確認方法は、サンプル画像を入力し結果が一致するかを調査しました。結果は出力の配列が不一致となりました。このため、個々の処理を調べる必要があると判断し、はじめに出力に近いリサイズの調査を行いました。この結果、同じバージョン、同じ補完方法でも結果が一致しませんでした。このため、他のライブラリを使ってみたり、githubのソースコード見にいったり色々調査をしましたが、これだと強く主張できる原因を見いだせていませんでした。ここで大きく時間をかけてしまいました。このときに自分の考えにバイアスがあり入力に着目するまで考えが及ばなかったことが本件の時間浪費の原因でした。バイアスよくない😰 画像読み込みの一致確認の詳細 何がきっかけか覚えていませんが、そもそも読み込んだ画像データに違いがあれば、 前処理の結果が一致するはずがない と思い至り、入力画像を読み込んだデータで比較しました。その結果、読み込んだ画像のピクセル値が一部一致しないことがわかりました。 ついに原因を特定することができました! 以下、公開して良いデータを使って一致しない結果を再現しました。 ※調査当時はGPUサーバーを使いましたが、MacBook Proも画像読み込みの結果がGPUサーバーと一致したので、再現はMacBook Proを使用しています。 以下、エッジ側で画像を保存するためのスクリプトです。非常に簡易なスクリプトでpillowで画像を読み込んだ後にndarrayに変換しnpyで保存しています。このnpyファイルをMacBook Proに持ってきて比較を行いました。 #!/usr/bin/env python # coding: utf-8 import argparse import numpy as np from PIL import Image if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('-f', '--file-name', required=True, type=str) args = parser.parse_args() img_dir = './sample-images/IMG-0269.JPG' img = Image.open(img_dir) img_arr = np.array(img) store_name = args.file_name np.save(store_name, img_arr) 以下、比較したnotebookです。7セル目のFalseが比較結果になります。 このの経験からpython上で扱うライブラリのバージョンが同じでも、結果が一致する保証はないという教訓を得ることができました。 notebook 問題はどのように対処したのか エッジ側はライブラリを色々インストール、アンインストールしても変えることができなかったので、クラウド側の画像読み取りを変えました。pillowではなくmxnetでの読み込みに置き換えたら画像のデータが一致したので、mxnetでの読み込みを採用しました。notebookの8セル目と9セル目の結果が再現となっています。 調査しきれなかったこと,わからなかったこと おそらくpillowとmxnetが画像読み込み時に利用しているlibjpegのバージョンなどが異なっていることが原因であると判断しました。しかし、エッジ側のlibjpegのバージョンを変更しても解決できませんでした。このため、きちんと原因を追い切れているわけではなく、再現しない可能性もあります。 まとめ 異なるフレームワーク、ライブラリを使って推論結果をあわせるのは予想以上に苦労しました。ディープラーニングのフレームワークをまたいで処理結果を近似することは経験していてそこが一番苦労すると思っていたことが落とし穴でした。また、データ読み込みに一貫性がないわけがないとう確信がより問題の特定に時間をかけてしました。これを教訓に調査する、比較するといったときはこうあるだろうなどのバイアスをなるべく持たないようにしたいと思います。 最後に,本ブログをここまで読んでいただきありがとうございます。これからも苦労したことや検証してみた内容などを引き続きブログにアップロードしていきたいと思います!
アバター
はじめに aptpod という会社のQAチーム横田です。 Aptpod Advent Calendar 2019  4日目の記事になります。 去年に引き続き、アドベントカレンダーを書いています。 去年は、テスト自動化について書きました。 qiita.com 今回は、QA(品質保証)とは何かを考えた話を書いていきたいと思います。 * QA = Quality Assurance(以下、QAと省略する) QAって何をするの はじめに、QAの一般的な定義を明記しておきます。 品質保証(ひんしつほしょう、英: quality assurance、QA)は、効率と品質が求められるあらゆる活動において、それらに保証を与えるのに必要な証拠を提供する活動一般を指す。計画され体系化された活動は一般に、その製品やサービスが要求された品質を満足していることを保証する必要がある。品質保証は品質管理と密接に関連しており、これらによって顧客や権利保有者のニーズ・期待・要求に製品が適合していることを保証する。QA は、品質が所定のレベルに到達していることを事前に確認する手続きを効率的に構築するものである。 QA は設計・開発・製造・実装・サービス・文書といったあらゆる活動をカバーする。また、QA には材料や部品、製造工程や検査工程などの品質の規定も含まれる。 Wikipediaより引用 品質保証 - Wikipedia 品質とは 本題のQAとはの前に、そもそも「品質」とは何を指すのかを自分なりに考えました。 千差万別の考え方があり、これが答えだとは思っていません。 あくまで、今回考えた際に、私なりにしっくりきた内容としています。 改めて考える前までも、「品質」という言葉は当たり前の様に使っていました。 その時は、 良い品質 = ユーザが心地よく使えること ぐらいの感覚でいました。 そこに、開発者含む提供する側の事は一切考えていません。 「開発者が疲弊した結果ユーザが心地よくなったら、それは良い品質なのだろうか?」(哲学的・・・) 自問自答した結果、答えは 『NO』 でした。 結論 「ユーザーも企業も安心していられる状態」が今の所一番しっくりくる答えになりました。 どんな状態か ユーザー 何の不便も不安も無く使用できている →言わずもがなですが、何の障害も無くユーザビリティ的にも不自由無く使用できている状態です。 企業 次に向かって進んでいる →例えば、リリースしたモノに対して、何も心配しなくて良い状態です。 じゃ、QAは何をするの? 「品質」の定義ができたので、本題のQAは何をするのかに話を戻します。 QA=品質保証=「ユーザーも企業も安心していられる状態」を整える活動 を指す。 これが現時点での私なりの答えになります。 リリースまでは、ユーザーが安心できる状態を「テスト」という手段で作っていきます。 リリース後は、PMや開発メンバーが何もせずに次のプロダクト開発ができる様な環境を作っていきます。 例えば、問い合わせが発生したバグの一次請けだったり、リグレッションテストを定期的に行うなどして 心配事を少しでも減らしていく活動を進めてい行くことかなと思います。 よく、QAやテストエンジニアは「最後の砦」と言われがちですがユーザーと企業と並走して進んでいくことが理想と考えています。 そんな活動を少しでもしていきたいなと思います。 まとめ こういった活動していくには、多彩な知識が必要になってきます。 テストの事だけでなく、開発手法や工程についての知識も。 また、限られたリソース(人員/時間など)内で行うには、自動化スキルだったりも必要になってきます。 もちろん、様々な人達と会話することが必然的に求められていくので、コミュニケーション能力も大事。 そういった成長ができる職種がQAとしての醍醐味かなと思っています。
アバター
この記事は Aptpod Advent Calendar 2019 の3日目の記事です。 先端技術調査グループの大久保です。 最近はWebAssemblyが注目されるようになり、弊社でもWebフロントエンド側での軽量化・高速化に応用できないか検討をしています。 そこで、今回はWebSocketのechoクライアントをRustとGoで作成し、wasmへコンパイルした時のファイルサイズを比較してみます。現状では、wasm内から直接WebSocketを取り扱う方法は無いらしいので、JavaScriptのAPIを呼び出してWebSocket通信を実現します。 Goでの実装 私はGoが書けないため、先輩からもらった以下のコードを使わせてもらいました。適当にwstest.goと名前を付けて保存します。 package main import ( "fmt" "syscall/js" ) func print (i []js.Value) { fmt.Println(i) } func websocket_test(this js.Value, args []js.Value) interface {} { fmt.Println( "start websocket_test" ) ws := js.Global().Get( "WebSocket" ).New( "wss://echo.websocket.org/" ) ws.Set( "onopen" , js.FuncOf( func (this js.Value, args []js.Value) interface {} { fmt.Println( "open" ) ws.Call( "send" , "hello world" ) return nil })) ws.Set( "onmessage" , js.FuncOf( func (this js.Value, args []js.Value) interface {} { data := args[ 0 ].Get( "data" ) fmt.Println( "Received =" , data) fmt.Println(args, args[ 0 ], data.Type(), data.String()) ws.Call( "close" ) return nil })) ws.Set( "onerror" , js.FuncOf( func (this js.Value, args []js.Value) interface {} { fmt.Println( "Error" ) return nil })) ws.Set( "onclose" , js.FuncOf( func (this js.Value, args []js.Value) interface {} { fmt.Println( "WebSocket connection closed." ) return nil })) return nil } func registerCallbacks() { js.Global().Set( "websocket_test" , js.FuncOf(websocket_test)) fmt.Println( "After callback register" ) } func main() { c := make ( chan struct {}, 0 ) registerCallbacks() <-c } index.htmlを次の内容で用意します。 <!doctype html> < html > < head > < meta charset = "utf-8" > < title > Go wasm </ title > </ head > < body > < script src = "wasm_exec.js" ></ script > < script > const go = new Go () ; WebAssembly.instantiateStreaming ( fetch ( "test.wasm" ) , go.importObject ) .then (( result ) => { go.run ( result.instance ) ; } ) ; </ script > < button onClick="websocket_test () ;" id = "runButton" > Run </ button > </ body > </ html > 次のコマンドでコンパイルします。 GOOS=js GOARCH=wasm go build -o test.wasm あと、wasm_exec.jsを用意します。 curl -sO https://raw.githubusercontent.com/golang/go/master/misc/wasm/wasm_exec.js これらの用意したファイルがあるディレクトリでサーバを立ち上げます。 python3 -m http.server 8080 Webブラウザで http://localhost:8080/ にアクセスすると、ボタンを押すたびに次のようにコンソールへ出力されます。 open Received = hello world [<object>] <object> string hello world WebSocket connection closed. エコーサーバにアクセスし、メッセージが返ってきていることが確認できます。 Rustでの実装 RustからWasmのHelloWorldは以下のドキュメントの通り行えば問題ありません。もちろんRustの処理系はあらかじめインストールしておく必要があります。 https://rustwasm.github.io/docs/book/game-of-life/hello-world.html WasmからWebSocketを利用する方法は、以下参考。 https://rustwasm.github.io/docs/wasm-bindgen/examples/websockets.html Goの方の実装に合わせて少々変えたので、以下ソースコードを記載します。まずはlib.rsから。 #![no_std] extern crate alloc ; use wasm_bindgen :: prelude :: * ; use wasm_bindgen :: JsCast; use web_sys :: {ErrorEvent, MessageEvent, WebSocket}; use alloc :: boxed :: Box ; use alloc :: string :: ToString ; #[global_allocator] static ALLOC: wee_alloc :: WeeAlloc = wee_alloc :: WeeAlloc :: INIT; #[wasm_bindgen] extern "C" { // console.log()をインポートする #[wasm_bindgen(js_namespace = console)] pub fn log (s: &str ); } macro_rules! console_log { // println!()風にconsoleへ出力するためのマクロ ( $($t :tt )* ) => ( log ( & format_args! ( $($t)* ). to_string ())) } #[wasm_bindgen] pub fn websocket_test () -> Result < (), JsValue > { // echoサーバにつなげる let ws = WebSocket :: new ( "wss://echo.websocket.org" )?; // コールバックを登録していく let onmessage_callback = Closure :: wrap ( Box :: new ( move | e: MessageEvent | { let response = e . data () . as_string () . expect ( "Can't convert received data to a string" ); console_log! ( "message event, received data: {:?}" , response); }) as Box < dyn FnMut (MessageEvent) > ); ws. set_onmessage ( Some (onmessage_callback. as_ref (). unchecked_ref ())); onmessage_callback. forget (); let onerror_callback = Closure :: wrap ( Box :: new ( move | e: ErrorEvent | { console_log! ( "error event: {:?}" , e); }) as Box < dyn FnMut (ErrorEvent) > ); ws. set_onerror ( Some (onerror_callback. as_ref (). unchecked_ref ())); onerror_callback. forget (); let cloned_ws = ws. clone (); let onopen_callback = Closure :: wrap ( Box :: new ( move | _ | { console_log! ( "socket opened" ); match cloned_ws. send_with_str ( "ping" ) { Ok (_) => console_log! ( "message successfully sent" ), Err (err) => console_log! ( "error sending message: {:?}" , err), } }) as Box < dyn FnMut (JsValue) > ); ws. set_onopen ( Some (onopen_callback. as_ref (). unchecked_ref ())); onopen_callback. forget (); Ok (()) } web_sysというクレート以下にJavaScriptのオブジェクトにアクセスするための各種APIが用意されているので、それを利用します。また、 #[wasm_bindgen] という属性をつけるだけで、RustとJavaScriptの間で関数やオブジェクトを相互にやりとりできるようにしてくれます。ここでは、 console.log() をRustから利用できるようにしたり、 websocket_test() という関数をJavaScript側から利用できるよう設定します。この websocket_test() が呼び出されると、WebSocketのインスタンスを作成し、on_openなどの各種コールバックを設定していきます。JavaScriptの関数やオブジェクトをシームレスに扱えるので、Goよりも洗練されている印象です。ただしクロージャまわりは若干トリッキーに書く必要があるようです。Rustのライフタイムを理解していないと意味不明かもしれません。 また、よりサイズを小さくするため #![no_std] を指定し、標準ライブラリが含まれないようにします。また、メモリアロケータに WeeAlloc を指定します。これはwasm向けのよりサイズの小さいメモリアロケータです。 index.htmlではボタンを配置します。 <!DOCTYPE html> < html > < head > < meta charset = "utf-8" > < title > Hello wasm-pack! </ title > </ head > < body > < noscript > This page contains webassembly and javascript content, please enable javascript in your browser. </ noscript > < script src = "./bootstrap.js" ></ script > < button id = "runButton" > Run </ button > </ body > </ html > index.jsにJavaScriptを書いていきます。ここでは、ボタンがクリックされた場合に、lib.rsで定義した websocket_test() を呼び出すようにします。 import * as wasm from "wsecho-client" ; document .getElementById( "runButton" ).onclick = function () { wasm.websocket_test(); } ; npm start でサーバを立ててアクセスすると、ボタンを押すたびにコンソールに次のような表示が出ます。 socket opened message successfully sent message event, received data: "ping" エコーサーバにメッセージを投げて、返ってくることを確認できました。 ファイルサイズの比較 RustとGoそれぞれで生成されたwasmファイルを比較してみます。どちらも生成されるwasmファイルは1つのみですが、wasmをロードしたりするためのJavaScriptファイルがいくつかついてきます。JavaScriptファイルのサイズはどちらも10KB程度ですが、Rustの方はJavaScript向けにバインディングを生成する関係上、サイズが変化する可能性があります。ちなみにRustからはTypeScript用のバインディングも勝手に生成してくれるというオマケつき。 wasmファイルのサイズは以下の通りです。 Rust Go wasmファイルのサイズ(バイト) 42875 2276691 Goはランタイムが重いせいか、Rustのほうが圧倒的にサイズが小さいです。 サイズを最適化 UNIXには実行ファイルを小さくする(シンボル情報を削除する)ための strip コマンドがありますが、似たようなものがwasmにも用意されています。以下の2つのツールを使ってサイズを最適化してみます。 wasm-strip ( https://github.com/WebAssembly/wabt ) カスタムセクション(シンボル情報みたいなもの)を削除してくれるツール。 wasm-opt ( https://github.com/WebAssembly/binaryen ) 用途に応じてwasmを最適化してくれるツール。サイズ最適化には -Os オプションを使う。 これらを適用した結果が以下の表になります。 (単位はバイト) Rust Go オリジナル 42875 2276691 wasm-strip適用 30649 2226331 wasm-opt適用 26663 2161744 両方適用 26538 2161607 どちらもサイズの削減ができましたが、Goの方は2MBを割ることはできませんでした。GC等のランタイムが入っているとしたらこんなものなのでしょうか。tinygoというものを使えばずっと小さくできるらしく、試したところwasmファイルの生成まで行きましたが、Webブラウザでアクセスした時にエラーが出たので今回は割愛します。 ちなみに、wasm-optはデフォルトでカスタムセクションを削除するのでwasm-stripを重ねて適用する必要は無いはずですが、wasm-strip -> wasm-opt の順で適用すると、wasm-optだけ適用した時と少しサイズが異なってました。 まとめ wasmのファイルサイズを見ると、RustはGoよりずっと軽量 RustとJavaScriptのやりとりはかなりシームレスに書けるようになっている。 wasmのバイナリをいじるツールもリリースされており、サイズ圧縮もできる。 WebAssemblyについては引き続き調査を行って参ります!
アバター
aptpod Advent Calendar 2019 2日目担当のキシダです。もともとただのエンジニアだったのですが、半年前ほどこちらに入社して、今では機械学習系の案件やデータ解析向け製品の開発に従事してます。周りの人も心優しい人ばかりで、楽しくお仕事しています。 (職種はデータサイエンティストですが、他にもいろいろやらせていただいてます) よろしくお願いいたします。 さて本記事では、私が入社したての頃に弊社の機械学習系案件の技術紹介の一貫で、 お菓子のリアルタイム検出システムデモ をAmazon SageMakerと自社製品を使って構築することになり、その際に奮闘した記録をこの場をかりてご紹介したいと思います。 このデモは、今開催されている 『AWS re:Invent 2019』 にも展示されているので、もしラスベガスにいらっしゃる方、ぜひ弊社 aptpod のブースまで! ※Amazon Sagemakerについてはこちらへ Amazon SageMaker(機械学習モデルを大規模に構築、トレーニング、デプロイ)| AWS どんなシステム? 当初の願望としてはこんな様子でした。 アプトポッドのロゴ入りお菓子(かわいい)をカメラにうつすと、お菓子の種類をシステム側が検出 検出結果はリアルタイムで弊社製品の可視化ツール Visual M2M (後述に簡単な説明記載)上で常に表示されている お客さんがお菓子をとったりおいたりすると、それに伴って Visual M2M 上でシステムが反応するので楽しい かわいいお菓子ももらえてさらにハッピー お客さんがよろこんで僕もハッピー みんなハッピー ・・・ という感じで作りたいね、となりました。 その結果・・・ 一ヶ月足らずで以下のようなデモができました。 Visual M2Mで写すお菓子たち お菓子の撮影現場 弊社デザインチームがデザインした主役のおかしたち。うん。かわいい。 意外に好評なデモの展示会場 と、イメージとしてはこのような感じです。 このデモで使用する自社製品/サービス 僭越ながら、今回のデモで使用している製品をざっくり紹介させていただきます。 intdash aptpodの主力製品である『intdash』 はご存知ですか?? 弊社HP( https://www.aptpod.co.jp/products/ )ではこう記載されています。 intdashとは、世界高速レベルの100ミリ秒∼1ミリ秒間隔程度の高頻度で、 発生する時系列データを品質保証のないネットワークを経由して、 高速・大容量かつ安定的にストリーミングするための双方向データ伝送プラットフォームです ちょっとあまりピンとこない方が多いかもしれませんが 「ものすごい速く、しかもデータが欠けることなく双方向に通信できるプラットフォーム」 とイメージいただければよいかと。。。   このブログでもintdashについて触れているのですが、より詳細を知りたいという方がいらっしゃいましたら こちら をご参照ください! Visual M2M 既に上記で紹介しましたが、今回の検出結果の可視化には『intdash Visual M2M(通称VM2M)』( https://www.aptpod.co.jp/products/vm2m/ ) と呼ばれるイケてる可視化ツールを使います。 intdash Visual M2M intdash Analytics Services intdashのみだとデータを双方向にストリーミングするため、通常はデータ通信途中のデータをストリーミングで解析・加工することができません。そこで、『intdash Analytics Services』 と呼ばれる「データの解析用実行基盤」も提供しています。この製品を使うことで、以下のユースケースに対応できます。今回は、お菓子を撮影した動画データを加工する基盤として使っています。 時系列データの計算処理・分析処理を実装したコードをintdashに反映し、処理することができる 機械学習環境の構築にも適用でき、高速な推論パイプラインを回す などなど システムのアピールポイント 前述も触れてますが、このシステムのポイントは リアルタイム性 です。 ローカルデータを分析して可視化するというパターンとは違い、動画の撮影中と同時にシステムはお菓子を検出し、UIに表示してくれるというわりと難しめなシステムを短期間で開発できることがこのデモのアピールポイントです。 intdashべんり。 展示会のコンテンツとしての旨味 お菓子が動画に映ると、システムがリアルタイムで反応して、「動いてる動いてる!!!」となって楽しい アプトポッドとしてのアピールポイント お客様向けには、欠損なくリアルタイムで機械学習の推論が回せることと、その開発が容易であることをアピールしました。 intdash Analytics Serviceによって、外部サービスと連携してストリーミングデータの加工を容易にする 加工を行っても、データ通信のリアルタイム性を担保する 開発者側は加工処理をスクリプトを書くだけで、あとはAPIを叩くだけでデータのストリーミングシステムの簡単に組み込むことができる 実現方法 いよいよ本題です。ここでは本システムを構築した手順をざっと記し、次項でより詳細な奮闘記を記します。 今回のシステム構築に伴い使用したサービスとその関係は以下の図の通りです。 使用サービスとその流れ 実現までのおおまかな手順 手順イメージ 通常の動画データを画像で切り出し、Amazon SageMaker Ground Truth にてアノテーションしトレーニング用データを作る Amazon SageMakerを使用してモデルをトレーニング モデルを通して推論できるようなエンドポイントを構築する(このエンドポイントに画像を渡すと、検出結果が返ってくるようになります) intdashから取得した動画データをSageMakerのエンドポイントに投げて、検出結果を可視化するスクリプトを、intdash Analytics Serviceにデプロイする これができればあとはWebカメラから実際に繋げてVM2Mで見ればOKです。 手順2,3箇所はこちらを参考にしました:  SageMakerで「うまい棒検出モデル」を作ってみた   https://dev.classmethod.jp/cloud/aws/sagemaker-umaibo-object-detection/ トレーニング用データの作成 お菓子の撮影 まずはお菓子の画像を撮影します。方向を45度ずつかたむけたり、複数お菓子を映したり、関係ないお菓子をいれたり、試行錯誤を続けました。 撮影したお菓子たち アノテーションの実施 実際に教師データ(正解データ)をつくるため、撮影したデータに対して、「どこに何がうつっているか」をツールを使って定義していきます。いわゆる アノテーション というものです。 今回は、AWSで展開されている、Amazon SageMaker Ground Truthを使用します。 実際には以下のように、対象のお菓子に対して四角(Bounding Box)で囲っていきます。 アノテーション実施中のUI ※Amazon SageMaker Ground Truthの詳細はこちらから   https://aws.amazon.com/jp/sagemaker/groundtruth/ 細かな手順を記載すると膨大な文章量となるので、こちらは割愛し個人的なGround Truthのお得ポイントをこちらにまとめておきました Amazon SageMaker Ground Truth お得ポイント せっかくなのでいくつか補足します。 1. ラベリングの種類が豊富 Ground Truthは作りたいモデルによって様々なアノテーションの種類が用意されています。また、自分用にアノテーションツールのカスタマイズもでき、自由度がだいぶ高いです。 2. ラベリングの作業をGround Truthがよしなにメンバーに割り振ってくれる ここでのGoodポイントは、 管理者はアドレスを追加するだけで一発で作業環境を提供できる ことです。IAMとかのセキュリティ設定や各ローカル環境の構築手順準備、作業結果のとりまとめなどなど、、、すべてやる必要がなくなります。超絶べんり。 今回はプライベートグループを使用して、こんな感じで社内の人たちに有志を募って作業をお願いしました。 ※お手伝いいただいた方々、ありがとうございました! 依頼したときの画面 モデルをトレーニングして、推論のAPIを構築する ここからは実際にAmazon SageMakerのモデルトレーニング機能を使用して、モデルをトレーニングしていきます。 使用するAPI ちなみにSageMakerを扱うAPIは2種類存在し、どちらを使用いただいても問題ないようです。 boto3 API s3などの処理を行うのにおなじみのAPIです。以下のインスタンスを起動すると、 boto3 から sagemaker 用のランタイムを起動できます client = boto3.client(service_name='sagemaker') SageMaker API こちらがメジャーとなっているAPIで、基本的にはこちらを使用するようです。 今回は馴染みのある 『boto3 API』を使用しました。 ハイパーパラメーターを指定する モデルを作成するにあたって、すべてSageMakerのAPIにおまかせ!!ってわけではなく、ある程度モデルに対するパラメーターをこちらで指定する必要があります。これは使用するモデルのアルゴリズムによって異なるので今回の記載は割愛しますが、詳細を見たい方は以下を参照ください。 オブジェクト検出アルゴリズムのハイパーパラメーター ちなみに今回指定したパラメーターは以下の通り training_params = \ { "AlgorithmSpecification": { "TrainingImage": training_image, "TrainingInputMode": "Pipe" }, "RoleArn": role, "OutputDataConfig": { "S3OutputPath": s3_output_path }, "ResourceConfig": { "InstanceCount": 1, "InstanceType": "ml.p3.2xlarge", "VolumeSizeInGB": 50 }, "TrainingJobName": job_name, "HyperParameters": { "base_network": "resnet-50", "use_pretrained_model": "1", "num_classes": "4", "mini_batch_size": "16", "epochs": "50", "learning_rate": "0.001", "lr_scheduler_step": "3,6", "lr_scheduler_factor": "0.1", "optimizer": "rmsprop", "momentum": "0.9", "weight_decay": "0.0005", "overlap_threshold": "0.5", "nms_threshold": "0.45", "image_shape": "300", "label_width": "350", "num_training_samples": str(num_training_samples) }, "StoppingCondition": { "MaxRuntimeInSeconds": 86400 }, "InputDataConfig": [ { "ChannelName": "train", "DataSource": { "S3DataSource": { "S3DataType": "AugmentedManifestFile", "S3Uri": s3_train_data_path, "S3DataDistributionType": "FullyReplicated", "AttributeNames": attribute_names } }, "ContentType": "application/x-recordio", "RecordWrapperType": "RecordIO", "CompressionType": "None" }, { "ChannelName": "validation", "DataSource": { "S3DataSource": { "S3DataType": "AugmentedManifestFile", # NB. Augmented Manifest "S3Uri": s3_validation_data_path, "S3DataDistributionType": "FullyReplicated", "AttributeNames": attribute_names # NB. This must correspond to the JSON field names in your augmented manifest. } }, "ContentType": "application/x-recordio", "RecordWrapperType": "RecordIO", "CompressionType": "None" } ] } トレーニングを実行 ハイパーパラメーターを定義したら、実際に実行してみます! client.create_training_job(**training_params) モデルをデプロイし、コンテナ上で推論を動かす SageMakerのすごいところは、予め用意された 組み込みアルゴリズム 以外にも、作成されたモデルを1ボタンで簡単にデプロイして、推論APIまでの構築を行ってくれることです。今までエンドポイント構築に苦労してきたデータサイエンティストにとっては、これからはモデルの作成や調整に時間をかけることができるというすぐれものです!! 実際にエンドポイントの設定を行い、 from time import gmtime, strftime import time import sagemaker as sage sage = boto3.Session().client(service_name='sagemaker') timestamp = time.strftime('-%Y-%m-%d-%H-%M-%S', time.gmtime()) endpoint_config_name = 'apt-snacks-endpoint-config' endpoint_config_response = sage.create_endpoint_config( EndpointConfigName = endpoint_config_name, ProductionVariants=[{ 'InstanceType':'ml.m4.xlarge', 'InitialInstanceCount':1, 'ModelName':'apt-snacks-model', 'AcceleratorType': 'ml.eia1.xlarge', 'VariantName':'AllTraffic'}]) エンドポイントをたてます。 endpoint_params = { 'EndpointName': endpoint_name, 'EndpointConfigName': endpoint_config_name, } endpoint_response = sage.create_endpoint(**endpoint_params) エンドポイントがたったことを確認したら、テスト用に推論APIを読み出すスクリプトを簡単に書き、実行してみます。 session = boto3.Session(region_name='us-east-2') runtime = session.client('sagemaker-runtime', config=config) #SageMakerのエンドポイント名の指定 endpoint_name = 'apt-snacks-endpoint' response = runtime.invoke_endpoint( EndpointName=endpoint_name, ContentType='image/jpeg', Body=payload ) result = json.loads(response['Body'].read().decode()) そして返ってきたデータを元に、Bounding Boxを出力してみると・・・ 検出結果たち いい感じに実行できました!(一部誤検出していますが。。) ものすごく簡単!!! intdashとSageMakerの仲介役となるスクリプトを作り、intdash Analytics Servicesにデプロイする 上記にて作成したスクリプトを拡張して、以下の処理を行うスクリプトを作成します。 raspiに導入している intdash edge から送られてきた画像データを取得する SageMakerの推論APIに画像データを送付し、推論結果を取得する 推論結果を可視化し、 intdash に アップロードする 作成したコードは、実際に動かすための実行環境である 『intdash Analytics Services』にデプロイします。 動かしてみる 上記を構築した上で、raspiから動画をストリーミングすると以下のように動かすことができます! Real-time object detection with Amazon SageMaker & intdash Services まとめ いかがでしたでしょうか。 今回はintdashとAmazon SageMakerを使ってお菓子のリアルタイム検出システムを簡単に構築することができました。難しいイメージの機械学習でも、SageMakerのAPIを使うことで簡単にモデルの作成からエンドポイントの構築まで自分で作成することができます。そこに弊社の高速データストリーミングプラットフォームと組み合わせることで、検出結果を動画の撮影と同時にリアルタイムで可視化でき、開発者側はインフラストラクチャーレベルを考慮せずシステムの構築を行うことができました。この記事を通して、Amazon SageMakerと弊社製品のintdashに少しでも興味をもっていただければ幸いです。 ※宣伝です。 ちなみにaptpodではデータサイエンティストを絶賛採用中です!もし本記事を見て、 『intdashと機械学習の技術を使ってサービス作ってみたい!』 など思ってくれる方がいらっしゃいましたら、ぜひ以下のHPまでどうぞ! 一緒に世界レベルの高速データ解析の実現を目指していきましょう! 採用情報: https://www.aptpod.co.jp/recruit/
アバター
先端技術調査グループの酒井です。 今年も Aptpod Advent Calendar 2019 に参加することになり 1日目を担当することになりました。 ちょっと前の話になってしまいますが、2019/12/2から始まるAWSのイベント 『re:Invent 2019』 へ展示していることもあり、AWS RoboMaker 関連の取り組みをお送りします。 AWS RoboMaker(ロボット工学アプリケーションの開発、テスト、デプロイ)| AWS AWS RoboMakerを使って、TurtleBot3 with OpenMANIPULATORに自社製品intdashを組み込んで、インターネット経由での遠隔制御に挑戦しました! 成果物は 2019/6/12〜14に開催された AWS Summit Tokyo 2019 で展示しました。 本記事ではその取り組みの中で、できたこと、できなかったこと、今後の展望などをまとめています。 ただ、AWS RoboMakerがTokyo Regionで提供される直前くらいからおおむね2か月くらいの取り組みだったので、できなかったことや積み残しも結構残っています。 できたこと AWS RoboMakerと自社製品のintdash Edge Moduleを使って、インターネット経由でTurtleBot3を遠隔制御できるようにしました。 具体的には、 PS3コントローラーを使って、TurtleBot3の実機とシミュレーション環境(Gazebo) 内のTurtleBot3を操作する 実機とシミュレーション両方を同時に操作する ことができます。 実際の動画 実際に動かしている様子を動画で撮影しました。 一つ目の動画は、コントローラーで操作している動画です。 Remote control TurtleBot3 with AWS RoboMaker+intdash 二つ目の動画は、シミュレーション環境との同時操作とその結果を可視化している動画です。 Visualize remote control TurtleBot3 with AWS RoboMaker+intdash 取り組みの背景 AWS RoboMakerと自社製品intdashでコラボレーションしたものを何か展示できないかというのがきっかけでした。 弊社としては、intdashがRoboMakerで使えると、パッケージとしての提供やデプロイが可能になるので、自社のデプロイの工数を減らすことができる可能性があります。 また弊社の製品を提供するという視点だと、 AWS RoboMakerを使うことによってROSの環境構築が簡単にできる点 Amazon SageMakerなどのAWSのアセットとの連携がしやすくなるという点 がメリットとして考えられそうです。 ビジネス的な価値はまだ明確にできていないので、今後も検討したいと思います。 使用したロボット、環境、自社製品の紹介 TurtleBot3 with OpenMANIPULATOR ロボットは、Turtlebot3 (with waffle pi) というロボットにOpenMANIPULATORというアームを取り付けた TurtleBot3 with OpenMANIPULATOR を使用しました。 Turtlebot3は研究、教育、プロダクトのプロトタイピングなどに使われるロボットです。ハードウェア、ファームウェア、ソフトウェアのすべてがオープンソースで開発されています。ROS界隈ではよく使われています。また、すぐに使える色々なパッケージが提供されています。例えば、Bluetoothで接続したコントローラーを使った操作、SLAMを使った地図作成、自己位置推定、Navigationを行うためのROSのパッケージが提供されています。 詳しい情報は、 Robotis のサイトで見ることができます。 Open Manipulatorはロボットアームです。こちらもTurtlebot3と同様、ハードウェア、ファームウェア、ソフトウェアがオープンソースで開発されています。コントローラーを使った操作、軌道を生成して軌道通りにアームを動かすためのパッケージなどが提供されています。こちらも、 Robotis のサイトに詳しい説明が載っています。 TurtleBot3とOpenMANIPULATORを組み合わせた時に必要となるファームウェアやソフトウェアなどもオープンソースで提供されています。 実際に組み立てた完成品は以下のようになります。 Turtlebot3 with OpenManipulator 完成品 AWS RoboMakerの紹介 AWS RoboMaker は、AWSが提供するロボットアプリケーションの開発、シミュレーション(テスト)、デプロイが行えるサービスです。 開発 Cloud9を使って、ROSアプリケーションの開発ができます。Cloud9はクラウド上で開発ができる統合開発環境です。AWS RoboMakerでは、Cloud9にROSアプリケーション開発用の拡張がされています。それによって、ビルド、バンドル、シミュレーションジョブの起動までの処理をすべてCloud9 上から行うことができます。 Cloud9 利用画面 ※バンドルとは、ROSアプリケーションの実行時に依存するライブラリ群をすべてひとまとめにパッケージ化する処理のことです。必要なライブラリがすべてまとまっているので、デプロイ先ではライブラリの依存関係などに悩まされることを無くすための仕組みです。バンドルの詳細は 公式のこちら で確認することができます。 シミュレーション(テスト) 実装したROSアプリケーションをGazebo、rqt、Rvizなどを使ってシミュレーションする環境がされています。またターミナルも用意されているのでコマンドラインを使うことも可能です。 シミュレーションジョブ利用画面 シミュレーションには、turtlebot3_gazeboなどのシミュレーション環境上で必要なROSパッケージをまとめたSimulation Applicationと、(最終的に)実機にデプロイして使うROSパッケージをまとめたロボットアプリケーションをそれぞれバンドルしたものを使います。 下の画像は実際にシミュレーション環境でTurtleBot3 with OpenMANIPULATOR を動かした画面をキャプチャしたものになります。 シミュレーションジョブ上でGazeboを利用してTurtletbo3 with OpenManipulator 動かした例 デプロイ AWS IoT Greengrassを使って、ロボットアプリケーションを実際の機体にデプロイできます。 ※事前にTurtleBot3のRaspberry Pi上でGreengrassの設定が必要です。 デプロイを行うと、バンドルしたROSアプリケーションがGreengrass経由でTurtleBot3のRaspberry Piにダウンロード、展開されます。それらを使ってROSアプリケーションを実機上で起動します。 実際には↓のような画面からデプロイの設定を行います。 デプロイ画面 intdashとは? 自社で開発を行っている製品です。 intdashは、100ミリ秒∼1ミリ秒間隔程度の高頻度で発生する時系列データを品質保証のないネットワークを経由して、高速・大容量かつ安定的にストリーミングするための双方向データ伝送プラットフォームです。 intdashは、プラットフォームを構成する製品・サービスの総称(ブランドネーム)を兼ねており、 INTeractive DAta Streaming Hub の頭文字を並べた略称です。 https://www.aptpod.co.jp/basetech/ より エッジデバイスから時系列のデータを収集する機構、サーバ側で時系列のデータを保存する機構、UIで時系列のデータを可視化する機構などを備えた製品になります。 双方向のデータのやり取りができるため、本記事のようにロボットを使用する場合は、モニタリングや遠隔制御に使うことができます。自社製品のintdash Edge ModuleはRaspberry Pi 上でも使えるので、今回はそれを使ってデータを流しています。 どうやって動かしたのか 操作側は、PS3コントローラーにRaspberry Pi を接続したものを用意しました。操作情報を送信する側と、Turtlebot3側にそれぞれintdash Edge Moduleを組み込みます。これにより、intdash Edge Moduleはrosbridge経由でPS3コントローラー側の操作情報を、TurtleBot3に渡すことが可能になります。 ROSはローカルネットワークで使うことを前提としています。調べた限りでは、インターネット経由でメッセージのやり取りをする標準的な方法はなさそうでした。なので、インターネットを経由して操作情報を渡すために自社製品のintdash Edge Moduleを使いました。 全体の構成 これによってPS3コントローラーから吸い上げた操作情報をTurtleBot3に届けて、遠隔で制御することができるようになりました。 データの流れ ここから実際どういうメッセージが流れているかを説明します。 PS3コントローラーの制御情報は以下の図のように、 PS3コントローラー → PS3コントローラー用Raspberry PiのROSノード → intdash Edge Module → インターネット → クラウド上のサーバ → インターネット → intdash Edge Module → turtlebot3用Raspberry PiのROSノード → OpenCR と伝達されます。 その結果をもとにdynamixel (モーター)を制御します。 データの流れ 具体的な制御メッセージは以下のように流れます。 PS3コントローラーからBluetoothでRaspberry Piに制御信号を飛ばします。PS3コントローラー側内部のROSのノードで信号を拾い sensor_msgs/Joy 型の /teleop/joy メッセージに変換します。 変換された /teleop/joy は、PS3コントローラー用Raspberry Pi上で動いているintdash Edge Moduleに渡されます。 PS3コントローラー側のintdash Edge ModuleからTurtleBot3側のintadsh-edgeまで自社製品経由で、 /teleop/joy メッセージを送ります。PS3コントローラー側のintdash Edge Moduleがpublishした /teleop/joy メッセージを、turtlebot3側のintdash Edge Module がsubscribeする形になっています。 turtlebot3側のintdash Edge ModuleはTurtleBot3用Raspberry Piの /rosbridge_tcp に /teleop/joy メッセージを渡します。 /rosbridge_tcp  は、 /teleop/joy メッセージをpublishします。これによって、インターネット経由で取得したPS3コントローラーによる操作情報が無事に、ROSのネットワーク内部まで到達しました。 /om_with_tb3/teleop_twist_joy が sensor_msgs/Joy 型の teleop/joy メッセージを受信します。 /om_with_tb3/teleop_twist_joy は /teleop/joy メッセージを、 geometry_msgs/Twist 型に変換して、 /om_with_tb3/cmd_vel をpublishします。 その後、 /om_with_tb3/cmd_vel をOpenCR内部にいるROSノードが受け取って、TurtleBot3の車輪の制御をしているdynamixelを制御します。ちなみに、OpenCR上でもROSノードが動いていて、 /om_with_tb3/cmd_vel を subscribe しています。また、シミュレーション環境では、 /gazebo/om_with_tb3/cmd_vel を受信します。 実現できなかったこと アームを動かす Turtlebot3に装着したOpenMANIPULATORを遠隔制御で動かすのは、今回のAWS Summit Tokyo 2019までの準備期間では間に合いませんでした。Gripperは動かすことができましたが関節は動かせませんでした・・・。 できなかった理由 原因として考えているのは以下の2点です。 Turtlebot3にOpenMANIPULATORを装着した状態で、OpenMANIPULATORをコントローラーで動かす方法が見つけられなかった点 一般的にはMoveIt経由で動かします。(参考: http://emanual.robotis.com/docs/en/platform/turtlebot3/manipulation/ ) OpenMANIPULATOR単体をコントローラーで動かす方法はあります。しかし、TurtleBot3と結合した状態のOpenMANIPULATORをコントローラーで動かす方法は探した限りでは見つかりませんでした。 ROSのノードの構成が、本来TurtleBot3で想定している構成と差異がある点 上記と関連しますが、 /arm/moveit は本来remote PCで動かすことを想定しています。 Raspberry Pi上で /arm/moveit を動かそうとしたが、クラッシュしてしまいました。ログを見た限りではメモリ確保の処理で落ちている挙動でした。Raspberry PiではRaspbianを使っていたので、元々64bit向けに実装されていた部分があったとすると、それを32bitで動作させようとしたことが原因になっているかもしれません。 データ吸い上げ シミュレーション環境では実現できましたが、実機ではRaspberry Piの性能の問題で遠隔制御との両立ができませんでした。 詳細な調査はしていませんが、原因はパフォーマンスの問題の可能性が高いと考えます。内部のプロセスを htop コマンドで確認したところ、rosbridge_serverのCPU使用率がほぼ100%に張り付いている状態でした。 rosbridge_serverの負荷が高かった原因は、TurtleBot3内部でodometry, imuがかなり高頻度でpublishされていた点と、PS3コントローラーからのメッセージもかなりの高頻度だった2点だと予想しています。 カメラを動かす raspi-cameraは依存関係上バンドルされていなかったライブラリがあったのが原因で動いていませんでした。 今後試したいこと rosbridgeに渡すデータ量を減らす odometry、imuといった情報がかなりの高頻度でpublishされています。rosbridgeに渡す前にトピックの量を間引くことで、rosbridgeの負荷を減らすことはできると思います。PS3コントローラー側から出しているトピックも今はかなりの高頻度で出力しているので、これも操作に支障がないレベルまで減らすことができそうです。 トピック量を減らすことで、モニタリングと遠隔制御が両立できるとよさそうです。 OpenMANIPULATORを動かす。 Raspberry Pi自体はもともと64bitのアーキテクチャなので、Raspbianを別なOSに変えることも検討したいと思います。 Raspberry Pi置き換え。 Raspberry PiをJetsonなどのほかの組み込みボードへの置き換えが考えられます。Raspberry PiとOpenCRは、USB経由でシリアル接続をしています。だから、OpenCRとシリアル接続ができれば問題なく使えるのではと考えています。 これにより、CPUの処理負荷の問題は解決できると考えています。どのOSを使うかにもよりますが、64bitを想定した実装を32bit向けにビルドしている問題は解決も一緒に解決できる可能性があります。 Amazon SageMakerとの連携 完全に妄想ですが、集めたデータを、 Amazon SageMaker を使って機械学習したり、そこから制御コマンド発行できたりする連携が可能になると面白いと思います。 ビジネス的な価値の検討 弊社の製品をAWS RoboMaker、あるいはAmazon SageMakerなどと組み合わせてどういう価値が生み出せるのか、まだまだ掘り切れてないところがあるのでそれを明確にする活動は今後も続けたいと思います。 AWS RoboMakerを使ってみて課題に感じた点 ROS Masterの構成の違い 一般的に使われているTurltleBot3とROSのネットワークの構成が違うのが課題に感じました。 調べた限りでは、TurltleBot3はもともとローカルネットワークで動くことを想定しています。AWS RoboMakerを使用しない場合は、以下の図のようにPCとRaspberry Pi上にROSのノードが存在しています。 Turtlebot3のROSノードの構成 これによって、PCとturtlebot3のRaspberry Piで動作が分散されます。例えば、 SLAM はPCで動かすことが想定されています。またこのような構成の場合、ROS MasterはPC側で動かすのが普通なのではないかと個人的には思います。 一方、AWS RoboMakerを使用した場合、Greengrass経由でデプロイされるので、ROS Masterを含むすべてのROSノードがraspberry pi上で実行されます。そのため、Raspberry Piの負荷が高くなる可能性が高いです。 RoboMaker使用時のROSノードの構成 詳細な調査は行っていませんが、今回の構成でSLAMなどをRaspberry Pi側で実行するのは負荷的に厳しかったです。 確認はしていないですが、AWS RoboMaker経由でデプロイした場合でも、TurtleBot3と同じネットワーク上にいるPCを使って処理の分散はできるかもしれないです。 また、intdashを使うことで、PC上との分散処理が実現できる可能性もあると思います。 感想 私は今回がROSを扱うのが初めてでした。4月入社でAWS Summit Tokyoまではおおむね2か月ほどの開発期間でしたが、ひとまず動くものができてよかったです。また、AWS RoboMakerを使うことで、開発環境の構築は苦戦することなく、ROSの使い方を覚えて開発を進めることに集中できたのでよかったです。 技術的には、ロボットの物理的な組み立て、OpenCRを使ったファームウェア、Raspberry Pi、AWS上での開発、ROSの開発など短期間で集中的にいろいろなことができて楽しかったです。手探りの状態で少しずつ進めないといけなかった点はとても大変でした。 開発では、バンドルの処理時間が重かった点で苦労しました。バンドル処理は並列処理されずにCPU1コアで処理されます。処理にかかる時間はバンドルするライブラリやパッケージの量により変わります。私が試していたときは、10~20分くらいバンドルに処理がかかることがありました。実機へのデプロイ時には、デプロイしたファイルの展開にも10から20分くらい時間がかかることがありました。これによって、わからないことや動作を実機上で確認する試行錯誤のための待ち時間がかなり長くなってしまった点が大変でした。 この点やほかにもAWS RoboMakerを使っていて苦労した点などは、AWS様にフィードバックをする機会がありましたので、今後の改善に期待しています。 そういった中で驚いた点は、AWS RoboMakerの改善の早さです。 具体的に例を一つ上げます。当初はデプロイ先が /tmp でしたが、6/25辺りにgreengrass user直下のディレクトリに変更されました。当初はデプロイ先が /tmp だったため電源を落とすとすべてデータが消えてしまいました。greengrass user直下にデプロイ先が変更されたことによって、電源を切るごとにバンドルされたファイルをダウンロードして展開する処理が必要なくなりました。 また、私が開発している期間の中で、シミュレーション環境のダッシュボードの改善なども行われていました。 最初にリリースした段階でAWS RoboMakerのコアの機能は実装されており、そののちにユーザーの利便性のために改善していくという点がMVP(Minimum Viable Product)の考え方に近い感じがしてとても参考になりました。 以上になります。 最後まで読んでいただきありがとうございました! おまけ1 本記事で扱ったAWS Summit 2019 Tokyoへ向けた取り組みを2019/11/13に 『IoT@Loft #5 - クラウドとロボティクス、オープンソース活用による次世代ロボットの可能性』 にて「AWS RoboMakerと連携するクラウド経由の遠隔制御の取り組み」というタイトルで発表させていただきました。 おまけ2 2019/12/2~12/6に米国ラスベガスで開催されるAWSのイベント 『re:Invent 2019』 にも展示します! AWS Summit Tokyo 2019での展示よりも進化しています!続編に期待!?
アバター
はじめに CTOの梶田です。 弊社も技術ブログを始めることにしました! アプトポッドは、現在 オートモーティブ 産業モビリティ(重機、建機、農機、ロジスティクス) ロボティクス を中心とした産業向けIoTプラットフォーム事業を展開しています。 会社全体としてエンジニアもしくはエンジニア出身の割合が8割程度と多く、多様なエンジニアが在籍しているなか、様々な取り組みを行っています。 実際どんなことをやってるのかよくわからないという声もあり、 技術調査や製品/研究開発における取り組み、エンジニア組織への取り組み、イベント出展における技術的なフォロー等々、技術やエンジニアリングにフォーカスした内容を発信していきたいと思っています。 初回としては、弊社について知っていただくためにエンジニア組織の概要を薄〜く広い内容でお届けします。 エンジニア組織の概要 背景 IoTのテクノロジーは、複数の専門分野をまたがる、総合格闘技のような側面があり、 1社で全ての技術をカバーするのは難しいとされています。 そういった中でアプトポッドは、 ハードウェア〜組み込みソフト〜サーバー〜アプリケーションまで一貫した開発を強みとしており、 レイヤー間を跨いだ総合的な課題解決ができる組織であると考えています。 ※ちなみにデザインも自社でやってます!!けっこう好評です! 組織 エンジニア組織は、様々な専門領域のレイヤーのエンジニアで構成されており、大きく以下の3つの開発を行っています。 製品開発 案件開発 研究開発 専門領域のレイヤーのエンジニアとしては、現状以下のように多種多様です。 ハードウェア 組み込みソフトウェア サーバー インフラ / ネットワーク フロントエンド(Webアプリ) モバイルアプリ(iOS、Android) Windowsアプリ QA(品質保証) 機械学習 その他プロトコルやロボティクス等々、いろんな話題があります。 まだまだそんな大きな組織ではないので小さなチームの連合体として日々戦っている状況です。 おまけ:技術スタック 詳細はまた別の機会に。。。 最後に このあと弊社エンジニアによって様々な取り組みを発信していきますので乞うご期待! 早速ですが、このあとすぐ12月から今年もQiita Advent Calendar 2019に参加し、今年はこの技術ブログを活用していきます。 aptpod Advent Calendar 2019 まだまだやりたいこともやれてないこともたくさんあり、エンジニアは絶賛募集中です! このブログを発信していく中で興味があるエンジニアの方はぜひぜひご応募お願いします! 採用情報: https://www.aptpod.co.jp/recruit/
アバター