ロボットのプログラムにレイヤードアーキテクチャを採用してみる

TL;DR

  • アーキテクチャに沿って記述することである程度書きやすくなる
  • ロボットのプログラムという性質による限界を許容する必要がある
  • DI・依存を気にかけてコーディングする場合にPythonはかなりしんどい

動機

以前からロボットを作っているのですが、実装が複雑になるにつれて何かしらの構造に従った方が書きやすいと思った為、ここ最近趣味の方で学習していたアーキテクチャを採用してみました。あまりがっつりドメイン駆動でアーキテクチャを組むというよりは、各レイヤーの責務を意識したかった、というくらいの気持ちです。

また、ハードウェアを検討する際に、以前はCPUの乗ったボード(Jetson nano)から直接命令を送っていたのですが、故障のリスクを考えた場合に計算機能とハードウェアの中継器となるボードを分離した方が良いと考え、WindowsPC+Arduinoで実装することにしました。それにあたり、ロジックとハードウェアに接続する部分の実装を綺麗に分けたかったりしました。

細かい部分としてはサーボの角度やロボットの意味的な角度をそれぞれ値オブジェクトとして管理したかった点があります。サーボ角だと90度を基準に左右に動かしますが、ロボットの首の角度としては0度を基準として-90~90度ほどの可動域が考えられ、この値を実装でミスしてしまうとありえない角度にサーボが動いてしまう懸念がありました。floatで扱うが意味も値域も異なる為、それぞれ型を持ちたかったわけです。

加えて、ロボットのモデルが計算論低神経科学の枠組み(もといマーのモデル)に合致するのではないか?と思ったので、どこまでできそうか試した次第です。

godiva-frappuccino.hatenablog.com

ドメインモデル・ユースケースを組み立てる

まずはロボットがどの様なものか考えていきます。ハードウェア的に組み立ててこんな感じかな…というイメージを作っていきます。ロボットの上半身を考えると、胸と首があって、それぞれDegreesの角度を持ちます。それと同時に、内部的にはサーボモータが自由度の数だけ存在し、サーボが持つ状態としてサーボ角があります。サーボは出力先なのでInfrastructure層で管理するべきでは?という問いがあるのですが、後ほど言及します。

 

これでイメージはついたのですが、実際どう動くのか?というイメージがつきづらいです。今現在の想定としては、自律操作と人間による遠隔操作が両方できると嬉しいのですが、特に前者の場合ロボットは常に動き続ける為、基本的にはループを回したり、分散されたモジュールがメッセージを送りあう形になります。レイヤードアーキテクチャの実装例として知っているものはWebアプリケーションのようにRequest/Response形式で、ものによってはstate-lessな単発の通信をするイメージがあります(無知ゆえに…)。そんなわけでただ適用するのは難しいので、別スレッドでループしてロボットを制御し続けるモジュールが必要になりました。逆に、発話させるみたいな行動は意味的に扱いやすいしある時刻において動作を実施すればよいので扱いやすいですね。

UseCaseを考えると、遠隔操作で「ある一点を見る」「自律操作を開始する」などが挙げられます。もう少し高度なユースケースも思いつくのですが、現状必要ないので割愛、ただ自律と遠隔を統合できると嬉しいです。

リクエストはApiからUseCase経由で降ってくるんですが、Domain層ではリクエストの窓口を用意し、動作を生成するモジュールと共に統合され、インフラ層経由で外部にサーボ値を送るイメージです。ここでスレッドは3つ必要で、Api層からのリクエストを待つメインスレッド、動作を生成するMovingGeneratorをループしておくスレッド、それらを統合して常にループしながらサーボ値を外部に送り続けるIntegratorのスレッドが必要になりました。こう考えると、やっぱりROSみたいに分散して管理した方が楽になる感じがしますね。こういったところからも適したパターンのみ採用した方が良い、という学びがあります。

Infrastructure層問題

まず、Infrastructure層にはMockとArduinoにシリアル通信でメッセージを送るRepositoryがあります(普段永続化に使われているRepositoryという名称が気に食わず、Connectorと名付けました)。個人的にはMockに切り替えることで実際のハードウェア接続しなくても論理的にロボットが動作しているかテストできるのが嬉しかったです。Unityでシミュレータを作ればそこにロボットの姿勢を流すこともできますしね。

ただ、サーボモータはハードウェアの実現の仕方でドメインロジックとは関係ないのでは?という先の疑問があるのですが、個人的にはドメインで表現する知識足りえるものが2つあったので、ドメイン層に実装するべきだと思いました。

まず一つ目に、ロボットの首の向きのような意味的な角度とサーボの角度が異なる点にあります。自分の作っているものはリンク機構で差動するようになっており、首をかしげるroll方向の動きに二つのサーボが必要になります。動かし方自体はシンプルですがその動きの変換をInfrastructure層でやるのは違和感があります。

二つ目に、メッセージの送り方にも知識がある点が挙げられます。10fps程度で姿勢を送るくらいなら実際の問題はないのですが、例えば1秒間で右から左に首を向けるといった命令を行う際に実際のサーボの動きとしては間を補完して0.1秒ずつ動かすことになります。Webアプリケーションのイメージだとバッチ処理になるのでしょうか。厳密にドメイン駆動アーキテクチャをやるとRepositoryの作業はモデルを保存するのですが、それだとパフォーマンス面で効率が良くないです。具体的な実装方法はInfrastructureに任せるにしても、ドメイン層側でBatchServoOutputみたいなインターフェースは欲しいかな…問う感じになります。実際バッチっぽい動きをドメイン層でやって都度都度モデルをInfrastructureに投げてもよいですが、ちょっとDDD好きがSQL周りを気にしていない人を見て驚いた…みたいなTweetをみたので気にしておきます。結局はアーキテクチャを綺麗にするのが最終目的ではなく、パフォーマンスも業務要件になり得ますし、CQRSみたいな大胆な方法でUseCaseの都合を優先してあげたり、トランザクションドメインの方で気にする場合も発生しうるのではないかと思います。UseCaseの方でUnitOfWork使ってよしなにできると嬉しいですが、今回の場合だとUseCase都合というよりはドメインに持っているサーボの知識になってしまうのかなと思います。

静的型付け言語を使おう

多分この文章を読んでいる人はそうですね…となりそうですが、Pythonだとかなりきついです。Pythonにも型ヒントの機能とDIコンテナを作る為のライブラリは提供されているのですが、C#のinterfaceみたいな強制力がなく、Abstract Classを継承したはいいものの(VSCode拡張機能辺りを使わないと)実行時エラーでしか検知できなかったり、型の恩恵を受けてこその開発のスムーズさに欠ける感じがします。

今後の話

ほぼ趣味の範疇でコードを綺麗にしたのですが、見通しはよくなった感じがします。今まで首の3自由度だったものが5自由度に増える予定なのですが、サーボのモデルを実装したことでそれを使えば上半身の2自由度のモデルも同様に作れますし、値をArudinoに送る方法もinterface経由で一つの窓口に送れば良いことが明確になり、ロジックの分散を回避できているのは結構嬉しいです。何より単体テストができるようになったのでロジックの修正の時にハードを動かさなくてもよくなったのは大きいです。

しばらく大きめの改修はないので他のアプリケーションを進めたり、ハードウェアの機構の設計をしないといけないので趣味的な改修は一旦お休みです。人形の作業にハードウェアの作業に(このプログラムはサーバサイドアプリケーションなので)HMDで動くクライアントアプリケーションをきっちり作らないといけなかったり、といった作業が待っています。正直コードを綺麗にしている場合じゃないので、早めに機構の設計をしてモデリング・材料購入・印刷などを進めていきます。概念的な部分が進んできたので、ようやく目に見える形のあるものができそうなので、楽しみですね。

 

 

 

 

 

人形に憑依しつつ…

肉体から解放されたいので自分以外の意識のない肉体に入り込んでいこうと思います。VRアバターになるのも良さそうなんですが、現実空間で肉体を持って早数十年ということで現実空間への期待があり、まだあきらめるのは早いかなと思っています。

ということで、以下の形式をやっていきます。

デモ

youtu.be

途中から画面が切り替わっているように見えますが、HMD内でテクスチャを表示して、そこにカメラの映像が貼り付けられています。カメラの目の前に自分がいるので、単に切り替わったように見えますね。

システム構成

図の通りで、かなりシンプルです。PICO4の実行環境はUnityアプリケーションなので、別スレッドでビデオを受け取ってTextureに貼り付けるスレッドとHMDの姿勢を取得してロボットに送るスレッドからなっています。ロボット側はそれに対応してメッセージをやり取りする複数のスレッド(プロセスでも良いです)と、ハードウェアの接続をしています。

今後の話

VRのアプリケーションとしてクリティカルになるのが遅延で、基本的にはフレームレートが90fpsくらいほしいところですが、HMD内部でレンダリングするのではなく映像を送る為、フレームレートはあきらめて低遅延で送ることにしました。

今回は概念実証的な側面が強かったので、とりあえず送ることを重視してUDPで送りました。調べた範囲だとWebRTCを使うとパブリックなネットワークで通信できるんですが内部的にはUDPプロトコルなので、まずローカル環境で動かす…といったことを目標にしました。

因みに、5Gのネットワークを使ってない、(おそらく)メッセージが詰まっているなどでデモ動画はかなりカクカクして重たい動きをしているので、この辺りが改善点です。(送信制御何もせず送ってるだけなので…因みにTCPのソケット通信だとfpsが落ちる代わりに滑らかではあったので、後でそっちも試してみようと思います)

ちょっと実装的な話にはなりましたが、課題が多いですね…この辺り結構悩んでいて、現状の技術のレベルだと結構難しいらしいです。Teamsを両側で開くのも考えたんですが、そういったソリューションを提供しているAzure Communication Serviceは本格的なUnity対応をする予定がなさそうなので微妙な気持ちになっています。あとTeamsはWebRTC使ってるっぽくて内部的にはUDPのパケット送ってるっぽいんですが、遅延が400ms程度はあるので、やっぱりリアルタイムの映像配信はかなり難しいみたいですね。

完全な同期は少なくとも現時点では不可能と判断したため、アプリケーション的に遅延が許容されるものとして、今年中に何とか出来たらなと思います。カクカクするとストレスはあるんですが、VR酔いしやすい自分でも歩き回ったり激しい動作が無ければあまり酔いは感じなかったので、システムのレベルではなく、運用まで込みで考えています。

さすがに頭の中でタスクを抱えきれなくなったので大きなレベルで書き出してみたんですが、この一つ一つが更に細分化される形になるので作業量の多さに絶望してます。(例えばセキュリティ対応だと通信周りで認証入れる実装をしたり、それだけで最低1日はつぶれる気がしますが、そもそも人形の造形が数か月かかってるので終わりですね)

 

 

PICO4でヘッドセットの姿勢を取得してロボットを動かす

Demo

youtu.be

前書き

以前から人形を動かしており、Androidから加速度センサの値を元に姿勢をトレースするアプリケーションを作っていたのですが、せっかくなのでHMDで作ることにしました。HMDを持っていなかったので試しにPICO4を買ってみたのですが、前評判で聞いていた通り全然情報が無かったので、少し苦労しました(VR開発歴が7日なのでご指摘等あればぜひお願いします)。

結論から述べると、Main Cameraの姿勢を取得します。解決法だけ興味のある方は下の方までスクロールしてください。

PICO4の開発方法

VRアプリケーションの開発では、OpenXRというVR/ARの標準規格があり、UnityのSDKが提供されている為、このSDKを使用してUnity上にカメラやPrefabを置いて開発ができます。その他に、Oculus QuestシリーズやPICOシリーズではそれぞれ専用のSDKが提供されており、機器ごとに機能やコントローラーのモデルが提供されています。

PICO4での開発の基本設定はこちらの記事が参考になりました。逆にこの方以外で情報を提供されている方がおらず、泣きながらSDKのリファレンスやGitHubのコードを見ていました。

qiita.com

また、PICOシリーズのUnityのSDKは古いバージョンがあり、そちらは2022年末でメンテナンスが終了しますよとの告知がされています。

developer-global.pico-interactive.com

ここまで調べたところで両バージョンのSDKのリファレンスを一通り確認したのですが、少し問題がありました。まず、古いSDKの方にはヘッドセットの姿勢を取得するメソッドがありました*1。一方で、新しいSDKのリファレンスを確認すると、Eye Tracker関連のクラスはあったのですが、全てのメソッドがPICO Neo2, Neo3用でPICO4非対応でした。Documentの更新漏れに期待してPXR_EyeTracking.GetPoseMatrixメソッドさえ使えればと思い試したところ、Unityのコンパイルは実機に依存しないため通りますが、実機でエラーを吐くのでダメでした。因みに、Oculus Questの方はそれらしい情報が出てきたので、枯れた技術を使った方がよいと思いました。

GitHubにサンプルコードが上がってないかと思ったのですが、旧バージョンのSDKを使用したサンプルがほとんどで、新バージョンの方でどうやって書けばよいか分からないものも多いです*2

というわけで路頭に迷いました。

解決法

XR Origin配下にあるMainCameraの姿勢取ればよいじゃん、というStack Over Flowの回答を見つけました。PICO4開発の際にSDKで提供されているXR OriginというPrefabを設置することでヘッドセットの移動に合わせてカメラが動くので、このカメラの姿勢を取得すればよかったんですね*3

というわけで以下Updateメソッドのようにカメラから姿勢を取得します。折角なのでDemoで見せたような姿勢の送信までの処理を載せておきますが、裏側を隠ぺいしているので疑似コードの気持ちで眺めてください。

GetPoseメソッドでは5自由度(yaw, pitch, rollの回転+左右, 前後の移動)のプロパティを格納するPoseModelにしています。回転角の計算式は少し調べると出てくる式で、Degreesで角度が取れます。また、移動距離の方がメートル単位で取れるので変換が簡単だったのは結構嬉しかったです。実際にヘッドセットを10cm前に動かすとposition[2](z軸)が0.10の値を返します。

あとはロボット側でヘッドセットの姿勢を受け取ったらその角度にロボットを動かすプログラムを走らせればヘッドセットの動きをトレースしてくれます。The Endってね。

完全な余談

ロボットの姿勢を扱うとき、cmで扱うかmで扱うか結構悩むことが多く、この辺りValueObjectでうまく扱えたらな…とか思いつつ、// cm単位とか書いていて対応しなきゃな…と思っています。その辺りのベストプラクティスを知りたいですね。

また、-180度と180度の境目を越えるときの処理がかなり面倒なので何とかしたいです。以前こういうものを見つけたので、多分その辺りを複素数で扱うとよしなにできそうなのですが、考慮できずにいます。

qiita.com

 

*1:ただ、内部で使用しているjarファイルが古いなどのエラーを吐くようで、旧バージョンのSDKは使えるか怪しい上メンテナンスされない予定なので使用をあきらめました

*2:僕もソースコードを公開してないので、はい。

*3:All you need is StacOverFlow.

雑記、作り手と受け手の非対称性について、人形作り等

以前、コンテンツに対する飽きみたいなテーマで人と話すことがありました。大雑把にまとめると、「若いうちから大量のコンテンツを摂取しすぎて、新しいコンテンツが生まれても既存のコンテンツとの類似性を感じてしまう」といったものでした。オタクは任意のコンテンツをドラゴンボールジョジョの奇妙な冒険グラップラー刃牙だと思い込むし、実際巨大なコンテンツが後続の人々の創作に与えてきた影響は大きく、何かしら感じ取らずにはいられません。この類似性から生じる飽きについて、考えてみたのですがあまり明確な回答が出せずにいます*1

この問題は現代以降の問題かなと思っています。例えばテレビが登場したころまでさかのぼると、テレビ番組はとても少なく、ひょっこりひょうたん島とか知り合いの家でテレビを囲んで皆でみたものでした*2。ここでの特徴として、コンテンツが非常に少なかったことと、皆が同じ対象を見ていたことがあります。当時そう思っていた訳ではないにしろ、コンテンツを選択できないからにはそれをひたすら見続けることになりますし、いつになってもその当時の熱狂は忘れられませんし、皆の話題となって会話も盛り上がる構図が生まれます。

対して現代はモノに限らず概念も大量生産・大量消費社会なのでたくさん流れてきます。これらを処理しようとすると自ずと一つ一つのコンテンツに対する効率を求め始め、他人の感想や考察を頭に詰め込んで派生作品を見るだけの焼きなまし人間になります。コンテンツ自体に対する目線ばかりが鋭くなり、大雑把でも盛り上がればよいという雰囲気ではなくなります。いつの時代でも細かい情報に詳しいオタクはいますが、そういうのは必修科目のように強制されるものではなく、興味を持つにつれてやれば良いものなのに、コンテンツを知ることに目が向きがちです。以前Twitterで驚いた投稿として、鬼滅の刃を水の呼吸も知らずに楽しんでいる大人の方がいたのですが、思い返してみれば僕の若いころは炭治郎!いけー!とかいって何も分からずに楽しんでいましたし、別に知らなくても面白いものは面白かったと記憶しています。案外そういった人の方が世の中には多くて、広告業者の意図を華麗にくみ取って愚直に目の前のコンテンツを受け取るだけの人間が多いということを、東京に出ると感じます。

まとめると、コンテンツの精緻化、詳細化は確かに素晴らしいものですが、同時に呪いでもあるのかな、と思います。やはりそれだけ詳しくなれば他のコンテンツを見る際にも詳細に目が行きますし、新しさの喜びを得るのは次第に難しくなります。スルメの様に噛み続ける胆力によって詳細化の喜びを享受するのも一つの手ではありますが、得られる喜びの質が異なることに目をつぶれないのです。

今まで背景的な議論に終始していたのですが、この新しさの喜びを頭部が肥大化した人間がどう享受し得るか、と考えるともうそのコンテンツの内には存在せず、ただ受け取る存在ではいられないのかなと思います*3。僕は暗黙的に構造主義を求めていた背景に基づいて自然言語処理に興味を持っていたおかげで、シソーラス言葉意味上の関係に基づき整理した辞書・辞典語彙)が好きで、物事を包含関係や関連で捉えることを考えていた時期がありました。例えば、動物ー哺乳類ー犬ースコティッシュフォールドといった包含関係があり、コンテンツに当てはめると「俺は大量の犬を見てきたから、どんな犬を見てもスコティッシュフォールドとの違いで捉えてしまう」わけです*4。犬に詳しくなり続ける人生の中で犬の精緻化を続けるというのは研究でも界隈によってはある話なのかなと思います。機械学習分野はここ数年で革新的なモデルが大量に登場しているので、新しい概念の発見→それを活用した可能性の模索や詳細化→新しい概念の発見のサイクルが進んでいるように見えますが、詳細化がひたすら続いている学問もあるように見えます。僕の最強の地図が完成するのはよいことですが、パラダイムが今後永久に変わらないのは周りから取り残されて枯れ果てた知識になってしまいます。動物完全に理解したレベルのことを述べてくれるならよいですが、人間の営みで完全なものは難しいので、インクリメンタルに発展していく方が現実的じゃあないでしょうか。話が少し脱線しましたが、詳細化のみを続けると先には枯れ果てた完成図ができあがるか詳細化のゲンセリアの奥深くに迷い込むかの道を辿ることになるのではないかと思います。

ここまで考えてきて、やはり新しさの喜びはそのコンテンツ自体から受け取ることはできないのかな…と心が折れました。ではオタクは何をしているのでしょうか?コンテンツを擦り、二次創作を生み出したり、影響を受けてコンテンツの作り手に変わりました。学生として研究をしていた時も、既存のコンテンツを詳細化する試みも”生み”の試みであり、存在しない何かを存在させることであったのは理解していました。

暫定的な結論として、「妥協案としての喜びの享受としての創作」と書いておきます。人形を作り始めて約2年経ち、技術及び思想面での未熟さをより一層深く感じていますが、作ることによる喜びは、見ることによる喜びと質が異なることを知りつつあります。僕が初めて人形をしっかりと見たのは2018年の2月に静岡のミワドールさんにお伺いした時のことですが、当時は綺麗な人形さん的な感想しかいだけませんでしたし、形式知としての説明文を少し読んだ程度でした。ただ、自分で作ることでの発見は、その肉体のデザインの全てが自分の裁量で好きに作れる*5ことや、形式知として確立された技法の中に暗黙知的な技術がどれほど隠されていたか、そして作り手の新しいものを作り出そうという気概を同じ土俵に立とうとすることなど、多岐に渡りました。

僕は手が不器用で中々細かい作業が苦手で、完成を目指しつつ今回は瞼を綺麗にするけど手の造形は次回に持ち越したり、と永遠に終わらない作業を切り上げつつ、自分を乗り越えることの難しさを感じています*6。逃げずに追い込む、というのを常に続ける胆力がないので数を作りつつ少しずつ進めていますが、案外できることが増えるとその気力が生まれてくる感覚があるので、最近まつ毛を綺麗に貼ることができたのを覚えておいて次は他の部位もうまくやってやろうと思えるようになりました。反論はあるかと思いますが、アジャイル的に少しずつ良くしていく進め方が創作においても必要かなと思います。Done is better than perfectは最終的なperfectを目指すうえでの指針と解釈していますし、最高の研究をするのに一生勉強し続けていたら死後に論文を書かなきゃいけないですしね。惜しむらくは一度完成させた人形に機能追加的にクオリティを上げる手段に乏しいところですかね、ソフトウェアならリファクタリングや機能追加ができますが、人形は手を差し替えるみたいなモジュールレベルでの大きな変化を求めますし、それは結局一人新しい子を作るのと変わらないように思います。

作ることによる喜びの享受は作り手としてだけではなく、受け手としても影響があるように感じます。人形展で人形を見た時に、多少は苦労が理解できるようになり、何に注目してそれを作っているか意識できるようになりました。一方で非対称的に、あくまで受け取る側はそれを完成品としてしか見られないということも感じます。特に人形展だと数十~数百時間かかって作られたそれらを数十分眺めるくらいのコミュニケーションしかとらないわけですから、一緒に暮らして長い時を過ごすくらいのことをしないと結局はインスタントな消費になってしまいます。作り手、受け手の相対化について考えると、生まれるまでを一緒に過ごすことが、作り手の本人にしか享受できない喜びなのかなと思います。

僕は人形を作る理由として、2つを挙げていて、上述したような作り手としての創作の過程で生まれる価値の享受と共に、この世に存在しないから作りたいというのがあります。普通の人間なので、前者的な動機で体が鉱物でできていて内部が露出していると嬉しい!みたいな感情で背中に水晶ジオードを埋め込んでみたりしたこともありますし、オーソドックスな”創作人形”としてインクリメンタルな成果の過程として作った子もいますが、この世に存在しないものを作りたいですね。軽めの蒐集癖があるのでこの前も小ぶりなガーデンクォーツをお迎えしたりしましたが、この世に特定の概念を具体化した人形がいれば、それだけで十分嬉しいです。

丁度2018年の初めに、橋本ルルというドールモデルの方を知りました*7。着ぐるみで顔を被り球体関節タイツを着用して踊ったりするのですが、いわゆる中の人は入れ替わることができ、その時に既存の肉体の枠組みから抜け出せる可能性を感じました。要するにガチャピン方式です。今ではVR空間で人々が自由な肉体を手に入れて精神バトルを繰り広げていますが、現実世界で肉体からの逃れができると嬉しいです。学生のころからロボットである意味、バーチャルである意味の線引きを考えていますが、現実の存在感や触れられることの価値は、現状の、特に市販レベルのVRの精度では代替できないものかなと思います。今憑依できるハードウェアとしてPepperを含めた人型ロボットを眺めてみると、ある種のキュートさはあるが美ではない…と感じで、作るしかないわけですね…美しい憑依先の肉体を…俺たちの肉体は生命の維持の最低限が必要ですが、人形の良いところの一つに生命とは無関係な肉体を持つことができることがあり、鉱物であったり、不必要な部位が無かったり、球体のようなモチーフが具体化されたり*8、既存の肉体の枠組みから逃れ、自らの感覚からも逃れていきたいですね。実は、社会という巨大な枠組みからの逃れのミクロコスモスでの表現なのかもしれないですね。

肉体からの逃れの思想は未來のイヴに影響を受けているわけですが、やはり美しい肉体が代替可能な存在であることや、その肉体に宿る精神を模索することができると嬉しいですね*9。検証も兼ねた作業を並行しているお陰で構想から始めると数か月かかっていますが、2023年中に完成の目途を立てないと人生において生み出せる子の数が目減りするのを感じるので、期限を決めつつ進めていきたいですね。作業していく中で規模が肥大化していて大変なことになってきたので、後退のネジを外す覚悟が必要になってきました。もう後戻りできない…

最後に少し趣向を変えた創作の喜びについて述べます。「人間に授けられた過剰なエネルギーを理性的活動に行使して自身の存在を認知することもできず、巨大な仕組みに隷属することを人生の主とする苦しみ」から逃れたいというのが大きいんじゃあないでしょうか。何かに隷属するからには、それを社会や他人ではなく、自らの作りだした目標という幻想にして、それを具体化させるのが最も人間的な人間存在の行使じゃないかと思います。逆に自分しか責任を取れず誰かに任せられない苦しみがあるのでかなり辛さはありますが、少しずつでもやっていきましょうね、”自分”としての活動を。

*1:助けて。

*2:現代の子供に、サンダーバードひょっこりひょうたん島は伝わるのでしょうか。

*3:助けて。

*4:余談ですが、Word2Vecの埋め込み空間をポワンカレ空間に埋め込むことで階層構造をエレガントに表現できる論文があったりして、かなり好きです。個人的にはそれが点ではなく多峰ガウス分布で表現されると更に嬉しいと思うのですが、計算量的には厳しいんでしょうか。現在の研究の動向も追えたら良いですね。

異空間への埋め込み!Poincare Embeddingsが拓く表現学習の新展開 - ABEJA Tech Blog

*5:逆にデザインしなければ曖昧になってしまうのが難しいですね。

*6:岸部露伴も最も難しいことだと言っていました

*7:今は活動されていないのがとても寂しいですが、当時はかなり影響を受けました

*8:身体が球体であることは美しいので、球の美の思想として、「キュウビズム」とでも呼びましょう

*9:未來のイヴの物語に従うと、高潔な精神の持ち主が肉体に入り込まないと、ただ美しいだけのアリシアの焼きなましになりそうですね笑

ロボットのプログラムをレイヤードアーキテクチャで考える

少し前にドメイン駆動設計の本を読んだり勉強したのですが、手元のロボットのプログラムをリファクタリングしているとき、突然「似ている…!」と思ったので、書いていきます。

レイヤードアーキテクチャとは

詳細は省きます。ドメイン駆動設計というソフトウェアの設計手法では、ドメインモデリング(業務知識をモデルとして表現)に着目し、それをコードに落とし込んでいきます。業務知識を一か所にまとめることでコンポーネントごとの責務が明確になりコードの保守性が上がったりするのですが、そのコンポーネントの依存関係を階層構造にしたのがレイヤードアーキテクチャです。

レイヤードアーキテクチャは4つの層からなっており、外部からのrequest/responseを担当するInterface層、アプリケーションレイヤでユースケースを表現するusecase層、業務ドメインに関する値及び振舞いを集約したdomain層、DBへのデータの永続化などの外部との接続方式を担うinfrastructure層からなります。*1

一般的にリクエストを受け付けて何かデータやページなどのコンテンツを返す…と考えるとWebAPIやブラウザーアプリケーションの実装に使えるイメージがあるんですが、ロボットにも使えそうです。ちなみに、依存性の逆転でInfrastructure層がDomain層を見ていますが、今回はそういったDDD的な関係性は置いておいて、層ごとの責務の分離に着目します。

マーの計算レベル

ロボットの話に進む前に、少し遠回りして、人間の話をします。計算論的神経科学者のデビッド・マー神経科学の理論的理解の枠組みとして、計算理論、表現とアルゴリズム、実装の3つのレベルを提唱しました。生化学的に脳を物理的な観点で扱っていた神経科学を数学的な構造によるモデル化などの手法を通じて、理論的に理解する試み…と言えばよいでしょうか。そして、3つのレベルは順番に、「脳が果たすべき目的は何か、それを果たすためにどのような計算が必要か」「計算理論のレベルで定められた計算を遂行するための表現や、具体的なアルゴリズム」「それらの目的・具体的な計算をハードウェアで実現するためにどうすればよいか」と分けられます。

ロボットを作る…と考えたときに、人間を同じ枠組みとして捉えると結構似ていることが分かります。僕は顔のロボットのコードをリファクタリングしながら気づいたのですが、まずモータを動かす為のコードを書いていて、PWMで電気的信号を送る実装とソフトウェア的な可動域の制約や動きの制御を分離するべきだと考えました。これが、それぞれ実装レベルと表現とアルゴリズムレベルに対応づきます。そして、モータが動くことの意味付けとして、ロボットがある場所を見るという行動目的があります。これが計算理論レベルに対応付けられるのではないかと考えました。

ちょっとコードをべた書きすると、以下のイメージです。

Robot.Look(yaw, pitch, roll); // 計算理論レベル

void Look(yaw, pitch, roll){ servoYaw.MoveTo(angleYaw), servoPitch.MoveTo() ...// 表現とアルゴリズムレベル

void MoveTo(angle){PWM.setPWM(150, 600, pulse(angle * rate))} // 実装レベル

レイヤードアーキテクチャを振り返る

具体的なコード片を書いたところで、レイヤードアーキテクチャと先ほどの計算レベルが似ていることに気づきます。以下の図のようなイメージになります。

もう少しイメージを膨らませてみます、ロボットといえば定義的には入力、制御、出力が揃っていることが条件となります*2。これを図にすると、こうです。

これは完全な自律ロボットが外界とコミュニケーションする様子です、ロボットの具体的なイメージは何でもよいですが、例えば監視カメラもカメラ映像がセンサとして入って、人を見つけたらその方向に動く為の制御を計算して、モータが動いてカメラが人の方を向きます。
そして、これを人間が遠隔操作するロボットに置き換えるとどうなるでしょうか。こうなります。

ロボットと操作者の人間の構造が同じ話はまた別の機会にしますが*3、ロボットの制御系は人から命令を受けてモータを動かし、そして代わりに動いた先の映像を操作者に送り返しています。…Request/Responseですね?埋まりました。

ロボットのプログラムでもレイヤードアーキテクチャができてうれしい!ちなみに自律ロボットでも同じ仕組みで作れて、Interface層に人間によるリクエストだけではなく自動操作アルゴリズムによるリクエストを受ける窓口を作ればOKです。そういう意味では、フロントUI→バックエンドWebAPI→DBの構造と(経路計画等のレベルの)制御アルゴリズム→遠隔操作ロボットの仕組み→アクチュエータの構造はかなり似通ったものになりますね。
DDDの例を見るとIntarface層がUIとして存在しInfrastructure層にDBやその他外部APIが接続されるイメージからWebAPIやブラウザーアプリケーションの例を見かけることが多いと感じていたのですが、Infraはハードウェアにつながるし、UIは別に自律操縦プログラムの受け口として存在していてもよいわけで、応用先は結構広いんじゃあないかと思います。

終わりに

DDDについては、「DDDが必要になるくらい業務ドメインが複雑な場合、そのための要件定義や言葉のすり合わせが大変だよね」といった趣旨のTweetを以前みたことがあり、そうだね…という気持ちになったことがあります。社会人経験が浅く業務とは…?という人間からするとそのレイヤーの気持ちはわからないので、まずは自分が知っている領域で何か書いてみるのも面白いかもしれないですね。

少し前に読んでいた構造主義の入門本*4で人類学者のレヴィ=ストロースが見つけた部族内のコミュニケーションでのルール(婚姻クラス)がクラインの四元群と似ているのを発見した記述があったのですが、僕も「ロボットが人間のモデル化故にマーの計算レベルに当てはまるところがあり、さらにはレイヤードアーキテクチャの層の分け方にも通ずるところがある」と気づいた時は数学の発見的な喜びがありました。

触れていきたいですね、様々な物事に隠された「構造」に…

*1:かなり参考になりました

【Go】DDD + レイヤードアーキテクチャでREST APIを実装する | みんたく

*2:諸説ありますが、伝統的にはそう

*3:元々遠隔操作のモデル化のために作っていた図なので、その背景を強めに入れたブログを書きます

*4:不勉強ゆえに、構造主義を知らずにポスト構造主義の思想が登場する書籍を読んで、この本には意☆味☆不☆明な思想!と泣いていたので、こうすればよかったんだ~!と叫びながら構造主義の本を買いました

首、そして球体関節を考える

人形を作ると決めてから、どうにか首を人間のように自由に動かす機構を作れないかと考えていました。
できました。*1

youtube.com

首、できてみるとあっけない感じがしますが、人間のサイズにその機構を収めようとすると意外にも苦労する点があります。

球体関節の機構を考えてみる

そもそも球体関節人形は主に以下のような仕組みを持っています。一つは球の上に受けがそのまま乗っかり3自由度で動かせるもので、もう一つはスリットが入っており1自由度、作りによっては2自由度動かせるものです。人形を作るとき関節というのは結構重要で、その子がどのように体を動かすかを規定します。『人形愛の精神分析』の関節の章にそういった記述がありましたが、実際人間が動かせる箇所は200ほどある中で人形作家はどこを動かせるか選ぶわけです。基本的には意味的な単位で首やひじ、膝、足首や手首などロボットライクな粒度で作っていることが多いかなと思います。指はかなり細かく球を作るのも大変になるので、作りこまれていると努力を感じますね…他にも二十関節機構にすることで可動域を増やしたり、腹部をどうするか、とか考えどころがあります。ちなみに、球体関節にするか楕円関節にするかといった話もあり、前者だと可動が自然になる分人間としてのリアリティを損ない、後者だとその逆になる

余談ですが、『ソッカの美術解剖学ノート』*2では人体の関節の分類を以下のように紹介しています。そう考えると球体間接人形の関節もその範疇に収まっている感じがします。

フリーハンドの図が世界一苦手ですが、1…車軸関節、2…球関節、3…蝶番関節、4…楕円関節、5…複関節(3つ以上の骨を結ぶ関節、これだけ分類の粒度が異なります)と種類があり、関節によって可能な回転運動の軸が異なります。

では、なぜ球体関節なのでしょうか?と考えたとき、基本的には可動域の問題と、重要な点として球体関節人形における球体の意味があると思います。その辺りはベルメールがどう…ということで詳しくないので割愛します。ただ、真球の関節は3自由度で1点で2つのパーツを結ぶ際は回転に関して自由な動きが保証されます(直進運動は別の考え方が必要になります)。そこにスリットなどで自由度を制限することで、より低い自由度も同じ形で表しています。

余談ですが、『球体のはなし』という球体のことを3分野ほどの視点で横断して紹介している書籍をこの前ブックオフで見つけました。工学的見地でどのようにより真球に近い球を作るかであったり、昔から勾玉や三種の神器など様々な場面で球体が重視されていた文化であったり、結構面白い内容になっていました。

モータを仕込んだ機構を考える

モータを仕込んで動かす際に大きな問題になるのはモータのサイズです。一般的な小型サーボモータのSG92Rは23x12.2x27mmのほぼ直方体で、これを首だけで3つ仕込む必要があります。80cmサイズの人形の首球体関節は直径40mmほどでしかも球体です。よって、内部にすべてを入れることはできません。また、大きな人形の場合はより強力なMG996Rなどを検討することになりますが、これは40.7x19.7x42.9mmと少し大きくなり、これまた球の中に入れるのは難しくなります。

ちなみに、2自由度の場合、ある程度仕組みは簡単になります。球を考えるうえで大切なのは、1点を中心に回転することで、半径によっておおわれる面に沿うように外側の枠が動けばよいです。図のように、モータを二つ組み合わせて支点を決めれば疑似的な球体になります。左図の2自由度のイメージを中央のようにモータを二つ用意して、上のモータに外枠を付けると、右図のように2自由度で回転します。
ここで重要なポイントとして、ことロボットの機構については常に完全な球体が回転する必要はありません。関節に接するパーツ(ここでは頭部)が接する部分だけが存在していれば十分です。右図の外枠に頭が乗っていれば、疑似的な球体によって便宜上は人間の頭が動いているように見えます。*3イメージとしては天球儀です。天球儀は中央に地球を模した球体がありますが、外側には薄い円盤が3つ重なっているだけですが、それを動かすとその軌道が球体として中央の地球を包みます。

 

しかし、ここで問題となるのが、もう一つの自由度をどこに足すか、です。ここにモータを追加すると外側からこの2つのモータの組み合わせを囲う必要があります。天球儀などが参考になりますが、3つの軸が、順番に重なっていく構造になります。そして、ここにモータを付ける場合球体の外側に取り付ける必要があります。また、先ほどの2自由度のモータに目を向けると、下のモータが上のモータを回転させています。要するに、3つ目のモータを追加すると2つのモータを動かす大掛かりな仕掛けになってしまうわけです。

人体に立ち返る

そういえば実際の人間の首はどういった構造をしているのでしょうか?自分の首を触ってみると、どうやら球体関節ではないようです。筋肉が16種類ほどあるので複雑でよくわからないですが、頭が球の上をすべるのではなく、引っ張り合う動きで成り立っていることが分かります。下図のイメージです。1…横を向く動きは先ほどの図の車軸関節で、2…上下を向く、3…首をかしげる、といった動きは2つの軸が連動することで成り立っています。
…これを機構で作れば良さそうですね。

似たような機構をインターネットで探しつつ…
できました。最初に乗せた動画のとおりです。支点がモータの可動部ではなくほかの場所に移動しているのがポイントになります。つまり、首の球体関節ではなく、肩甲骨や肩のあたりにモータをしまい込んでおくわけです。

ここでちょっと注目したいのが、支点部分です。機構の都合上、1の動きはともかく2,3の動きをする場合2自由度分の動きを許容する仕組みが必要です。
ここで思い出すのが、2自由度を許容する為には関節に接するパーツが接する部分だけが存在していれば十分ということです。以下のように、疑似的な球体を作っていきます。見やすさのために一度分解しましたが、円柱を二つ組み合わせるとその上にのせたパーツが2自由度で動くわけです。

 

今回はそこまでやりませんでしたが、この2自由度分の支点を1か所にまとめることで、最終的には論理的な球体が生まれるわけです。ロボットの機構を見たときはなんだこの複雑な仕組みは…と思いましたし、これが球なのか?となりました。しかし、このように考えてみると球体であることには変わりないですし、そもそも人間の首を球体関節で表した人形作家の試みと同じわけですね。

 

というわけで、首を球体関節で作るうちに仮想的な球体が人間の首の中に生まれた話でした。

*1:参考:論文の中身は読めなかったので公開されている図を基にモデルを作りました 

Figure 3 from Facial expression on robot SHFR-III based on head-neck coordination | Semantic Scholar

*2:ページ数も多く不真面目なので流し読み程度ですが…

*3:肌が無いので機構が丸見えですが。

スマートフォンでもマスタスレーブがしたい!

youtube.com

 

しました。

TL;DR

  • スマホの加速度センサから取得した値をWeb経由でモータ直結のマシンに送ることでマスタスレーブをやりました。
  • スマホのセンサが安定しないのでVRHMDを買うと良いと思います。
  • 途中経過のまとめなのでシステムが安定して機能が出そろったところでちゃんとした記事にします。
  • 以下の記事の続きです。

godiva-frappuccino.hatenablog.com

 

なぜVRHMDではなくスマートフォンでやろうとしたか

動画で載せたスマホ→ロボットの姿勢送信の他にロボット→スマホへの映像ストリーミングをやる際に、VRHMDの開発に使われるC#(Unity)で映像のストリーミングをやる為の情報があまりなかったのが理由です。

Azure Communication ServiceというWebRTCができてサンプルコードでTeamsミーティングに参加できるサービスがありますが、そこではWeb、iOSAndroidだけしかなかったので悲しいですね。

learn.microsoft.com

WebRTCをやろうとしたときにJavaScriptJavaAndroid)辺りは画面を前提としたアプリケーションの開発が多くて映像のストリーミング周りの情報が多く、サンプルコードもあったのでそれを流用する形で作るのが楽かなという感じです。

ちなみにロボット側はJavaScriptでやる予定ですが、スマホ側はJavaScriptだと画面方向の固定や姿勢などのスマホの情報にアクセスするのに不便な場合があるので、制御しやすいAndroidアプリを生成するのが都合がよかったりしました。(あとで映像ストリーミングと姿勢送信を別スレッドで一つのアプリにまとめればよいかなと思ったり)

現在の仕組みを振り返ってみて

前回姿勢を送る際にロボットの姿勢送信のマルチテナント化(やる予定なし)やステートレスな方式のメリット、ロボット側で通信するかどうか決めたい思想などからRedis Cacheに姿勢を置いておく方式にしました。

今現在はスマホ、ロボット側マシン両方が同じWebAPIにHttpRequestを送ってアクセスしていますが、WebAPI経由でRedis Cacheを叩く仕組みは考え直してみると負荷やオーバーヘッドの関係で微妙なので、直にRedis Cacheを読み書きした方が良いです。

今後の話

Oculus Quest Proほしいですね。