TIER IV Tech Blog 2022-06-02T16:40:26+09:00 TierIV Hatena::Blog hatenablog://blog/10257846132673302365 TIER IV Tech BlogをMediumに移行しました。 hatenablog://entry/13574176438098288514 2022-06-02T16:40:26+09:00 2022-06-02T17:00:18+09:00 この度、TIER IV Tech BlogをMediumに移行しました。最新の記事は以下のサイトをご覧ください。 medium.com medium.com <p><span style="color: #292929; font-family: charter, Georgia, Cambria, 'Times New Roman', Times, serif; font-size: 20px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: -0.06px; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none;">この度、TIER IV Tech BlogをMediumに移行しました。最新の記事は以下のサイトをご覧ください。</span></p> <p> </p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fmedium.com%2Ftier-iv-tech-blog%2Ftagged%2Ftech-blog" title="Tech Blog – TIER IV MEDIA BLOG – Medium" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://medium.com/tier-iv-tech-blog/tagged/tech-blog">medium.com</a></cite></p> <p><br /><cite class="hatena-citation"><a href="https://medium.com/tier-iv-tech-blog">medium.com</a></cite></p> TierIV ProtobufでREST APIを快適に開発する方法のご紹介 hatenablog://entry/13574176438056364489 2022-02-02T16:00:00+09:00 2022-02-02T16:00:01+09:00 こんにちは、ティアフォーで認証認可基盤を開発している澤田です。 最近取り入れたProtobufで、素晴らしいREST APIの開発体験をしたのでご紹介します。 なお、ティアフォーではマイクロサービスを支える認証認可基盤を一緒に開発いただけるメンバーを募集しています。ご興味のある方は下記ページからご応募ください。 herp.careers 実現したかったこと マイクロサービス間連携のAPI開発において、以下の条件を満たすやり方を探していました。 スキーマを最初に定義してリクエストとレスポンスの型が自動で生成される ドキュメント(openapi.yaml)が生成される バリデーションが定義できて、… <p>こんにちは、ティアフォーで認証認可基盤を開発している澤田です。</p> <p>最近取り入れたProtobufで、素晴らしいREST APIの開発体験をしたのでご紹介します。</p> <p>なお、ティアフォーではマイクロサービスを支える認証認可基盤を一緒に開発いただけるメンバーを募集しています。ご興味のある方は下記ページからご応募ください。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fherp.careers%2Fv1%2Ftier4%2Fhd8y-l009irp" title="56_Auth Engineer - 株式会社ティアフォー" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://herp.careers/v1/tier4/hd8y-l009irp">herp.careers</a></cite></p> <h3>実現したかったこと</h3> <p>マイクロサービス間連携のAPI開発において、以下の条件を満たすやり方を探していました。</p> <ul> <li>スキーマを最初に定義してリクエストとレスポンスの型が自動で生成される</li> <li>ドキュメント(openapi.yaml)が生成される</li> <li>バリデーションが定義できて、その実装が自動で生成される</li> </ul> <h3>実現方法</h3> <p>Go言語で開発する場合は<a href="https://github.com/go-swagger/go-swagger">go-swagger</a>でも実現できますが、本記事では、Protobufで実現できるgRPC Gatewayとprotoc-gen-validate (PGV)を使った方法をご紹介します。</p> <h4>gRPC Gateway</h4> <p><a href="https://github.com/grpc-ecosystem/grpc-gateway">https://github.com/grpc-ecosystem/grpc-gateway</a></p> <p>gRPC GatewayはProtobufの定義からREST APIのプロキシを生成してくれるプラグインです。gRPCサーバの前段に置くことで、REST APIのインターフェイスを提供することができます。</p> <p><figure class="figure-image figure-image-fotolife" title="gRPC Server の前段に gRPC Gateway を置くパターン"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/s/shotasawada/20220125/20220125104611.png" alt="f:id:shotasawada:20220125104611p:plain" width="1200" height="356" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>gRPC Server の前段に gRPC Gateway を置くパターン</figcaption></figure></p> <p>単にREST APIを開発する場合は、gRPCサーバは不要なので、gRPC Gatewayにサービスの実装を登録することができます。</p> <p><figure class="figure-image figure-image-fotolife" title="gRPC Server を置かずに gRPC Gateway だけのパターン"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/s/shotasawada/20220125/20220125104832.png" alt="f:id:shotasawada:20220125104832p:plain" width="1200" height="356" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>gRPC Server を置かずに gRPC Gateway だけのパターン</figcaption></figure></p> <p>以下の例のように、Protobufから生成された<code>RegisterXXXHandlerServer</code>を利用すれば、Gatewayにサービスの実装を登録することができます。</p> <pre class="code lang-go" data-lang="go" data-unlink> mux := runtime.NewServeMux() err := pb.RegisterEchoServiceHandlerServer(ctx, mux, &amp;EchoHandler{}) <span class="synStatement">if</span> err != <span class="synStatement">nil</span> { <span class="synComment">// Error Handling</span> } </pre> <p>ご参考までにProtobufの定義も載せておきます。message定義の中で必須のフィールドを指定しておくと、swaggerとして吐き出されるときにrequiredとして表現されます。設定を忘れやすいところではありますが、Goの場合は生成したopenapi.yamlからAPI Clientを自動生成し、インテグレーションテストの仕様により必須でないフィールドはポインタになるため、設定を忘れていたことに気づけます。</p> <pre class="code lang-proto" data-lang="proto" data-unlink><span class="synPreProc">syntax</span> = <span class="synConstant">&quot;proto3&quot;</span>; <span class="synType">package</span> example; <span class="synPreProc">option</span> go_package = <span class="synConstant">&quot;./;pb&quot;</span>; <span class="synPreProc">import</span> <span class="synConstant">&quot;google/api/annotations.Protobuf&quot;</span>; <span class="synPreProc">import</span> <span class="synConstant">&quot;validate/validate.Protobuf&quot;</span>; <span class="synPreProc">import</span> <span class="synConstant">&quot;Protobufc-gen-openapiv2/options/annotations.Protobuf&quot;</span>; <span class="synStatement">service</span> EchoService { <span class="synStatement">rpc</span> Echo (EchoRequest) <span class="synStatement">returns</span> (EchoResponse) { <span class="synPreProc">option</span> (google.api.http) = { post: <span class="synConstant">&quot;/echo&quot;</span> body: <span class="synConstant">&quot;*&quot;</span> }; } } <span class="synType">message</span> EchoRequest { <span class="synType">string</span> name = <span class="synConstant">1</span>; <span class="synPreProc">option</span> (grpc.gateway.Protobufc_gen_openapiv2.options.openapiv2_schema) = { json_schema: { <span class="synStatement">required</span>: [<span class="synConstant">&quot;name&quot;</span>] } }; } <span class="synType">message</span> EchoResponse { <span class="synType">string</span> <span class="synType">message</span> = <span class="synConstant">1</span>; <span class="synPreProc">option</span> (grpc.gateway.Protobufc_gen_openapiv2.options.openapiv2_schema) = { json_schema: { <span class="synStatement">required</span>: [<span class="synConstant">&quot;message&quot;</span>] } }; } </pre> <p>ちなみに、生成されるドキュメントはOpenAPI v2なので、v3の形式で欲しい場合は以下のようなツールを使ってさらに変換をかける必要があります。</p> <p><a href="https://github.com/Mermade/oas-kit/blob/main/packages/swagger2openapi/README.md">https://github.com/Mermade/oas-kit/blob/main/packages/swagger2openapi/README.md</a></p> <p>また、openapi.yamlからAPI Clientの自動生成はoapi-codegenを利用しています。</p> <p><a href="https://github.com/deepmap/oapi-codegen">https://github.com/deepmap/oapi-codegen</a></p> <h4>protoc-gen-validate (PGV)</h4> <p><a href="https://github.com/envoyproxy/protoc-gen-validate">https://github.com/envoyproxy/Protobufc-gen-validate</a></p> <p>ProtobufからgRPCのメッセージバリデーションを生成してくれるプラグインです。アノテーションでバリデーションルールを表現できます。</p> <pre class="code lang-proto" data-lang="proto" data-unlink><span class="synPreProc">syntax</span> = <span class="synConstant">&quot;proto3&quot;</span>; <span class="synType">package</span> examplepb; <span class="synPreProc">import</span> <span class="synConstant">&quot;validate/validate.Protobuf&quot;</span>; <span class="synType">message</span> Person { <span class="synType">uint64</span> id = <span class="synConstant">1</span> [(validate.rules).<span class="synType">uint64</span>.gt = <span class="synConstant">999</span>]; <span class="synType">string</span> email = <span class="synConstant">2</span> [(validate.rules).<span class="synType">string</span>.email = <span class="synConstant">true</span>]; <span class="synType">string</span> name = <span class="synConstant">3</span> [(validate.rules).<span class="synType">string</span> = { pattern: <span class="synConstant">&quot;^[^[0-9]A-Za-z]+( [^[0-9]A-Za-z]+)*$&quot;</span>, max_bytes: <span class="synConstant">256</span>, }]; Location home = <span class="synConstant">4</span> [(validate.rules).<span class="synType">message</span>.<span class="synStatement">required</span> = <span class="synConstant">true</span>]; <span class="synType">message</span> Location { <span class="synType">double</span> lat = <span class="synConstant">1</span> [(validate.rules).<span class="synType">double</span> = { gte: <span class="synConstant">-90</span>, lte: <span class="synConstant">90</span> }]; <span class="synType">double</span> lng = <span class="synConstant">2</span> [(validate.rules).<span class="synType">double</span> = { gte: <span class="synConstant">-180</span>, lte: <span class="synConstant">180</span> }]; } } </pre> <p>gRPCサーバがある場合は、Interceptorでバリデーションできますが、サービスを登録したgRPC Gatewayで使う場合はInterceptorの出番がなく、またHTTPのMiddlewareレイヤではバリデータが使用できません。そのため、Handler内で <code>request.Validate()</code> メソッドを呼ぶ必要があります。</p> <p>愚直にHandlerの処理でバリデーションメソッドを呼んでもいいのですが、私のチームでは、専用のレイヤでバリデーションするようにしました。コード量は増えてしまいますが、バリデーションの実装忘れは発生しにくいと思います。</p> <h3>BufでProtobufをビルドする</h3> <p>REST APIに限った話ではないのでテーマから少し脱線してしまいますが、開発体験を良くしてくれたBufについても簡単にご紹介させてください。</p> <p>BufはProtobufの依存管理やprotocで実行していたコマンドをいい感じにまとめてくれるツールです。これを使うことで、 依存管理の悩みから開放され、protocコマンドで長たらしく書いていたものを<code>buf generate</code>とシンプルにまとめることができます。</p> <p><a href="https://docs.buf.build/introduction">https://docs.buf.build/introduction</a></p> <p>protoディレクトリをprotoファイルの置き場とした場合、以下のような構成になります。</p> <pre class="code" data-lang="" data-unlink>RepositoryRoot ├── buf.gen.yaml // protoc コマンドの引数ここで定義する ├── buf.work.yaml // workspaceを指定。この場合は proto ディレクトリを指定する └── proto ├── buf.lock // buf.yaml を作成後、 buf mod update コマンドで自動生成される ├── buf.yaml // .proto ファイルで使用されている依存の定義 └── example └── echo.proto</pre> <h4>BSR(Buf Schema Registry)</h4> <p>BufはBSRというProtobuf(Repository)とプラグインのレジストリを提供しています。</p> <p><a href="https://buf.build/">https://buf.build/</a></p> <p>Protobufを提供しているRepositoryは充実していますが、<strong>プラグインはBSRに登録されていないことがあります</strong>。例えば、protoc-gen-validateのRepositoryはありますが、2022年1月現在プラグインは提供されていないので、プラグインが実行可能なDockerfileを自分で用意、BSRに登録し、使えるようにする必要があります。</p> <h3>まとめ</h3> <p>今回は、Protobufを使ってREST APIを開発する方法と、ProtobufのツールであるBufについてご紹介しました。バリデーションまでできるスキーマ駆動開発の方法はかなり少ないと感じており、今後しばらくは有力な選択肢の一つになるのではないかと思っています。</p> shotasawada ORCAモデルを応用した軽量でよりリアルなNPCロジックの実現 hatenablog://entry/13574176438015298240 2021-10-27T16:00:00+09:00 2023-05-24T18:44:37+09:00 こんにちは、ティアフォーでパートタイムエンジニアをしている吉本です。 本記事では、計算量を抑えつつシミュレータ内のNPCロジックをよりリアルにする手法について紹介します。 なお、ティアフォーでは「自動運転の民主化」をともに実現していく、学生パートタイムエンジニアを常時募集しています。 自動運転という活発に研究開発が行われている分野で生き残っていくためには、自社で技術開発を行っていくと同時に常に最新の論文からキャッチアップし続ける必要があり、論文の内容の実装や改良を行っていくなど、幅広い領域でパートタイムエンジニアの募集があります。 まずは「話を聞いてみたい」でも結構ですので、もしご興味があれば… <p>こんにちは、ティアフォーでパートタイムエンジニアをしている吉本です。</p> <p>本記事では、計算量を抑えつつシミュレータ内のNPCロジックをよりリアルにする手法について紹介します。</p> <p>なお、ティアフォーでは「自動運転の民主化」をともに実現していく、学生パートタイムエンジニアを常時募集しています。 自動運転という活発に研究開発が行われている分野で生き残っていくためには、自社で技術開発を行っていくと同時に常に最新の論文からキャッチアップし続ける必要があり、論文の内容の実装や改良を行っていくなど、幅広い領域でパートタイムエンジニアの募集があります。</p> <p>まずは「話を聞いてみたい」でも結構ですので、もしご興味があれば以下のページからコンタクトいただければと思います。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftier4.jp%2Fcareer%2F" title="TIER IV Careers" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://tier4.jp/career/">tier4.jp</a></cite></p> <p><br data-mce-bogus="1"></p> <h3 id="NPCロジック改良の背景">NPCロジック改良の背景</h3> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftech.tier4.jp%2Fentry%2F2021%2F06%2F17%2F160000" title="Autowareの開発を更に加速!Openなシナリオテストフレームワークを紹介! - TIER IV Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://tech.tier4.jp/entry/2021/06/17/160000">tech.tier4.jp</a></cite></p> <p>シミュレーションチームでは、こちらの記事で紹介があったようにシナリオテストによって自動運転の安全性担保に取り組んでいます。 様々な交通状況のシーンをシナリオに書き起こしてテストを行うわけですが、現在は人間のシナリオライターが行っています。</p> <p>シナリオでは道路上の車両はもちろんのこと、自転車や歩行者などのNPC(Non Player Character)までもその挙動を細かく指定する必要があります。 この大きな手間を削減するためにシミュレーションチームではBehavior Treeを用いたNPCロジックの強化を行いました。</p> <p>この改良により、NPCに関してシナリオを細かく指定しなくてもある程度動くようになり、シナリオ書き起こしの作業負荷は大幅に軽減しました。</p> <p>ただし、これでも短時間に状態間を行ったり来たりするチャタリング問題が起こったり、ある種類のNPCに対して適用した状態機械を他のNPCに流用しようとすると、状態遷移条件が状態の中に記述されているため簡単には流用できない等の問題が残っていて、現行のNPCロジックでは今後多数のシナリオを書いていく際に大きな懸念事項となります。 また、10体以上のNPCが出現するシナリオもあるため、NPCロジックには計算量の少なさが強く求められます。</p> <h3 id="NPCロジック改良のインパクト">NPCロジック改良のインパクト</h3> <p>以上のような問題点を解決するために、私たちはORCA(Optimal Reciprocal Collision Avoidanceの略称)というアルゴリズムを導入することにしました。</p> <p>今まではシナリオ上で「この速度でこの経路の上を通って動きなさい」といった詳細な”NPCの挙動”を指定していたところを、ORCAでは「この中で動きなさい」というよう動作時に求められる”NPCの挙動の制約条件”を指定するようになっていて、難しい状況に対しても状態のチャタリング現象などが発生することなく動作計画が作れます。</p> <p>チャタリング現象と言うと難しく聞こえるかもしれませんが、みなさんも歩道などで向こうからやってくる歩行者が右に避けるか左に避けるか分からずに右往左往したことはないでしょうか? はじめは右に避けることが最適に思えても対向者が同じ方向に避けると最適な避ける方向が左に変わってしまいます。 それを見た対向者が今度は逆の方向に避けようとするともう大変。 同じことが無限ループしてしまい、対面でお互い進路を譲りたいはずなのに妨害して立ち往生してしまいます。 <figure class="figure-image figure-image-fotolife" title="チャタリングする会社員のイラスト"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/H/HansRobo/20211018/20211018163008.png" width="1200" height="432" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>チャタリングする会社員のイラスト</figcaption></figure> もちろん、人間ならそうなる前に相手とコミュニケーションをとってすれ違うことができますが、アルゴリズムに則って動くNPCはそうではありません。 チャタリング現象も陽に考慮したアルゴリズムを適用しなければ至る所でNPCが立ち往生する事態に陥りかねません。 特にBehavior Treeや階層ステートマシンといった状態機械に強く依存するNPCロジックほどチャタリングの影響を強く受けます。 ORCAモデルであれば行動を制約条件の形に落とし込むので、状態の数を減らすことができチャタリングするリスクを減らすことができます。</p> <p>ORCAではそのようなチャタリング現象にもしっかりと対策されているので、導入によりNPCの立ち往生の防止が期待できます。</p> <p>また、ORCAにおける各NPCの行動計画は独立して計算できるので、並列計算などで計算機のリソースを最大限に活用できます。 また、計算量が少なくなるように設計されていて多数のNPCが出現するようなシナリオでもスムーズに動作します。</p> <h3 id="ORCAとは">ORCAとは?</h3> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fyoutu.be%2FzmTgj4SKftc" title="Optimal Reciprocal Collision Avoidance" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://youtu.be/zmTgj4SKftc">youtu.be</a></cite></p> <p>ORCAは2010年に提案された衝突回避アルゴリズムです。[1] 提案後も様々な改良がなされ、非ホロノミック拘束をもつエージェントに対応したモデル[2]や、市街地環境で複数のドローンを使って環境を効率よくスキャンするといったマルチロボットでタスクを効率よく実行するための制約条件を入れたモデル[3]等も提案されており、様々な応用先が考えられています。 お互いに意思を持つ多数のエージェント同士が衝突を回避するための行動計画をそれぞれ短い時間で計算できます。 10年経った現在では様々な派生手法が発表されていますが、ベースモデルとしてまだまだ現役で使われています。</p> <p>ORCAでは、速度空間内でのエージェント同士がぶつからないような線形不等式制約を相対速度と距離から作り出し、制約内で最適な(目標速度に最も近い)速度を計算します。 ORCAのスゴイところは、この計算した線形不等式制約がエージェント同士で通信せずともお互い回避できるような制約になっている点です。 普通なら片方が右に避けるからもう片方は左に避けるといったコミュニケーションをとったり中央集権的なアルゴリズムを用いたくなるものですが、ORCAでは各エージェントごとの行動計画は独立して計算できるため、多数のエージェントが存在する場合でも計算を並列化して高速に計算できます。</p> <p>この制約条件を近くに存在する他のエージェントに対して計算して(下図)、残った速度空間内で所望の速度に最も近い速度をNPCに適用します。</p> <p><figure class="figure-image figure-image-fotolife" title="ORCAによるマルチエージェントナビゲーション[1]"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/H/HansRobo/20211020/20211020103307.png" width="1014" height="826" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>ORCAによるマルチエージェントナビゲーション([1]のFig. 5より引用)</figcaption></figure></p> <p>複雑な制約でも線形不等式制約という簡単な制約に落とし込むことで計算が軽くなるように工夫されています。</p> <p>また、この手法は拡張性の高さも魅力の1つです。 速度空間内の線形不等式制約にさえ落とし込めばその他の制約も追加できるため、例えば自動車なら対向車線に行かないような制約、歩行者なら歩道や横断歩道からはみ出ないような制約を追加することもできるでしょう。</p> <h3 id="NPCロジック改良の実装とデモ">NPCロジック改良の実装とデモ</h3> <p>実はOCRAのアルゴリズムはRVO2というOSS(Open Source Software)のライブラリで公開されているので、それをライセンスにしたがって使わせていただいています。 ただし、実際に使うにあたり、NPCの種類や個体ごとにパラメータや避ける障害物を調整できるようにカスタマイズ版を開発しました。 自動車や人などが通行するときには様々な制約のもとで行動しています。 例えば、道路から飛び出さないといった単純なものから信号が赤であれば停止線より前には行かないといった様々な制約があります。 そのため、このORCAモデル単体では賢いNPCを作ることはできず、そこに交通状況のコンテキストを考慮できる機能を導入する必要があります。</p> <p><iframe width="560" height="315" src="https://www.youtube.com/embed/rF-n52gnMw0?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen title="SUMMIT: A Simulator for Urban Driving in Massive Mixed Traffic"></iframe><cite class="hatena-citation"><a href="https://youtu.be/rF-n52gnMw0">youtu.be</a></cite></p> <p>そこで現在ティアフォーのシミュレーションチームでは、scenario_simulator_v2のNPCロジックをプラグイン化し、こちらの論文[4]で採用されているContext-GAMMAというORCAに周囲の交通状況のコンテキストを考慮させたモデルにさらにティアフォー独自のアレンジを加えたNPCロジックを実装中です。</p> <p><figure class="figure-image figure-image-fotolife" title="Context-GAMMAを利用したNPC Plannerのソフトウェアアーキテクチャ"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/m/masaya-kataoka/20211026/20211026140853.png" width="1200" height="612" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>Context-GAMMAを利用したNPC Plannerのソフトウェアアーキテクチャ</figcaption></figure></p> <p>具体的には、Context-GAMMA単体では参照経路は事前に与える必要があるので、参照経路をBehavior Treeアルゴリズムを使用して作成、それにおおよそしたがいつつ衝突等は避けるといった感じの挙動をContext-GAMMAを使用して生成します。 まずは歩行者から実装を開始し、次は自動車、自転車、バイクとどんどん対象を広げられればと考えています。</p> <p>今後もティアフォーのシミュレーションチームではさらなるシミュレータの高度化およびAutowareの評価手法の自動化、効率化を目指します。</p> <h5 id="参考文献">参考文献</h5> <p>[1] Van Den Berg, Jur, et al. "Optimal reciprocal collision avoidance for multi-agent navigation." 2010 IEEE International Conference on Robotics and Automation (ICRA). IEEE, 2010.<br/> [2] Alonso-Mora, Javier, et al. "Optimal reciprocal collision avoidance for multiple non-holonomic robots." Distributed autonomous robotic systems. Springer, Berlin, Heidelberg, 2013. 203-216.<br/> [3] Arul, Senthil Hariharan, et al. "LSwarm: Efficient collision avoidance for large swarms with coverage constraints in complex urban scenes." IEEE Robotics and Automation Letters 4.4 2019. 3940-3947.<br/> [4] Cai, Panpan, et al. "Summit: A simulator for urban driving in massive mixed traffic." 2020 IEEE International Conference on Robotics and Automation (ICRA). IEEE, 2020.</p> HansRobo より安全な自動運転へ向けた死角手前での減速 hatenablog://entry/26006613802863818 2021-09-22T16:00:00+09:00 2023-05-24T18:46:05+09:00 // 死角手前での減速機能によって向上する自動運転の安全性 こんにちは、ティアフォーでPlanning/Controlの開発をしている田中です。今回は、交通ルールによって速度を決定するモジュールの一部である死角手前での減速機能を紹介し、この機能が自動運転に与えるインパクトについてお話します。 なお、ティアフォーでは、「自動運転の民主化」をともに実現していく様々なエンジニア・リサーチャーを募集しています。もしご興味があればカジュアル面談も可能ですので以下のページからコンタクトいただければと思います。 TIER IV Careers tier4.jp 背景・課題 通常走行時、Autowareは自車… <p> <script type="text/javascript" async="" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-MML-AM_CHTML">// <![CDATA[ // ]]></script> </p> <style><!-- body { color: black; } --></style> <h3 id="-">死角手前での減速機能によって向上する自動運転の安全性</h3> <p><span style="color: #000000;">こんにちは、ティアフォーでPlanning/Controlの開発をしている田中です。今回は、交通ルールによって速度を決定するモジュールの一部である死角手前での減速機能を紹介し、この機能が自動運転に与えるインパクトについてお話します。</span></p> <p data-renderer-start-pos="7448"><span style="color: #000000;"><span style="font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; float: none; display: inline !important;">なお、ティアフォーでは、「自動運転の民主化</span><span style="font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; float: none; display: inline !important;">」をともに実現していく様々なエンジニア・リサーチャーを募集しています。もしご興味があればカジュアル面談も可能ですので以下のページからコンタクトいただければと思います。</span></span></p> <p><a href="https://careers.tier4.jp/">TIER IV Careers</a></p> <p><span style="color: #000000;"><br /><cite class="hatena-citation"><a href="https://tier4.jp/careers/" style="color: #000000;">tier4.jp</a></cite></span></p> <h3 id="-"><span style="color: #000000;">背景・課題</span></h3> <p><span style="color: #000000;">通常走行時、Autowareは</span><span style="color: #000000;">自車の制限速度にしたがって走行しますが、走行中のレーンに人や車が飛び出してきたときは衝突しないように緊急停止します。閉鎖空間や立ち入り禁止区域など、人が入れないような場所では飛び出しが起こりえないので考慮する必要はありませんが、公道では交差点でないところでも飛び出しは起こりえます。上限速度で走行していた場合は、万が一の飛び出しに対応できない可能性もあります。したがって、緊急停止時にきちんと停止できるかどうかは非常に重要な問題となります。</span><span style="color: #000000;">そこで、死角手前から緩やかに減速する機能を開発しました。</span></p> <p><span style="color: #000000;"><img src="https://user-images.githubusercontent.com/65527974/131307537-86304ff8-b1c6-4504-961a-fd3d9ae58c8e.png" alt="image.png" /></span></p> <h3 id="-"><span style="color: #000000;">想定シナリオ</span></h3> <p><span style="color: #000000;"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/639823/d15a4b79-dfa3-0b96-43db-34f9eb72a87f.png" alt="image.png" /></span></p> <p><span style="color: #000000;">自車が走行しているレーン付近に停車中の車両がある場合、その車両の裏が死角となって歩行者が飛び出してくる可能性があるため、停車車両が作る死角地点の十分手前から適切な減速を行います。</span></p> <p><span style="color: #000000;"><img src="https://user-images.githubusercontent.com/65527974/133370409-be84bc71-3363-47ba-8363-776ac96380dd.png" alt="f:id:t4ttanaka:20210831101646p:plain" loading="lazy" title="" class="hatena-fotolife" itemprop="image" width="634" height="349" /></span></p> <p><span style="color: #000000;">衝突前に緊急停止可能な上限速度を \(v_\mathit{ebs}\) とします。\(v_\mathit{ebs}\) は、フルブレーキの減速度 \(a_\mathit{ebs}\) と歩行者が衝突地点にたどり着くまでの時間 \(\frac{d_\mathit{lateral}}{v_\mathit{obstacle}}\) 、システム遅延 \(t_\mathit{safe}\) を用いて以下のように求められます。</span></p> <p><span style="color: #000000;">\begin{align} v_\mathit{ebs}=a_\mathit{ebs} \cdot \left(\frac{d_\mathit{lateral}}{v_\mathit{obstacle}}-t_\mathit{safe}\right) \end{align}</span></p> <p><span style="color: #000000;">なお、ここでは死角から出てくる歩行者は \(v_\mathit{obstacle}\) の速度で等速直線運動をするものと仮定しています。</span></p> <p><span style="color: #000000;">次に、現在地点から死角地点まで一定のブレーキ量で安全に減速するための目標速度の上限を \(v_\mathit{pbs}\) とすると、\(v_\mathit{pbs}\) は現在の自車速度 \(v_0\)、死角までの縦方向距離 \(d_\mathit{longitudinal}\) 、死角手前での減速として許容できるブレーキ量 \(a_\mathit{pbs}\) を用いて、等加速度直線運動の関係式から以下のように求められます。</span></p> <p><span style="color: #000000;">\begin{align} v_\mathit{pbs}= \sqrt{v_0^2 - a_\mathit{pbs} \cdot d_\mathit{longitudinal}} \end{align}</span></p> <p><span style="color: #000000;">理論上目標速度に向かって減速しきることが好ましいのですが、誤検出によって死角と判定されたものが急にできたときなどすべての死角に対応できないこと、急減速時の車内の人の安全担保、そして後続車からの衝突回避を考慮して上記の上限速度を用いています。</span></p> <p><span style="color: #000000;">最後に、走行時に交通の妨げとならないための最低速度定数 \(v_\mathit{min}\) を後続車との車間距離 \(d_\mathit{follow}\)、制限速度 \(v_\mathit{limit}\)、後続車が減速を認識するのにかかる時間 \(s_\mathit{safe}\) を用いて以下のように求めます。</span></p> <p><span style="color: #000000;">\begin{align} v_\mathit{min}=v_\mathit{limit}-\frac{d_\mathit{follow}}{s_\mathit{safe}} \end{align}</span></p> <p><span style="color: #000000;">私有地や狭い道路であれば高速で走行する車両は少ないのですが、車の通行量が多い国道や大通りなどではある程度速度を出して走らないと交通の妨げになったり、後続車から追突されてしまうことが考えられます。</span></p> <p><span style="color: #000000;">これら \(v_\mathit{ebs}\), \(v_\mathit{pbs}\), \(v_\mathit{min}\) を用いて、死角手前での減速計画は以下のようになります。</span></p> <p><span style="color: #000000;"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/639823/88365d6c-9764-c0b1-b132-13555cd99570.png" alt="OcclusionSpot-occlusion_spot.png" /></span></p> <h3 id="-"><span style="color: #000000;">死角手前での減速フロー</span></h3> <p><span style="color: #000000;">最後に、死角手前での減速フローを載せておきます。</span></p> <p><span style="color: #000000;"><img src="https://user-images.githubusercontent.com/65527974/133370170-46d2df47-8d27-4454-b300-2e75ce9c03e5.png" alt="image.png" /></span></p> <h3 id="-"><span style="color: #000000;">まとめ</span></h3> <p><span style="color: #000000;">このように、死角手前であらかじめ減速しておくことで予期せぬ事故を回避できます。今後もより安全な自動運転へ向けた減速計画について検討していきたいと考えています。</span></p> <h3 id="-"><span style="color: #000000;">参考文献<br /></span></h3> <p>この機能の実装には以下の文献を参考にしました。</p> <ul> <li>Euro NCAP. European New Car Assessment Programme (Euro NCAP)—Test Protocol—AEB VRU systems, Version 3.0.4. Technical Report, 2021. <a href="https://cdn.euroncap.com/media/62795/euro-ncap-aeb-vru-test-protocol-v304.pdf">https://cdn.euroncap.com/media/62795/euro-ncap-aeb-vru-test-protocol-v304.pdf</a></li> <li>Yohei Fujinami, Pongsathorn Raksincharoensak, Dirk Ulbricht, and Rolf Adomat. Risk Predictive Driver Assistance System for Collision Avoidance in Intersection Right Turns. Journal of Robotics and Mechatronics, Vol.30, No.1, pp.15-23, 2018. <a href="https://doi.org/10.20965/jrm.2018.p0015">https://doi.org/10.20965/jrm.2018.p0015</a></li> </ul> t4ttanaka Autowareにおける3次元物体検出アルゴリズムの再検討【サーベイ編】 hatenablog://entry/13574176438009038967 2021-09-15T16:00:00+09:00 2023-05-24T18:46:26+09:00 ティアフォーのSensing/Perceptionチームで開発を行っている村松です。Autowareの動物体検出アルゴリズムのうち一部を再検討し、Autowareに組み込むまでについて紹介します。今回はそのサーベイ編として、調査した概要や手法についてお話します。 なお、ティアフォーでは、「自動運転の民主化」をともに実現していく様々なエンジニア・リサーチャーを募集しています。もしご興味があればカジュアル面談も可能ですので以下のページからコンタクトいただければと思います。 TIER IV Careers tier4.jp 自動運転における3次元物体検出について 3次元物体検出とは、3次元空間での物… <p><span style="font-weight: 400;">ティアフォーのSensing/Perceptionチームで開発を行っている村松です。</span><span style="font-weight: 400;">Autowareの動物体検出アルゴリズムのうち一部を再検討し、Autowareに組み込むまでについて紹介します。今回はそのサーベイ編として、調査した</span><span style="font-weight: 400;">概要や手法についてお話します。</span></p> <p data-renderer-start-pos="7448"><span style="font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; float: none; display: inline !important;">なお、ティアフォーでは、「自動運転の民主化</span><span style="font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; float: none; display: inline !important;">」をともに実現していく様々なエンジニア・リサーチャーを募集しています。もしご興味があればカジュアル面談も可能ですので以下のページからコンタクトいただければと思います。</span></p> <p><a href="https://careers.tier4.jp/">TIER IV Careers</a></p> <p><br /><cite class="hatena-citation"><a href="https://tier4.jp/careers/">tier4.jp</a></cite></p> <h3 id="自動運転における3次元物体検出について"><span style="font-weight: 400;">自動運転における3次元物体検出について</span></h3> <p><span style="font-weight: 400;">3次</span>元物体検<span style="font-weight: 400;">出とは、3次元空間での物体のクラス(種類)・位置・大きさ・向きなどを推定する技術です。自動運転において、事故なく目的地まで移動するためには、他車両や歩行者などがどこにどの大きさで存在するかという周辺環境の認識が必須となります。より正確に物体検出を行うことで、自車両がどのように動くか判断することができます。</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="MVLidarNet: Real-Time Multi-Class Scene Understanding for Autonomous Driving Using Multiple Views より引用"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/y/yukke42/20210907/20210907112514.png" alt="f:id:yukke42:20210907112514p:plain" width="1200" height="705" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable"><a href="#f-b2006c93" name="fn-b2006c93" title="Ke Chen, et al. &quot;MVLidarNet: Real-Time Multi-Class Scene Understanding for Autonomous Driving Using Multiple Views.&quot; 2020 IEEE/RSJ International Conference on Intelligent Robots and Systems (IROS). IEEE, 2020.">*1</a>より引用</figcaption> </figure> <p><span style="font-weight: 400;">自動運転車両にはLiDAR(Light Detection and Ranging)やカメラ・レーダーなどのセンサーが搭載されています。その中でも、多くの3次元物体検出手法でLiDARが採用されています。LiDARは、レーザー光を照射し、反射して戻ってくるまでの時間を計測することで空間の位置情報が取得できます。この空間の位置情報が3次元物体検出には重要な特徴量となります。</span></p> <p><span style="font-weight: 400;">一方で、単眼画像やステレオ画像からの3次元物体検出も数多く研究されています。しかし、一般的なカメラ画像には深度の情報がないため、RGB(Red-Green-Blue color model)のみから深度を推定する必要があり、特に単眼画像からの推定はとても難しいタスクです。</span><span style="font-weight: 400;">また、カメラのキャリブレーションがかなり正確でないと画像から空間へ投影した際にずれが生じるという難しさもあります。そして、一番大きな問題として学習したカメラ画像のキャリブレーションのパラメータも含めて学習してしまうために、カメラの取り付け位置を変更すると学習したモデルは全く使えなくなってしまうことがあります。オープンソースであるAutowareとしては、センサーの取り付け位置が完全に固定されてしまうことは致命的な問題です。</span></p> <p><span style="font-weight: 400;">また、自動運転システムに3次元物体検出手法を組み込む際の計算リソースが限られていることも考慮する必要があります。点群を比較的効率的に処理できるVoxelNet<a href="#f-970c51cd" name="fn-970c51cd" title="Yin Zhou and Oncel Tuzel. &quot;VoxelNet: End-to-End Learning for Point Cloud Based 3D Object Detection.&quot; Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition, 2018.">*2</a>と呼ばれる手法があります。VoxelNetについて簡単に説明すると、空間をVoxel化し、点群をCNNs(Convolutional Neural Networks)で処理できる特徴量に落とし込むことで効率的な処理を可能にする手法です。しかし、このVoxelNetには3D CNNsが使われているため、とても大きな計算リソースを必要とします。この問題を解決するためにSECOND<a href="#f-05d3ad95" name="fn-05d3ad95" title="Yan Yan, Yuxing Mao, and Bo Li. &quot;SECOND: Sparsely Embedded Convolutional Detection.&quot; Sensors 18.10 (2018): 3337.">*3</a>とPointPillars<a href="#f-bc91e86d" name="fn-bc91e86d" title="Alex H. Lang, et al. &quot;PointPillars: Fast Encoders for Object Detection from Point Clouds.&quot; Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR), 2019.">*4</a>と呼ばれる2つの手法があり、点群をVoxel特徴量に落とし込む3次元物体検出手法のほとんどはこのどちらかをベースとしています。</span></p> <p><span style="font-weight: 400;">2つの手法の大まかな特徴は以下のようになります。</span></p> <p>SECOND</p> <ul> <li>3D CNNsを独自のSparse 3D CNNsに置き換えることで高速化</li> <li>検出精度がよい</li> </ul> <p>PointPillars</p> <ul> <li>3D CNNsを除去することで高速化</li> <li>SECONDと比較し検出精度は落ちるが軽量で高速</li> </ul> <p>今回、実行時間とAutowareへの組み込みのためのC++への移植性を考慮し、上記2つのうちPointPillarsをベースとする手法を候補にしました。</p> <h3 id="手法紹介"><span style="font-weight: 400;">手法紹介</span></h3> <p><span style="font-weight: 400;">今回、3次元物体検出を調査した論文として、CenterPoint<a href="#f-f14b0ddd" name="fn-f14b0ddd" title="Tianwei Yin, Xingyi Zhou, and Philipp Krähenbühl. &quot;Center-based 3D Object Detection and Tracking.&quot; Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR), 2021.">*5</a>とAFDet<a href="#f-80247da9" name="fn-80247da9" title="Runzhou Ge, et al. &quot;AFDet: Anchor Free One Stage 3D Object Detection.&quot; arXiv preprint arXiv:2006.12671, 2020.">*6</a>と呼ばれる2つの手法を紹介します。PointPillarsについては、以前の記事で紹介されているためそちらを参照ください。</span></p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftech.tier4.jp%2Fentry%2F2019%2F04%2F25%2F185724" title="Autowareにおける三次元物体認識アルゴリズム「PointPillars」の紹介 - Tier IV Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://tech.tier4.jp/entry/2019/04/25/185724">tech.tier4.jp</a></cite></p> <h4 id="Anchor-free-Detection"><span style="font-weight: 400;">Anchor-free Detection</span></h4> <p><span style="font-weight: 400;">今回紹介するCenterPointとAFDetはAnchor-freeと呼ばれる手法です。従来のPointPillarsなどの手法では、Anchorと呼ばれるBounding Boxの基準となるもので検出範囲内にマッチング検索をし、Intersection over Union (IoU)がしきい値を超えた物体を学習するという手法でした。Anchor-basedの手法では、検索方法やしきい値を適切に決定しなければ、効率よく物体を学習することができません。そのため、より多くの物体がIoUのしきい値を超えるようにヒューリスティックにパラメータ探索をしなくてはなりません(下図a)。</span></p> <p><span style="font-weight: 400;">一方で、Anchor-freeの手法では、Anchorを使わずに物体の中心をヒートマップとして学習するため、様々な形状の物体をとりこぼすことがありません(下図b)。</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="Objects as Points より引用"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/y/yukke42/20210907/20210907115557.png" alt="f:id:yukke42:20210907115557p:plain" width="637" height="363" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable"><a href="#f-2405988c" name="fn-2405988c" title="Xingyi Zhou, Dequan Wang, and Philipp Krähenbühl. &quot;Objects as Points.&quot; arXiv preprint arXiv:1904.07850, 2019.">*7</a>より引用</figcaption> </figure> <p><span style="font-weight: 400;">一般的な画像からの物体検出では、上図のように回転のない長方形として物体の位置を示します。しかし、自動運転の3次元物体検出では、物体の向きも考慮する必要があります。また、歩行者や自転車などの小さい物体やトラックやバスなどの長さのある物体なども多く、向きを含めたBounding BoxでIoUがしきい値を超えるようなAnchorを設定するには多くのパラメータやチューニングが必要となります(下図参照)。</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="CenterPointより引用"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/y/yukke42/20210907/20210907125227.png" alt="f:id:yukke42:20210907125227p:plain" width="568" height="515" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable"><a href="#f-03db702e" name="fn-03db702e" title="前掲、5に同じ ">*8</a>より引用</figcaption> </figure> <h5 id="Center-based-3D-Object-Detection-and-Tracking-CenterPoint"><span style="font-weight: 400;">Center-based 3D Object Detection and Tracking (CenterPoint)</span></h5> <p><span style="font-weight: 400;">CenterPointは、The Conference on Computer Vision and Pattern Recognition (CVPR) 2021で採択された論文で、画像から物体検出を行うCenterNet <a href="#f-a26d8b75" name="fn-a26d8b75" title="前掲、7に同じ">*9</a>を3次元物体検出に応用した手法です。CenterNetの著者も共著者の一人となっており、基本的な考え方については</span><span style="font-weight: 400;">同じものとなっています。</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="CenterPointの概要図"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/y/yukke42/20210907/20210907154530.png" alt="f:id:yukke42:20210907154530p:plain" width="953" height="369" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">CenterPointの概要図 <a href="#f-bf376be0" name="fn-bf376be0" title="前掲、5に同じ">*10</a>より引用</figcaption> </figure> <p><span style="font-weight: 400;">CenterPointの概要について紹介します。CenterPointは3D Backbone、First Stage、Second Stageと主に3つの処理で構成されています。</span></p> <p><span style="font-weight: 400;">3D Backboneは点群を入力とし、Bird's-eye-viewの疑似画像特徴量へと変換します。この処理はPointPillarsやSECONDで採用されている手法をそのまま用いているため詳しく知りたい方はそれぞれの論文を参照していただければと思います。</span></p> <p><span style="font-weight: 400;">First Stageと呼ばれる処理では、疑似画像特徴量から各物体のパラメータを推定します。まず、ヒートマップのピーク位置から物体の大まかな位置を推定します。次に、各ネットワークの出力からそのピーク位置に対応するオフセットの推定値を用いることで、物体のより詳細な位置を推定します。そして、高さ・サイズ・向きをそれぞれ推定することで、</span><span style="font-weight: 400;">3D Bounding Boxの位置・サイズ・向きが推定できます。</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="AFDetより引用"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/y/yukke42/20210907/20210907144832.png" alt="f:id:yukke42:20210907144832p:plain" width="748" height="231" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">ネットワークから出力する各推定値 <a href="#f-b817b65d" name="fn-b817b65d" title="前掲、6に同じ">*11</a>より引用</figcaption> </figure> <p><span style="font-weight: 400;">Second Stageでは、First Stageで推定された3次元物体の中心と四辺の中心の位置に対応する特徴量を疑似画像から抽出し、MLP(Multilayer Perceptron)を適用することでScoreと3D Bounding Boxの調節を行います(CenterPointの概要図のd)。</span></p> <p><span style="font-weight: 400;">他の3次元物体検出手法と異なる点として、3次元トラッキングを行うために物体の速度推定も行っています。現在のフレームの物体位置と速度から過去フレームの位置を逆算することで、過去の位置に物体が存在した場合に同一物体だと割り当てることができます。</span></p> <p><span style="font-weight: 400;">CenterPointは今年のWaymo Open Dataset ChallengeのReal-time 3D Detection分野で2位を獲得しました。そのレポートについては<a href="https://drive.google.com/file/d/1wG1zPc2PyWgBIC-dLSFbxzeZ3FhA708_/view">こちらのリンク</a></span><span style="font-weight: 400;">にあります。今回の記事の内容は、このコンペティションの前に調査したものなので、コンペティションで使われた手法等の詳しい内容はレポートを参照していただければと思います。</span></p> <h5 id="AFDet-Anchor-Free-One-Stage-3D-Object-Detection"><span style="font-weight: 400;">AFDet: Anchor Free One Stage 3D Object Detection</span></h5> <p><span style="font-weight: 400;">AFDetは昨年のWaymo Open Dataset Challengeの3D Detectionと今年のReal-time 3D Detectionで1位を獲得した手法です。CenterPointとほぼ同じタイミングでarXivに公開されましたが、基本的な考え方はCenterPointのFirst Stageまでの手法と同じです。</span><span style="font-weight: 400;">CenterPointと大きく異なる点は3つあります。</span></p> <p><span style="font-weight: 400;">1つ目は、学習時に物体の中心を推定するためのヒートマップの生成方法です。CenterPointではガウス分布を用いていましたが、AFDetでは2点間のユークリッド距離の逆数を用いています。</span></p> <p><span style="font-weight: 400;">2つ目は、学習時のオフセットのlossの計算方法です。CenterPointでは物体の中心のグリッドに対応する値のみをlossとして計算しますが、AFDetでは物体の中心に対応する値だけでなく、その周辺のグリッドの値まで含めてlossの計算をします。この方法は、物体のヒートマップのピークが物体の中心とずれていた場合でも、オフセットで物体の中心を正しく推定できるようにすることが目的です。</span></p> <p><span style="font-weight: 400;">3つ目は、物体の向きの推定方法です。CenterPointでは向きθをcos(θ)、sin(θ)に分解することで向きベクトルとして学習していますが、AFDetではMulti-binと呼ばれる手法を用いています。この手法は複雑なため簡単に説明すると、θを2つの範囲に区切り、どちらの範囲に入るかの分類とcos(θ)、sin(θ)のregressionを活用することでθを推定する手法です。詳しい内容は論文を参照していただければと思います。</span></p> <h4 id="実験"><span style="font-weight: 400;">実験</span></h4> <p><span style="font-weight: 400;">ここまでCenterPointとAFDetについて紹介してきましたが、AFDetは実装が公開されていなかったため、今回はCenterPointのみを検証することにしました。比較対象は、Autowareに実装済みであるPointPillarsです。PointPillarsはAnchor-based、CenterPointはAnchor-freeであることがポイントです。</span></p> <p><span style="font-weight: 400;">データセットは規模や画像のBounding Boxのアノテーションも含まれることを考慮してWaymo Open Dataset <a href="#f-a9c390c5" name="fn-a9c390c5" title="https://waymo.com/open/">*12</a>を採用しました。実験には</span><a href="https://github.com/open-mmlab/OpenPCDet"><span style="font-weight: 400;">https://github.com/open-mmlab/OpenPCDet</span></a><span style="font-weight: 400;">のリポジトリを活用しました。</span></p> <p><span style="font-weight: 400;">学習条件:</span></p> <ul> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">データセット: trainデータの4分の1</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">検出範囲: -75m ~ 75m四方</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">Voxelサイズ: 0.32m x 0.32m x 10m</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">Optimizer: Adam</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">Scheduler: OneCycle</span></li> </ul> <h5 id="評価"><span style="font-weight: 400;">評価</span></h5> <p><span style="font-weight: 400;">評価条件:</span></p> <ul> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">データセット: validationデータの4分の1</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">評価方法: nuScenes形式</span></li> </ul> <p>一般的な画像からの物体検出の評価方法は、主にIoUをしきい値として検出結果にTrue/Falseを割り当てることで計算できるAverage Precision(AP)が使われています。3次元物体検出でも同様にこのAPが使われていますが、このTrue/Falseの割り当て方法では位置や向きのズレをほとんど許容できません。今回は、このズレを許容し物体が検出されていることを優先的に判断するために、nuScenes<a href="#f-0bc2f20a" name="fn-0bc2f20a" title="https://www.nuscenes.org/">*13</a>の評価方法である物体の中心間距離をしきい値としてTrue/Falseを割り当ててAPを計算する評価方法を採用しました。nuScenesと同様に中心間距離0.5mをしきい値として用いています。</p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="evaluation"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/y/yukke42/20210910/20210910142938.png" alt="f:id:yukke42:20210910142938p:plain" width="770" height="111" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">evaluation</figcaption> </figure> <h5 id="考察"><span style="font-weight: 400;">考察</span></h5> <p><span style="font-weight: 400;">車と自転車はCenterPoint、歩行者はPointPillarsの方が高精度という結果になりました。したがって、この結果から総合的に判断して、Autowareでは既存の動物体検出アルゴリズムと入れ替える形でCenterPointを採用することにしました。</span></p> <p><span style="font-weight: 400;">PointPillarsの</span><span style="font-weight: 400;">自転車検出性能がCenterPointより著しく低い理由として、自転車のサンプル数が他のクラスと比べて圧倒的に少ないこと、自転車は小さくて細長い形状のため、Anchorマッチングのしきい値を超えるようなサンプルが少なくなったことが考えられます。学習に使用したデータは、車が約480万サンプル、歩行者が約220万サンプルに対して自転車が約5万サンプルと他のクラスの1~2%にとどまります。</span></p> <p><span style="font-weight: 400;">このサンプル数が少ないケースでの問題を解決するために、ground-truth sampling augmentationと呼ばれる手法が多くの論文で採用されています。このground-truth sampling augmentationとは、物体のアノテーションとその物体に対応する点群をデータベースとして保持し、学習フレームにデータベースから物体を追加することで学習するサンプル数を増やすという手法です(下図)。しかし、このフレームに追加されるサンプルは、アノテーションの値をそのまま用いているため学習フレームの幾何的特徴を無視しています。壁や地面にめり込んだ物体や空中に浮いている物体など、現実に存在しない物体も生成し学習してしまいます。これはデータセットの学習フレーム間で似たようなシーンが多い場合には問題ありませんが、立体的な交通環境が多い日本のデータにはそのまま採用できないaugmentationの手法だと考えているため、今回は採用を見送りました。この問題は、地図データを活用することでより現実のデータと整合性のとれるような配置に修正することで解決できると考えています。</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="w/o gt-sampling]"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/y/yukke42/20210907/20210907180615.png" alt="f:id:yukke42:20210907180615p:plain" width="820" height="458" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable"> ground-truth samplingなし</figcaption> </figure> <figure class="figure-image figure-image-fotolife mceNonEditable" title="w/ gt-sampling"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/y/yukke42/20210907/20210907180639.png" alt="f:id:yukke42:20210907180639p:plain" width="820" height="458" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">ground-truth samplingあり</figcaption> </figure> <h3 id="まとめ"><span style="font-weight: 400;">まとめ</span></h3> <p><span style="font-weight: 400;">今回は、3次元物体検出の手法としてCenterPointを採用したところまで紹介しました。次回以降、実際にティアフォーが実証実験を行っている日本の道路環境において物体検出できるよう工夫した方法などについて紹介する予定です。</span></p><div class="footnote"> <p class="footnote"><a href="#fn-b2006c93" name="f-b2006c93" class="footnote-number">*1</a><span class="footnote-delimiter">:</span><span class="footnote-text">Ke Chen, et al. "MVLidarNet: Real-Time Multi-Class Scene Understanding for Autonomous Driving Using Multiple Views." 2020 IEEE/RSJ International Conference on Intelligent Robots and Systems (IROS). IEEE, 2020.</span></p> <p class="footnote"><a href="#fn-970c51cd" name="f-970c51cd" class="footnote-number">*2</a><span class="footnote-delimiter">:</span><span class="footnote-text">Yin Zhou and Oncel Tuzel. "VoxelNet: End-to-End Learning for Point Cloud Based 3D Object Detection." Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition, 2018.</span></p> <p class="footnote"><a href="#fn-05d3ad95" name="f-05d3ad95" class="footnote-number">*3</a><span class="footnote-delimiter">:</span><span class="footnote-text">Yan Yan, Yuxing Mao, and Bo Li. "SECOND: Sparsely Embedded Convolutional Detection." Sensors 18.10 (2018): 3337.</span></p> <p class="footnote"><a href="#fn-bc91e86d" name="f-bc91e86d" class="footnote-number">*4</a><span class="footnote-delimiter">:</span><span class="footnote-text">Alex H. Lang, et al. "PointPillars: Fast Encoders for Object Detection from Point Clouds." Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR), 2019.</span></p> <p class="footnote"><a href="#fn-f14b0ddd" name="f-f14b0ddd" class="footnote-number">*5</a><span class="footnote-delimiter">:</span><span class="footnote-text">Tianwei Yin, Xingyi Zhou, and Philipp Krähenbühl. "Center-based 3D Object Detection and Tracking." Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR), 2021.</span></p> <p class="footnote"><a href="#fn-80247da9" name="f-80247da9" class="footnote-number">*6</a><span class="footnote-delimiter">:</span><span class="footnote-text">Runzhou Ge, et al. "AFDet: Anchor Free One Stage 3D Object Detection." arXiv preprint arXiv:2006.12671, 2020.</span></p> <p class="footnote"><a href="#fn-2405988c" name="f-2405988c" class="footnote-number">*7</a><span class="footnote-delimiter">:</span><span class="footnote-text">Xingyi Zhou, Dequan Wang, and Philipp Krähenbühl. "Objects as Points." arXiv preprint arXiv:1904.07850, 2019.</span></p> <p class="footnote"><a href="#fn-03db702e" name="f-03db702e" class="footnote-number">*8</a><span class="footnote-delimiter">:</span><span class="footnote-text">前掲、5に同じ </span></p> <p class="footnote"><a href="#fn-a26d8b75" name="f-a26d8b75" class="footnote-number">*9</a><span class="footnote-delimiter">:</span><span class="footnote-text">前掲、7に同じ</span></p> <p class="footnote"><a href="#fn-bf376be0" name="f-bf376be0" class="footnote-number">*10</a><span class="footnote-delimiter">:</span><span class="footnote-text">前掲、5に同じ</span></p> <p class="footnote"><a href="#fn-b817b65d" name="f-b817b65d" class="footnote-number">*11</a><span class="footnote-delimiter">:</span><span class="footnote-text">前掲、6に同じ</span></p> <p class="footnote"><a href="#fn-a9c390c5" name="f-a9c390c5" class="footnote-number">*12</a><span class="footnote-delimiter">:</span><span class="footnote-text"><a href="https://waymo.com/open/">https://waymo.com/open/</a></span></p> <p class="footnote"><a href="#fn-0bc2f20a" name="f-0bc2f20a" class="footnote-number">*13</a><span class="footnote-delimiter">:</span><span class="footnote-text"><a href="https://www.nuscenes.org/">https://www.nuscenes.org/</a></span></p> </div> yukke42 カルマンフィルターが自動運転の自己位置推定で使われるまで hatenablog://entry/26006613790731267 2021-08-04T16:00:00+09:00 2023-05-24T18:42:40+09:00 はじめまして、ティアフォー技術本部 Planning / Controlチームで開発を行っている堀部と申します。 今回は状態推定の王道技術「カルマンフィルター」が実際に自動運転で用いられるまでの道のりやノウハウなどを書いていこうと思います。 みなさんはカルマンフィルターという言葉を聞いたことがありますでしょうか。 カルマンフィルターとは「状態推定」と呼ばれる技術の一種であり、自動運転においては現在の走行状態、例えば車速や自分の位置を知るために用いられます。 非常に有名な手法で、簡単に使えて性能も高く、状態推定と言えばまずカルマンフィルターと言われるほど不動の地位を確立しており、幅広いアプリケー… <p>はじめまして、ティアフォー技術本部 Planning / Controlチームで開発を行っている堀部と申します。</p> <p>今回は状態推定の王道技術「カルマンフィルター」が実際に自動運転で用いられるまでの道のりやノウハウなどを書いていこうと思います。</p> <p>みなさんはカルマンフィルターという言葉を聞いたことがありますでしょうか。</p> <p>カルマンフィルターとは「状態推定」と呼ばれる技術の一種であり、自動運転においては現在の走行状態、例えば車速や自分の位置を知るために用いられます。</p> <p>非常に有名な手法で、簡単に使えて性能も高く、状態推定と言えばまずカルマンフィルターと言われるほど不動の地位を確立しており、幅広いアプリケーションで利用されています。</p> <p>使い勝手に定評のあるカルマンフィルターですが、実際に自動運転のシステムとして実用レベルで動かすためには多くの地道な作業が必要になります。</p> <p>この記事では、カルマンフィルターが実際に自動運転で使われるまでに何が行われているのか、自動運転を支える基礎技術の裏側をご紹介したいと思います。</p> <p>目次は以下のようになっています。</p> <ul class="table-of-contents"> <li><a href="#カルマンフィルターって">カルマンフィルターって?</a><ul> <li><a href="#Autowareでどのようにカルマンフィルターが使われているのか">Autowareでどのようにカルマンフィルターが使われているのか</a></li> </ul> </li> <li><a href="#自動運転の自己位置推定でカルマンフィルターが使われるまで">自動運転の自己位置推定でカルマンフィルターが使われるまで</a><ul> <li><a href="#車両運動の非線形性非線形拡張">車両運動の非線形性(非線形拡張)</a></li> <li><a href="#センサーに遅延がある遅延補償">センサーに遅延がある(遅延補償)</a></li> <li><a href="#センサー間の時刻同期センサー同期">センサー間の時刻同期(センサー同期)</a></li> <li><a href="#取得した点群が歪んでいる歪み補正">取得した点群が歪んでいる(歪み補正)</a></li> <li><a href="#モデルに誤差があるバイアス誤差モデル">モデルに誤差がある(バイアス誤差モデル)</a></li> <li><a href="#周期の異なるセンサーの統合滑らかな補間">周期の異なるセンサーの統合(滑らかな補間)</a></li> <li><a href="#急に自己位置が変な場所へ飛んでしまう外れ値除去">急に自己位置が変な場所へ飛んでしまう(外れ値除去)</a></li> <li><a href="#今の推定精度はどれくらいなのか共分散の検討">今の推定精度はどれくらいなのか(共分散の検討)</a></li> <li><a href="#緊急時の対応">緊急時の対応</a></li> </ul> </li> <li><a href="#最後に">最後に</a></li> </ul> <h3 id="カルマンフィルターって">カルマンフィルターって?</h3> <p>カルマンフィルター(KF:Kalman Filter)の説明は詳しい文献がたくさんありますので、ここは概念的な説明に限定して説明します。</p> <p><strong>KFの主な目的は、複数の情報を適切に統合し、より精度の高い推定値を計算すること </strong>です。ここで言う「複数の情報」とは、「複数の観測値」とそれらの「信頼度」、「対象の運動モデル」、現在の「推定値の信頼度」などです。1960年にアルゴリズムが提唱されてから、長いこと工学分野の第一線で用いられてきました。<a href="#f-ccdd2671" name="fn-ccdd2671" title="Kalman, R. E. (March 1, 1960). &quot;A New Approach to Linear Filtering and Prediction Problems.&quot; ASME. J. Basic Eng. March 1960; 82(1): 35–45.">*1</a></p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/T/TierIV/20210804/20210804200233.png" alt="f:id:TierIV:20210804200233p:plain" width="902" height="353" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /><br />実際に、自動運転における自己位置推定での使われ方を例に見ていきましょう。</p> <p>自動運転における観測値とは、車輪エンコーダーから取得できる車速や、IMUの加速度・角速度情報、GPSから得られる位置情報などになります。</p> <p>これらの情報は単体でも利用可能ですが、例えばGPSの位置情報は絶えずノイズが乗っています。一方で、人間の知識として「車両は真横に移動しない」と言った車両の運動に関する情報を持っています。これらの情報を「車速センサ」や「車両運動モデル」を用いて統合することによって、より精度の高い車両位置を推定することができるのです。 </p> <p>この複数情報の統合に数学的な最適性を取り入れたものがKFとなります。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/taka_horibe/20210730/20210730111857.png" alt="f:id:taka_horibe:20210730111857p:plain" width="1200" height="468" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /> </p> <h4 id="Autowareでどのようにカルマンフィルターが使われているのか">Autowareでどのようにカルマンフィルターが使われているのか</h4> <p>我々の開発する自動運転OS「Autoware」においても、自己位置推定や移動物体のトラッキングなどにKFが使われています。今回は自己位置推定を例に深堀りしていきます。</p> <p>自己位置推定(Localization)とはその名の通り、自分の位置を推定する技術です。下図に、AutowareにおけるSensing/Localizationモジュールの構成図を示しました。右側のLocalizationブロックの<strong>Pose Twist Fusion Filter</strong>にKFが実装されており、<strong>Pose Estimator</strong>と<strong>Twist Estimator</strong>で計算された自車両のPose(位置・姿勢情報)とTwist(速度・加速度情報)を統合して最終的な推定値を計算することが目的となります。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/taka_horibe/20210803/20210803133043.png" alt="f:id:taka_horibe:20210803133043p:plain" width="1200" height="670" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p><br /> なお、AutowareではPose Estimatorとして<strong>NDT scan matching</strong>と呼ばれる手法を用いており、事前に用意した点群地図(下図:白色)と、自動運転車に搭載されたLiDARセンサーの観測点群データ(下図:赤や黄緑色)を比較して、パズルのように点群が最もうまく当てはまる場所を探し出して自己位置を計算しています。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/taka_horibe/20210729/20210729114603.png" alt="f:id:taka_horibe:20210729114603p:plain" width="1200" height="679" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p>このNDT scan matching単体でもかなり正確な自己位置を計算することができますが、LiDARのセンサーノイズや外環境の変化により絶えず数センチ程度のノイズが乗っています。ここにKFを導入することにより、推定精度をさらに向上させることが可能となります。</p> <p>NDT scan matchingについての詳しい情報が知りたい方は過去の記事で述べていますので、こちらをご覧ください。前後編、二部構成の大作となっております。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftech.tier4.jp%2Fentry%2F2021%2F05%2F06%2F160000" title="読み解くNDT Scan Matchingの計算 [前編] - Tier IV Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://tech.tier4.jp/entry/2021/05/06/160000">tech.tier4.jp</a></cite></p> <p>  </p> <h3 id="自動運転の自己位置推定でカルマンフィルターが使われるまで">自動運転の自己位置推定でカルマンフィルターが使われるまで</h3> <p>さて、ここからはいよいよ本題の実装編に入っていきます。</p> <p>いざ実際にカルマンフィルターを実装すると、特定環境で上手くノイズを除去できなかったり、推定値が一方向にズレる、といった問題が出てきます。</p> <p>これらの問題の原因は、カルマンフィルターが想定している前提条件と実環境との差異を基準に議論することができます。</p> <p>例えばカルマンフィルターは「センサーデータのノイズは白色ガウス分布である」といった仮定に基づいて最適化を行います。白色ガウス分布とは非常に理想的な形状をしているノイズなのですが、実環境でノイズがこのような理想形状をしていることは稀であり、自動運転においても例外ではありません。</p> <p>センサーの遅延を例に見てみましょう。どんなセンサーにも遅延は存在しますが、通常のカルマンフィルターではセンサーデータに遅延が含まれることは想定していません。従って、特別な対処をせずにカルマンフィルターを適用すると、この遅延は白色ガウスノイズであるという仮定の下で処理されます。この仮定は実際のノイズ特性とは大きくかけ離れたものであり、推定精度の劣化に繋がります。 </p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/taka_horibe/20210730/20210730122602.png" alt="f:id:taka_horibe:20210730122602p:plain" width="1200" height="314" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p>カルマンフィルターの想定する仮定を乱す要因は他にもあり、例えば</p> <ul> <li>運動モデルの非線形性</li> <li>外れ値の存在</li> <li>ノイズの多峰性</li> </ul> <p>などです。これらの原因を見定め、1つずつ適切な対処をしていくと、仮定と現実の乖離が徐々に小さくなり、最終的な推定精度が向上していきます。</p> <p>以下では代表的な問題と、その対応について解説します。</p> <h4 id="車両運動の非線形性非線形拡張">車両運動の非線形性(非線形拡張)</h4> <p>まずは非線形拡張についてです。ここはご存知の方も多いかと思います。</p> <p>本来KFは線形モデルに対して理論が構築されたものでした。一方で車両の運動は非線形の数式で表されます。以下の式を見てみましょう。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/taka_horibe/20210729/20210729201802.png" alt="f:id:taka_horibe:20210729201802p:plain" width="888" height="355" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /><br />この式は車両が速度v、角速度ωで走行しているときの運動を簡易的に表現したものであり、上の二行の式によって「車両は自分が向いている方向に進む」ことを表しています。ここで問題になるのがsinとcosの存在です。彼らの存在によって式は非線形となってしまい、通常のKFでは対処できません。</p> <p>この非線形への対処はすでに多くの方法が提案されています。有名なものでは<strong>Extended Kalman Filter (EKF)</strong>、<strong>Unscented Kalman Filter (UKF)</strong>、<strong>Particle Filter (PF)</strong> などがあり、対象となる非線形性の強さなどに応じて利用するアルゴリズムを使い分けます。</p> <p>これらのアルゴリズムは非線形性への対応度と調整・計算コストのトレードオフとなっています。例えば、最も柔軟に非線形に対応できるParticle Filterと呼ばれるアルゴリズムは、一方で非常に計算コストが高く、出力結果にランダム性が生じるといった課題もあり、モデルの非線形特性を適切に理解した上でアルゴリズムを選定する必要があります。</p> <p>Autowareでは現在はEKFと呼ばれる手法を用いて非線形モデルに対応しています。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/taka_horibe/20210729/20210729163155.png" alt="f:id:taka_horibe:20210729163155p:plain" width="1200" height="671" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /><br /><br /></p> <h4 id="センサーに遅延がある遅延補償">センサーに遅延がある(遅延補償)</h4> <p>センサーには必ず遅延が存在します。例えばティアフォーで利用している回転式のLiDARは100msかけて360度のスキャンを行うため、平均50msの遅延が存在します。また、KFの前段のNDTによる計算処理も数10msの時間を要します。</p> <p>数10msと言われると誤差のようにも聞こえますが、高速で移動する自動運転においてこの遅延は致命的であり、例えば時速60kmで走行中に自己位置推定に100msの遅延が生じたとすると、それだけで約1.7mの誤差を生み出します。</p> <p>Autowareでは<strong>Augmented State Kalman Filter</strong>と呼ばれる手法を用いて遅延補償を行っています。これはKFの状態を時間方向に拡張し、「過去の状態」を陽に考慮することによって遅延に対応する手法であり、これによって<strong>遅延を含んだ情報を、拡張された次元の一部が遅延無しで観測されたとみなす</strong>ことができます。</p> <p> </p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/taka_horibe/20210729/20210729204159.png" alt="f:id:taka_horibe:20210729204159p:plain" width="1026" height="619" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> 詳しくはこちらの書籍 <a href="#f-a9682da7" name="fn-a9682da7" title="Anderson, B. D. O., &amp;amp; Moore, J. B. (1979). Optimal Filtering. Englewood Cliffs, NJ: Prentice-Hall.">*2</a> にまとめられています。</p> <p><span style="font-size: 80%; color: #666666;">(こちらは1979年の論文集なのですが、遅延よりも先にデジタル処理による離散化の影響と補償法について述べられています。当時は計算機の処理が遅く、KFの処理自体に時間がかかっていたのでしょう。こういった時代背景も踏まえて論文を読むといろいろな発見があって面白いですね。)  </span></p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/taka_horibe/20210729/20210729174517.png" alt="f:id:taka_horibe:20210729174517p:plain" width="1200" height="666" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> </p> <h4 id="センサー間の時刻同期センサー同期">センサー間の時刻同期(センサー同期)</h4> <p>さて、KFを使って遅延に対処する方法が分かりました。しかし、肝心の遅延時間はどのように測定するのでしょうか。</p> <p>センサーが観測をした真の時間を知る必要があるのですが、ここでもいくつか問題が生じます。それが<strong>時刻同期</strong>や<strong>タイミング同期</strong>です。</p> <p><strong>時刻同期</strong>はイメージしやすいと思います。センサーが観測した時刻を知るためには、センサーの時刻ソースと自動運転システムの時刻ソースを揃えたり、観測〜データ受信までの遅延を事前計測しておく必要があります(センサ側でタイムスタンプが得られる場合は前者、出来ない場合は後者)。自動運転には多くの計算機が搭載されており、それぞれの時刻を全て同期させる必要があります。</p> <p><strong>タイミング同期</strong>は、複数センサーの観測タイミングを制御する仕組みです。Autowareでは複数のLiDARデータから得られた情報を結合し、一つの大きなデータとして処理します。このときそれぞれのLiDARが異なるタイミングでスキャンを実行していては、空間的なズレが生じてしまい適切な結合が出来ません。そこで、全てのLiDARの動作タイミングを同期し、仮想的に一つの大きなLiDARが回転しているように振る舞わせることによってこの問題に対処しています。</p> <p>また、このセンサー同期には他にもいくつかの目的があり、<strong>LiDAR同士の干渉問題</strong>の解決や、動物体検出における<strong>LiDAR-カメラフュージョン</strong>の性能向上にも一役買っています(下図参照)。</p> <p>これはこれで話が広がる部分ですが、また次の機会に。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/taka_horibe/20210729/20210729114637.png" alt="f:id:taka_horibe:20210729114637p:plain" width="1200" height="688" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> </p> <h4 id="取得した点群が歪んでいる歪み補正">取得した点群が歪んでいる(歪み補正)</h4> <p>時間方向の点群の歪みも問題になります。</p> <p>LiDARの「一定時間かけてデータを取得する」という特性上、データ取得の開始・終了時点で車両位置が違う、という問題が出てきます。このため、LiDARの生データをそのまま「特定の時刻の情報」として扱うことはできません。</p> <p>これはカーブ走行時などに特に顕著に現れ、低速走行においても大きな測定誤差を生じます。</p> <p>この問題を解決するため、Autowareでは<strong>LiDARの取得点群一つ一つに時刻を埋め込み、その時の車速・角速度情報を用いて点群に時刻補正を掛ける</strong>という対応を行っています。</p> <p>これによって自車の移動に依存しない安定した点群を取得することが可能となり、自己位置推定の精度が大幅に向上します。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/taka_horibe/20210729/20210729181112.png" alt="f:id:taka_horibe:20210729181112p:plain" width="1200" height="769" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> </p> <h4 id="モデルに誤差があるバイアス誤差モデル">モデルに誤差がある(バイアス誤差モデル)</h4> <p>次は車両モデルの誤差についての話です。例として、LiDARセンサーの取り付け角度がズレている場合を考えてみます。</p> <p>NDT scan matchingはセンサーによって得られた点群によって自己位置を推定しますが、あくまでも推定できるのはセンサーの位置姿勢であり、センサーと車両の位置関係は事前に与える必要があります。</p> <p>この位置関係が間違っているとどうなるでしょうか。</p> <p>例えば下図のように、実際の車両は右に向かって走行していますが、センサーが誤って斜め上の方向に向かって取り付けられており、車両の向きを間違って推定してしまったとします。すると、KFが推定する位置と実際の位置に乖離が生じます。これはKFから見るとノイズの一種なのですが、常に特定方向に偏ったノイズが与えられてしまい、これは事前に説明した白色ガウスノイズの仮定から逸れてしまいます。結果、常に推定結果が横に逸れた状態で計算されます。</p> <p>これは<strong>適応オブザーバー(外乱オブザーバー)</strong>と呼ばれる方法を用いて解決されます。</p> <p>適応オブザーバーとは、KFのモデルに「センサーの取り付け角度がズレる可能性があるよ」という情報を付加することによって、走行中にこのズレを自動で推定する手法です。 </p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/taka_horibe/20210729/20210729204912.png" alt="f:id:taka_horibe:20210729204912p:plain" width="1200" height="547" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /><br />実際には、このセンサーの取り付け誤差は走行前のセンサーキャリブレーションによって取り除かれます。</p> <p>一方で、どうしても事前に取り除けない誤差、例えば温度変化によるヨーレートセンサーのバイアス項や、空気圧変化によるタイヤ径の変化、路面環境の変化などは、このように動的な補償によって対処する必要があります。</p> <p> </p> <h4 id="周期の異なるセンサーの統合滑らかな補間">周期の異なるセンサーの統合(滑らかな補間)</h4> <p>複数のセンサー情報を統合するKFの技術は、センサーフュージョンと呼ばれることもあります。ここで問題になるのがセンサーごとの周期の違いです。</p> <p>例えば、IMUのような内界センサーは数100~数1000Hzで情報を出力することができる一方、NDT scan matchingのような外界センサーに依存した手法は(現在は)10~20Hzでしか情報を出力できません。これらのセンサー周期の違いを考慮せずに統合してしまうと、低周期のセンサー情報がKFに統合されたときに大きく自己位置が変化する、という現象が発生します(下図:左側)。</p> <p>この「大きな自己位置の変化」自体はKFとしては正常な動作であり、その瞬間にもっとも信頼度の高い位置を出力しているだけに過ぎません。それに対して、この自己位置を車両制御で用いる際には、自己位置のズレがステアの振動に直結するため問題が生じます。</p> <p>AutowareのKFでは、<strong>自己位置の変動に大きな影響を及ぼす情報が得られた場合は、その入力を時間方向に分散させて更新を掛ける</strong>ことによって、滑らかな自己位置の遷移を行っています(下図:右側)。</p> <p>これは、遅延補償機能との合わせ技であり、遅れて更新を掛けても適切に処理可能であるという前提に基づいています。 </p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/taka_horibe/20210731/20210731105715.png" alt="f:id:taka_horibe:20210731105715p:plain" width="1200" height="649" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <h4 id="急に自己位置が変な場所へ飛んでしまう外れ値除去">急に自己位置が変な場所へ飛んでしまう(外れ値除去)</h4> <p>続いて、センサーの外れ値対応についてです。</p> <p>例えばGPSのキッドナップ問題と呼ばれる有名な課題があり、GPS信号のマルチパスなどによって、急にGPSの位置が大きくズレることがあります。NDTも同じく、アルゴリズムが収束しなかった場合などは推定値が大きく真値から外れます。</p> <p>KFはガウスノイズを仮定しているという性質上、外れ値に大きく引きずられるという特徴があり、これらの外れ値は別途対応する必要があります。</p> <p>Autowareではこの外れ値判定に2つのゲートを設けて対応しています。</p> <p>まず、NDT側でイテレーション回数などの内部情報を元に<strong>外れ値・アルゴリズムの失敗を検出</strong>し、計算結果がおかしい場合は結果を出力しないという方針を取っています。これは基本的にワンショットの情報(これまでの時系列の統計情報を含まない情報)で判断されます。</p> <p>その後段で、KFによって<strong>時系列情報を用いた外れ値判定(マハラノビスゲート)</strong>を適用します。KFでは推定結果の信頼度(誤差共分散)を内部情報として蓄えており、この情報を元に、KFへの入力がどれだけ確からしいのかを計算することができます。</p> <p>例えば、これまでの入力の信頼度が低く十分な推定ができていない場合に、実は自己位置の場所が大きく異なっていましたと言われたら、その値は考慮すべきです。一方で、すでに十分な推定精度が得られている場合は、たとえ外部情報が自信満々に値を出してきたとしても、それがあり得ない確率であればその入力を棄却する必要があります。この外れ値の計算にはマハラノビス距離と呼ばれる、入力ベクトルの距離を共分散行列で正規化した値が用いられており、確率論ベースで情報の統合・棄却を判定します。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/taka_horibe/20210804/20210804103641.png" alt="f:id:taka_horibe:20210804103641p:plain" width="1200" height="676" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <h4 id="今の推定精度はどれくらいなのか共分散の検討">今の推定精度はどれくらいなのか(共分散の検討)</h4> <p>上節で、共分散行列を元に推定値の信頼度を計算するという話をしました。この「信頼度が計算できる」というKFの機能は非常に有用であり、自動運転の安全性に大きく影響します。</p> <p>例えば、自己位置の推定精度が悪い場合はレーンからはみ出てしまう可能性があるため、速度を落として走行したり、停止することが求められます。</p> <p>しかし、この信頼度を正確に計算するためには、KFで統合される信号のノイズ情報が正しく設定されている必要があり、「運動モデルがどの程度正しいのか」「どのくらいのズレがあるのか」「観測値の誤差はどのようなノイズ特性を持つのか」などを一つ一つ検証する必要があります。</p> <p>このノイズ情報の設定はなかなかに骨の折れる作業で、"How To NOT Make the Extended Kalman Filter Fail" <a href="#f-b9afbbcf" name="fn-b9afbbcf" title="René Schneider and Christos Georgakis. &quot;How To NOT Make the Extended Kalman Filter Fail.&quot; Industrial &amp;amp; Engineering Chemistry Research 2013 52 (9), 3354–3362.">*3</a>という論文で取り扱われるほど多くのエンジニアを悩ませてきた問題です。</p> <p>例えばIMUのヨーレートセンサーのノイズです。まずは真値と比較を行い、ノイズ情報(二次モーメント)を計算します。このときのノイズ特性が、どれだけKFの仮定(白色ガウス)とズレているのか、が大きなポイントとなります。ヨーレートセンサーは一般的にバイアスノイズの影響が大きいため、まずはこのノイズを除去する必要があります。</p> <p>その他のセンサーや運動モデルにおいても、どうやったら白色ガウス分布からのズレを除去できるのか、除去できない場合はワーストケースを考慮すると共分散はどう設定すべきなのか、などを検討する必要があります。</p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="ヘッセ行列から計算されたNDTの誤差共分散楕円の可視化。カーブ時に楕円が大きくなっているのが分かる。"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/taka_horibe/20210802/20210802113458.png" alt="f:id:taka_horibe:20210802113458p:plain" width="1200" height="785" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">ヘッセ行列から計算されたNDTの誤差共分散楕円の可視化。カーブ時に楕円が大きくなっているのが分かる。</figcaption> </figure> <p> </p> <h4 id="緊急時の対応">緊急時の対応</h4> <p>ここまでKFの拡張や精度、外れ値対応などについて述べてきました。しかし、自動運転において「外れ値が来たので無視します」という処理だけでは安全性を担保することができません。</p> <p>ここでAutowareのLocalizationモジュールを再見すると、Localizer Diagnosticsというモジュールが存在していることが分かります。</p> <p>このモジュールはAutowareの自己位置推定の機能群を常に監視しており、外れ値が計算された、位置推定の精度が落ちた、などの情報を統合して現在の自己位置推定の状態を判断します。</p> <p>この診断情報は別のSystemモジュールへ送られ、状態に応じて適切な指示が車両に送られます。例えば、LiDARに依存した自己位置推定アルゴリズムが何らかの異常によって再起不能になった場合でも、内界センサー(車速センサーやIMU)による自己位置推定によってしばらくは走行が可能であり、自己位置の推定誤差が閾値を超過する前に適切な駐車場所を見つけ、路肩に停車するといった動作が可能となります。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/taka_horibe/20210731/20210731110129.png" alt="f:id:taka_horibe:20210731110129p:plain" width="1200" height="576" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <h3 id="最後に">最後に</h3> <p>最後まで読んでいただきありがとうございました。</p> <p>このブログで述べた機能は、いくつか開発途中のものもありますが、大半はOSS(Open Source Software)として利用可能となっています。興味があればぜひ御一見ください。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fgithub.com%2Ftier4%2FAutowareArchitectureProposal.proj" title="GitHub - tier4/AutowareArchitectureProposal.proj: This is the source code of the feasibility study for Autoware architecture proposal." class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://github.com/tier4/AutowareArchitectureProposal.proj">github.com</a></cite></p> <p>いろいろと機能の説明をしてきましたが、自動運転技術は発展途上であり、まだまだ開発が必要な領域が残っています。</p> <p>このブログを読んで、自動運転って面白そう...!と思った方がいましたら、ぜひ一緒に開発をしましょう!<span style="color: #111111; font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none;">下記リンクからお問い合わせをお待ちしています。</span></p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fcareers.tier4.jp%2F" title="TIER IV Careers" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://careers.tier4.jp/">careers.tier4.jp</a></cite></p> <p><br /><cite class="hatena-citation"><a href="https://tier4.jp/careers/">tier4.jp</a></cite></p><div class="footnote"> <p class="footnote"><a href="#fn-ccdd2671" name="f-ccdd2671" class="footnote-number">*1</a><span class="footnote-delimiter">:</span><span class="footnote-text">Kalman, R. E. (March 1, 1960). "A New Approach to Linear Filtering and Prediction Problems." ASME. <em>J. Basic Eng</em>. March 1960; 82(1): 35–45.</span></p> <p class="footnote"><a href="#fn-a9682da7" name="f-a9682da7" class="footnote-number">*2</a><span class="footnote-delimiter">:</span><span class="footnote-text">Anderson, B. D. O., &amp; Moore, J. B. (1979). Optimal Filtering. Englewood Cliffs, NJ: Prentice-Hall.</span></p> <p class="footnote"><a href="#fn-b9afbbcf" name="f-b9afbbcf" class="footnote-number">*3</a><span class="footnote-delimiter">:</span><span class="footnote-text">René Schneider and Christos Georgakis. "How To NOT Make the Extended Kalman Filter Fail." Industrial &amp; Engineering Chemistry Research 2013 52 (9), 3354–3362.</span></p> </div> taka_horibe Visual-Inertial Odometryが自動運転に与えるインパクトと応用への課題 hatenablog://entry/26006613784530164 2021-07-22T12:00:00+09:00 2023-05-24T18:47:01+09:00 こんにちは、ティアフォーでVisual SLAMの研究開発をしている石田です。今回はVisual-Inertial Odometryという、カメラとIMU(慣性計測装置)を用いた経路推定手法を紹介し、これを自動運転に応用できた場合のインパクトと、応用までに乗り越えなければならない課題についてお話します。 走行経路の推定結果 なお、ティアフォーでは、「自動運転の民主化」をともに実現していく様々なエンジニア・リサーチャーを募集しています。もしご興味があればカジュアル面談も可能ですので以下のページからコンタクトいただければと思います。 tier4.jp 自動運転における自己位置推定 自己位置推定とは… <p> <span style="color: #000000;">こんにちは、ティアフォーでVisual SLAMの研究開発をしている石田です。今回はVisual-Inertial Odometryという、カメラとIMU(慣性計測装置)を用いた経路推定手法を紹介し、これを自動運転に応用できた場合のインパクトと、応用までに乗り越えなければならない課題についてお話します。</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="走行経路の推定結果"> <div class="images-row mceNonEditable"> <div class="images-row-item"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/s/sonicair/20210709/20210709081544.png" alt="" width="344" height="600" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></div> <div class="images-row-item"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/s/sonicair/20210709/20210709081554.png" alt="" width="345" height="600" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></div> </div> <figcaption class="mceEditable"><span style="color: #000000;">走行経路の推定結果</span></figcaption> </figure> <p data-renderer-start-pos="7448"><span style="color: #000000;"><span style="font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; float: none; display: inline !important;">なお、ティアフォーでは、「自動運転の民主化</span><span style="font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; float: none; display: inline !important;">」をともに実現していく様々なエンジニア・リサーチャーを募集しています。もしご興味があればカジュアル面談も可能ですので以下のページからコンタクトいただければと思います。</span></span></p> <p><span style="color: #000000;"><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftier4.jp%2Fcareers%2F" title="Careers | 株式会社ティアフォー" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://tier4.jp/careers/" style="color: #000000;">tier4.jp</a></cite></span></p> <h3 id="自動運転における自己位置推定"><span style="color: #000000;">自動運転における自己位置推定</span></h3> <p><span style="color: #000000;"> 自己位置推定とは、名前のとおり車両やセンサーデバイスなどが地図の中でどこにいるのかを推定するための技術であり、自動運転において欠かせない要素のひとつです。自分がどこを走っているか把握できなければ迷子になってしまいますし、自分が走っている場所の先に何があるか把握することも難しくなってしまいます。正確な自己位置推定が実現できれば、車両のスムーズな制御につなげることができて、さらに信号機や標識、停止線などの場所をあらかじめ地図に埋め込んでおき、車両がこれらに近づいたことを正確に検知できれば、安全かつ確実な制御を行うことができます。</span></p> <h4 id="自己位置推定の難しさ"><span style="color: #000000;">自己位置推定の難しさ</span></h4> <p><span style="color: #000000;"> 自己位置推定の課題は大きく分けて3つあります。1つ目は精度、2つ目はロバスト性、そして3つ目はこれらを小さい計算量で達成することです。</span><br /><span style="color: #000000;"> 公道を走る車両の自己位置推定は少なくとも数十センチの精度が要求されます。この精度を達成できないと、走行レーンをはみ出したり他車にぶつかったりしてしまいます。</span><br /><span style="color: #000000;"> 自動車は様々な環境や場所を走るため、自動運転車に搭載される自己位置推定システムも正確な動作が必要となります。市街地も森も田園も橋の上も安全に走れる必要がありますし、雨や雪が降っていても正確に動作する必要があります。このように様々な場所や環境で動作する能力は「ロバスト性」と呼ばれ、精度と同様に自己位置推定手法における重要な指標とされています。</span><br /><span style="color: #000000;"> 計算量を抑えることも重要な課題のひとつです。自分の位置を計算するのに1秒かかっていたら、その間に車が動いてしまい、周囲の物体にぶつかってしまいます。しかし、計算を高速化させたいからといって車に巨大なコンピュータを積むと、車両の価格が上がったり、膨大なエネルギーを消費したり、コンピュータの周囲が高温になってしまいます。このため、自動運転のための自己位置推定手法は小さいコンピュータでも高速に動作しなければなりません。</span><br /><span style="color: #000000;"> 高精度で、ロバストで、ライトな自己位置推定を実現する。これが我々の仕事です。</span></p> <h4 id="自己位置推定を実現するためのセンサー"><span style="color: #000000;">自己位置推定を実現するためのセンサー</span></h4> <p><span style="color: #000000;"> 自己位置推定を実現するためのセンサーには様々なものが存在します。皆さんにとって最も身近なものは、おそらくスマートフォンやカーナビに搭載されているGPSでしょう。しかし、皆さんもご存知のようにGPSは屋内などではうまく動作できないうえ、自動運転に使えるほどの精度が常に実現できるわけではありません。</span><br /><span style="color: #000000;"> 現在のティアフォーの自動運転車は主にLiDARというセンサーを用いています。LiDARはレーザー光によって周囲の形状を把握するセンサーで、LiDARによって得られた車両の周囲の形状と、あらかじめ作成しておいた点群地図を照合することで、車両の位置を高い精度で推定することができます。しかし、LiDARにも弱点があります。LiDARを用いた自己位置推定手法は主に周囲の環境の構造情報を頼りにしているため、特徴的な構造が観測しづらい場所、たとえば田園などではうまく動作できません。また、性能のよいLiDARは非常に高価で数千万円もしてしまうため、これをそのまま自動運転車に用いると、車両も同様に高価になり自動運転車の普及の妨げになってしまいます。したがって、自動運転の実用化および普及促進のためには、LiDARだけに頼るのではなく複数の安価なセンサーを組み合わせることが不可欠です。</span><br /><span style="color: #000000;"> ここで今回私が紹介するVisual-Inertial Odometryの出番です。Visual-Inertial Odometry(VIO)とは、カメラとIMU(慣性計測装置)を使って移動経路を求める手法です。</span><br /><span style="color: #000000;"> カメラはスマートフォンにも搭載されていますし、昨今のリモートワークでお世話になっている方も多いでしょう。もしかしたら毎日使っている方もいるかもしれません。IMUもカメラと同様に多くのスマートフォンに搭載されているのですが、こちらは馴染みのない方もいらっしゃるかと思います。IMUは人間における三半規管のようなもので、加速度と回転速度を計測することができるセンサーです。皆さんは車やバスに乗っているとき、目を閉じても車が加速しているのか減速しているのか、右に曲がっているのか左に曲がっているのかを、大まかに感じ取ることができると思います。IMUもこれと似ていて、物体の加速度や回転速度を計測することができ、この情報をもとにしてセンサーがどの方向にどれぐらい動いたかを大まかに計算することができます。これらのセンサーから得られる情報を組み合わせて移動経路を推定するのがVisual-Inertial Odometryです。</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="VIOに用いられるセンサーの一例。画像中央にある小型の横長のものがカメラとIMUが一体になったものである。画像で示されているのは検証用のものであり、実際の制御に用いられているものではない。画像左上に見えている筒状のものがLiDARであり、こちらは形状ベースの位置推定に利用される"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/s/sonicair/20210709/20210709073750.jpg" alt="f:id:sonicair:20210709073750j:plain" width="1147" height="715" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable"> <p><span style="color: #000000;">VIOに用いられるセンサーの一例。画像中央にある小型の横長のものがカメラとIMUが一体になったもの。画像で示されているのは検証用のものであり、実際の制御に用いられているものではない。画像左上に見えている筒状のものがLiDARであり、こちらは形状ベースの位置推定に利用される。</span></p> </figcaption> </figure> <p><span style="color: #000000;"> カメラやIMUはほとんどのスマートフォンに搭載されている非常にありふれたセンサーです。自動運転車に利用するためにはより高信頼なものが必要になるものの、それでも数万円から数十万円で調達することができます。VIOはLiDARベースの手法と比べるとまだまだ精度やロバスト性の点で劣るため、いますぐLiDARに置き換えられるというものではありません。しかし、カメラやIMUから得られた情報を組み合わせれば、同じ性能の自己位置推定をより安価なLiDARで実現できる可能性があります。結果として、車両全体の価格を押し下げることができ、自動運転の迅速な普及に貢献することができます。</span></p> <h3 id="Visual-Inertial-Odometryの具体的な手法"><span style="color: #000000;">Visual-Inertial Odometryの具体的な手法</span></h3> <p><span style="color: #000000;"> VIOはすでに多くの研究がなされており、様々な手法が存在します。今回紹介するのは、現在私が性能検証を行っている、<a href="https://github.com/HKUST-Aerial-Robotics/VINS-Fusion" style="color: #000000;">VINS-Fusion</a>というVIOの手法です。VINS-Fusionを選定した理由として、VIOの手法の中では精度が高いこと、他のセンサーと組み合わせやすいこと、計算量を抑える仕組みが導入されていることが挙げられます。ここでは、VINS-Fusionの手法の特徴を大まかに解説し、安心安全な自動運転を実現するために必要な研究と今後の開発についてお話します。</span></p> <h4 id="手法の特徴"><span style="color: #000000;">手法の特徴</span></h4> <p><span style="color: #000000;"> VINS-Fusionは、センサーの観測値を用いてあるエラー値を算出し、それをできるだけ小さくするようなセンサーの姿勢を求めることで、センサーの移動経路を推定します。たとえば、ある静止した物体を見ているとき、カメラが近くにいるならその物体は大きく見えますし、カメラが遠くにいるなら小さく見えるはずです。カメラが遠ざかっているのにその物体がだんだん大きく見えるようになるのはおかしいですよね。IMUについても同様で、IMUに対して加速度が前にかかっているなら、IMUは前に進んでいるはずです。加速度が前にかかっているのに、IMUが後ろに進んでいるなら、これもやはりおかしいです。この「おかしさ」を数値にし、それができるだけ小さくなるようなセンサー姿勢を求めるのがVINS-Fusionのアプローチです。物体が徐々に大きく見えるようになっているとき、「カメラが物体に近づいている」と推論すればこの「おかしさ」の数値は減っていきます。同様に、IMUが前向きの加速度を検知しているとき、「IMUは前に進んでいる」と推論すればやはりこの「おかしさ」の数値は減っていきます。このように、物理現象とつじつまが合うように「おかしさ」の数値を設計し、それが減るようなセンサーの姿勢を求めるのがVINS-Fusionの戦略です。</span></p> <h4 id="計算量を減らすための工夫"><span style="color: #000000;">計算量を減らすための工夫</span></h4> <p><span style="color: #000000;">1. IMU積分値近似</span><br /><span style="color: #000000;"> VINS-Fusionのアプローチは、先ほどの「おかしさ」を徐々に減らしながらセンサーの姿勢を調節するため、一般に計算コストが高いとされています。この問題を解決するため、VINS-Fusionにはこの「おかしさ」を高速に計算するためのIMU積分値近似という仕組みが備わっています。</span><br /><span style="color: #000000;"> IMUで観測された加速度や回転速度はしばしば実際の値よりも少し大きく、あるいは小さく出力されます。これはIMUの特性上どうしても起きてしまうもので、VIOの開発者たちはがんばってこのズレを補正することで、実際の値にできるだけ近い観測値を得ようとします。</span><br /><span style="color: #000000;"> 観測値と実際の値のズレは先ほどの「おかしさ」を計算するときに問題になります。「おかしさ」を計算するためにはIMUの観測値を積分して、IMUが進んだ距離を計算する必要があります。たとえば、「今はIMUから1.0という加速度が観測されているから、1秒間に8.0cm進んでいるはずだ。でも姿勢推定システムは1秒間に6.0cm進んでいると考えているから、おかしさは2.0cmだな!」というふうに考えるわけです。しかし、観測値のズレを補正するということは、距離計算の入力値(加速度や回転速度、先ほどの例だと1.0という数字)が変わることに相当するので、観測値の補正を行うたびに進んだ距離の計算をやり直さなければならなくなってしまいます。「さっきは加速度1.0で計算したけど本当は1.2なの?じゃあ今何cm進んでいるんだろう...」という計算を何度も何度も繰り返さなければならなくなってしまうのです。冒頭で述べたように、VIOは小さい計算コストで高速に動作することが求められるので、この計算に時間を取られてしまうと実用化の大きな支障になります。そこでVINS-Fusionは、この計算を近似的に行うことで処理の高速化を図っています。たとえば、「加速度を+0.1補正したら進む距離が0.4cm増える。ならば、加速度を+0.2補正したら進む距離は0.8cm増えるだろう」というように、非常に大まかに、しかし高速に計算を行います。これにより、姿勢推定全体を高速化することができます。</span></p> <p><span style="color: #000000;">2. キーフレーム選択</span><br /><span style="color: #000000;"> 動画撮影用のカメラは1秒間に何枚ものフレームを撮影することができます。たとえばiPhoneのビデオ機能は1秒間に30フレーム撮影しているそうです。では1秒間に30回撮影されるフレームそれぞれについて、位置や姿勢を推定する必要があるでしょうか。カメラが高速に移動していれば、たしかにそうかもしれません。では、静止している場合はどうでしょうか。静止しているなら、1秒間に30回も姿勢推定を行う必要はありませんね。VINS-Fusionをはじめ、多くのVIOには、キーフレーム選択と呼ばれる「大きく動いたときにだけフレームの姿勢を推定する」という機能が備わっています。このように、必要なときのみ姿勢推定を行うことで実行速度を上げることができます。また、余った計算コストを必要な部分に振り分けることで、精度も高められるというわけです。</span></p> <h3 id="これから"><span style="color: #000000;">これから</span></h3> <p><span style="color: #000000;"> 最後に、VIOの今後の課題と将来性についてお話して、記事の締めくくりとします。</span></p> <h4 id="他のセンサーとの組み合わせ"><span style="color: #000000;">他のセンサーとの組み合わせ</span></h4> <p><span style="color: #000000;"> VIOはまだまだ発展途上の技術であり、精度やロバスト性はLiDARベースの自己位置推定手法におよびません。しかし、VIOをLiDARベースの手法と組み合わせることで、お互いの弱点を補いあい、強みを活かすことができます。たとえば、VIOはカメラ画像を入力とするため、対向車のヘッドライトのような大きな照度変化に影響されやすいという弱点があります。一方でLiDARはレーザー光で周囲の形状を把握するセンサーなので、明るさの変化の影響をほとんど受けないという特性があります。したがって、VIOとLiDARを組み合わせることで、様々な環境で安定して動作する自己位置推定システムを作ることができます。現在私はこういったセンサーの組み合わせに取り組み始めているところです。</span></p> <h4 id="動けないときに動けないと言ってくれる自己位置推定"><span style="color: #000000;">動けないときに「動けない!」と言ってくれる自己位置推定</span></h4> <p><span style="color: #000000;"> 霧や大雨の中では、人間でさえ安全な運転が難しいと感じることがあり、これは皆さんも経験したことがあるかもしれません。同様に、自己位置推定の手法も環境によっては確実に動作できないことが考えられます。こういったときに無理に自己位置推定を行って危険な走行をするのではなく、「動かない!」と言って停止することも自動運転車の大事な機能です。VIOはまだまだ普通の環境でしっかり動くことを目指す段階なので、このような停止判断機能はもう少し先の話になりますが、高信頼な自動運転を実現するためにはいずれ取り組まなければならない課題です。</span></p> <h4 id="誰もが安心して乗れる車を実現するために"><span style="color: #000000;">誰もが安心して乗れる車を実現するために</span></h4> <p><span style="color: #000000;"> Visual-Inertial OdometryはAR(Augmented Reality、拡張現実)などではすでに実用化されているものの、自動運転に応用するためにはまだまだ多くのハードルを乗り越えなければなりません。様々な環境で正確かつ高速に、しかも高信頼に動作する自己位置推定手法を開発するのは、非常にチャレンジングでワクワクするものです。もしこのような仕事にご興味ある方がいましたら、改めてにはなりますが、以下のページからご応募ください!!</span></p> <p><a href="https://careers.tier4.jp/">TIER IV Careers</a></p> <p><span style="color: #000000;"><br /><cite class="hatena-citation"><a href="https://tier4.jp/careers/" style="color: #000000;">tier4.jp</a></cite></span></p> <p><span style="color: #000000;"> </span></p> sonicair 読み解くNDT Scan Matchingの計算 [後編] hatenablog://entry/26006613786463296 2021-07-16T12:00:00+09:00 2023-05-24T18:47:26+09:00 こんにちは、ティアフォーエンジニアの村上です。 今回は、 読み解くNDT Scan Matchingの計算 [前編] - Tier IV Tech Blog の続きとして、自動運転位置推定のターニングポイントとなった、Scan Matchingによる高精度自己位置推定技術の華、NDT Scan Matchingを読み解いてみようと思います。 まだの方は、前編もあわせてぜひご覧ください。 tech.tier4.jp なお、ティアフォーでは、「自動運転の民主化」をともに実現していく様々なエンジニア・リサーチャーを募集しています。もしご興味があればカジュアル面談も可能ですので以下のページからコンタク… <p><span style="color: #000000;">こんにちは、ティアフォーエンジニアの村上です。</span></p> <p><span style="color: #000000;">今回は、 <a href="https://tech.tier4.jp/entry/2021/05/06/160000" style="color: #000000;">読み解くNDT Scan Matchingの計算 [前編] - Tier IV Tech Blog</a> の続きとして、<span style="font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; float: none; display: inline !important;">自動運転位置推定のターニングポイントとなった、Scan Matchingによる高精度自己位置推定技術の華、NDT Scan Matchingを読み解いてみようと思います。</span></span></p> <p><span style="color: #000000;">まだの方は、前編もあわせてぜひご覧ください。</span></p> <p><span style="color: #000000;"><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftech.tier4.jp%2Fentry%2F2021%2F05%2F06%2F160000" title="読み解くNDT Scan Matchingの計算 [前編] - Tier IV Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://tech.tier4.jp/entry/2021/05/06/160000" style="color: #000000;">tech.tier4.jp</a></cite></span></p> <p data-renderer-start-pos="7448"><span style="color: #000000;"><span style="font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; float: none; display: inline !important;">なお、ティアフォーでは、「自動運転の民主化</span><span style="font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; float: none; display: inline !important;">」をともに実現していく様々なエンジニア・リサーチャーを募集しています。もしご興味があればカジュアル面談も可能ですので以下のページからコンタクトいただければと思います。</span></span></p> <p><a href="https://careers.tier4.jp/">TIER IV Careers</a></p> <p><span style="color: #000000;"><br /><cite class="hatena-citation"><a href="https://tier4.jp/careers/" style="color: #000000;">tier4.jp</a></cite></span></p> <h3 id="Scan-Matchingのスコア計算へ"><span style="color: #000000;">Scan Matchingのスコア計算へ</span></h3> <p><span style="color: #000000;">復習になりますが、LiDAR点(ここではSourceと呼びます)とMap点(ここではTargetと呼びます)との点と点のScan Matchingをそのまま考えると、その整合度合いを計算するために、O(N) * O(M) [where N = Source点数, M = Target点数]の計算量が必要となります。ここで、Target点群をいくつかの格子に分割後、"格子中の点群の正規分布"、つまり雰囲気のようなものへ変換してしまい、Sourceの各点がその分布上その位置に存在する確率を「スコア値」として考えてしまう発想に至ります。もはや分布となってしまったTargetは(当然分割格子数は実計算の多寡に影響するとはいえ)、定数扱いとなり、計算量はぐっと減少し、O(N)となります。また、雰囲気との比較というのは、局所最適解に陥りやすいマッチング処理において、ロバスト性を高める点にも一役買っています。</span></p> <p><span style="color: #000000;">このTarget点群の正規分布化(Normal Distribution Transform)を用いた、Scan Matching処理こそがNDT Scan Matchingであり、今日の自動運転の高精度自己位置推定において大活躍しています。</span></p> <p><span style="color: #000000;">前編において解説した、近傍Voxelの取得によって、Source各点に対するTarget中近傍Voxel(の"雰囲気")が取得されました。本編では、その取得された近傍に対して、Source点がたしかにそこにあるという"たしからしさ" = スコア値計算の部分を見ていきます。</span></p> <h4 id="OpenCL-accelerated-NDT-Scan-Matcher"><span style="color: #000000;">OpenCL accelerated NDT Scan Matcher</span></h4> <p><span style="color: #000000;">前編でもOpenCLを用いた再実装を行いましたが、今回は前編の成果物もまとめ、NDT Scan MatcherをOpenCLで実装し、他のデバイス(もちろんCPUもです!)へ容易にオフロードできるパッケージを作成しました。以降コードリーディングの際にも折に触れて登場します。</span></p> <p><span style="color: #000000;"><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fgithub.com%2Ftier4%2FAutowareArchitectureProposal.proj%2Ftree%2Ffeature%2Fndt_opencl" title="tier4/AutowareArchitectureProposal.proj" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://github.com/tier4/AutowareArchitectureProposal.proj/tree/feature/ndt_opencl" style="color: #000000;">github.com</a></cite></span></p> <p><span style="color: #000000;">OpenCL版のREADME</span><span style="color: #000000;">は</span><a href="https://github.com/tier4/AutowareArchitectureProposal.iv/tree/feature/ndt_opencl/localization/pose_estimator/ndt_scan_matcher/ndt_ocl#readme">こちら</a>をご覧ください。</p> <p><span style="color: #000000;">前項で述べた通り、NDT Scan Matchingにおいては、その内部の処理は、Source各点に対して、各点並列でスコアを計算していきます。最終的にはそのSource各点のスコア値は合算されますが、この処理は並列化が比較的容易なアルゴリズムとなっており、AutowareではOpenMPによる並列化実装が採用されています。</span></p> <p><span style="color: #000000;">OpenCLでの並列化も、基本的にはOpenMPと同じ戦法をとっており、さらに幅広いデバイス(Embedded GPU, GPGPU, CPU, Accelerator...)への適用を念頭にしたチューニングがなされています。</span></p> <h3 id="NDT-Scan-Matcher外観"><span style="color: #000000;">NDT Scan Matcher外観</span></h3> <p><span style="color: #000000;">それではソースコードを読みこんでいきますが、前編では省略した、NDT Scan Matcherの外観から読んでいきたいと思います。</span></p> <p><span style="color: #000000;">NDT Scan Matcherは、LiDARからの点群を受けとった時点から処理がはじまります。NDT Scan Matcherに限ったことではありませんが、Autowareのソースコードリーディングにおいては、まずそのnodeが購読するtopicを知り、そのtopicを処理するcallbackを見つける所が最初の一歩です。</span></p> <p>LiDAR点に対しては、<a href="https://github.com/tier4/AutowareArchitectureProposal.iv/blob/513dee86584018117983178a94a6635ff40a7070/localization/pose_estimator/ndt_scan_matcher/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L313">void NDTScanMatcher::callbackSensorPoints</a> がまさにそのcallbackにあたります。</p> <p><span style="color: #000000;">さて、いきなり色々な処理があり面くらう所ですが、NDTにおいてその処理の大部分を占めるのは、俗に “align” 処理と呼ばれるものであり、一例として経過時間を以下に添付しますが、実際の所、計算機パフォーマンス的にはalign処理さえ抑えれば良いということがわかります。</span></p> <div class="code-block sc-kIXKos ituWYA" style="margin: 0.75rem 0px 0px; padding: 0px; tab-size: 4; clear: both; max-width: 100%; display: grid; grid-template-columns: minmax(0px, 1fr); position: relative; border-radius: 3px; overflow-wrap: normal; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff;"><span class="prismjs css-1xfvm4v" style="display: flex; line-height: 1.5rem; overflow-x: auto; white-space: pre; font-size: 0.875rem; font-family: SFMono-Medium, 'SF Mono', 'Segoe UI Mono', 'Roboto Mono', 'Ubuntu Mono', Menlo, Consolas, Courier, monospace; font-weight: normal; background-color: var(--ds--code--bg-color,#f4f5f7); border-style: none; border-radius: 3px; background-image: linear-gradient(to left, #f4f5f7 8px, transparent 8px), linear-gradient(to left, rgba(9, 30, 66, 0.13) 0px, rgba(99, 114, 130, 0) 8px), linear-gradient(to right, rgba(9, 30, 66, 0.13) 0px, rgba(99, 114, 130, 0) 8px); background-attachment: local, scroll, scroll; background-position: 100% 0px, 100% 0px, 0px 0px; grid-column: 1 / auto; color: #000000;" data-code-lang="" data-ds--code--code-block=""><code style="font: unset; font-feature-settings: unset; font-kerning: unset; font-optical-sizing: unset; font-variation-settings: unset; forced-color-adjust: unset; text-orientation: unset; text-rendering: unset; -webkit-font-smoothing: unset; -webkit-locale: unset; -webkit-text-orientation: unset; -webkit-writing-mode: unset; writing-mode: unset; zoom: unset; place-content: unset; place-items: unset; place-self: unset; alignment-baseline: unset; animation: unset; appearance: unset; aspect-ratio: unset; backdrop-filter: unset; backface-visibility: unset; background-attachment: unset; background-blend-mode: unset; background-clip: unset; background-color: unset; background-image: linear-gradient(to right,var(--ds--code--line-number-bg-color,#EBECF0),var(--ds--code--line-number-bg-color,#EBECF0) calc(1ch + 16px),transparent calc(1ch + 16px),transparent); background-origin: unset; background-position: unset; background-repeat: unset; background-size: unset; baseline-shift: unset; block-size: unset; border-block: unset; border: unset; border-radius: unset; border-collapse: unset; border-end-end-radius: unset; border-end-start-radius: unset; border-inline: unset; border-start-end-radius: unset; border-start-start-radius: unset; inset: unset; box-shadow: unset; box-sizing: unset; break-after: unset; break-before: unset; break-inside: unset; buffered-rendering: unset; caption-side: unset; caret-color: unset; clear: unset; clip: unset; clip-path: unset; clip-rule: unset; color-interpolation: unset; color-interpolation-filters: unset; color-rendering: unset; color-scheme: unset; columns: unset; column-fill: unset; gap: unset; column-rule: unset; column-span: unset; contain: unset; contain-intrinsic-size: unset; content: unset; content-visibility: unset; counter-increment: unset; counter-reset: unset; counter-set: unset; cursor: unset; cx: unset; cy: unset; d: unset; display: unset; dominant-baseline: unset; empty-cells: unset; fill: unset; fill-opacity: unset; fill-rule: unset; filter: unset; flex: 1 0 auto; flex-flow: unset; float: unset; flood-color: unset; flood-opacity: unset; grid: unset; grid-area: unset; height: unset; hyphens: unset; image-orientation: unset; image-rendering: unset; inline-size: unset; inset-block: unset; inset-inline: unset; isolation: unset; letter-spacing: unset; lighting-color: unset; line-break: unset; list-style: unset; margin-block: unset; margin: unset; margin-inline: unset; marker: unset; mask: unset; mask-type: unset; max-block-size: unset; max-height: unset; max-inline-size: unset; max-width: unset; min-block-size: unset; min-height: unset; min-inline-size: unset; min-width: unset; mix-blend-mode: unset; object-fit: unset; object-position: unset; offset: unset; opacity: unset; order: unset; orphans: unset; outline: unset; outline-offset: unset; overflow-anchor: unset; overflow-clip-margin: unset; overflow-wrap: unset; overflow: unset; overscroll-behavior-block: unset; overscroll-behavior-inline: unset; overscroll-behavior: unset; padding-block: unset; padding-inline: unset; page: unset; page-orientation: unset; paint-order: unset; perspective: unset; perspective-origin: unset; pointer-events: unset; position: unset; quotes: unset; r: unset; resize: unset; ruby-position: unset; rx: unset; ry: unset; scroll-behavior: unset; scroll-margin-block: unset; scroll-margin: unset; scroll-margin-inline: unset; scroll-padding-block: unset; scroll-padding: unset; scroll-padding-inline: unset; scroll-snap-align: unset; scroll-snap-stop: unset; scroll-snap-type: unset; shape-image-threshold: unset; shape-margin: unset; shape-outside: unset; shape-rendering: unset; size: unset; speak: unset; stop-color: unset; stop-opacity: unset; stroke: unset; stroke-dasharray: unset; stroke-dashoffset: unset; stroke-linecap: unset; stroke-linejoin: unset; stroke-miterlimit: unset; stroke-opacity: unset; stroke-width: unset; tab-size: unset; table-layout: unset; text-align: unset; text-align-last: unset; text-anchor: unset; text-combine-upright: unset; text-decoration: unset; text-decoration-skip-ink: unset; text-indent: unset; text-overflow: unset; text-shadow: unset; text-size-adjust: unset; text-transform: unset; text-underline-offset: unset; text-underline-position: unset; touch-action: unset; transform: unset; transform-box: unset; transform-origin: unset; transform-style: unset; transition: unset; user-select: unset; vector-effect: unset; vertical-align: unset; visibility: unset; -webkit-app-region: unset; border-spacing: unset; -webkit-border-image: unset; -webkit-box-align: unset; -webkit-box-decoration-break: unset; -webkit-box-direction: unset; -webkit-box-flex: unset; -webkit-box-ordinal-group: unset; -webkit-box-orient: unset; -webkit-box-pack: unset; -webkit-box-reflect: unset; -webkit-highlight: unset; -webkit-hyphenate-character: unset; -webkit-line-break: unset; -webkit-line-clamp: unset; -webkit-mask-box-image: unset; -webkit-mask: unset; -webkit-mask-composite: unset; -webkit-perspective-origin-x: unset; -webkit-perspective-origin-y: unset; -webkit-print-color-adjust: unset; -webkit-rtl-ordering: unset; -webkit-ruby-position: unset; -webkit-tap-highlight-color: unset; -webkit-text-combine: unset; -webkit-text-decorations-in-effect: unset; -webkit-text-emphasis: unset; -webkit-text-emphasis-position: unset; -webkit-text-fill-color: unset; -webkit-text-security: unset; -webkit-text-stroke: unset; -webkit-transform-origin-x: unset; -webkit-transform-origin-y: unset; -webkit-transform-origin-z: unset; -webkit-user-drag: unset; -webkit-user-modify: unset; white-space: pre; widows: unset; width: unset; will-change: unset; word-break: unset; word-spacing: unset; x: unset; y: unset; z-index: unset;"><span class="comment linenumber react-syntax-highlighter-line-number" style="flex-shrink: 0; box-sizing: border-box; padding-left: 8px; margin-right: 8px; text-align: right; user-select: none; display: inline-block; min-width: 1.25em; padding-right: 1em; font-style: normal !important;">1</span><span class="">align_time: 21.448ms (align処理が占めた時間、大体exe_time - 2.0ms程度) </span><span class="comment linenumber react-syntax-highlighter-line-number" style="flex-shrink: 0; box-sizing: border-box; padding-left: 8px; margin-right: 8px; text-align: right; user-select: none; display: inline-block; min-width: 1.25em; padding-right: 1em; font-style: normal !important;">2</span>exe_time: 23.242ms (callbackSensorPoints全体の時間) </code></span></div> <p><span style="color: #000000;">そして、そのalign処理を呼び出しているのが <a href="https://github.com/tier4/AutowareArchitectureProposal.iv/blob/513dee86584018117983178a94a6635ff40a7070/localization/pose_estimator/ndt_scan_matcher/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L371" title="https://github.com/tier4/AutowareArchitectureProposal.iv/blob/513dee86584018117983178a94a6635ff40a7070/localization/pose_estimator/ndt_scan_matcher/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L371" a="">ndt_scan_matcher_core.cpp L.371</a> の箇所です。</span></p> <p><span style="color: #000000;">上記で登場する <code class="code css-9z42f9" style="font-family: SFMono-Medium, 'SF Mono', 'Segoe UI Mono', 'Roboto Mono', 'Ubuntu Mono', Menlo, Consolas, Courier, monospace; font-size: 0.875em; font-weight: normal; background-color: var(--ds--code--bg-color,#f4f5f7); border-style: none; border-radius: 3px; display: inline; padding: 2px 0.5ch; white-space: pre-wrap; overflow-wrap: break-word; overflow: auto; -webkit-box-decoration-break: clone; --ds--code--bg-color: rgba(9,30,66,0.08);" data-renderer-mark="true">ndt_ptr_</code> という変数は、NDT Scan Matcherの各実装を示しており、<a href="https://github.com/tier4/AutowareArchitectureProposal.iv/blob/513dee86584018117983178a94a6635ff40a7070/localization/pose_estimator/ndt_scan_matcher/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L84">node起動時のパラメーター</a>によってどの実装が使用されるか決まります。今回のOpenCL実装は、<a href="https://github.com/tier4/AutowareArchitectureProposal.iv/blob/513dee86584018117983178a94a6635ff40a7070/localization/pose_estimator/ndt_scan_matcher/ndt/include/ndt/ocl.h#L39">NormalDistributionTransformOCLクラス</a>によって実装がなされている…かと思いきや、その実装はさらに、別の <code class="code css-9z42f9" style="font-family: SFMono-Medium, 'SF Mono', 'Segoe UI Mono', 'Roboto Mono', 'Ubuntu Mono', Menlo, Consolas, Courier, monospace; font-size: 0.875em; font-weight: normal; background-color: var(--ds--code--bg-color,#f4f5f7); border-style: none; border-radius: 3px; display: inline; padding: 2px 0.5ch; white-space: pre-wrap; overflow-wrap: break-word; overflow: auto; -webkit-box-decoration-break: clone; --ds--code--bg-color: rgba(9,30,66,0.08);" data-renderer-mark="true">ndt_ptr_</code> (class名としては<a href="https://github.com/tier4/AutowareArchitectureProposal.iv/blob/feature/ndt_opencl/localization/pose_estimator/ndt_scan_matcher/ndt_ocl/include/ndt_ocl/ndt_ocl_impl.hpp">ndt_ocl::NormalDistributionsTransform</a>) のalign関数、実際には<a href="http://docs.ros.org/en/hydro/api/pcl/html/classpcl_1_1Registration.html">親クラス (pcl::Registration) のalign関数</a>を呼び出しており、この中で、</span>その子クラスで実装される関数である、<a href="https://github.com/tier4/AutowareArchitectureProposal.iv/blob/513dee86584018117983178a94a6635ff40a7070/localization/pose_estimator/ndt_scan_matcher/ndt_ocl/include/ndt_ocl/ndt_ocl_impl.hpp#L195">ndt_ocl::NormalDistributionsTransform::computeTransformation</a>を呼び出しています。ここまでの相関関係を図示しておくと以下の通りになりますが、これは実装の形式の話であり、最終的に重要なものは、自己位置計算の実装である、computeTransformationです。</p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="クラス/関数相関図"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/j/james-murakami/20210715/20210715144909.png" alt="f:id:james-murakami:20210715144909p:plain" width="960" height="540" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">クラス/関数相関図</figcaption> </figure> <p><span style="color: #000000;">このcomputeTransformation関数の中では、マッチングスコアがよくなる方向へ移動、スコア計算の流れを何度かイテレーションし、スコア(正確にはスコアを元に計算した値)が事前設定した数値条件 (transformation_epsilon_) を満足したら、その時点での変換行列を最終的な結果として終了します。このようにalign処理は、移動とスコア計算のイテレーションという一連の流れのことであるとソースコードからわかります。</span></p> <p><span style="color: #000000;">これ以降の処理追跡では、重要な部分を動的な観測から"あたり"をつけつつ、行っていきます。</span></p> <h3 id="さらに深くへ"><span style="color: #000000;">さらに深くへ</span></h3> <p><span style="color: #000000;">ソースコード上では様々な処理が存在しますが、複雑な記述だからといって重要度が高い、あるいは処理負荷が高いといったのはよくある誤謬です。</span></p> <p><span style="color: #000000;">今回はperfの結果可視化ツールのFlameGraphと、ValgrindのツールであるCallgrindの2つの結果を、ソースコードリーディングの座右に置きたいと思います。</span></p> <p><span style="color: #000000;"><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fgithub.com%2Fbrendangregg%2FFlameGraph" title="brendangregg/FlameGraph" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://github.com/brendangregg/FlameGraph" style="color: #000000;">github.com</a></cite></span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="ndt scan matcher flamegraph"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/j/james-murakami/20210713/20210713195833.png" alt="f:id:james-murakami:20210713195833p:plain" width="961" height="954" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable"><span style="color: #000000;">ndt scan matcher FlameGraph</span></figcaption> </figure> <figure class="figure-image figure-image-fotolife mceNonEditable" title="ndt scan matcher call graph"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/j/james-murakami/20210713/20210713195924.png" alt="f:id:james-murakami:20210713195924p:plain" width="549" height="1200" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable"><span style="color: #000000;">ndt scan matcher Call Graph</span></figcaption> </figure> <p><span style="color: #000000;">Call Graphにおいて上から3番目の緑のBOXが <code class="code css-9z42f9" style="font-family: SFMono-Medium, 'SF Mono', 'Segoe UI Mono', 'Roboto Mono', 'Ubuntu Mono', Menlo, Consolas, Courier, monospace; font-size: 0.875em; font-weight: normal; background-color: var(--ds--code--bg-color,#f4f5f7); border-style: none; border-radius: 3px; display: inline; padding: 2px 0.5ch; white-space: pre-wrap; overflow-wrap: break-word; overflow: auto; -webkit-box-decoration-break: clone; --ds--code--bg-color: rgba(9,30,66,0.08);" data-renderer-mark="true">callbackSensorPoints</code> であり、先程のコードリーディングで登場しました。ここを起点に下に目を移していきます。最初の枝分かれで、 <code class="code css-9z42f9" style="font-family: SFMono-Medium, 'SF Mono', 'Segoe UI Mono', 'Roboto Mono', 'Ubuntu Mono', Menlo, Consolas, Courier, monospace; font-size: 0.875em; font-weight: normal; background-color: var(--ds--code--bg-color,#f4f5f7); border-style: none; border-radius: 3px; display: inline; padding: 2px 0.5ch; white-space: pre-wrap; overflow-wrap: break-word; overflow: auto; -webkit-box-decoration-break: clone; --ds--code--bg-color: rgba(9,30,66,0.08);" data-renderer-mark="true">init</code> の方は 72:1 で呼び出しの頻度が低いため、左に降りていきましょう。すると <code class="code css-9z42f9" style="font-family: SFMono-Medium, 'SF Mono', 'Segoe UI Mono', 'Roboto Mono', 'Ubuntu Mono', Menlo, Consolas, Courier, monospace; font-size: 0.875em; font-weight: normal; background-color: var(--ds--code--bg-color,#f4f5f7); border-style: none; border-radius: 3px; display: inline; padding: 2px 0.5ch; white-space: pre-wrap; overflow-wrap: break-word; overflow: auto; -webkit-box-decoration-break: clone; --ds--code--bg-color: rgba(9,30,66,0.08);" data-renderer-mark="true">computeDerivatives</code> があり、これがFlameGraphにも登場している、処理割合が大きい関数です。</span></p> <p><span style="color: #000000;">最終的に2つの関数にたどりつきます。それは <code class="code css-9z42f9" style="font-family: SFMono-Medium, 'SF Mono', 'Segoe UI Mono', 'Roboto Mono', 'Ubuntu Mono', Menlo, Consolas, Courier, monospace; font-size: 0.875em; font-weight: normal; background-color: var(--ds--code--bg-color,#f4f5f7); border-style: none; border-radius: 3px; display: inline; padding: 2px 0.5ch; white-space: pre-wrap; overflow-wrap: break-word; overflow: auto; -webkit-box-decoration-break: clone; --ds--code--bg-color: rgba(9,30,66,0.08);" data-renderer-mark="true">updateDerivatives</code> と <code class="code css-9z42f9" style="font-family: SFMono-Medium, 'SF Mono', 'Segoe UI Mono', 'Roboto Mono', 'Ubuntu Mono', Menlo, Consolas, Courier, monospace; font-size: 0.875em; font-weight: normal; background-color: var(--ds--code--bg-color,#f4f5f7); border-style: none; border-radius: 3px; display: inline; padding: 2px 0.5ch; white-space: pre-wrap; overflow-wrap: break-word; overflow: auto; -webkit-box-decoration-break: clone; --ds--code--bg-color: rgba(9,30,66,0.08);" data-renderer-mark="true">radiusSearch</code> でありますが、後者は前編で解説をした部分ですので、ここで <code class="code css-9z42f9" style="font-family: SFMono-Medium, 'SF Mono', 'Segoe UI Mono', 'Roboto Mono', 'Ubuntu Mono', Menlo, Consolas, Courier, monospace; font-size: 0.875em; font-weight: normal; background-color: var(--ds--code--bg-color,#f4f5f7); border-style: none; border-radius: 3px; display: inline; padding: 2px 0.5ch; white-space: pre-wrap; overflow-wrap: break-word; overflow: auto; -webkit-box-decoration-break: clone; --ds--code--bg-color: rgba(9,30,66,0.08);" data-renderer-mark="true">updateDerivatives</code> をもう少し掘り下げて見てみましょう。</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="ndt scan matcher call graph (detailed)"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/j/james-murakami/20210713/20210713200307.png" alt="f:id:james-murakami:20210713200307p:plain" width="1200" height="908" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable"><span style="color: #000000;">ndt scan matcher Call Graph (detailed)</span></figcaption> </figure> <p><span style="color: #000000;">computeDerivatives は <code class="code css-9z42f9" style="font-family: SFMono-Medium, 'SF Mono', 'Segoe UI Mono', 'Roboto Mono', 'Ubuntu Mono', Menlo, Consolas, Courier, monospace; font-size: 0.875em; font-weight: normal; background-color: var(--ds--code--bg-color,#f4f5f7); border-style: none; border-radius: 3px; display: inline; padding: 2px 0.5ch; white-space: pre-wrap; overflow-wrap: break-word; overflow: auto; -webkit-box-decoration-break: clone; --ds--code--bg-color: rgba(9,30,66,0.08);" data-renderer-mark="true">updateDerivatives</code> および <code class="code css-9z42f9" style="font-family: SFMono-Medium, 'SF Mono', 'Segoe UI Mono', 'Roboto Mono', 'Ubuntu Mono', Menlo, Consolas, Courier, monospace; font-size: 0.875em; font-weight: normal; background-color: var(--ds--code--bg-color,#f4f5f7); border-style: none; border-radius: 3px; display: inline; padding: 2px 0.5ch; white-space: pre-wrap; overflow-wrap: break-word; overflow: auto; -webkit-box-decoration-break: clone; --ds--code--bg-color: rgba(9,30,66,0.08);" data-renderer-mark="true">computePointDerivatives</code> から成ることがわかります。</span></p> <p><span style="color: #000000;">以上をまとめると、NDT align処理の主関数は下記のたった3つであり、これにより重点的に見ていく場所が明らかになりました。</span></p> <ol> <li><span style="color: #000000;">radiusSearch</span></li> <li><span style="color: #000000;">updateDerivatives</span></li> <li><span style="color: #000000;">computePointDerivatives</span></li> </ol> <p><span style="color: #000000;">computeDerivativesの中では、まずSource各点に対するTarget内の近傍探索、点の雰囲気とのマッチングスコア計算、そしてスコアがよくなる方向を上記の関数を用いて計算しています。</span></p> <p><span style="color: #000000;">ここからはOpenCL実装の話ですが、上記の通り"Source各点に対する並列化"が容易であるため、1, 2, 3をSource各点に対して呼び出すカーネル関数 <code class="code css-9z42f9" style="font-family: SFMono-Medium, 'SF Mono', 'Segoe UI Mono', 'Roboto Mono', 'Ubuntu Mono', Menlo, Consolas, Courier, monospace; font-size: 0.875em; font-weight: normal; background-color: var(--ds--code--bg-color,#f4f5f7); border-style: none; border-radius: 3px; display: inline; padding: 2px 0.5ch; white-space: pre-wrap; overflow-wrap: break-word; overflow: auto; -webkit-box-decoration-break: clone; --ds--code--bg-color: rgba(9,30,66,0.08);" data-renderer-mark="true">computeDerivatives</code> を用意しています。</span></p> <p><span style="color: #000000;"><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fgithub.com%2Ftier4%2FAutowareArchitectureProposal.iv%2Fblob%2F513dee86584018117983178a94a6635ff40a7070%2Flocalization%2Fpose_estimator%2Fndt_scan_matcher%2Fndt_scan_matcher%2Focl%2Fcompute_derivatives.cl%23L858" title="tier4/AutowareArchitectureProposal.iv" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://github.com/tier4/AutowareArchitectureProposal.iv/blob/513dee86584018117983178a94a6635ff40a7070/localization/pose_estimator/ndt_scan_matcher/ndt_scan_matcher/ocl/compute_derivatives.cl#L858" style="color: #000000;">github.com</a></cite></span></p> <p><span style="color: #000000;">なお、Autowareが採用している <a href="https://github.com/tier4/AutowareArchitectureProposal.iv/blob/8a1343019aca3a648754fa50e6cab72b98db2df5/localization/pose_estimator/ndt_scan_matcher/ndt_omp/include/ndt_omp/ndt_omp_impl.hpp#L260" title="https://github.com/tier4/AutowareArchitectureProposal.iv/blob/8a1343019aca3a648754fa50e6cab72b98db2df5/localization/pose_estimator/ndt_scan_matcher/ndt_omp/include/ndt_omp/ndt_omp_impl.hpp#L260">OpenMP版</a> でも同様の並列化が、omp_parallelを用いて実装されています。</span></p> <h3 id="補足-地図のVoxel分割と地図KD木構築実装"><span style="color: #000000;">(補足) 地図のVoxel分割と地図KD木構築実装</span></h3> <p><span style="color: #000000;">OpenCL版で大きく異なるのは、むしろ地図のVoxel分割(およびそのKD木の構築)の部分であり、概念としては前編の通りですが、今一度package化に際しての実装を説明しておきます。</span></p> <p><span style="color: #000000;">OpenCL版NDT Scan Matcherでは<a href="https://github.com/tier4/AutowareArchitectureProposal.iv/blob/513dee86584018117983178a94a6635ff40a7070/localization/pose_estimator/ndt_scan_matcher/ndt_ocl/include/ndt_ocl/ndt_ocl.h#L135">ndt_ocl::NormalDistributionsTransform::setInputTarget</a>関数内のinitから、<a href="https://github.com/tier4/AutowareArchitectureProposal.iv/blob/513dee86584018117983178a94a6635ff40a7070/localization/pose_estimator/ndt_scan_matcher/ndt_ocl/include/ndt_ocl/ndt_ocl.h#L262">target_cells_.filter()</a>関数(なお、target_cells_の型は、<a href="https://github.com/tier4/AutowareArchitectureProposal.iv/blob/513dee86584018117983178a94a6635ff40a7070/localization/pose_estimator/ndt_scan_matcher/ndt_ocl/include/ndt_ocl/ndt_ocl.h#L112">ndt_ocl::VoxelGridCovariance&lt;PointTarget&gt;</a>) 、さらにPCLの関数を経由した後、最終的に voxel_grid_covariance_ocl_impl の<a href="https://github.com/tier4/AutowareArchitectureProposal.iv/blob/513dee86584018117983178a94a6635ff40a7070/localization/pose_estimator/ndt_scan_matcher/ndt_ocl/include/ndt_ocl/voxel_grid_covariance_ocl_impl.hpp#L522">この箇所</a>で木を構築しています。</span></p> <p><span style="color: #000000;">OpenMPとの違いとしては、FLANN Libraryを経由せず、そのメモリ配置を <a href="https://github.com/tier4/AutowareArchitectureProposal.iv/blob/513dee86584018117983178a94a6635ff40a7070/localization/pose_estimator/ndt_scan_matcher/ndt_ocl/include/ndt_ocl/voxel_grid_covariance_ocl_impl.hpp#L522">voxel_grid_covariance_ocl_impl</a> 内で任意に制御できる点にあります。この点は組み込み環境の制限されたメモリ環境においては必須となります。</span></p> <p><span style="color: #000000;">そして最終的に作成された木メモリは、<a href="https://github.com/tier4/AutowareArchitectureProposal.iv/blob/513dee86584018117983178a94a6635ff40a7070/localization/pose_estimator/ndt_scan_matcher/ndt_ocl/include/ndt_ocl/ndt_ocl_impl.hpp#L621">SVM (Shared Virtual Memory) argumentとして</a>kernelに渡され、デバイス側の近傍探索に使用されます。</span></p> <h3 id="スコア計算部の命令実行的性質"><span style="color: #000000;">スコア計算部の&quot;命令実行的性質&quot;</span></h3> <p><span style="color: #000000;">計算量といってしまうと、それはランダウ表記で示される、入力数に対するチューリングマシン上での操作手数の関係(スケーラビリティ)という抽象性を持つものになってしまいますが、ここではより具体的に、特定の命令セット命令を持つ(load/store型)計算機上における、命令の実行性質をみたいと思います。</span></p> <h4 id="computePointDerivatives"><span style="color: #000000;">computePointDerivatives<button class="sc-hzDkRC dsymMa" style="font-family: inherit; display: inline; outline: none; background-color: transparent; border: none; cursor: pointer; right: 0px; padding-left: 0px; padding-right: 0px; opacity: 0; transform: translate(-8px, 0px); transition: opacity 0.2s ease 0s, transform 0.2s ease 0s;"><svg height="24" role="presentation" viewbox="0 0 24 24" width="24"><g fill="currentColor" fill-rule="evenodd"><path d="M12.856 5.457l-.937.92a1.002 1.002 0 000 1.437 1.047 1.047 0 001.463 0l.984-.966c.967-.95 2.542-1.135 3.602-.288a2.54 2.54 0 01.203 3.81l-2.903 2.852a2.646 2.646 0 01-3.696 0l-1.11-1.09L9 13.57l1.108 1.089c1.822 1.788 4.802 1.788 6.622 0l2.905-2.852a4.558 4.558 0 00-.357-6.82c-1.893-1.517-4.695-1.226-6.422.47"></path><path d="M11.144 19.543l.937-.92a1.002 1.002 0 000-1.437 1.047 1.047 0 00-1.462 0l-.985.966c-.967.95-2.542 1.135-3.602.288a2.54 2.54 0 01-.203-3.81l2.903-2.852a2.646 2.646 0 013.696 0l1.11 1.09L15 11.43l-1.108-1.089c-1.822-1.788-4.802-1.788-6.622 0l-2.905 2.852a4.558 4.558 0 00.357 6.82c1.893 1.517 4.695 1.226 6.422-.47"></path></g></svg></button></span></h4> <p><span style="color: #000000;">2つの行列演算といくつかの行列のエレメント生成から成ります。</span></p> <ul> <li><span style="background-color: var(--ds--code--bg-color,#f4f5f7); font-family: SFMono-Medium, 'SF Mono', 'Segoe UI Mono', 'Roboto Mono', 'Ubuntu Mono', Menlo, Consolas, Courier, monospace; font-size: 0.875em; white-space: pre-wrap; letter-spacing: -0.005em; color: #000000;">j_ang * x4 (&lt;8, 4&gt; * &lt;4, 1&gt;)</span></li> <li><span style="background-color: var(--ds--code--bg-color,#f4f5f7); font-family: SFMono-Medium, 'SF Mono', 'Segoe UI Mono', 'Roboto Mono', 'Ubuntu Mono', Menlo, Consolas, Courier, monospace; font-size: 0.875em; white-space: pre-wrap; letter-spacing: -0.005em; color: #000000;">h_ang * x4 (&lt;16, 4&gt; * &lt;4, 1&gt;)</span></li> </ul> <p><span style="color: #000000;">いずれもかなり小規模な行列であるため、行列演算自体のカーネル化やSIMD packedな演算化は行っていません。実際にカーネルコードを、RISC-Vのコンパイラ(RV32if)でコンパイルした結果における、命令ヒストグラムを見てみます。</span></p> <p><span style="color: #000000;">大体がflw(FPRメモリロード) → fmadd.s(乗算加算複合) → fsw(FPRメモリストア)の系統であり、またspill outも極端でないため、fsw &lt;&lt; flwとなっていることがわかります。ちなみにfmv.w.xはGPR → FPR移動命令だったり、retは(仮想命令)関数リターン(jalr x0)だったりしますが、本筋とは関係ありません。ちなみに乗算加算複合命令はgccでは-O3でないと出現しないようです。</span></p> <p><span style="color: #000000;"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/j/james-murakami/20210713/20210713202418.png" alt="f:id:james-murakami:20210713202418p:plain" width="600" height="371" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></span></p> <h4 id="updateDerivatives"><span style="color: #000000;">updateDerivatives</span></h4> <p><span style="color: #000000;">多数の小規模行列演算と、スカラー値演算、およびexponent演算が使用されているのが特徴的です(スカラー値演算も多数ありますが、以下では割愛しています)。</span></p> <ul> <li> <p><span style="font-size: 0.875em; color: #000000;"><span style="background-color: var(--ds--code--bg-color,#f4f5f7); font-family: SFMono-Medium, 'SF Mono', 'Segoe UI Mono', 'Roboto Mono', 'Ubuntu Mono', Menlo, Consolas, Courier, monospace; letter-spacing: -0.005em;">e_x_cov_x&lt;scalar&gt; = exp(-gauss_d2&lt;scalar&gt; * x_trans4&lt;1, 4&gt;.dot(x_trans4&lt;1, 4&gt; * c_inv4&lt;4, 4&gt;) * 0.5f</span></span></p> </li> <li> <p><span style="font-size: 0.875em; color: #000000;"><span style="background-color: var(--ds--code--bg-color,#f4f5f7); font-family: SFMono-Medium, 'SF Mono', 'Segoe UI Mono', 'Roboto Mono', 'Ubuntu Mono', Menlo, Consolas, Courier, monospace; letter-spacing: -0.005em;">c_inv4_x_point_gradient4&lt;4, 6&gt; = c_inv4&lt;4, 4&gt; * point_gradient4&lt;4, 6&gt;</span></span></p> </li> <li> <p><span style="font-size: 0.875em; color: #000000;"><span style="background-color: var(--ds--code--bg-color,#f4f5f7); font-family: SFMono-Medium, 'SF Mono', 'Segoe UI Mono', 'Roboto Mono', 'Ubuntu Mono', Menlo, Consolas, Courier, monospace; letter-spacing: -0.005em;">x_trans4_dot_c_inv4_x_point_gradient4&lt;6, 1&gt; = x_trans4&lt;1, 4&gt; * c_inv4_x_point_gradient4&lt;4, 6&gt;</span></span></p> </li> <li> <p><span style="font-size: 0.875em; color: #000000;"><span style="background-color: var(--ds--code--bg-color,#f4f5f7); font-family: SFMono-Medium, 'SF Mono', 'Segoe UI Mono', 'Roboto Mono', 'Ubuntu Mono', Menlo, Consolas, Courier, monospace; white-space: pre-wrap; letter-spacing: -0.005em;">x_trans4_x_c_inv4&lt;1, 4&gt; = x_trans4&lt;1, 4&gt; * c_inv4&lt;4, 4&gt;</span></span></p> </li> <li><span style="font-family: SFMono-Medium, 'SF Mono', 'Segoe UI Mono', 'Roboto Mono', 'Ubuntu Mono', Menlo, Consolas, Courier, monospace; color: #000000; font-size: 14px;"><span style="letter-spacing: -0.07px; white-space: pre-wrap; background-color: #f4f5f7;">point_gradient4_colj_dot_c_inv4_x_point_gradient4_col_i&lt;6, 6&gt; = point_gradient4.transpose()&lt;6, 4&gt; * c_inv4_x_point_gradient4&lt;4, 6&gt;</span></span></li> <li> <p style="color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-size: 1em; white-space: pre-wrap; margin-top: 0px; margin-bottom: 0px; line-height: 1.714; letter-spacing: -0.005em; display: inline !important;" data-renderer-start-pos="5162"><span style="color: #000000;">for i in 0 ... 5</span></p> </li> <ul> <li><span style="font-family: SFMono-Medium, 'SF Mono', 'Segoe UI Mono', 'Roboto Mono', 'Ubuntu Mono', Menlo, Consolas, Courier, monospace; color: #000000; font-size: 14px;"><span style="letter-spacing: -0.07px; white-space: pre-wrap; background-color: #f4f5f7;">x_trans4_dot_c_inv4_x_ext_point_hessian_4ij.noalias()&lt;6, 1&gt; = x_trans4_x_c_inv4&lt;1, 4&gt; * point_hessian_.block&lt;4, 6&gt;(i * 4, 0)</span></span></li> </ul> </ul> <p><span style="color: #000000;">最終的に、このupdateDerivativesの返却値がscoreとなり、これをinput点群数で割り正規化したものが、Transform Probabilityとして、推定のもっともらしさを表す数値として使用されることになります。</span></p> <p><span style="color: #000000;">こちらも、RISC-Vコンパイラでのコンパイル結果とその命令分布を見てみましょう。</span></p> <p><span style="color: #000000;"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/j/james-murakami/20210713/20210713202742.png" alt="f:id:james-murakami:20210713202742p:plain" width="600" height="371" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></span></p> <p><span style="color: #000000;">こちらはソースコードでも依存関係のある行列演算であるため、flwやfswよりもかなりfmul.s, fmadd.sの比重が大きいこととちょうど符合しています。</span></p> <h3 id="OpenCL実装について"><span style="color: #000000;">OpenCL実装について</span></h3> <p><span style="color: #000000;">紹介したOpenCL実装とOpenMP実装について、実際に(README記載の)サンプルを動作させて比較してみます。今回は、OpenCLもCPUにoffloadする形となっています。</span></p> <h4 id="Align-TimeとTransform-Probabilityの時間推移"><span style="color: #000000;">Align TimeとTransform Probabilityの時間推移</span></h4> <p><span style="color: #000000;"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/j/james-murakami/20210713/20210713203100.png" alt="f:id:james-murakami:20210713203100p:plain" width="600" height="371" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></span></p> <p><span style="color: #000000;"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/j/james-murakami/20210713/20210713203115.png" alt="f:id:james-murakami:20210713203115p:plain" width="600" height="371" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></span></p> <p><span style="color: #000000;">結論としては、平均的にOpenCLの方がAlign Timeの時間は大きく、分散が小さいです。これは、OpenMPでは処理のロードバランシング等の最適化が行われており、応答性に関してはより優れた結果になっていると思われます。例えば、GPGPUやAccelerator等のCPU外のdeviceにもoffloadすることが可能な点がOpenCL版の魅力ではありますが、ナイーブな実装もあってCPUは少し苦手といった所のようです。</span></p> <p><span style="color: #000000;">Transform Probabilityとしては同程度の推移です。</span></p> <p><span style="color: #000000;">最後にFlameGraphを取得してみると、libgomp (OpenMP) libraryの代わりに、intel::internal::arena (Threading Building Block)が使用されていることがわかります。</span></p> <p><span style="color: #000000;"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/j/james-murakami/20210713/20210713203632.png" alt="f:id:james-murakami:20210713203632p:plain" width="1200" height="917" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></span></p> <p><span style="color: #000000;">ndt_ocl packageのREADMEでは、Intel環境におけるOpenCL 2.x環境の構築の例も紹介していますので、実行する際にぜひご参照ください。</span></p> <h3 id="リソース管理厳格化"><span style="color: #000000;">リソース管理厳格化</span></h3> <p><span style="color: #000000;">OpenCLの実装にあたっては、使用する各種のリソースにも制限を意図的に加えています(いずれも設定が可能です)。</span></p> <p><span style="color: #000000;">実際問題として車載環境のような組み込みによった環境では、動的で潤沢なメモリ確保ができない場合の方が多いですし、何より実行毎に予想できない挙動であることは、一つのリスクとなります。</span></p> <p><span style="color: #000000;">重要なことは、平均でも最小でもなく、最大値を予め設定できるということです。</span></p> <p><span style="color: #000000;">具体的には、NDT Scan Matchingにおいて、その処理量に影響を与える要素は3つしかなく、以下の3要素の最大値を予め定めさえすれば、処理時間を予測できるということになります。</span></p> <ol> <li><span style="color: #000000;">LiDAR点数</span></li> <li><span style="color: #000000;">発見近傍Voxel数</span></li> <li><span style="color: #000000;">スコア値計算の最大繰り返し数</span></li> </ol> <p><span style="color: #000000;">OpenMP実装では、3のmax_iterationのみの制限でありますが、OpenCL実装では全てに以下のような制限をかけることができます。</span></p> <ul> <li><span style="color: #000000;">LIMIT_NUM (MAX_NEIGHBOR_VOXELS)</span> <ul> <li><span style="color: #000000;">Radius Searchが発見する近傍Voxcelの限界数、これを超過すると単純に近傍として追加されず、Scan Matchingが不安定となる恐れがあります。</span></li> </ul> </li> <li><span style="color: #000000;">MAX_PCL_INPUT_NUM (MAX_NUM_OF_LIDAR_POINTS)</span> <ul> <li><span style="color: #000000;">LiDARからの入力点群数の最大値を設定する。</span></li> </ul> </li> </ul> <h3 id="おわりに"><span style="color: #000000;">おわりに</span></h3> <p><span style="color: #000000;">前編/後編と2回にわたり、NDT Scan Matchingの計算面の調査を行い、その結果を一緒に眺めてきましたが、いかがでしたでしょうか。</span></p> <p><span style="color: #000000;">途中から解析や、再実装の話に始終してしまいましたが、腰をすえてソースコードを追ってみる時、ただやみくもに読むよりも定量的に姿を捉えながら全体を理解していく、そんな一例をご紹介できたかと思います。</span></p> <p><span style="color: #000000;">魔法のような自動運転のアルゴリズムも、実装となってしまえばただの計算です。Autowareはオープンなソフトウェアです。実際に読み、触れ、動作させることで理解ができます。臆することなく挑戦していきましょう!</span></p> james-murakami 安全への取り組み:③自動運転車のサイバーセキュリティについて hatenablog://entry/26006613561432532 2021-07-08T16:00:00+09:00 2023-05-24T18:47:45+09:00 こんにちは、ティアフォーのSafety Engineerの須永です。 ティアフォーの安全への取り組みを数回にわたって紹介していくシリーズ。時間がたってしまいましたが今回は第3回目になります。 1回目は法律・ガイドラインについてでした。 tech.tier4.jp 2回目は安心・安全についてでした。 3回目の今回は自動車のサイバーセキュリティについての取り組みを説明していこうと思います。 なお、ティアフォーでは、「自動運転の民主化」をともに実現していくサイバーセキュリティエンジニアを絶賛大募集しています。自動車および自動運転のサイバーセキュリティは最先端、かつ広域にわたる知識が必要になってきます… <p> こんにちは、ティアフォーのSafety Engineerの須永です。</p> <p>ティアフォーの安全への取り組みを数回にわたって紹介していくシリーズ。時間がたってしまいましたが今回は第3回目になります。</p> <p> 1回目は法律・ガイドラインについてでした。</p> <p><span style="color: #000000;"><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftech.tier4.jp%2Fentry%2F2020%2F05%2F08%2F163000" title="安全への取り組み: ①自動運転関連の法律・ガイドライン - Tier IV Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://tech.tier4.jp/entry/2020/05/08/163000" style="color: #000000;">tech.tier4.jp</a></cite></span></p> <p><span style="color: #000000;"> 2回目は安心・安全についてでした。</span></p> <p><span style="color: #000000;"><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftech.tier4.jp%2Fentry%2F2020%2F11%2F25%2F160000" title="安全への取り組み:②自動運転の安心・安全について - Tier IV Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe></span></p> <p> 3回目の今回は自動車のサイバーセキュリティについての取り組みを説明していこうと思います。</p> <p> なお、ティアフォーでは、「自動運転の民主化」をともに実現していくサイバーセキュリティエンジニアを絶賛大募集しています。自動車および自動運転のサイバーセキュリティは最先端、かつ広域にわたる知識が必要になってきます。我こそは、という方が居ましたら、気軽にカジュアル面談からでも対応しますので是非応募ください。</p> <p><a href="https://careers.tier4.jp/">TIER IV Careers</a></p> <p> </p> <p><ul class="table-of-contents"> <li><a href="#自動車のサイバーセキュリティと安全">自動車のサイバーセキュリティと安全</a></li> <li><a href="#自動車へのサイバー攻撃の現状">自動車へのサイバー攻撃の現状</a></li> <li><a href="#自動車サイバーセキュリティのルール化">自動車サイバーセキュリティのルール化</a></li> <li><a href="#自動車のサイバーセキュリティルールの概要">自動車のサイバーセキュリティルールの概要</a></li> <li><a href="#自動車のサイバーセキュリティ開発プロセス">自動車のサイバーセキュリティ開発プロセス</a></li> <li><a href="#安全分析サイバーセキュリティ分析およびリスクアセスメントの差分">安全分析・サイバーセキュリティ分析およびリスクアセスメントの差分</a></li> <li><a href="#おわりに">おわりに</a></li> </ul></p> <h4 id="自動車のサイバーセキュリティと安全"><span style="color: #000000;">自動車のサイバーセキュリティと安全</span></h4> <p><span style="color: #000000;"> 自動車のサイバーセキュリティと安全にはどのような関係があるのでしょうか?</span></p> <p><span style="color: #000000;">2015年に行われたBlack Hat USA 2015という大規模なセキュリティカンファレンスで、ホワイトハッカーであるCharlie Miller氏とChris Valasek氏がFiat Chrysler Automobiles(FCA)社<span style="font-family: Meiryo, メイリオ, ArialMT, 'Hiragino Kaku Gothic Pro', 'ヒラギノ角ゴ Pro W3', Osaka, Verdana, 'MS Pゴシック'; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; float: none; display: inline !important;">のJeep Cherokeeという車両のハッキングに成功したことを報告し、140万台がリコールという話になりました。このハッキングは、はじめはWi-Fi経由でオーディオ音量を調整したりGPSで車両をトラッキングするなど、いわゆる車両内のマルチメディアシステムを掌握していました。さらにハッキングを進めると、マルチメディアシステムとは独立した車両の運転制御用のCANバスにアクセスできるまでになり、結果として外部から車両の運転制御までできるようになりました。つまり、車両を遠隔操作できることが分かったのです。</span>ホワイトハッカーが実験的に行ったハッキングではあったものの、もし悪意のあるハッカーが遠隔操作で車両をコントロールすれば、故意に事故を起こすこともできるわけです。</span></p> <p><span style="color: #000000;"><iframe width="560" height="315" src="https://www.youtube.com/embed/MK0SrxBC1xs?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" id="widget2"></iframe><cite class="hatena-citation"><a href="https://youtu.be/MK0SrxBC1xs" style="color: #000000;">youtu.be</a></cite></span></p> <h4 id="自動車へのサイバー攻撃の現状"><span style="color: #000000;">自動車へのサイバー攻撃の現状</span></h4> <p><span style="color: #000000;"> 2010年から2019年の10年間に公開された世界の車両サイバー攻撃インシデントの総件数は把握されている件数のみでも400件余り、2019年は単年で150件相当とのデータがあり、把握できていないものも含めるとその数倍はある可能性があります。このように、車両のサイバー攻撃は急増してきています。</span>(参照:<a href="https://tokiocyberport.tokiomarine-nichido.co.jp/cybersecurity/s/column-detail62 ">自動車へのサイバー攻撃の新常識と対応の考察</a>)<br /><span style="color: #000000;"> サイバー攻撃対象は、キーエントリシステムやテレマティクスや自動車メーカーのサーバ、カーシェアリングや自動車警報サービスなどのモバイルアプリケーションサーバといった自動車窃盗目的が多く、ホワイトハッカーの研究目的の攻撃から、悪意あるハッカーの攻撃に移行しているのは確実なようです。もし悪意のあるハッカーが<span style="font-family: Meiryo, メイリオ, ArialMT, 'Hiragino Kaku Gothic Pro', 'ヒラギノ角ゴ Pro W3', Osaka, Verdana, 'MS Pゴシック'; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; float: none; display: inline !important;">Jeep Cherokee</span>の事例のように遠隔操作で車両をコントロールすれば、故意に事故を起こすこともできるわけです。自動車のハッキングは最悪人命に関わることから、車両のサイバーセキュリティ侵害は安全侵害の一つになりえるとし、世界中が事態を重大にとらえている状況です。</span></p> <h4 id="自動車サイバーセキュリティのルール化"><span style="color: #000000;">自動車サイバーセキュリティのルール化</span></h4> <p><span style="color: #000000;"><span style="font-family: Meiryo, メイリオ, ArialMT, 'Hiragino Kaku Gothic Pro', 'ヒラギノ角ゴ Pro W3', Osaka, Verdana, 'MS Pゴシック'; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; float: none; display: inline !important;"> Jeep Cherokee</span>のハッキングと時を同じくして、自動車業界はCASE(Connected・Autonomous・Shared &amp; Services・Electric)時代といわれる100年に一度の変革期を迎えました。これらの背景を受けて、自動車業界や自動車のサイバーセキュリティルールを定めようとする国際的な動きが本格化したのです。</span></p> <p><span style="color: #000000;"> 主に国際間での自動車のルールを取り決める国連のワーキンググループWP29(自動車基準調和世界フォーラム)および国際規格を制定するISOでルール化が動きはじめます。これらの活動は国際協調するために整合するのに時間がかかり、WP29では2020年6月にUN-R-155(車両型式・サイバーセキュリティマネジメントシステム)・UN-R156(車両型式・ソフトウェアマネジメントシステム)として、またISOでは2021年の5月にFDIS として<a href="https://www.iso.org/standard/70918.html" style="color: #000000;">ISO/SAE 21434</a>が正式な承認を迎える一歩手前まで来ている状況です。</span></p> <p><span style="color: #000000;"> 日本は自動車のサイバーセキュリティに関して各国を先導するように、WP29では<span style="font-family: Meiryo, メイリオ, ArialMT, 'Hiragino Kaku Gothic Pro', 'ヒラギノ角ゴ Pro W3', Osaka, Verdana, 'MS Pゴシック'; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; float: none; display: inline !important;">共同議長または副議長を務めてきました。その活動の中で</span>国土交通省は、2020年8月に<a href="https://www.mlit.go.jp/report/press/jidosha08_hh_003789.html" style="color: #000000;">自動車の特定改造等に関わる許可制度</a>を発表しており対応が必要になっています。</span></p> <p><span style="color: #000000;"> 自動運転もまだ完全に完成されたソフトウェアが存在しないことから、適宜ソフトウェアをアップデートして機能をどんどん追加・改良していく段階です。市販車に搭載された場合でもアップデートしていけるようにOTA(Over-The-Air)が行われることが想定されています。また、自動運転システムになると車両だけでなくそれを取り巻くサブシステムとしてクラウドを利用します。また、先の説明でも行ったようにサイバーセキュリティ侵害がそのまま安全侵害に直結する可能性も出てきています。</span></p> <p><span style="color: #000000;"> 自動運転を見据えた規格では、SaFAD(Safety First for Automated Driving)が標準規格化されたISO/TR 4804や民間規格であるUL 4600もあります。これらの中でも、システムのライフサイクルの中でサイバーセキュリティの確保および適宜見直しを行ってアップデートしていくことが求められています。</span></p> <h4 id="自動車のサイバーセキュリティルールの概要"><span style="color: #000000;">自動車のサイバーセキュリティルールの概要</span></h4> <p><span style="color: #000000;">今まで説明してきたルールでは概ね考え方の連携ができており、サイバーセキュリティの守り方は2種類に大別されます。</span></p> <p><span style="color: #000000;">1. サイバーセキュリティ・ソフトウェアアップデートを運用できる組織体制</span></p> <p><span style="color: #000000;">2. サイバーセキュリティ・ソフトウェアアップデートを安全に行うためのリスクアセスメント</span></p> <p><span style="color: #000000;"> 1の運用できる組織体制とは、いわゆるCSMS(Cyber Security Management System)のことで、サイバーセキュリティに関わるリスクマネジメントを効果的・効率的に実施するための仕組みになります。サイバーセキュリティを完全にすることはできないため、一般的にはスイスチーズモデルのように何層かの対策を打つのが一般的ですが、深刻な脆弱性問題が出た時にすぐに対処できる組織体制が必要、かつ準備しておくことが必要ということになります。</span></p> <p><span style="color: #000000;"> 2のリスクアセスメントとは、人はミスをすることを前提に、設計手法(プロセス)の中でミスを見つけてつぶし、設計の変更があった場合はその影響を見つけて設計に反映させていくものです。この設計プロセスの中でミスを抑える手法は、安全規格であるISO 26262のV字プロセスと同じ手法になるため、V字を使用した</span><span style="color: #000000;">開発プロセスという意味で兄弟的存在になります。また、製品の企画段階から廃棄までの製品ライフサイクルの中で活動していく部分に関しては同じく安全規格のISO/PAS 21448 (SOTIF) と兄弟的な存在になってきます。これからの自動車・自動運転車のルール・規格としてはこの3つの規格を総合・統合した形で見ていき、サイバーセキュリティを含んだ安全を確保していくことが業界の暗黙のルールになっています。</span></p> <p> </p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="a"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/s/sunagaya/20210708/20210708122806.png" alt="f:id:sunagaya:20210708122806p:plain" width="1200" height="723" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable"><span style="color: #000000;">自動車・自動運転システムのサイバーセキュリティ規格と安全規格</span></figcaption> </figure> <h4 id="自動車のサイバーセキュリティ開発プロセス"><span style="color: #000000;">自動車のサイバーセキュリティ開発プロセス</span></h4> <p><span style="color: #000000;"> 安全とサイバーセキュリティは、同じような開発プロセスでルール化されていますが、当然全く同じというわけではないので、その違いについて簡単に説明していきます。</span></p> <p><span style="color: #000000;"> まず、自動車の安全設計プロセスとして有名なISO 26262は、自動車でも特に車両の電気電子機器の機能安全(壊れても安全・壊れたら分かる)設計を行うもので、V字プロセスとして開発(設計・検証)を進めるものになります。対象のシステムの構成をアイテム定義し、定義したアイテムの潜在的・危険因子を特定するためのハザード分析を行い、壊れたらどのような危害を加えてしまうか危険度や被害度・回避可能性などのリスク評価を行います。そのリスク評価に対して安全目標を立ててリスクを許容可能なレベルまで落とせるように安全要件を作成し、設計・実装していきます。設計・実装したものが意図したとおり、効果あるものか確認・検証していきます。 </span></p> <p><span style="color: #000000;"> 併せて、重要な安全設計プロセスとしてのISO/PAS 21448では、システムとして未知で不安全である事象を減らし、既知で安全である事象を増やすことを続けていきます。これは車両・システムが破棄されるまで継続していき、安全性をどんどん上げていく取り組みになります。</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="自動車の安全開発プロセス"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/s/sunagaya/20210706/20210706141601.png" alt="f:id:sunagaya:20210706141601p:plain" width="720" height="349" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable"><span style="color: #000000;">自動車の安全開発プロセス</span></figcaption> </figure> <p><span style="color: #000000;"> 同じように、自動車のサイバーセキュリティ設計プロセスについて、ISO/SAE 21434の概要をなぞる形で説明します。この規格は車両の電気電子機器の開発、生産、運用、保守を含めたサイバーセキュリティのリスク管理のためのエンジニアリング要件になっています。対象となるシステムの構成でアイテムおよび守るべき資産を定義し、定義したアイテム・資産のサイバーセキュリティ侵害による影響を脅威分析として実施し、攻撃の経路および影響からリスク評価を行います。そのリスク評価に対してサイバーセキュリティ目標を立てて許容可能なリスクレベルまで落とせるように要件を作成し、設計・実装していきます。設計・実装したものが意図したとおり、効果あるものか確認・検証していきます。さらにサイバーセキュリティポリシーを設定し、その製品に脆弱性があった場合は対策・対応およびインシデントの管理を車両が廃棄されるまで継続していきます。これらのサイバーセキュリティインシデントは、PSIRT(Product Security Incident Response Team)という組織横断的なチームによって管理していきます。</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="自動車のセキュリティ開発プロセス"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/s/sunagaya/20210706/20210706141636.png" alt="f:id:sunagaya:20210706141636p:plain" width="720" height="360" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable"><span style="color: #000000;">自動車のサイバーセキュリティ開発プロセス</span></figcaption> </figure> <h4 id="安全分析サイバーセキュリティ分析およびリスクアセスメントの差分"><span style="color: #000000;">安全分析・サイバーセキュリティ分析およびリスクアセスメントの差分</span></h4> <p><span style="color: #000000;"> 開発領域では似たようなプロセスであるものの、安全・サイバーセキュリティ設計では大きく違うところがあります。</span></p> <p><span style="color: #000000;">1. サイバーセキュリティでは資産の特定がある</span></p> <p><span style="color: #000000;"> サイバーセキュリティで侵害があると、影響があるステークホルダーを明らかにし、資産をCIA (秘匿性、完全性、可用性:Confidentiality、Integrity、Availability)の3要素に分類し</span><span style="color: #000000;">ます。 サイバーセキュリティ侵害による影響は、無視できるものから深刻なものまで測定され、SFOP(安全性、財務、運用、プライバシー:Safety、Financial、Operational、Privacy)に分類します。安全は万人に影響がありますが、サイバーセキュリティは非常に範囲が広いので守るべき人や</span><span style="color: #000000;">物に対して領域の線引きをする必要があるということを示しています。</span></p> <p><span style="color: #000000;">2. 分析方法</span></p> <p><span style="color: #000000;"> 安全分析ではHARA(Hazard Analysis and Risk Assessment)を実施し安全性の評価をしていきます。この分析にはFTA(Fault Tree Analysis)・FMEA(Failure Mode and Effects Analysis)・FMEDA(Failure Modes, Effects, and Diagnostics Analysis)・HAZOP(HAZard and OPerability studies)・STAMP(Systems-Theoretic Accident Model and Processes) /STPA(STAMP based Process Analysis)などの多くの安全分析手法が使用されます。</span></p> <p><span style="color: #000000;"> 一方、サイバーセキュリティ分析ではTARA(Threat Analysis and Risk Assessment)を実施しサイバーセキュリティ評価をしていきます。ハザードが脅威(Threat)に置き換わったものになります。この分析手法にも様々な種類がありますが、DFD(Data Flow Diagram)によってデータの流れを可視化し、STRIDE法や5W法およびAttack Treeでサイバーセキュリティリスクを洗い出し、CVSS(Common Vulnerability Scoring System)で脆弱性を評価、</span><span style="color: #000000;">対策を検討し、要件化を通して設計に反映していきます。</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="あ"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/s/sunagaya/20210707/20210707213933.png" alt="f:id:sunagaya:20210707213933p:plain" width="1200" height="384" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">安全分析・リスクアセス・要求プロセス</figcaption> </figure> <figure class="figure-image figure-image-fotolife mceNonEditable" title="あ"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/s/sunagaya/20210708/20210708123119.png" alt="f:id:sunagaya:20210708123119p:plain" width="1200" height="364" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">サイバーセキュリティ分析・リスクアセス・要求プロセス</figcaption> </figure> <p><span style="color: #000000;"> 車両のサイバーセキュリティは一般のコンピュータに比べると分析結果や知見など、まだまだなところがあります。また、自動運転システム自体巨大なシステムになっているのでサイバーセキュリティは安全と同様、膨大な分析と対策検討が必要になってきます。</span></p> <p><span style="color: #000000;"> ティアフォーでは自動運転システムを搭載したPoC車両を開発しています。車両を改造してのシステムになるので、できる範囲からサイバーセキュリティ分析およびその対策を入れてはいますが、まだまだ発展途上という状況です。</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="サイバーセキュリティ分析抜粋"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/s/sunagaya/20210707/20210707215845.png" alt="f:id:sunagaya:20210707215845p:plain" width="450" height="590" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">サイバーセキュリティ分析抜粋</figcaption> </figure> <h4 id="おわりに"><span style="color: #000000;">おわりに</span></h4> <p><span style="color: #000000;"><span style="font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; float: none; display: inline !important;"> 以上、簡単ではありますが、自動車のサイバーセキュリティに関する内容を説明させて頂きました。簡単に表現しすぎているところもあるのでルールの詳細はご確認ください。</span><span style="font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; float: none; display: inline !important;">自動運転のサイバーセキュリティへの対応はソフトウェアに関する部分だけでなく、ハードウェアやシステム、さらに組織体制まで見る必要があり、安全と同様、もしくはそれ以上に大変なものです。したがって自動運転車での対応はそれだけ必要かつチャレンジングになっています。</span></span></p> <p> <span style="color: #000000; font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none;">最後に、改めてになりますが、ティアフォーで自動運転システムのサイバーセキュリティ構築にチャレンジしたい方がおりましたら、</span><span style="color: #000000; font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; background-color: #ffffff; float: none; display: inline !important;">以下のページよりコンタクトいただければと思います。</span><span style="color: #000000; font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; background-color: #ffffff; float: none; display: inline !important;">カジュアルな面談も大歓迎ですので気軽にアクセスください!</span></p> <p><a href="https://careers.tier4.jp/">TIER IV Careers</a></p> <p> </p> sunagaya 自動運転の地図、ベクターマップについて hatenablog://entry/26006613778352266 2021-06-23T16:00:00+09:00 2023-05-24T18:47:59+09:00 こんにちは、ティアフォーでベクターマップの作成ツールの開発をしている浦本と申します。今回は、Autowareで使われている地図の中でも、特にベクターマップとその作成ツールについてお話しようと思います。 なお、ティアフォーでは、「自動運転の民主化」をともに実現していく様々なエンジニア・リサーチャーを募集しています。もしご興味があればカジュアル面談も可能ですので以下のページからコンタクトいただければと思います。 TIER IV Careers tier4.jp 自動運転の地図 点群地図とベクターマップについて Lanelet2について Point LineString Polygon Lanele… <p><span style="font-weight: 400;">こんにちは、ティアフォーでベクターマップの作成ツールの開発をしている浦本と申します。今回は、Autowareで使われている地図の中でも、特にベクターマップとその作成ツールについてお話しようと思います。</span></p> <p data-renderer-start-pos="7448"><span style="font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; float: none; display: inline !important;">なお、ティアフォーでは、「自動運転の民主化</span><span style="font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; float: none; display: inline !important;">」をともに実現していく様々なエンジニア・リサーチャーを募集しています。もしご興味があればカジュアル面談も可能ですので以下のページからコンタクトいただければと思います。</span></p> <p><a href="https://careers.tier4.jp/">TIER IV Careers</a></p> <p><br /><cite class="hatena-citation"><a href="https://tier4.jp/careers/">tier4.jp</a></cite></p> <ul class="table-of-contents"> <li><a href="#自動運転の地図">自動運転の地図</a><ul> <li><a href="#点群地図とベクターマップについて">点群地図とベクターマップについて</a></li> <li><a href="#Lanelet2について">Lanelet2について</a><ul> <li><a href="#Point">Point</a></li> <li><a href="#LineString">LineString</a></li> <li><a href="#Polygon">Polygon</a></li> <li><a href="#Lanelet">Lanelet</a></li> <li><a href="#Area">Area</a></li> <li><a href="#RegulatoryElement">RegulatoryElement</a></li> </ul> </li> </ul> </li> <li><a href="#Vector-Map-Builderの紹介">Vector Map Builderの紹介</a></li> <li><a href="#まとめ">まとめ</a></li> </ul> <h3 id="自動運転の地図"><strong>自動運転の地図</strong></h3> <h4 id="点群地図とベクターマップについて"><strong>点群地図とベクターマップについて</strong></h4> <p><span style="font-weight: 400;">Autowareで使われる地図には、自己位置推定のための点群地図と、その地図上の走行可能領域や信号・標識などを定義したベクターマップがあります。</span></p> <p><span style="font-weight: 400;">Autowareは、道路や周囲の環境の形状を持っている点群地図と、走行中に取得したスキャンデータが最もマッチする重ね合わせから、車両の位置や向きを推定しています。この仕組みをスキャンマッチングといいます。スキャンマッチングについての詳細はこちらをご覧ください。</span></p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftech.tier4.jp%2Fentry%2F2021%2F05%2F06%2F160000" title="読み解くNDT Scan Matchingの計算 [前編] - Tier IV Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://tech.tier4.jp/entry/2021/05/06/160000">tech.tier4.jp</a></cite></p> <p><span style="font-weight: 400;">ベクターマップには、走行可能領域や信号・標識以外にも、速度制限、優先道路などの交通ルールや注意が必要なエリアのような情報を入れることができ、これらの情報を適切に設定することで、車両がその場所に適した走行をできるようにしています。</span></p> <p><span style="font-weight: 400;">Autowareは現在、このベクターマップのフォーマットとしてLanelet2を採用しており、このフォーマットをAutoware用に一部拡張して使っています(これ以降、この記事ではLanelet2はAutoware用に拡張したものを指します)。ティアフォーで開発中のベクターマップ作成ツール、Vector Map Builder (VMB)もこのAutoware拡張のLanelet2の地図作成が可能です。以下の画像はこのツール上で地図を表示している例です。白い点群地図と色がついているベクターマップを重ねています。</span></p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/y/yuramoto/20210621/20210621153302.png" alt="f:id:yuramoto:20210621153302p:plain" width="1200" height="606" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <h4 id="Lanelet2について"><strong>Lanelet2について</strong></h4> <p><span style="font-weight: 400;">ここでは、Lanelet2の詳細について説明したいと思います。</span></p> <p><span style="font-weight: 400;">Lanelet2はOpenStreetMap(OSM)形式を拡張したもので、拡張子は.osm、ファイルに出力する際にはXML形式となります。Lanelet2は以下の基本オブジェクトで構成されますが、出力時にはOSMに合わせてnode、way、relationの3種類に分類されます。各基本オブジェクトの説明とファイルに出力した際のサンプルは以下のとおりです。なお、画像はVMBでの表示例です。</span></p> <h5 id="Point"><strong>Point</strong></h5> <ul> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">一番基本となるオブジェクトで、座標や信号の色情報などを持ちます。</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">OSMのnodeに分類されます。z座標はeleというタグで表されます。</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">ローカル座標を使いたい場合は、local_x、local_yというタグを設定することもできます。</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">lat/lonは緯度経度、local_x、local_y、eleの単位はメートルです。</span></li> </ul> <pre class="code lang-xml" style="overflow: auto; font-family: Monaco, Consolas, 'Courier New', Courier, monospace, sans-serif; font-size: 16px; border: 1px solid #dddddd; margin: 0px 0px 10px; padding: 20px; white-space: pre; color: #111111; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;" data-lang="xml" data-unlink=""><span class="synIdentifier" style="color: #51cfcf;">&lt;node </span><span class="synType" style="color: #3ec63e;">id</span>=<span class="synConstant" style="color: #ff6666;">"1"</span> <span class="synType" style="color: #3ec63e;">lat</span>=<span class="synConstant" style="color: #ff6666;">"35.0000"</span> <span class="synType" style="color: #3ec63e;">lon</span>=<span class="synConstant" style="color: #ff6666;">"139.0000"</span><span class="synIdentifier" style="color: #51cfcf;">&gt;</span>   <span class="synIdentifier" style="color: #51cfcf;">&lt;tag </span><span class="synType" style="color: #3ec63e;">k</span>=<span class="synConstant" style="color: #ff6666;">"ele"</span> <span class="synType" style="color: #3ec63e;">v</span>=<span class="synConstant" style="color: #ff6666;">"19.000"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span> <span class="synIdentifier" style="color: #51cfcf;">&lt;/node&gt;</span></pre> <p> <img src="https://cdn-ak.f.st-hatena.com/images/fotolife/y/yuramoto/20210621/20210621153224.png" alt="f:id:yuramoto:20210621153224p:plain" width="136" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <h5 id="LineString"><strong>LineString</strong></h5> <ul> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">Pointのリストを順番に線で結んだオブジェクト。LineString2つでLaneletを構成したり、信号機や一時停止線に使われます。</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">OSMのwayに分類されます。</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">構成要素のPointをndタグで持ちます。</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;"><span style="font-weight: 400;">一時停止線はtypeをstop_line、点線はsubtypeをdashedにすることで表します。Laneletの境界線のLineStringをdashedにすると隣接レーンに車線変更が可能になるなど、タグの付け方を変えることで様々な設定が可能です。詳細はこちらをご覧ください。</span></span> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fgithub.com%2Ffzi-forschungszentrum-informatik%2FLanelet2%2Fblob%2Fmaster%2Flanelet2_core%2Fdoc%2FLaneletAndAreaTagging.md" title="fzi-forschungszentrum-informatik/Lanelet2" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://github.com/fzi-forschungszentrum-informatik/Lanelet2/blob/master/lanelet2_core/doc/LaneletAndAreaTagging.md">github.com</a></cite></p> </li> </ul> <pre class="code lang-xml" style="overflow: auto; font-family: Monaco, Consolas, 'Courier New', Courier, monospace, sans-serif; font-size: 16px; border: 1px solid #dddddd; margin: 0px 0px 10px; padding: 20px; white-space: pre; color: #111111; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;" data-lang="xml" data-unlink=""><span class="synIdentifier" style="color: #51cfcf;">&lt;way </span><span class="synType" style="color: #3ec63e;">id</span>=<span class="synConstant" style="color: #ff6666;">"1"</span><span class="synIdentifier" style="color: #51cfcf;">&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;nd </span><span class="synType" style="color: #3ec63e;">ref</span>=<span class="synConstant" style="color: #ff6666;">"1"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;nd </span><span class="synType" style="color: #3ec63e;">ref</span>=<span class="synConstant" style="color: #ff6666;">"2"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;nd </span><span class="synType" style="color: #3ec63e;">ref</span>=<span class="synConstant" style="color: #ff6666;">"3"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;nd </span><span class="synType" style="color: #3ec63e;">ref</span>=<span class="synConstant" style="color: #ff6666;">"4"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;tag </span><span class="synType" style="color: #3ec63e;">k</span>=<span class="synConstant" style="color: #ff6666;">"type"</span> <span class="synType" style="color: #3ec63e;">v</span>=<span class="synConstant" style="color: #ff6666;">"line_thin"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;tag </span><span class="synType" style="color: #3ec63e;">k</span>=<span class="synConstant" style="color: #ff6666;">"subtype"</span> <span class="synType" style="color: #3ec63e;">v</span>=<span class="synConstant" style="color: #ff6666;">"solid"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span> <span class="synIdentifier" style="color: #51cfcf;">&lt;/way&gt;</span></pre> <p> <img src="https://cdn-ak.f.st-hatena.com/images/fotolife/y/yuramoto/20210621/20210621153308.png" alt="f:id:yuramoto:20210621153308p:plain" width="351" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <h5 id="Polygon"><strong>Polygon</strong></h5> <ul> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">Pointで囲まれた領域を表します。障害物検知領域を表すDetectionAreaなどで使われます。</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">OSMのwayに分類され、area=yesというタグをつけます。</span></li> </ul> <pre class="code lang-xml" style="overflow: auto; font-family: Monaco, Consolas, 'Courier New', Courier, monospace, sans-serif; font-size: 16px; border: 1px solid #dddddd; margin: 0px 0px 10px; padding: 20px; white-space: pre; color: #111111; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;" data-lang="xml" data-unlink=""><span class="synIdentifier" style="color: #51cfcf;">&lt;way </span><span class="synType" style="color: #3ec63e;">id</span>=<span class="synConstant" style="color: #ff6666;">"1"</span><span class="synIdentifier" style="color: #51cfcf;">&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;nd </span><span class="synType" style="color: #3ec63e;">ref</span>=<span class="synConstant" style="color: #ff6666;">"1"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;nd </span><span class="synType" style="color: #3ec63e;">ref</span>=<span class="synConstant" style="color: #ff6666;">"2"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;nd </span><span class="synType" style="color: #3ec63e;">ref</span>=<span class="synConstant" style="color: #ff6666;">"3"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;nd </span><span class="synType" style="color: #3ec63e;">ref</span>=<span class="synConstant" style="color: #ff6666;">"4"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;tag </span><span class="synType" style="color: #3ec63e;">k</span>=<span class="synConstant" style="color: #ff6666;">"type"</span> <span class="synType" style="color: #3ec63e;">v</span>=<span class="synConstant" style="color: #ff6666;">"detection_area"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;tag </span><span class="synType" style="color: #3ec63e;">k</span>=<span class="synConstant" style="color: #ff6666;">"area"</span> <span class="synType" style="color: #3ec63e;">v</span>=<span class="synConstant" style="color: #ff6666;">"yes"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span> <span class="synIdentifier" style="color: #51cfcf;">&lt;/way&gt;</span></pre> <p> <img src="https://cdn-ak.f.st-hatena.com/images/fotolife/y/yuramoto/20210621/20210621153247.png" alt="f:id:yuramoto:20210621153247p:plain" width="252" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <h5 id="Lanelet"><strong>Lanelet</strong></h5> <ul> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">左右にLineStringを1つずつ持ち、その間の領域を表します。向きを持っており、車線や横断歩道などに使われます。</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">OSMのrelationに分類され、type=laneletというタグをつけます。</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">左右のLineStringをmemberとして持ちます。</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">その車線で守る必要のある交通ルール(RegulatoryElement)がある場合は、それもmemberとして持ちます。</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">制限速度や通行対象(車や歩行者など)、一方通行かどうかなどの情報を持てます。</span></li> </ul> <pre class="code lang-xml" style="overflow: auto; font-family: Monaco, Consolas, 'Courier New', Courier, monospace, sans-serif; font-size: 16px; border: 1px solid #dddddd; margin: 0px 0px 10px; padding: 20px; white-space: pre; color: #111111; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;" data-lang="xml" data-unlink=""><span class="synIdentifier" style="color: #51cfcf;">&lt;relation </span><span class="synType" style="color: #3ec63e;">id</span>=<span class="synConstant" style="color: #ff6666;">"1"</span><span class="synIdentifier" style="color: #51cfcf;">&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;member </span><span class="synType" style="color: #3ec63e;">type</span>=<span class="synConstant" style="color: #ff6666;">"way"</span> <span class="synType" style="color: #3ec63e;">role</span>=<span class="synConstant" style="color: #ff6666;">"left"</span> <span class="synType" style="color: #3ec63e;">ref</span>=<span class="synConstant" style="color: #ff6666;">"1"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;member </span><span class="synType" style="color: #3ec63e;">type</span>=<span class="synConstant" style="color: #ff6666;">"way"</span> <span class="synType" style="color: #3ec63e;">role</span>=<span class="synConstant" style="color: #ff6666;">"right"</span> <span class="synType" style="color: #3ec63e;">ref</span>=<span class="synConstant" style="color: #ff6666;">"2"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;member </span><span class="synType" style="color: #3ec63e;">type</span>=<span class="synConstant" style="color: #ff6666;">"relation"</span> <span class="synType" style="color: #3ec63e;">role</span>=<span class="synConstant" style="color: #ff6666;">"regulatory_element"</span> <span class="synType" style="color: #3ec63e;">ref</span>=<span class="synConstant" style="color: #ff6666;">"2"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;tag </span><span class="synType" style="color: #3ec63e;">k</span>=<span class="synConstant" style="color: #ff6666;">"type"</span> <span class="synType" style="color: #3ec63e;">v</span>=<span class="synConstant" style="color: #ff6666;">"lanelet"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;tag </span><span class="synType" style="color: #3ec63e;">k</span>=<span class="synConstant" style="color: #ff6666;">"subtype"</span> <span class="synType" style="color: #3ec63e;">v</span>=<span class="synConstant" style="color: #ff6666;">"road"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;tag </span><span class="synType" style="color: #3ec63e;">k</span>=<span class="synConstant" style="color: #ff6666;">"speed_limit"</span> <span class="synType" style="color: #3ec63e;">v</span>=<span class="synConstant" style="color: #ff6666;">"50"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;tag </span><span class="synType" style="color: #3ec63e;">k</span>=<span class="synConstant" style="color: #ff6666;">"location"</span> <span class="synType" style="color: #3ec63e;">v</span>=<span class="synConstant" style="color: #ff6666;">"urban"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;tag </span><span class="synType" style="color: #3ec63e;">k</span>=<span class="synConstant" style="color: #ff6666;">"participant:vehicle"</span> <span class="synType" style="color: #3ec63e;">v</span>=<span class="synConstant" style="color: #ff6666;">"yes"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;tag </span><span class="synType" style="color: #3ec63e;">k</span>=<span class="synConstant" style="color: #ff6666;">"one_way"</span> <span class="synType" style="color: #3ec63e;">v</span>=<span class="synConstant" style="color: #ff6666;">"yes"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span> <span class="synIdentifier" style="color: #51cfcf;">&lt;/relation&gt;</span></pre> <p> <img src="https://cdn-ak.f.st-hatena.com/images/fotolife/y/yuramoto/20210621/20210621153241.png" alt="f:id:yuramoto:20210621153241p:plain" width="374" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <h5 id="Area"><strong>Area</strong></h5> <ul> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">LineStringで囲まれた領域を表します。車両や人の通行領域を表す場合によく使われますが、Laneletと違って向きは持ちません。</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">OSMのrelationに分類され、type=multipolygonというタグをつけます。</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">構成要素のLineStringをmemberとして時計回りの順番に持ちます。</span></li> </ul> <pre class="code lang-xml" style="overflow: auto; font-family: Monaco, Consolas, 'Courier New', Courier, monospace, sans-serif; font-size: 16px; border: 1px solid #dddddd; margin: 0px 0px 10px; padding: 20px; white-space: pre; color: #111111; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;" data-lang="xml" data-unlink=""><span class="synIdentifier" style="color: #51cfcf;">&lt;relation </span><span class="synType" style="color: #3ec63e;">id</span>=<span class="synConstant" style="color: #ff6666;">"1"</span><span class="synIdentifier" style="color: #51cfcf;">&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;member </span><span class="synType" style="color: #3ec63e;">type</span>=<span class="synConstant" style="color: #ff6666;">"way"</span> <span class="synType" style="color: #3ec63e;">role</span>=<span class="synConstant" style="color: #ff6666;">"outer"</span> <span class="synType" style="color: #3ec63e;">ref</span>=<span class="synConstant" style="color: #ff6666;">"1"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;member </span><span class="synType" style="color: #3ec63e;">type</span>=<span class="synConstant" style="color: #ff6666;">"way"</span> <span class="synType" style="color: #3ec63e;">role</span>=<span class="synConstant" style="color: #ff6666;">"outer"</span> <span class="synType" style="color: #3ec63e;">ref</span>=<span class="synConstant" style="color: #ff6666;">"2"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;tag </span><span class="synType" style="color: #3ec63e;">k</span>=<span class="synConstant" style="color: #ff6666;">"type"</span> <span class="synType" style="color: #3ec63e;">v</span>=<span class="synConstant" style="color: #ff6666;">"multipolygon"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span> <span class="synIdentifier" style="color: #51cfcf;">&lt;/relation&gt;</span></pre> <p> <img src="https://cdn-ak.f.st-hatena.com/images/fotolife/y/yuramoto/20210621/20210621153227.png" alt="f:id:yuramoto:20210621153227p:plain" width="361" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p><span style="font-weight: 400;">※Polygonとの見た目の違いは、周囲がLineStringで囲まれているかどうかです。</span></p> <h5 id="RegulatoryElement"><strong>RegulatoryElement</strong></h5> <ul> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">一時停止、信号、優先道路などの種類があり、それらがどの車線や一時停止線、信号機と紐付いているのかという情報を持っています。オブジェクト間の紐付けとルール情報を持つだけなので地図上に表示されるものではなく、画像はありません。</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">OSMのrelationに分類されます。type=regulatory_elementというタグをつけます。</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">subtypeでルールの種類を指定します(例:traffic_lightは信号、right_of_wayは優先道路)。</span></li> </ul> <pre class="code lang-xml" style="overflow: auto; font-family: Monaco, Consolas, 'Courier New', Courier, monospace, sans-serif; font-size: 16px; border: 1px solid #dddddd; margin: 0px 0px 10px; padding: 20px; white-space: pre; color: #111111; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;" data-lang="xml" data-unlink=""><span class="synIdentifier" style="color: #51cfcf;">&lt;relation </span><span class="synType" style="color: #3ec63e;">id</span>=<span class="synConstant" style="color: #ff6666;">"1"</span><span class="synIdentifier" style="color: #51cfcf;">&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;member </span><span class="synType" style="color: #3ec63e;">type</span>=<span class="synConstant" style="color: #ff6666;">"way"</span> <span class="synType" style="color: #3ec63e;">role</span>=<span class="synConstant" style="color: #ff6666;">"refers"</span> <span class="synType" style="color: #3ec63e;">ref</span>=<span class="synConstant" style="color: #ff6666;">"1"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;member </span><span class="synType" style="color: #3ec63e;">type</span>=<span class="synConstant" style="color: #ff6666;">"way"</span> <span class="synType" style="color: #3ec63e;">role</span>=<span class="synConstant" style="color: #ff6666;">"light_bulbs"</span> <span class="synType" style="color: #3ec63e;">ref</span>=<span class="synConstant" style="color: #ff6666;">"2"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;member </span><span class="synType" style="color: #3ec63e;">type</span>=<span class="synConstant" style="color: #ff6666;">"way"</span> <span class="synType" style="color: #3ec63e;">role</span>=<span class="synConstant" style="color: #ff6666;">"ref_line"</span> <span class="synType" style="color: #3ec63e;">ref</span>=<span class="synConstant" style="color: #ff6666;">"3"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;tag </span><span class="synType" style="color: #3ec63e;">k</span>=<span class="synConstant" style="color: #ff6666;">"type"</span> <span class="synType" style="color: #3ec63e;">v</span>=<span class="synConstant" style="color: #ff6666;">"regulatory_element"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;tag </span><span class="synType" style="color: #3ec63e;">k</span>=<span class="synConstant" style="color: #ff6666;">"subtype"</span> <span class="synType" style="color: #3ec63e;">v</span>=<span class="synConstant" style="color: #ff6666;">"traffic_light"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span> <span class="synIdentifier" style="color: #51cfcf;">&lt;/relation&gt;</span></pre> <p><span style="font-weight: 400;">RegulatoryElementはルールの種類によってmemberの数や種類も変わってきます。例としてサンプルにも記載している信号を説明します。</span><span style="font-weight: 400;">信号のmemberは3つで、refers、ref_line、light_bulbsがあります。それぞれtypeがwayとなっているので、LineStringがPolygonを表すのですが、信号に紐付くのは全てLineStringです。</span></p> <p><span style="font-weight: 400;">まずはrefersですが、これは信号の外形を表します。ファイルに出力すると以下のwayのようになるのですが、ndの2と3は画像の丸(Point)の部分で信号機の幅を表し、heightタグで高さを表します。</span></p> <pre class="code lang-xml" style="overflow: auto; font-family: Monaco, Consolas, 'Courier New', Courier, monospace, sans-serif; font-size: 16px; border: 1px solid #dddddd; margin: 0px 0px 10px; padding: 20px; white-space: pre; color: #111111; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;" data-lang="xml" data-unlink=""><span class="synIdentifier" style="color: #51cfcf;">&lt;way </span><span class="synType" style="color: #3ec63e;">id</span>=<span class="synConstant" style="color: #ff6666;">"1"</span><span class="synIdentifier" style="color: #51cfcf;">&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;nd </span><span class="synType" style="color: #3ec63e;">ref</span>=<span class="synConstant" style="color: #ff6666;">"2"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;nd </span><span class="synType" style="color: #3ec63e;">ref</span>=<span class="synConstant" style="color: #ff6666;">"3"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;tag </span><span class="synType" style="color: #3ec63e;">k</span>=<span class="synConstant" style="color: #ff6666;">"type"</span> <span class="synType" style="color: #3ec63e;">v</span>=<span class="synConstant" style="color: #ff6666;">"traffic_light"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;tag </span><span class="synType" style="color: #3ec63e;">k</span>=<span class="synConstant" style="color: #ff6666;">"height"</span> <span class="synType" style="color: #3ec63e;">v</span>=<span class="synConstant" style="color: #ff6666;">"0.450000"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span> <span class="synIdentifier" style="color: #51cfcf;">&lt;/way&gt;</span></pre> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/y/yuramoto/20210621/20210621153250.png" alt="f:id:yuramoto:20210621153250p:plain" width="385" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p> <span style="font-weight: 400;">次にlight_bulbsは、以下のwayのようになり、traffic_light_idは信号機の外形のLineStringのidを表しています。ndの4から6はPointで、以下のidが4のnodeのような形でそれぞれcolorタグで信号の色情報を持ちます(画像の信号の場合はred、yellow、greenの3つ)。</span></p> <pre class="code lang-xml" style="overflow: auto; font-family: Monaco, Consolas, 'Courier New', Courier, monospace, sans-serif; font-size: 16px; border: 1px solid #dddddd; margin: 0px 0px 10px; padding: 20px; white-space: pre; color: #111111; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;" data-lang="xml" data-unlink=""><span class="synIdentifier" style="color: #51cfcf;">&lt;way </span><span class="synType" style="color: #3ec63e;">id</span>=<span class="synConstant" style="color: #ff6666;">"2"</span><span class="synIdentifier" style="color: #51cfcf;">&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;nd </span><span class="synType" style="color: #3ec63e;">ref</span>=<span class="synConstant" style="color: #ff6666;">"4"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;nd </span><span class="synType" style="color: #3ec63e;">ref</span>=<span class="synConstant" style="color: #ff6666;">"5"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;nd </span><span class="synType" style="color: #3ec63e;">ref</span>=<span class="synConstant" style="color: #ff6666;">"6"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;tag </span><span class="synType" style="color: #3ec63e;">k</span>=<span class="synConstant" style="color: #ff6666;">"type"</span> <span class="synType" style="color: #3ec63e;">v</span>=<span class="synConstant" style="color: #ff6666;">"light_bulbs"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;tag </span><span class="synType" style="color: #3ec63e;">k</span>=<span class="synConstant" style="color: #ff6666;">"traffic_light_id"</span> <span class="synType" style="color: #3ec63e;">v</span>=<span class="synConstant" style="color: #ff6666;">"1"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span> <span class="synIdentifier" style="color: #51cfcf;">&lt;/way&gt;</span> <span class="synIdentifier" style="color: #51cfcf;">&lt;node </span><span class="synType" style="color: #3ec63e;">id</span>=<span class="synConstant" style="color: #ff6666;">"4"</span> <span class="synType" style="color: #3ec63e;">lat</span>=<span class="synConstant" style="color: #ff6666;">"35.0000"</span> <span class="synType" style="color: #3ec63e;">lon</span>=<span class="synConstant" style="color: #ff6666;">"139.0000"</span><span class="synIdentifier" style="color: #51cfcf;">&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;tag </span><span class="synType" style="color: #3ec63e;">k</span>=<span class="synConstant" style="color: #ff6666;">"ele"</span> <span class="synType" style="color: #3ec63e;">v</span>=<span class="synConstant" style="color: #ff6666;">"19.546"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;tag </span><span class="synType" style="color: #3ec63e;">k</span>=<span class="synConstant" style="color: #ff6666;">"color"</span> <span class="synType" style="color: #3ec63e;">v</span>=<span class="synConstant" style="color: #ff6666;">"red"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span> <span class="synIdentifier" style="color: #51cfcf;">&lt;/node&gt;</span> </pre> <p><span style="font-weight: 400;">最後にref_lineですが、信号のref_lineは信号が赤だった時に停止する停止線を表すため、以下のwayのように、stop_lineというtypeを設定します。</span></p> <pre class="code lang-xml" style="overflow: auto; font-family: Monaco, Consolas, 'Courier New', Courier, monospace, sans-serif; font-size: 16px; border: 1px solid #dddddd; margin: 0px 0px 10px; padding: 20px; white-space: pre; color: #111111; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;" data-lang="xml" data-unlink=""><span class="synIdentifier" style="color: #51cfcf;">&lt;way </span><span class="synType" style="color: #3ec63e;">id</span>=<span class="synConstant" style="color: #ff6666;">"3"</span><span class="synIdentifier" style="color: #51cfcf;">&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;nd </span><span class="synType" style="color: #3ec63e;">ref</span>=<span class="synConstant" style="color: #ff6666;">"7"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;nd </span><span class="synType" style="color: #3ec63e;">ref</span>=<span class="synConstant" style="color: #ff6666;">"8"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span>  <span class="synIdentifier" style="color: #51cfcf;">&lt;tag </span><span class="synType" style="color: #3ec63e;">k</span>=<span class="synConstant" style="color: #ff6666;">"type"</span> <span class="synType" style="color: #3ec63e;">v</span>=<span class="synConstant" style="color: #ff6666;">"stop_line"</span><span class="synIdentifier" style="color: #51cfcf;">/&gt;</span> <span class="synIdentifier" style="color: #51cfcf;">&lt;/way&gt;</span></pre> <p><span style="font-weight: 400;">このようなオブジェクトを組み合わせて、ベクターマップを作っています。</span></p> <h3 id="Vector-Map-Builderの紹介"><strong>Vector Map Builderの紹介</strong></h3> <p><span style="font-weight: 400;">これまで説明してきたようなベクターマップを作成するためのツールとして、ティアフォーではVMBを開発しています。ブラウザで動作するツールで、TypeScript、React、Three.jsを主に使っています。</span></p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/y/yuramoto/20210621/20210621153254.png" alt="f:id:yuramoto:20210621153254p:plain" width="1200" height="575" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p><span style="font-weight: 400;">リンクはこちらになりますが、最初に</span><span style="font-weight: 400;">ティアフォーアカウントを作成いただいてからログインが可能となります。</span></p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftools.tier4.jp%2Fvector_map_builder_ll2%2F" title="Tier IV Account" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://tools.tier4.jp/vector_map_builder_ll2/">tools.tier4.jp</a></cite></p> <p><span style="font-weight: 400;">ここでは、地図を作りやすくするために実装しているVMBの機能を一部紹介します。</span></p> <p><span style="font-weight: 400;">1つ目は、点群地図の表示範囲指定機能です。この機能を使うケースとして、例えば屋内のベクターマップを作成するときに、点群に屋根が入ってしまっていてそのままでは屋内の形状が見にくいというものがあります。そういう場合は、この機能で不要な屋根部分の点群をカットし、見たい範囲の点群だけを見えるようにすることで、地図作成がしやすくなります。他にも、下の画像のように木が邪魔で車線が見づらい場合にも使えたり、上下の高さを指定できるので、ビルのような複数階を含む点群があったときには、見たい階だけを残して作業することも可能です。</span></p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/y/yuramoto/20210621/20210621153244.png" alt="f:id:yuramoto:20210621153244p:plain" width="298" loading="lazy" title="" class="hatena-fotolife" itemprop="image" />   <img src="https://cdn-ak.f.st-hatena.com/images/fotolife/y/yuramoto/20210621/20210621153238.png" alt="f:id:yuramoto:20210621153238p:plain" width="304" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /><br /><span style="font-weight: 400;">2つ目は、地図のリアルタイムチェック機能です。車線や交通ルールが増えて地図が複雑になると、作成・編集時にミスが起こりやすくなり、チェックも大変になります。ミスが残ってしまっていても、地図作成後はシミュレータで動作チェックを実施するため、想定外の挙動をする場合はそこでわかるのですが、複数箇所が間違っているとVMBに戻って該当箇所を修正→走行チェックという作業を何度か繰り返さなければいけない場合があります。</span></p> <p><span style="font-weight: 400;">VMBではそのような作業を少しでも減らすため、フォーマットとして間違っている点に加え、ティアフォーのこれまでの地図作成経験からリストアップしたチェック項目を作成作業中にチェックするようにしています。問題のある設定をすると、その設定を行った直後に問題のあるオブジェクトとその詳細を表示し、修正を促します。また、修正をしないまま地図の保存を行った場合は、問題点が残っていることを表示し、問題点に気づかずに保存してしまうことをできるだけ避けられるようにしています。</span></p> <p><span style="font-weight: 400;">画像は設定している制限速度を超えたLaneletが存在する場合の例です。何が問題なのかという説明とIDを表示しており、IDをクリックすることで該当オブジェクトの設定が確認できるようになっています。</span></p> <p> <img src="https://cdn-ak.f.st-hatena.com/images/fotolife/y/yuramoto/20210621/20210621153232.png" alt="f:id:yuramoto:20210621153232p:plain" width="323" loading="lazy" title="" class="hatena-fotolife" itemprop="image" /></p> <p><span style="font-weight: 400;">チェックすべき項目は、現在も実証実験等から問題を吸い上げたりしながら増やしており、今以上に充実させていく予定です。</span> </p> <h3 id="まとめ"><strong>まとめ</strong></h3> <p><span style="font-weight: 400;">今回は、Autowareで使われている地図の中でも、特にベクターマップについてお話しました。自動運転車がどのような地図を使って走行しているのか、イメージできたでしょうか。</span></p> <p><span style="font-weight: 400;">ベクターマップは精度が求められるので作成時は細かな作業が多く、持たせる情報も多いことから設定とチェックに時間がかかります。これらの問題を解消し、より安全な地図をより早く作ることができるツール・仕組みの開発<span style="color: #000000;">をこれからも進めていきます。</span></span></p> yuramoto Autowareの開発を更に加速!Openなシナリオテストフレームワークを紹介! hatenablog://entry/26006613703948721 2021-06-17T16:00:00+09:00 2023-05-24T18:48:16+09:00 はじめに こんにちは!ティアフォーの片岡と申します。 本日は、ティアフォーのSimulation Teamで開発してきたシナリオテストフレームワークであるscenario_simulatorをApache-2.0ライセンスでOSS(オープンソースソフトウェア)とした件についてお話します。 github.comまた、ティアフォーでは「自動運転の民主化」をともに実現すべく、ロボット技術、ゲームエンジンを使った開発等幅広い分野に知見を持ったSimulation Engineerを募集しております。 自動運転のSimulator開発は、バグの少ない高品質なコードを書くのはもちろんのこと、三次元幾何や統… <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/m/masaya-kataoka/20210527/20210527135238.png" width="1200" height="630" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> <div class="section"> <h3 id="はじめに">はじめに</h3> <p>こんにちは!ティアフォーの片岡と申します。<br /> 本日は、ティアフォーのSimulation Teamで開発してきたシナリオテストフレームワークであるscenario_simulatorをApache-2.0ライセンスでOSS(オープンソースソフトウェア)とした件についてお話します。<br /> <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fgithub.com%2Ftier4%2Fscenario_simulator_v2" title="GitHub - tier4/scenario_simulator_v2: A scenario-based simulation framework for Autoware" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://github.com/tier4/scenario_simulator_v2">github.com</a></cite></p><p>また、ティアフォーでは「自動運転の民主化」をともに実現すべく、ロボット技術、ゲームエンジンを使った開発等幅広い分野に知見を持ったSimulation Engineerを募集しております。<br /> 自動運転のSimulator開発は、バグの少ない高品質なコードを書くのはもちろんのこと、三次元幾何や統計、はてはプログラミング言語開発まで様々な知識が要求される分野であり、広く深く様々なことをやってみたい方には非常にマッチするポジションであると思います。<br /> もし興味等ございましたら以下のページよりコンタクトいただければ大変幸いです。<br /> カジュアルな面談等も大歓迎です!<br /> <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftier4.jp%2Fcareer%2F" title="TIER IV Careers" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://tier4.jp/career/">tier4.jp</a></cite></p> <ul class="table-of-contents"> <li><a href="#はじめに">はじめに</a></li> <li><a href="#Autoware開発におけるSimulation-Test">Autoware開発におけるSimulation Test</a><ul> <li><a href="#ティアフォーで行われているSimulation-Testの種類">ティアフォーで行われているSimulation Testの種類</a></li> <li><a href="#AutowareをサポートしているSimulator">AutowareをサポートしているSimulator</a><ul> <li><a href="#SVL-Simulator">SVL Simulator</a></li> <li><a href="#CARLA-Simulator">CARLA Simulator</a></li> <li><a href="#AutoCore-Simulator">AutoCore Simulator</a></li> <li><a href="#Simple-Planning-Simulator">Simple Planning Simulator</a></li> </ul> </li> <li><a href="#複数のSimulatorを使う場合に起こる問題点">複数のSimulatorを使う場合に起こる問題点</a><ul> <li><a href="#シナリオフォーマットがSimulatorに依存している">シナリオフォーマットがSimulatorに依存している</a></li> <li><a href="#NPCロジックがSimulatorごとに異なる">NPCロジックがSimulatorごとに異なる</a></li> <li><a href="#SimulatorごとにIntegrationの仕方が違う">SimulatorごとにIntegrationの仕方が違う</a></li> <li><a href="#シナリオフォーマットは現在も技術開発が盛んな領域">シナリオフォーマットは現在も技術開発が盛んな領域</a></li> </ul> </li> <li><a href="#ティアフォーのシナリオテストフレームワークのアプローチ">ティアフォーのシナリオテストフレームワークのアプローチ</a><ul> <li><a href="#Co-Simulation-Modelの採用">Co-Simulation Modelの採用</a></li> <li><a href="#シナリオテストフレームワークとシナリオ解釈器のコンポーネント分離">シナリオテストフレームワークとシナリオ解釈器のコンポーネント分離</a></li> <li><a href="#Simulatorを抽象化">Simulatorを抽象化</a></li> <li><a href="#Open-Source">Open Source</a></li> </ul> </li> </ul> </li> <li><a href="#ティアフォーのシナリオテストフレームワークのアーキテクチャ">ティアフォーのシナリオテストフレームワークのアーキテクチャ</a><ul> <li><a href="#アーキテクチャ全体の紹介">アーキテクチャ全体の紹介</a></li> <li><a href="#開発時に注力した要素">開発時に注力した要素</a><ul> <li><a href="#レーン座標系のサポート">レーン座標系のサポート</a></li> <li><a href="#強化されたNPCロジック">強化されたNPCロジック</a></li> <li><a href="#自動テスト">自動テスト</a></li> </ul> </li> </ul> </li> <li><a href="#今後の開発計画">今後の開発計画</a><ul> <li><a href="#NPCロジックの更なる性能向上">NPCロジックの更なる性能向上</a></li> <li><a href="#公道走行ログからのシナリオ自動起こし">公道走行ログからのシナリオ自動起こし</a></li> </ul> </li> </ul> </div> <div class="section"> <h3 id="Autoware開発におけるSimulation-Test">Autoware開発におけるSimulation Test</h3> <div class="section"> <h4 id="ティアフォーで行われているSimulation-Testの種類">ティアフォーで行われているSimulation Testの種類</h4> <p>現在ティアフォーではSimulatorによってそれぞれ得意・不得意な領域があることを認識しており、テストケースごとに適切なSimulatorを選定し評価を行っています。<br /> <span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/m/masaya-kataoka/20210316/20210316160300.png" width="1200" height="676" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span></p> </div> <div class="section"> <h4 id="AutowareをサポートしているSimulator">AutowareをサポートしているSimulator</h4> <p>上の図で記されているのは大枠のカテゴリであり、実際にはAutoware対応のSimulatorには様々なものが存在しています。代表的なものには以下のようなものがあります。</p> <div class="section"> <h5 id="SVL-Simulator">SVL Simulator</h5> <p><iframe width="560" height="315" src="https://www.youtube.com/embed/6n5Gl1-7QZ8?start=608&feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen title="Unity x 自動運転シミュレーション、自動運転におけるGame Engineの役割"></iframe><cite class="hatena-citation"><a href="https://youtu.be/6n5Gl1-7QZ8?t=608">youtu.be</a></cite><br /> <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fgithub.com%2Flgsvl%2Fsimulator" title="GitHub - lgsvl/simulator: A ROS/ROS2 Multi-robot Simulator for Autonomous Vehicles" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://github.com/lgsvl/simulator">github.com</a></cite><br /> LGエレクトロニクスのシリコンバレー研究所が開発しているUnityベースのSimulatorで、Pythonでテストシナリオを記述できます。<br /> LiDARやCameraを多数取り付けたリッチな自動運転システムがSimulation可能です。</p> </div> <div class="section"> <h5 id="CARLA-Simulator">CARLA Simulator</h5> <p><iframe width="560" height="315" src="https://www.youtube.com/embed/7jej46ALVRE?start=145&feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen title="CARLA 0.9.10"></iframe><cite class="hatena-citation"><a href="https://youtu.be/7jej46ALVRE?t=145">youtu.be</a></cite><br /> <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fgithub.com%2Fcarla-simulator%2Fcarla" title="GitHub - carla-simulator/carla: Open-source simulator for autonomous driving research." class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://github.com/carla-simulator/carla">github.com</a></cite><br /> IntelやToyota Research Instituteの出資のものとOpen Sourceで開発されているUnreal EngineベースのSimulatorで、OpenSCENARIO V1.0やPython等でテストシナリオを記述できます。<br /> 野心的な機能が多数盛り込まれており、非常に高機能なSimulatorです。</p> </div> <div class="section"> <h5 id="AutoCore-Simulator">AutoCore Simulator</h5> <p><iframe width="560" height="315" src="https://www.youtube.com/embed/CUFMKZAbgCk?start=62&feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen title="AutoCore Open Source Simulator"></iframe><cite class="hatena-citation"><a href="https://youtu.be/CUFMKZAbgCk?t=62">youtu.be</a></cite><br /> <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fgithub.com%2Fautowarefoundation%2Fautocore_sim" title="GitHub - autowarefoundation/autocore_sim: A ROS1/ROS2 Multi-robot Simulator for Autoware" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://github.com/autowarefoundation/autocore_sim">github.com</a></cite><br /> The Autoware Foundation (AWF) メンバーのAutoCoreが開発したUnityベースのSimulatorです。<br /> 非常に軽量でGTX750Tiでも動作可能になっています。</p> </div> <div class="section"> <h5 id="Simple-Planning-Simulator">Simple Planning Simulator</h5> <p><iframe width="560" height="315" src="https://www.youtube.com/embed/6n5Gl1-7QZ8?start=701&feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen title="Unity x 自動運転シミュレーション、自動運転におけるGame Engineの役割"></iframe><cite class="hatena-citation"><a href="https://youtu.be/6n5Gl1-7QZ8?t=701">youtu.be</a></cite><br /> <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fgithub.com%2Ftier4%2FAutowareArchitectureProposal.iv%2Ftree%2Fmaster%2Fsimulator%2Fsimple_planning_simulator" title="AutowareArchitectureProposal.iv/simulator/simple_planning_simulator at use-autoware-auto-msgs · tier4/AutowareArchitectureProposal.iv" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://github.com/tier4/AutowareArchitectureProposal.iv/tree/master/simulator/simple_planning_simulator">github.com</a></cite><br /> AutowareArchitectureProposalに同梱されているSimulatorです。<br /> ROSノードとして実装されており、OpenSCENARIO V0.9.2をベースとしたティアフォーの独自フォーマットでのシナリオ記述が可能で、軽量であるため非常に高速に動作します。</p> </div> </div> <div class="section"> <h4 id="複数のSimulatorを使う場合に起こる問題点">複数のSimulatorを使う場合に起こる問題点</h4> <p>複数のSimulatorを使ってシナリオテストを行っていく過程でティアフォーは以下のような問題に直面しました。</p> <div class="section"> <h5 id="シナリオフォーマットがSimulatorに依存している">シナリオフォーマットがSimulatorに依存している</h5> <p>汎用なシナリオフォーマットはOpenSCENARIO等様々なものが提案されていますが、Simulator固有の拡張が入っていたり、SVL Simulator等独自シナリオフォーマットを中心としているようなSimulatorも多いため、一度書いたシナリオを使い回すのは簡単ではありません。<br /> シナリオを異なるSimulatorの間でやり取りするには人力で動作確認をしながらポーティングを行う必要があり、シナリオ変更履歴のトレーサビリティの観点からも大きな問題があります。</p> </div> <div class="section"> <h5 id="NPCロジックがSimulatorごとに異なる">NPCロジックがSimulatorごとに異なる</h5> <p>完全に等価なシナリオを人力でポーティングできたとしても、それを処理する処理系が異なるのであれば処理結果は異なってしまいます。<br /> 具体的な例として、「車の前に自転車が飛び出す」という状況を考えてみましょう。<br /> <span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/m/masaya-kataoka/20210316/20210316212415.png" width="450" height="418" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><br /> これをシナリオに起こす時、以下のような処理が記述されることになります。</p> <ol> <li>ある地点から N(m) 以内に自車両が入った時</li> <li>自転車のNPCをSpawnさせ、Waypointを与える。</li> </ol><p>ここで、自転車NPCの行動ロジックがSimulator Aでは「直線の点列をカクカクなぞる」、Simulator Bでは「スプライン補間したあと単純追跡コントローラでその経路をできるだけなぞる」のように異なっていた場合、これらは等価なテストシナリオとは言えません。<br /> こういったNPC行動ロジックは厳密に一致している必要があります。<br /> これをCARLAやSVL Simulatorに備わっているテストランナーの枠組み上で解決しようとすると、彼らのソースコードに含まれる何千行ものNPC行動ロジック記述部分に手を入れて異なる言語やプラットフォームを超えて完全に等価なロジックを実装し、メンテナンスし続けなくてはなりません。<br /> これはほとんど不可能に近いと言えます。<br /> こういった問題を解決するために仕様策定されたのがOpenSCENARIOですが、例えば以下のような基本的な箇所ですら未定義動作が非常に多く、OpenSCENARIOに対応したからと言って一度書いたシナリオがすべてのSimulatorで簡単に動くということは担保できません。</p><p>OpenSCENARIO V1.0の未定義動作の例</p> <ul> <li>道路端点や世界の端に到達したNPCはどう振る舞うべきか</li> <li>AssignRouteActionで経路指定した結果ゴールに到達したNPCはそのまま走っていくべきか、それともその場で停止するべきか</li> <li>レーンチェンジができない場所でレーンチェンジ指示が出た場合はどのような挙動をすべきか</li> </ul> </div> <div class="section"> <h5 id="SimulatorごとにIntegrationの仕方が違う">SimulatorごとにIntegrationの仕方が違う</h5> <p>例えばCARLAにおいては独自ブリッジでROSおよびAutowareとのIntegrationを行っており、ブリッジ内部でPID制御器が動いていたりと他のSimulatorと全く異なるロジックで制御がなされています。<br /> <iframe width="560" height="315" src="https://www.youtube.com/embed/ChIgcC2scwU?start=256&feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen title="CARLA Talks 2020 - Integration of Autoware and ROS"></iframe><cite class="hatena-citation"><a href="https://youtu.be/ChIgcC2scwU?t=256">youtu.be</a></cite><br /> 他にも、SVL SimulatorはAutowareとrosbridgeで接続しており、ROSの標準的なツールを用いてインターフェースが設計されています。<br /> <a href="https://www.lgsvlsimulator.com/docs/autoware-instructions/">https://www.lgsvlsimulator.com/docs/autoware-instructions/</a><cite class="hatena-citation"><a href="https://www.lgsvlsimulator.com/docs/autoware-instructions/">www.lgsvlsimulator.com</a></cite><br /> このように、Simulatorごとに根本的に異なるインターフェースが設計されており、これはクラウド上にテストパイプラインを構築、メンテナンスしていく上で大きな障害になります。<br /> また、明示的な標準仕様がないため、新しいSimulatorをIntegrationする際には毎回設計を1からやり直す必要があり莫大な工数が発生することになります。</p> </div> <div class="section"> <h5 id="シナリオフォーマットは現在も技術開発が盛んな領域">シナリオフォーマットは現在も技術開発が盛んな領域</h5> <p>現在シナリオフォーマットには様々なものが提案されています。<br /> 例えば、ASAMという標準化団体が提唱しているOpenSCENARIO V1.0が有名です。<br /> <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.asam.net%2Fstandards%2Fdetail%2Fopenscenario%2F" title="Detail" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://www.asam.net/standards/detail/openscenario/">www.asam.net</a></cite><br /> その他にも、現在策定が進められているOpenSCENARIO V2.0およびそのベースとなっているM-SDL<br /> <iframe width="560" height="315" src="https://www.youtube.com/embed/puM8v8KIK2k?start=2112&feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen title="Webinar: Open M-SDL for scenario-based verification of ADAS &amp; Autonomous Vehicles"></iframe><cite class="hatena-citation"><a href="https://youtu.be/puM8v8KIK2k?t=2112">youtu.be</a></cite><br /> といった様々なフォーマットが現在も開発されています。<br /> 産業界だけでなく、2019年ので発表されたGeoSCENARIO等アカデミア方面からも研究開発が進められています。<br /> <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fgeoscenario.readthedocs.io%2Fen%2Flatest%2F" title="Home - GeoScenario" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://geoscenario.readthedocs.io/en/latest/">geoscenario.readthedocs.io</a></cite><br /> どのシナリオフォーマットをどう使うのがAutowareの評価を最も効率化できるのかというのは未だ結論が出ていない領域の1つです。<br /> そのため、同時に複数のシナリオフォーマットをサポートできるようなシナリオテストフレームワークが強く求められます。</p><p>ティアフォーにおいてはこれらの問題点を以下のアプローチで解決しました。</p> </div> </div> <div class="section"> <h4 id="ティアフォーのシナリオテストフレームワークのアプローチ">ティアフォーのシナリオテストフレームワークのアプローチ</h4> <div class="section"> <h5 id="Co-Simulation-Modelの採用">Co-Simulation Modelの採用</h5> <p>すべてのSimulatorにおいてNPCロジックを共通化するため、NPCロジックをシナリオテストフレームワーク中の交通流Simulatorに対して実装しました。<br /> センサSimulatorが交通流Simulatorとプロセス間通信を行い、歩調を合わせながらCo-SimulationをすることでNPCロジック共通化を実現しています。<br /> これにより、交通流SimulatorはセンサSimulatorに対するOpenSCENARIOの「翻訳機」かのように振る舞い、OpenSCENARIOの未定義動作によるSimulatorごとの差異を吸収します。<br /> プロセス間通信はすべて同期呼び出しで実装されており、シナリオテストフレームワークのうちROS 2に依存しない部分に関しては決定性を担保しています。</p> </div> <div class="section"> <h5 id="シナリオテストフレームワークとシナリオ解釈器のコンポーネント分離">シナリオテストフレームワークとシナリオ解釈器のコンポーネント分離</h5> <p>シナリオテストフレームワークにC++ APIを用意し、シナリオフォーマットの解釈器がそれを叩くアーキテクチャ構成にすることで同時に複数のシナリオフォーマットをサポートしています。<br /> 完全にコンポーネントが分離されているので、スッキリとしたアーキテクチャに仕上がっています。</p> </div> <div class="section"> <h5 id="Simulatorを抽象化">Simulatorを抽象化</h5> <p>SimulatorとAutowareとのインターフェースを統一し、複数のSimulatorを同時にサポートできるシナリオテストフレームワークを開発しました。<br /> Autowareとの結合部分や、NPCロジックで使われている微分幾何アルゴリズムやHD MapとのインテグレーションをSimulatorで独自実装する必要はありません。<br /> また、Autowareは非常に高い頻度で更新が行われているソフトウェアであり、常に結合確認を取りながらインテグレーションを行う必要があり、メンテナンスコストが非常に高いです。<br /> これらの複雑で開発を難航させる原因になりがちなロジックはすべてシナリオテストフレームワークに含まれていますし、メンテナンスもティアフォーのSimulation Team主体で行っているため、Simulator開発者は短期間でSimulatorとAutowareを結合し、その結合を維持することが非常に簡単になりSimulatorとしてより本質的なセンサSimulationの高精度化や車両の運動モデルといった開発に時間を使うことができるようになります。</p> </div> <div class="section"> <h5 id="Open-Source">Open Source</h5> <p>更に、ティアフォーではこのシナリオテストフレームワークをオープンにすることでAutowareを様々なSimulator上で動かしてAutowareの評価を更に高速化していく仕組みを担保しようと考えています。<br /> ライセンスはApache-2.0で統一されているため非常に使いやすいツール群となっています。</p> </div> </div> </div> <div class="section"> <h3 id="ティアフォーのシナリオテストフレームワークのアーキテクチャ">ティアフォーのシナリオテストフレームワークのアーキテクチャ</h3> <div class="section"> <h4 id="アーキテクチャ全体の紹介">アーキテクチャ全体の紹介</h4> <figure class="figure-image figure-image-fotolife" title="シナリオテストフレームワークを構成するツールチェイン"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/m/masaya-kataoka/20210614/20210614182842.png" width="830" height="576" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>シナリオテストフレームワークを構成するツールチェイン</figcaption></figure><p>本シナリオテストフレームワークのAWFの公式シナリオフォーマットであるTier IV Scenario Format version 2.0フォーマットあるいはテストシーケンスを記述したworkflowファイルの読み込みは、テストを起動するScenario Test Runner、OpenSCENARIO 1.0フォーマットで記述されたシナリオを解釈するOpenSCENARIO Interpreter、交通流をSimulationするTraffic Simulatorおよび本フレームワークにセンサSimulatorを統合する際の簡易なセンサSimulatorのリファレンス実装となるSimple Sensor Simulatorが含まれています。<br /> OpenSCENARIO InterpreterおよびTraffic Simulatorは下のような実装になっており、シングルプロセスなROS 2 Nodeとして実装されています。</p> <figure class="figure-image figure-image-fotolife" title="シナリオテストフレームワーク全体アーキテクチャ"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/m/masaya-kataoka/20210316/20210316221411.png" width="1200" height="319" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>シナリオテストフレームワークアーキテクチャ</figcaption></figure><p>ティアフォーのシナリオテストフレームワークはAutowareとSimulatorの間をつなぐ役割を果たします。<br /> シナリオテストフレームワークはROS 2との通信部分以外がシングルスレッドで動作する単独のROS 2 nodeとして設計されており、ROS 2 topicをPub / Subする部分を除いて完全に決定性があります。<br /> シナリオテストフレームワークと通信してCo-Simulationを行うSimulatorはZeroMQで同期的に通信を行います。<br /> <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fzeromq.org%2F" title="ZeroMQ" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://zeromq.org/">zeromq.org</a></cite><br /> ZeroMQは様々な言語をサポートしており、Unity (C#)やUnreal Engine (C++)等様々な言語、プラットフォームで作られているSimulatorと簡単に通信することができます。<br /> また、ZeroMQで送信されるデータはProtocol Buffersを使ってシリアライズすることで、スキーマを明確に定義してSimulator開発者がインターフェースが変わったことをすぐに把握できるよう工夫しています。<br /> <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fdevelopers.google.com%2Fprotocol-buffers" title="Protocol Buffers" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://developers.google.com/protocol-buffers">developers.google.com</a></cite><br /> SimulatorとROS 2はAutoware APIというAutowareを操作するために定義されたROS 2 topic群を利用して通信します。シナリオテストフレームワークは内部にBehavior Treeを用いたNPCロジックやHD Map管理機構を内包しており、それらを操作できるC++のインターフェースを備えています。<br /> まず第一弾としてSimulatorに依存しないシナリオフォーマットの代表格の一つであるOpenSCENARIO V1.0をシナリオフォーマットとして採用し、シナリオテストフレームワークのC++ Interfaceを叩いてOpenSCENARIO規格に基づいてSimulationを行えるツールを開発しました。<br /> その過程で動作確認用に副次的に生まれたC++ Scenario(ROS 2ノードからシナリオテストフレームワークのインターフェースをダイレクトに操作して実現)の誕生により、はからずも複数シナリオフォーマットをサポートすることが可能なアーキテクチャであることが立証されました。<br /> 下のC++ Scenarioのサンプルコードに示すような非常に簡易な指示をscenario_simulator::APIクラス(シナリオテストフレームワークとのC++ Interface)を経由して出すだけでSimulator内部のNPCの行動を制御することが可能です。</p> <pre class="code lang-cpp" data-lang="cpp" data-unlink><span class="synComment">// Copyright 2021 Tier IV, Inc. All rights reserved.</span> <span class="synComment">//</span> <span class="synComment">// Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);</span> <span class="synComment">// you may not use this file except in compliance with the License.</span> <span class="synComment">// You may obtain a copy of the License at</span> <span class="synComment">//</span> <span class="synComment">// http://www.apache.org/licenses/LICENSE-2.0</span> <span class="synComment">//</span> <span class="synComment">// Unless required by applicable law or agreed to in writing, software</span> <span class="synComment">// distributed under the License is distributed on an &quot;AS IS&quot; BASIS,</span> <span class="synComment">// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</span> <span class="synComment">// See the License for the specific language governing permissions and</span> <span class="synComment">// limitations under the License.</span> <span class="synPreProc">#include </span><span class="synConstant">&lt;quaternion_operation/quaternion_operation.h&gt;</span> <span class="synPreProc">#include </span><span class="synConstant">&lt;ament_index_cpp/get_package_share_directory.hpp&gt;</span> <span class="synPreProc">#include </span><span class="synConstant">&lt;rclcpp/rclcpp.hpp&gt;</span> <span class="synPreProc">#include </span><span class="synConstant">&lt;traffic_simulator/api/api.hpp&gt;</span> <span class="synPreProc">#include </span><span class="synConstant">&lt;traffic_simulator/metrics/metrics.hpp&gt;</span> <span class="synComment">// headers in STL</span> <span class="synPreProc">#include </span><span class="synConstant">&lt;memory&gt;</span> <span class="synPreProc">#include </span><span class="synConstant">&lt;string&gt;</span> <span class="synPreProc">#include </span><span class="synConstant">&lt;utility&gt;</span> <span class="synPreProc">#include </span><span class="synConstant">&lt;vector&gt;</span> <span class="synComment">// headers in pugixml</span> <span class="synPreProc">#include </span><span class="synConstant">&quot;pugixml.hpp&quot;</span> <span class="synType">class</span> ScenarioRunnerMoc : <span class="synStatement">public</span> rclcpp::Node { <span class="synStatement">public</span>: <span class="synStatement">explicit</span> <span class="synIdentifier">ScenarioRunnerMoc</span>(<span class="synType">const</span> rclcpp::NodeOptions &amp; option) : <span class="synIdentifier">Node</span>(<span class="synConstant">&quot;scenario_runner&quot;</span>, option), <span class="synIdentifier">api_</span>( <span class="synStatement">this</span>, <span class="synConstant">__FILE__</span>, ament_index_cpp::<span class="synIdentifier">get_package_share_directory</span>(<span class="synConstant">&quot;kashiwanoha_map&quot;</span>) + <span class="synConstant">&quot;/map/lanelet2_map.osm&quot;</span>, <span class="synConstant">5</span>) { api_.<span class="synIdentifier">setVerbose</span>(<span class="synConstant">true</span>); api_.<span class="synIdentifier">initialize</span>(<span class="synConstant">1.0</span>, <span class="synConstant">0.05</span>); pugi::xml_document catalog_xml_doc; catalog_xml_doc.<span class="synIdentifier">load_string</span>(catalog_xml.<span class="synIdentifier">c_str</span>()); <span class="synType">auto</span> vehicle_params = traffic_simulator::entity::<span class="synIdentifier">VehicleParameters</span>(catalog_xml_doc).<span class="synIdentifier">toRosMsg</span>(); vehicle_params.name = <span class="synConstant">&quot;ego&quot;</span>; api_.<span class="synIdentifier">spawn</span>(<span class="synConstant">false</span>, <span class="synConstant">&quot;ego&quot;</span>, vehicle_params); api_.<span class="synIdentifier">setEntityStatus</span>( <span class="synConstant">&quot;ego&quot;</span>, traffic_simulator::helper::<span class="synIdentifier">constructLaneletPose</span>(<span class="synConstant">120545</span>, <span class="synConstant">0</span>), traffic_simulator::helper::<span class="synIdentifier">constructActionStatus</span>(<span class="synConstant">10</span>)); api_.<span class="synIdentifier">setTargetSpeed</span>(<span class="synConstant">&quot;ego&quot;</span>, <span class="synConstant">15</span>, <span class="synConstant">true</span>); pugi::xml_document pedestrian_xml_doc; pedestrian_xml_doc.<span class="synIdentifier">load_string</span>(pedestrian_xml.<span class="synIdentifier">c_str</span>()); <span class="synType">const</span> <span class="synType">auto</span> pedestrian_params = traffic_simulator::entity::<span class="synIdentifier">PedestrianParameters</span>(pedestrian_xml_doc).<span class="synIdentifier">toRosMsg</span>(); api_.<span class="synIdentifier">spawn</span>(<span class="synConstant">false</span>, <span class="synConstant">&quot;tom&quot;</span>, pedestrian_params); api_.<span class="synIdentifier">setEntityStatus</span>( <span class="synConstant">&quot;tom&quot;</span>, <span class="synConstant">&quot;ego&quot;</span>, traffic_simulator::helper::<span class="synIdentifier">constructPose</span>(<span class="synConstant">10</span>, <span class="synConstant">3</span>, <span class="synConstant">0</span>, <span class="synConstant">0</span>, <span class="synConstant">0</span>, -<span class="synConstant">1.57</span>), traffic_simulator::helper::<span class="synIdentifier">constructActionStatus</span>()); api_.<span class="synIdentifier">requestWalkStraight</span>(<span class="synConstant">&quot;tom&quot;</span>); api_.<span class="synIdentifier">setTargetSpeed</span>(<span class="synConstant">&quot;tom&quot;</span>, <span class="synConstant">3</span>, <span class="synConstant">true</span>); api_.<span class="synIdentifier">spawn</span>( <span class="synConstant">false</span>, <span class="synConstant">&quot;bob&quot;</span>, pedestrian_params, traffic_simulator::helper::<span class="synIdentifier">constructLaneletPose</span>(<span class="synConstant">34378</span>, <span class="synConstant">0.0</span>), traffic_simulator::helper::<span class="synIdentifier">constructActionStatus</span>(<span class="synConstant">1</span>)); api_.<span class="synIdentifier">setTargetSpeed</span>(<span class="synConstant">&quot;bob&quot;</span>, <span class="synConstant">1</span>, <span class="synConstant">true</span>); vehicle_params.name = <span class="synConstant">&quot;npc1&quot;</span>; api_.<span class="synIdentifier">spawn</span>( <span class="synConstant">false</span>, <span class="synConstant">&quot;npc1&quot;</span>, vehicle_params, traffic_simulator::helper::<span class="synIdentifier">constructLaneletPose</span>(<span class="synConstant">34579</span>, <span class="synConstant">20.0</span>), traffic_simulator::helper::<span class="synIdentifier">constructActionStatus</span>(<span class="synConstant">5</span>)); api_.<span class="synIdentifier">setTargetSpeed</span>(<span class="synConstant">&quot;npc1&quot;</span>, <span class="synConstant">5</span>, <span class="synConstant">true</span>); lanechange_executed_ = <span class="synConstant">false</span>; vehicle_params.name = <span class="synConstant">&quot;npc2&quot;</span>; api_.<span class="synIdentifier">spawn</span>( <span class="synConstant">false</span>, <span class="synConstant">&quot;npc2&quot;</span>, vehicle_params, traffic_simulator::helper::<span class="synIdentifier">constructLaneletPose</span>(<span class="synConstant">34606</span>, <span class="synConstant">20.0</span>), traffic_simulator::helper::<span class="synIdentifier">constructActionStatus</span>(<span class="synConstant">5</span>)); api_.<span class="synIdentifier">setTargetSpeed</span>(<span class="synConstant">&quot;npc2&quot;</span>, <span class="synConstant">0</span>, <span class="synConstant">true</span>); api_.<span class="synIdentifier">requestAssignRoute</span>( <span class="synConstant">&quot;ego&quot;</span>, <span class="synConstant">std</span>::<span class="synType">vector</span>&lt;openscenario_msgs::msg::LaneletPose&gt;{ traffic_simulator::helper::<span class="synIdentifier">constructLaneletPose</span>(<span class="synConstant">34675</span>, <span class="synConstant">0.0</span>), traffic_simulator::helper::<span class="synIdentifier">constructLaneletPose</span>(<span class="synConstant">34690</span>, <span class="synConstant">0.0</span>)}); api_.<span class="synIdentifier">requestAcquirePosition</span>( <span class="synConstant">&quot;npc1&quot;</span>, traffic_simulator::helper::<span class="synIdentifier">constructLaneletPose</span>(<span class="synConstant">34675</span>, <span class="synConstant">0.0</span>)); api_.<span class="synIdentifier">spawn</span>(<span class="synConstant">false</span>, <span class="synConstant">&quot;npc3&quot;</span>, vehicle_params); api_.<span class="synIdentifier">setEntityStatus</span>( <span class="synConstant">&quot;npc3&quot;</span>, traffic_simulator::helper::<span class="synIdentifier">constructLaneletPose</span>(<span class="synConstant">34468</span>, <span class="synConstant">0</span>), traffic_simulator::helper::<span class="synIdentifier">constructActionStatus</span>(<span class="synConstant">10</span>)); <span class="synComment">/*</span> <span class="synComment"> api_.addMetric&lt;metrics::TraveledDistanceMetric&gt;(&quot;ego_traveled_distance&quot;, &quot;ego&quot;);</span> <span class="synComment"> api_.addMetric&lt;metrics::MomentaryStopMetric&gt;(</span> <span class="synComment"> &quot;ego_momentary_stop0&quot;, &quot;ego&quot;,</span> <span class="synComment"> -10, 10, 34805, metrics::MomentaryStopMetric::StopTargetLaneletType::STOP_LINE,</span> <span class="synComment"> 30, 1, 0.05);</span> <span class="synComment"> api_.addMetric&lt;metrics::MomentaryStopMetric&gt;(</span> <span class="synComment"> &quot;ego_momentary_stop1&quot;, &quot;ego&quot;,</span> <span class="synComment"> -10, 10, 120635, metrics::MomentaryStopMetric::StopTargetLaneletType::STOP_LINE,</span> <span class="synComment"> 30, 1, 0.05);</span> <span class="synComment"> api_.addMetric&lt;metrics::MomentaryStopMetric&gt;(</span> <span class="synComment"> &quot;ego_momentary_stop_crosswalk&quot;, &quot;ego&quot;,</span> <span class="synComment"> -10, 10, 34378, metrics::MomentaryStopMetric::StopTargetLaneletType::CROSSWALK,</span> <span class="synComment"> 30, 1, 0.05);</span> <span class="synComment"> */</span> <span class="synConstant">std</span>::<span class="synType">vector</span>&lt;<span class="synConstant">std</span>::<span class="synType">pair</span>&lt;<span class="synType">double</span>, traffic_simulator::TrafficLightColor&gt;&gt; phase; phase = { {<span class="synConstant">10</span>, traffic_simulator::TrafficLightColor::GREEN}, {<span class="synConstant">10</span>, traffic_simulator::TrafficLightColor::YELLOW}, {<span class="synConstant">10</span>, traffic_simulator::TrafficLightColor::RED}}; api_.<span class="synIdentifier">setTrafficLightColorPhase</span>(<span class="synConstant">34802</span>, phase); <span class="synStatement">using</span> <span class="synType">namespace</span> <span class="synConstant">std</span>::<span class="synConstant">chrono_literals</span>; update_timer_ = <span class="synStatement">this</span>-&gt;<span class="synIdentifier">create_wall_timer</span>(50ms, <span class="synConstant">std</span>::<span class="synIdentifier">bind</span>(&amp;ScenarioRunnerMoc::update, <span class="synStatement">this</span>)); } <span class="synStatement">private</span>: <span class="synType">void</span> <span class="synIdentifier">update</span>() { <span class="synStatement">if</span> (api_.<span class="synIdentifier">getCurrentTime</span>() &gt;= <span class="synConstant">4</span> &amp;&amp; api_.<span class="synIdentifier">entityExists</span>(<span class="synConstant">&quot;tom&quot;</span>)) { api_.<span class="synIdentifier">despawn</span>(<span class="synConstant">&quot;tom&quot;</span>); } <span class="synComment">/*</span> <span class="synComment"> if (api_.getLinearJerk(&quot;ego&quot;)) {</span> <span class="synComment"> std::cout &lt;&lt; &quot;ego linear jerk :&quot; &lt;&lt; api_.getLinearJerk(&quot;ego&quot;).get() &lt;&lt; std::endl;</span> <span class="synComment"> }</span> <span class="synComment"> */</span> <span class="synStatement">if</span> (api_.<span class="synIdentifier">reachPosition</span>( <span class="synConstant">&quot;ego&quot;</span>, traffic_simulator::helper::<span class="synIdentifier">constructLaneletPose</span>(<span class="synConstant">34615</span>, <span class="synConstant">10.0</span>), <span class="synConstant">5</span>)) { api_.<span class="synIdentifier">requestAcquirePosition</span>( <span class="synConstant">&quot;ego&quot;</span>, traffic_simulator::helper::<span class="synIdentifier">constructLaneletPose</span>(<span class="synConstant">35026</span>, <span class="synConstant">0.0</span>)); <span class="synStatement">if</span> (api_.<span class="synIdentifier">entityExists</span>(<span class="synConstant">&quot;npc2&quot;</span>)) { api_.<span class="synIdentifier">setTargetSpeed</span>(<span class="synConstant">&quot;npc2&quot;</span>, <span class="synConstant">13</span>, <span class="synConstant">true</span>); } } <span class="synStatement">if</span> (api_.<span class="synIdentifier">reachPosition</span>(<span class="synConstant">&quot;ego&quot;</span>, traffic_simulator::helper::<span class="synIdentifier">constructLaneletPose</span>(<span class="synConstant">34579</span>, <span class="synConstant">0.0</span>), <span class="synConstant">5</span>)) { api_.<span class="synIdentifier">requestAcquirePosition</span>( <span class="synConstant">&quot;ego&quot;</span>, traffic_simulator::helper::<span class="synIdentifier">constructLaneletPose</span>(<span class="synConstant">34675</span>, <span class="synConstant">0.0</span>)); <span class="synStatement">if</span> (api_.<span class="synIdentifier">entityExists</span>(<span class="synConstant">&quot;npc2&quot;</span>)) { api_.<span class="synIdentifier">setTargetSpeed</span>(<span class="synConstant">&quot;npc2&quot;</span>, <span class="synConstant">3</span>, <span class="synConstant">true</span>); } } <span class="synStatement">if</span> (api_.<span class="synIdentifier">reachPosition</span>( <span class="synConstant">&quot;npc2&quot;</span>, traffic_simulator::helper::<span class="synIdentifier">constructLaneletPose</span>(<span class="synConstant">34513</span>, <span class="synConstant">0.0</span>), <span class="synConstant">5</span>)) { api_.<span class="synIdentifier">requestAcquirePosition</span>( <span class="synConstant">&quot;npc2&quot;</span>, traffic_simulator::helper::<span class="synIdentifier">constructLaneletPose</span>(<span class="synConstant">34630</span>, <span class="synConstant">0.0</span>)); api_.<span class="synIdentifier">setTargetSpeed</span>(<span class="synConstant">&quot;npc2&quot;</span>, <span class="synConstant">13</span>, <span class="synConstant">true</span>); } <span class="synComment">/*</span> <span class="synComment"> if (api_.checkCollision(&quot;ego&quot;, &quot;npc1&quot;)) {</span> <span class="synComment"> std::cout &lt;&lt; &quot;npc1 collision!&quot; &lt;&lt; std::endl;</span> <span class="synComment"> }</span> <span class="synComment"> if (api_.checkCollision(&quot;ego&quot;, &quot;npc2&quot;)) {</span> <span class="synComment"> std::cout &lt;&lt; &quot;npc2 collision!&quot; &lt;&lt; std::endl;</span> <span class="synComment"> }</span> <span class="synComment"> */</span> <span class="synStatement">if</span> (api_.<span class="synIdentifier">getCurrentTime</span>() &gt; <span class="synConstant">10.0</span> &amp;&amp; api_.<span class="synIdentifier">entityExists</span>(<span class="synConstant">&quot;bob&quot;</span>)) { api_.<span class="synIdentifier">despawn</span>(<span class="synConstant">&quot;bob&quot;</span>); } api_.<span class="synIdentifier">updateFrame</span>(); } <span class="synType">bool</span> lanechange_executed_; <span class="synType">bool</span> target_speed_set_; <span class="synType">int</span> port_; traffic_simulator::API api_; rclcpp::TimerBase::SharedPtr update_timer_; <span class="synConstant">std</span>::<span class="synType">string</span> catalog_xml = <span class="synSpecial">R&quot;(</span><span class="synConstant">&lt;Vehicle name= 'vehicle.volkswagen.t2' vehicleCategory='car'&gt;</span> <span class="synConstant"> &lt;ParameterDeclarations/&gt;</span> <span class="synConstant"> &lt;Performance maxSpeed='69.444' maxAcceleration='200' maxDeceleration='10.0'/&gt;</span> <span class="synConstant"> &lt;BoundingBox&gt;</span> <span class="synConstant"> &lt;Center x='1.5' y='0.0' z='0.9'/&gt;</span> <span class="synConstant"> &lt;Dimensions width='2.1' length='4.5' height='1.8'/&gt;</span> <span class="synConstant"> &lt;/BoundingBox&gt;</span> <span class="synConstant"> &lt;Axles&gt;</span> <span class="synConstant"> &lt;FrontAxle maxSteering='0.5' wheelDiameter='0.6' trackWidth='1.8' positionX='3.1' positionZ='0.3'/&gt;</span> <span class="synConstant"> &lt;RearAxle maxSteering='0.0' wheelDiameter='0.6' trackWidth='1.8' positionX='0.0' positionZ='0.3'/&gt;</span> <span class="synConstant"> &lt;/Axles&gt;</span> <span class="synConstant"> &lt;Properties&gt;</span> <span class="synConstant"> &lt;Property name='type' value='ego_vehicle'/&gt;</span> <span class="synConstant"> &lt;/Properties&gt;</span> <span class="synConstant"> &lt;/Vehicle&gt;</span><span class="synSpecial">)&quot;</span>; <span class="synConstant">std</span>::<span class="synType">string</span> pedestrian_xml = <span class="synSpecial">R&quot;(</span><span class="synConstant">&lt;Pedestrian model='bob' mass='0.0' name='Bob' pedestrianCategory='pedestrian'&gt;</span> <span class="synConstant"> &lt;BoundingBox&gt;</span> <span class="synConstant"> &lt;Center x='0.0' y='0.0' z='0.5'/&gt;</span> <span class="synConstant"> &lt;Dimensions width='1.0' length='1.0' height='2.0'/&gt;</span> <span class="synConstant"> &lt;/BoundingBox&gt;</span> <span class="synConstant"> &lt;Properties/&gt;</span> <span class="synConstant"> &lt;/Pedestrian&gt;</span><span class="synSpecial">)&quot;</span>; }; <span class="synType">int</span> <span class="synIdentifier">main</span>(<span class="synType">int</span> argc, <span class="synType">char</span> * argv[]) { rclcpp::<span class="synIdentifier">init</span>(argc, argv); rclcpp::NodeOptions options; <span class="synType">const</span> <span class="synType">auto</span> component = <span class="synConstant">std</span>::<span class="synIdentifier">make_shared</span>&lt;ScenarioRunnerMoc&gt;(options); rclcpp::<span class="synIdentifier">spin</span>(component); rclcpp::<span class="synIdentifier">shutdown</span>(); <span class="synStatement">return</span> <span class="synConstant">0</span>; } </pre><p>このように、ROS 2と密にIntegrationされ非常に簡易に使用できるインターフェースとなっていますので、今後他のシナリオフォーマットを採用する必要が出た場合は、その解釈器さえ書いてしまえば簡単にAutoware、Simulatorと接続を行うことができます。</p> </div> <div class="section"> <h4 id="開発時に注力した要素">開発時に注力した要素</h4> <p>シナリオテストフレームワーク開発においては、以下の要素に対して開発時に大きく注力しました。</p> <div class="section"> <h5 id="レーン座標系のサポート">レーン座標系のサポート</h5> <p>レーン座標系とは、レーンに沿って歪んだ座標系のことです(いわゆるフレネ座標系です)。</p> <figure class="figure-image figure-image-fotolife" title="https://releases.asam.net/OpenSCENARIO/1.0.0/ASAM_OpenSCENARIO_BS-1-2_User-Guide_V1-0-0.html#_cut_in"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/m/masaya-kataoka/20210316/20210316231351.png" width="300" height="150" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption><a href="https://releases.asam.net/OpenSCENARIO/1.0.0/ASAM_OpenSCENARIO_BS-1-2_User-Guide_V1-0-0.html#_cut_in">https://releases.asam.net/OpenSCENARIO/1.0.0/ASAM_OpenSCENARIO_BS-1-2_User-Guide_V1-0-0.html#_cut_in</a></figcaption></figure><p>みなさんが公道で車を運転する時、「前30mにトラックがいる」というとそれはデカルト座標系で距離を計算したら30m先にトラックがいるという意味ではなくレーンに沿ってこのまま進んだら30m先にトラックがいるという意味になるかと思います。<br /> レーン座標系でシナリオが記述できないと、直感的な記述ができず非常にシナリオ記述が煩雑なものとなります。<br /> また、レーン座標系を計算する時にはスプライン曲線等のパラメトリック曲線で点列を補間する処理が入るのですが、どんな式の形のパラメトリック曲線を使用するかで補間の結果は全く異なります。<br /> そのため、シナリオテストフレームワークでは内部にレーン座標系、ワールド座標系、物体間の相対座標系を相互に座標変換するAPIを備えており、Simulatorとプロセス間通信する際に渡される情報ではすべての物体位置はワールド座標系で記述されています。<br /> これらの座標変換はtfを介さずにフルスクラッチで実装されていますので、完全に決定性があります。<br /> この仕組みを導入することによってSimulatorはレーン座標系をサポートするためにHD Mapを解釈する必要がなくなり、AutowareとIntegrationする際の工数を大幅に削減することができる上、どのSimulatorを使っても完全に同じロジックで座標変換が行われるのでクオリティの担保が非常にやりやすくなります。</p> </div> <div class="section"> <h5 id="強化されたNPCロジック">強化されたNPCロジック</h5> <p>Autowareに同梱されているSimple Planning SimulatorのNPCロジックは非常にシンプルなものでした。</p> <ul> <li>レーンに沿って動く</li> <li>NPCの前方にBounding Boxを設け、その中に他のNPCやAutowareの車両が入った場合急ブレーキを踏む</li> </ul><p>実装されていたロジックはこの2点のみです。<br /> これではシナリオライターはNPCの一挙手一投足を指定しなければならず、シナリオ作成に大きな負荷が発生していました。<br /> そこでBehavior Treeを使用してNPCロジックを大幅に強化し、以下のような挙動を明示的に指示しなくても自動的にやってくれるようにしました。</p> <ul> <li>レーンに沿ってNPCが移動する。</li> <li>赤、黄色信号の前で停止する。</li> <li>HD Mapに埋め込まれた法定速度を遵守して走行する。</li> <li>明示的に速度指示があった場合にはそちらを目標速度として走行する。</li> <li>一時停止線で一時停止後、発車する。</li> <li>非優先道路において優先道路に他の車両がいる場合道を譲る。</li> <li>レーン座標系でみて自分の前方に車両がいる場合、速度を合わせて追従する。</li> <li>レーンチェンジの指示が出た場合、レーンチェンジ可能な地点であればレーンチェンジを行う。</li> <li>レーンチェンジが不可なエリアであった場合、レーンチェンジは行わない。</li> </ul> </div> <div class="section"> <h5 id="自動テスト">自動テスト</h5> <p>自動運転のテストパイプラインを運用していく上で「Simulatorにバグがあった」というケースは非常に厄介です。徹底的にバグは潰していかないといけませんし、早期発見しなくてはなりません。<br /> Simulatorにバグがあった場合、テスト担当の方はかなり深くSimulatorのソースコードやシナリオを追って問題の根源を考えないといけません。このコストは非常に高いですし、致命的な不具合が見つかった場合過去のテスト結果が信用できなくなる可能性もありえます。<br /> 大きなコード規模(2021年5月21日現在、リポジトリ全体で36481行)を誇るROS 2パッケージ群であるシナリオテストフレームワークはなにか致命的な問題が見つかったからといって簡単に大規模なリファクタや修正をすることはできませんし、機能追加やバグフィックスによってデグレが発生しうることは容易に想像できます。</p> <figure class="figure-image figure-image-fotolife" title="シナリオテストフレームワークのコード規模"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/m/masaya-kataoka/20210520/20210520184802.png" width="1200" height="780" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>シナリオテストフレームワークのコード規模</figcaption></figure><p>そこで、シナリオテストフレームワークの開発においてはGitHub Actionsを使用して以下のテストケースをシナリオテストフレームワーク本体のCIとして継続的に回しています。</p><p><figure class="figure-image figure-image-fotolife" title="GitHub ActionsでCIを実行している様子"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/m/masaya-kataoka/20210520/20210520181818.png" width="1200" height="459" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>GitHub ActionsでCIを実行している様子</figcaption></figure></p> <table> <tr> <th>テスト項目 </th> <th>テスト内容</th> <th>トリガー</th> </tr> <tr> <td>BuildTest</td> <td>リポジトリに含まれる各ROS 2パッケージが独立にビルドできること</br>各種linterチェックが通ること</br>単体テストの実施</br></td> <td>毎朝9時</br>PRへの更新</br>手動</td> </tr> <tr> <td>ScenarioTest</td> <td>リポジトリに含まれるパッケージ全体をビルド</br>結合テストの実施</br>テストの分岐網羅率チェック</br></td> <td>毎朝9時</br>PRへの更新</br>手動</td> </tr> <tr> <td>Docker</td> <td>(PRへの更新時)DockerImageのビルド</br>(master更新時)DockerImageのビルドとDocker Hubへのpush</td> <td>毎朝9時</br>PRへの更新</br>master更新</br>手動</td> </tr> <tr> <td>Documentation</td> <td>(PRへの更新時)ドキュメントのビルド</br>(その他)ドキュメントのビルドとGitHub Pagesへのデプロイ</td> <td>毎朝9時</br>PRへの更新</br>master更新</br>手動</td> </tr> <tr> <td>Release</td> <td>CHANGELOG発行とバージョン付与</td> <td>手動</td> </tr> <tr> <td>SpellCheck</td> <td>ドキュメント、ソースコードに対してスペルチェック</td> <td>PRへの更新</td> </tr> </table><p>単にテストケースを回すだけでなくGitHub Pagesに常に最新版ドキュメントがデプロイされるようになっています。<br /> これにより簡単に最新版のドキュメントにアクセスすることができます。</p><p><a href="https://tier4.github.io/scenario_simulator_v2/">https://tier4.github.io/scenario_simulator_v2/</a><cite class="hatena-citation"><a href="https://tier4.github.io/scenario_simulator_v2/">tier4.github.io</a></cite><br /> </p> </div> </div> </div> <div class="section"> <h3 id="今後の開発計画">今後の開発計画</h3> <p>今後ティアフォーのSimulation Teamでは以下のような改良をシナリオテストフレームワークに加えることを計画しています。</p> <div class="section"> <h4 id="NPCロジックの更なる性能向上">NPCロジックの更なる性能向上</h4> <p>現状のNPCロジックはある程度賢く動いてシナリオライターの作業負荷を大きく軽減してくれるものの、左折時の割り込みや信号無視、速度制限の超過といったより抽象的な指示を簡単に出せるようにするにはNPCロジックを更に賢くしていく必要があります。<br /> 現在、ICRA2020で発表されたこちらのNPCロジックを改良し、Autowareの更なるシナリオテスト効率化を推し進めていこうと考えています。</p><p><iframe width="560" height="315" src="https://www.youtube.com/embed/rF-n52gnMw0?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen title="SUMMIT: A Simulator for Urban Driving in Massive Mixed Traffic"></iframe><cite class="hatena-citation"><a href="https://www.youtube.com/watch?v=rF-n52gnMw0">www.youtube.com</a></cite><br /> <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Farxiv.org%2Fabs%2F1911.04074" title="SUMMIT: A Simulator for Urban Driving in Massive Mixed Traffic" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://arxiv.org/abs/1911.04074">arxiv.org</a></cite><br /> </p> </div> <div class="section"> <h4 id="公道走行ログからのシナリオ自動起こし">公道走行ログからのシナリオ自動起こし</h4> <p>公道走行中にあったヒヤリハットの状況をSimulatorの中で再現し、安全であることを検証する取り組みは非常に重要です。<br /> 以前紹介したRSSは公道において発生した危険な状況を数値化することが可能となります。<br /> <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftech.tier4.jp%2Fentry%2F2021%2F03%2F17%2F160000" title="Intelのad-rss-libを大解剖!RSSのライブラリのアーキテクチャと中身を解説する! - TIER IV Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://tech.tier4.jp/entry/2021/03/17/160000">tech.tier4.jp</a></cite><br /> Simulation TeamではRSS等のメトリクスを用いて検出した危険な状況のデータを取り出し、周囲の交通状況を自動的にシナリオ化する技術開発にもトライしていこうと考えています。</p><br /> <p>最後に改めてですが、興味等ございましたら以下のページよりコンタクトいただければ大変ありがたいです。<br /> カジュアルな面談も大歓迎です!<br /> <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftier4.jp%2Fcareer%2F" title="TIER IV Careers" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" loading="lazy"></iframe><cite class="hatena-citation"><a href="https://tier4.jp/career/">tier4.jp</a></cite></p><p>よろしくお願いいたします。</p> </div> </div> masaya-kataoka 読み解くNDT Scan Matchingの計算 [前編] hatenablog://entry/26006613722479125 2021-05-06T16:00:00+09:00 2023-05-24T18:48:44+09:00 こんにちは、ティアフォーパートタイムエンジニアの上野と、ティアフォーエンジニアの村上です。 今回読み解いたのは、自動運転位置推定のターニングポイントとなった、Scan Matchingによる高精度自己位置推定技術の華、NDT Scan Matchingです。点と点のMatchingから、点と分布のMatchingにすることで、計算負荷が現実的な程度まで削減されました。方法としては博士論文 M. Magnusson, “The three-dimensional normal-distributions transform : an efficient representation for re… <p><span style="color: #000000;">こんにちは、ティアフォーパートタイムエンジニアの上野と、ティアフォーエンジニアの村上です。</span></p> <p><span style="color: #000000;">今回読み解いたのは、自動運転位置推定のターニングポイントとなった、Scan Matchingによる高精度自己位置推定技術の華、NDT Scan Matchingです。点と点のMatchingから、点と分布のMatchingにすることで、計算負荷が現実的な程度まで削減されました。方法としては博士論文 <em>M. Magnusson, “The three-dimensional normal-distributions transform : an efficient representation for registration, surface analysis, and loop detection,” PhD dissertation, Örebro universitet, Örebro, 2009. </em>で説かれており、また論文中の方程式は、Autowareの実装コードの中でも度々言及されています。</span></p> <p><span style="color: #000000;">しかしながら、LiDARを使用した高精度な位置推定に今や必須となったこの方法は、なおも計算負荷が比較的高いままです。</span><span style="color: #000000;">計算負荷の観点でも目にする機会が多いこのアルゴリズムを、定量的/実装的な観点からあらためて見てみましょう。</span></p> <p><span style="color: #000000;">NDT Scan Matcherについて、Autowareが用いている実装としては、全体的には <a href="https://github.com/tier4/AutowareArchitectureProposal.iv/blob/3461b8f28db76546ad81d0d6566a5eaa79b95305/localization/pose_estimator/ndt_scan_matcher/ndt_omp/include/ndt_omp/ndt_omp_impl.hpp" style="color: #000000;">ndt_scan_matcher_core.cpp</a>、部分的には <a href="https://github.com/tier4/AutowareArchitectureProposal.iv/blob/3461b8f28db76546ad81d0d6566a5eaa79b95305/localization/pose_estimator/ndt_scan_matcher/ndt_omp/include/ndt_omp/ndt_omp_impl.hpp" style="color: #000000;">ndt_omp_impl.hpp</a> に主要な処理が記述されています。</span></p> <p><span style="color: #000000;">主要な処理は、その負荷の大きさや計算の姿から大きくは、1. 移動がある自動運転におけるMatchingスコア値収束性能向上のための「近傍地図点群の取得処理」と、2. LiDAR点群と近傍地図点群のDistributionを用いた「Matchingスコア値計算処理」との2つの処理に大別されます。</span></p> <p><span style="color: #000000;">以下にndt scan matcherのflame-graph画像を上げます。初期位置/姿勢の推定処理である <span class="code" style="white-space: pre-wrap;" spellcheck="false">alignUsingMonteCarlo</span> 部分を除外し <span class="code" style="white-space: pre-wrap;" spellcheck="false">callbackSensorPoints</span> 直下に注目します。</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="ndt scan matcher flame graph"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/j/james-murakami/20210430/20210430102443.jpg" alt="f:id:james-murakami:20210430102443j:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable"><span style="color: #000000;">ndt scan matcher; flame graph</span></figcaption> </figure> <p><span style="color: #000000;"><span class="code" style="white-space: pre-wrap;" spellcheck="false">KdTreeFLANN::radiusSearch</span>が1. 近傍地図点群の取得の部分で、これが大体40%近い処理量となります。その他の <span class="code" style="white-space: pre-wrap;" spellcheck="false">computeDerivatives</span> がおおよそ2. Matchingスコア値の計算をしている、演算中心の部分です。</span></p> <p><span style="color: #000000;">前半の今回は、まず入力として入ってきたLiDAR点それぞれに対し、物理的に近傍な地図点群を取得する方法を詳しく見ていきたいと思います。</span></p> <h3 id="Radius-Search-on-KD-Tree"><span style="color: #000000;">Radius Search on KD-Tree</span></h3> <p><span style="color: #000000;">近傍地図点群(のvoxel)を取得する方法には、木探索による方法と、位置をkeyとしたhashからvoxel(とその上下左右前後にあるvoxel)を直ちに求める方法の、大きく2種類があります。</span></p> <p><span style="color: #000000;">ここで取得される近傍voxelの数は、続く演算処理量を線形に増加させることに注意します。代表的な関数だけを抽出すると、以下の図のような関係となります。</span></p> <p><span style="color: #000000;"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/j/james-murakami/20210430/20210430102547.png" alt="f:id:james-murakami:20210430102547p:plain" title="" class="hatena-fotolife" itemprop="image" /></span></p> <p><span style="color: #000000;">木探索は近傍判定を精密にし、それ自体の処理量は重いですが、結果として近傍数が減少傾向となります。対してhash引きは、近傍判定を等閑にするため軽く、結果として近傍数が増加傾向となり、Scan Matching全体の処理量は増加する可能性があります。下のグラフにもこのことは表れています。</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="Radius Search(木探索)の場合のLiDAR InputsとNeighbor Voxelsの関係 (縦: 個数, 横: LiDAR frame)"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/T/TierIV/20210504/20210504213000.png" alt="f:id:TierIV:20210504213000p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable"> <p><span style="color: #000000;">Radius Search(木探索)の場合のLiDAR InputsとNeighbor Voxelsの関係</span></p> <p><span style="color: #000000;">(縦: 個数, 横: LiDAR frame)</span></p> </figcaption> </figure> <figure class="figure-image figure-image-fotolife mceNonEditable" title="HASH引き(周辺26voxel)の場合のLiDAR InputsとNeighbor Voxelsの関係 (縦: 個数, 横: LiDAR frame)"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/T/TierIV/20210504/20210504213051.png" alt="f:id:TierIV:20210504213051p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable"> <p><span style="color: #000000;">HASH引き(周辺26voxel)の場合のLiDAR InputsとNeighbor Voxelsの関係</span></p> <p><span style="color: #000000;">(縦: 個数, 横: LiDAR frame)</span></p> </figcaption> </figure> <p><span style="color: #000000;">近傍の多寡による処理量のトレードオフとともに、”近さ”の正確さは、位置推定精度にも大きく関わるため、判定方法の選択にはこれらを総合的に勘案して採用することになります。Autowareを使用する際のTuning対象として、様々な近傍探索の実装例や実証実験での採用例があります。</span></p> <p><span style="color: #000000;">ティアフォーでは表題の通りKD木(K-Dimensions tree)上でのRadius Searchを使用しており、今回はこの探索を見ていきたいと思います。</span></p> <h4 id="地図のKD木の構築方法"><span style="color: #000000;">地図のKD木の構築方法</span></h4> <p><span style="color: #000000;">KD木とは多次元(K-Dimensions)空間を分割して作る二分木です。KD木の構築は、多次元空間を各座標軸に垂直に分割していくことで行われます。KD木の各ノードは多次元空間の部分空間に対応しており、あるノードの子ノードに対応する空間は、親ノードの空間に包含されるという関係にあります。</span></p> <p><span style="color: #000000;">以下、地図点群からKD木を構築する方法について、具体的に説明します。なお、簡単にするために2次元を例として用いますが、実際にAutowareで用いられている地図は3次元であることは留意してください。また、空間の分割はX軸 → Y軸 → X軸 → … と交互に行われることとします。</span></p> <p><span style="color: #000000;">{(2, 3), (5, 4), (9, 6), (4, 7), (8, 1), (7, 2)}という6つの点から成る点群から構築する手順を以下のGIFで示します。</span></p> <p><span style="color: #000000;"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/j/james-murakami/20210430/20210430102818.gif" alt="f:id:james-murakami:20210430102818g:plain" title="" class="hatena-fotolife" itemprop="image" /></span></p> <p><span style="color: #000000;">まず最初に、全体の空間をX軸で2分割するにあたって、点群全体をX軸の値でソートし中央の点 (7, 2)を中心とし、全体を分割します。この時の中心が木のルートノードとなります。</span></p> <p><span style="color: #000000;">続いて、ルートノードから見て左側の子ノードを構築します。2段目ではY軸の値でソートし、中央となる(5, 4)を中心に2分割します。ルートノードから見て左側の構築が葉まで完了したら、最後に右側の子ノードを構築していきます。</span></p> <p><span style="color: #000000;">このようにKD木を構築すると、この2次元空間は下図のような領域に分割されることになります。</span></p> <div data-node-type="mediaSingle" data-layout="center" data-width=""> <p><span style="color: #000000;"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/j/james-murakami/20210430/20210430102931.png" alt="f:id:james-murakami:20210430102931p:plain" title="" class="hatena-fotolife" itemprop="image" /></span></p> </div> <h4 id="Radius-Search"><span style="color: #000000;">Radius Search</span></h4> <p><span style="color: #000000;">次に、上で構築した木構造に対してクエリ点(入力点)を与え、Radius Searchを行う方法について説明します。</span><span style="color: #000000;">例として、点(6, 1)から半径2以内の距離にあるノードを、Radius Searchで取得します。</span></p> <p><span style="color: #000000;"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/j/james-murakami/20210430/20210430103024.gif" alt="f:id:james-murakami:20210430103024g:plain" title="" class="hatena-fotolife" itemprop="image" /></span></p> <p><span style="color: #000000;">アニメーションの通り、深さ優先探索となります。近傍点の判定は、木を降りていく途中で各ノードに対応する分割点と与えられた点との距離を比較し、所与の半径以内であるか否かで行います。</span></p> <p><span style="color: #000000;">まず最初に、ルートノードの分割点とクエリ点のX軸の値を比較します。今回は、クエリ点のX軸の値の方が小さいため、左側の子ノードに降りていきます。また、ルートノードの分割点 (7, 2) とクエリ点 (6, 1) の距離は2以下であるので、このノード(7, 2)自身も近傍として判定します。</span></p> <p><span style="color: #000000;">次に、分割点とクエリ点のY軸の値を比べ、先と同様に、左右どちらの子ノードに降りるかを決定します。今回は(2, 3) のノードに降ります。さて、(5, 4)のノードとの距離は2より大なので、これは近傍点ではありません。また、(2, 3)のノードは葉ノードとなり、これ以上は探索しません。そして(2, 3)のノードもまた近傍点とは判定されません。</span></p> <p><span style="color: #000000;">正確に近傍点を探すためには、木を降りるだけではなく「登る」処理が必要となります。葉ノードに到達した後、一度1つ上の(5, 4)のノードに登ります。そして、最初に探索しなかった側の子ノード以下に近傍点が存在するかどうかの判定を行います。</span></p> <p><span style="color: #000000;">判定には、分割点 (5, 4) とクエリ点 (6, 1) のY軸の値の差の絶対値と探索半径との比較を用います。この時、探索半径の方が小さくなり、このことは (5, 4) のノードから見て右側の子ノード以下には近傍点が存在し得ないことを意味しますので、右側の子ノードに降りる必要はなく、探索は打切となります。</span></p> <p><span style="color: #000000;">上の手順で降りた方向とは逆の枝を判定しつつ、木を順に登っていき、ルートノードまで登ってくることになります。ルートノードでも、最初に降りた方向とは逆、つまり例の場合右側の子ノード以下に近傍点が存在するか確かめましょう。ルートノードにおいて、分割点とクエリ点のX軸の値の差は探索半径よりも小さいので、右側の子ノード以下に近傍点が存在する可能性があります。よって、右側の子ノード側へも改めて降りていき、探索を行っていきます。</span></p> <p><span style="color: #000000;">後は同様の手順を行い、結果として (7, 2) と (8, 1) の2点がクエリ点 (6, 1) の近傍として取得されます。</span></p> <p><span style="color: #000000;">ただし、近傍探索の精度よりも高速性を重視する場合、葉ノードに到達した時点で近傍探索を打ち切る、すなわち「登る」処理を行わないことも考えられます。Autowareにおけるこの近傍探索はFLANN (Fast Library for Approximate Nearest Neighbors) というライブラリを用いていますが、このライブラリにおいても、実際「登る」側の処理は行われていません。</span></p> <p><span style="color: #000000;">以下、OpenCLとして再実装を行いますが、同様の方針を取ることにします。</span></p> <h3 id="木構築とRadius-Searchの再実装"><span style="color: #000000;">木構築とRadius Searchの再実装</span></h3> <p><span style="color: #000000;">この節ではKD木の構築を純粋なCとして再実装し、KD木を用いたRadius SearchをLiDAR点に対して並列化するためにOpenCLを用いて実装します。</span></p> <p><span style="color: #000000;">LiDARの各点の処理や探索は、各点独立して並列に行うことができ、並列化のうまみが大きい部分です。また、KD木の構築も移植性やメモリ配置の透明性をもたせるため、Cとして再実装を行っています。</span></p> <p><span style="color: #000000;">探索コード: <a data-inline-card="" href="https://github.com/yuteno/kdtree_radius_search_opencl" data-card-data="" style="color: #000000;">https://github.com/yuteno/kdtree_radius_search_opencl</a></span></p> <p><span style="color: #000000;">なお、KD木の構築は<a data-inline-card="" href="https://github.com/fj-th/kd-tree-C-language-" data-card-data="" style="color: #000000;">https://github.com/fj-th/kd-tree-C-language-</a> のコードを参考にし、<span class="code" style="white-space: pre-wrap;" spellcheck="false">kdtree_construction.h</span>に実装しています(元のコードは2次元平面上の点群の分割を行なっているため、これを3次元に拡張する形で変更しています)。</span></p> <pre class="code lang-cpp" style="overflow: auto; font-family: Monaco, Consolas, 'Courier New', Courier, monospace, sans-serif; font-size: 16px; border: 1px solid #dddddd; margin: 0px 0px 10px; padding: 20px; white-space: pre; color: #111111; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;" data-lang="cpp" data-unlink="">kdtree_node * kdtree(kdtree_node * root_node, <span class="synType" style="color: #3ec63e;">unsigned</span> * alloc_pointer, <span class="synType" style="color: #3ec63e;">struct</span> point * pointlist, <span class="synType" style="color: #3ec63e;">int</span> left, <span class="synType" style="color: #3ec63e;">int</span> right, <span class="synType" style="color: #3ec63e;">unsigned</span> depth, <span class="synType" style="color: #3ec63e;">int</span> * node_indexes) { <span class="synStatement" style="color: #d88a17;">if</span> (right &lt; <span class="synConstant" style="color: #ff6666;">0</span>) { <span class="synComment" style="color: #4f80e5;">// not allocate</span> <span class="synStatement" style="color: #d88a17;">return</span> <span class="synConstant" style="color: #ff6666;">NULL</span>; } <span class="synComment" style="color: #4f80e5;">// allocate</span> kdtree_node * new_node = &amp;root_node[*alloc_pointer]; *alloc_pointer = *alloc_pointer + <span class="synConstant" style="color: #ff6666;">1</span>; <span class="synComment" style="color: #4f80e5;">// count up</span> <span class="synComment" style="color: #4f80e5;">// index list included in this node</span> new_node-&gt;left_index = left; new_node-&gt;right_index = left + right + <span class="synConstant" style="color: #ff6666;">1</span>; <span class="synComment" style="color: #4f80e5;">// tree's depth</span> new_node-&gt;depth = depth; <span class="synType" style="color: #3ec63e;">int</span> median = right / <span class="synConstant" style="color: #ff6666;">2</span>; <span class="synStatement" style="color: #d88a17;">if</span> (right == <span class="synConstant" style="color: #ff6666;">0</span> || depth &gt; MAX_DEPTH) { <span class="synComment" style="color: #4f80e5;">// new_node is leaf</span> new_node-&gt;location = pointlist[median]; <span class="synComment" style="color: #4f80e5;">// no child node</span> new_node-&gt;child1 = <span class="synConstant" style="color: #ff6666;">NULL</span>; new_node-&gt;child2 = <span class="synConstant" style="color: #ff6666;">NULL</span>; qsort(pointlist, right + <span class="synConstant" style="color: #ff6666;">1</span>, <span class="synStatement" style="color: #d88a17;">sizeof</span>(<span class="synType" style="color: #3ec63e;">struct</span> point), comparex); new_node-&gt;leftmost = pointlist[<span class="synConstant" style="color: #ff6666;">0</span>].x; new_node-&gt;rightmost = pointlist[right].x; qsort(pointlist, right + <span class="synConstant" style="color: #ff6666;">1</span>, <span class="synStatement" style="color: #d88a17;">sizeof</span>(<span class="synType" style="color: #3ec63e;">struct</span> point), comparey); new_node-&gt;downmost = pointlist[<span class="synConstant" style="color: #ff6666;">0</span>].y; new_node-&gt;upmost = pointlist[right].y; qsort(pointlist, right + <span class="synConstant" style="color: #ff6666;">1</span>, <span class="synStatement" style="color: #d88a17;">sizeof</span>(<span class="synType" style="color: #3ec63e;">struct</span> point), comparez); new_node-&gt;zlowmost = pointlist[<span class="synConstant" style="color: #ff6666;">0</span>].z; new_node-&gt;zupmost = pointlist[right].z; <span class="synStatement" style="color: #d88a17;">for</span> (<span class="synType" style="color: #3ec63e;">int</span> i = <span class="synConstant" style="color: #ff6666;">0</span>; i &lt; right+<span class="synConstant" style="color: #ff6666;">1</span>; i++) { node_indexes[new_node-&gt;left_index+i] = pointlist[i].id; } <span class="synStatement" style="color: #d88a17;">return</span> new_node; } <span class="synComment" style="color: #4f80e5;">// change the dividing direction</span> new_node-&gt;axis = depth % <span class="synConstant" style="color: #ff6666;">3</span>; <span class="synComment" style="color: #4f80e5;">// sorting by space (1 direction) for binary division</span> <span class="synStatement" style="color: #d88a17;">if</span> (new_node-&gt;axis == XAxis) { <span class="synComment" style="color: #4f80e5;">// ascending sorting by point.x</span> qsort(pointlist, right + <span class="synConstant" style="color: #ff6666;">1</span>, <span class="synStatement" style="color: #d88a17;">sizeof</span>(<span class="synType" style="color: #3ec63e;">struct</span> point), comparex); new_node-&gt;leftmost = pointlist[<span class="synConstant" style="color: #ff6666;">0</span>].x; new_node-&gt;rightmost = pointlist[right].x; } <span class="synStatement" style="color: #d88a17;">else</span> <span class="synStatement" style="color: #d88a17;">if</span> (new_node-&gt;axis == YAxis) { <span class="synComment" style="color: #4f80e5;">// by point.y</span> qsort(pointlist, right + <span class="synConstant" style="color: #ff6666;">1</span>, <span class="synStatement" style="color: #d88a17;">sizeof</span>(<span class="synType" style="color: #3ec63e;">struct</span> point), comparey); new_node-&gt;downmost = pointlist[<span class="synConstant" style="color: #ff6666;">0</span>].y; new_node-&gt;upmost = pointlist[right].y; } <span class="synStatement" style="color: #d88a17;">else</span> <span class="synStatement" style="color: #d88a17;">if</span> (new_node-&gt;axis == ZAxis) { <span class="synComment" style="color: #4f80e5;">// by point.z</span> qsort(pointlist, right + <span class="synConstant" style="color: #ff6666;">1</span>, <span class="synStatement" style="color: #d88a17;">sizeof</span>(<span class="synType" style="color: #3ec63e;">struct</span> point), comparez); new_node-&gt;zlowmost = pointlist[<span class="synConstant" style="color: #ff6666;">0</span>].z; new_node-&gt;zupmost = pointlist[right].z; } node_indexes[new_node-&gt;left_index+median] = pointlist[median].id; <span class="synComment" style="color: #4f80e5;">//printf("node-&gt;left_index+median: %d\n", new_node-&gt;left_index+median);</span> new_node-&gt;location = pointlist[median]; new_node-&gt;child2 = kdtree(root_node, alloc_pointer, pointlist + median + <span class="synConstant" style="color: #ff6666;">1</span>, <span class="synComment" style="color: #4f80e5;">/*left =*/</span> left + median + <span class="synConstant" style="color: #ff6666;">1</span>, <span class="synComment" style="color: #4f80e5;">/*right =*/</span> right - (median + <span class="synConstant" style="color: #ff6666;">1</span>), <span class="synComment" style="color: #4f80e5;">/*depth =*/</span> depth + <span class="synConstant" style="color: #ff6666;">1</span>, node_indexes); new_node-&gt;child1 = kdtree(root_node, alloc_pointer, pointlist, <span class="synComment" style="color: #4f80e5;">/*left =*/</span> left, <span class="synComment" style="color: #4f80e5;">/*right =*/</span> median - <span class="synConstant" style="color: #ff6666;">1</span>, <span class="synComment" style="color: #4f80e5;">/*depth =*/</span> depth + <span class="synConstant" style="color: #ff6666;">1</span>, node_indexes);</pre> <pre> </pre> <p><span style="color: #000000;">上記コードは、KD木を構築したい点群の配列を <span class="code" style="white-space: pre-wrap;" spellcheck="false">pointlist</span> として与え、再帰的に木構造を構築するコードです。<a href="https://github.com/yuteno/kdtree_radius_search_opencl/blob/63997365128776dc189db8ba6da29da350f88b3e/src/kdtree_construction.c#L80" style="color: #000000;">L. 51 ~ L. 66</a> では、X, Y, Zのいずれかの軸で空間を分割します。<span class="code" style="white-space: pre-wrap;" spellcheck="false">pointlist</span>を <span class="code" style="white-space: pre-wrap;" spellcheck="false">qsort</span> でソートし、その中央を分割点としてノードを構築する部分は、前節で説明した通りです。ソートした<span class="code" style="white-space: pre-wrap;" spellcheck="false">pointlist</span>のうち、分割点よりもindexが小さい点群を左の子ノード(<span class="code" style="white-space: pre-wrap;" spellcheck="false">child1</span>)に渡し、分割点よりもindexの大きい点群が右の子ノード(<span class="code" style="white-space: pre-wrap;" spellcheck="false">child2</span>)に渡されます。また、<span class="code" style="white-space: pre-wrap;" spellcheck="false">node_indexes</span>には点群のインデックスとノードのインデックスを対応させるのに必要な情報を格納します。</span></p> <p><span style="color: #000000;">新たなノードを作る際に受け取った点群数が1であるか、または木の深さが<span class="code" style="white-space: pre-wrap;" spellcheck="false">MAX_DEPTH</span>よりも大きくなれば、そのノードを葉ノードとして木の構築をそこで打ち切ります。この時、葉ノードであることは、<span class="code" style="white-space: pre-wrap;" spellcheck="false">child1</span>および<span class="code" style="white-space: pre-wrap;" spellcheck="false">child2</span>を <span class="code" style="white-space: pre-wrap;" spellcheck="false">NULL</span> とすることで表現します。</span></p> <p><span style="color: #000000;">また、<span class="code" style="white-space: pre-wrap;" spellcheck="false">root_node</span>ポインタにはあらかじめ木のノード数分の領域を確保しておき、<span class="code" style="white-space: pre-wrap;" spellcheck="false">alloc_pointer</span>を用いて、木のルートノードを先頭としてノードが構築された順にメモリ上に配置されるようにすることで、配置の透明性を上げています。</span></p> <p><span style="color: #000000;">Radius SearchをOpenCLで実装した際のカーネルコード<span class="code" style="white-space: pre-wrap;" spellcheck="false">kernel_radius_search.cl</span>を以下に示します。</span></p> <pre class="code lang-cpp" style="overflow: auto; font-family: Monaco, Consolas, 'Courier New', Courier, monospace, sans-serif; font-size: 16px; border: 1px solid #dddddd; margin: 0px 0px 10px; padding: 20px; white-space: pre; color: #111111; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;" data-lang="cpp" data-unlink="">__kernel <span class="synType" style="color: #3ec63e;">void</span> radiusSearchCL(<span class="synType" style="color: #3ec63e;">const</span> global <span class="synType" style="color: #3ec63e;">float</span> * lidar_points_x, <span class="synType" style="color: #3ec63e;">const</span> global <span class="synType" style="color: #3ec63e;">float</span> * lidar_points_y, <span class="synType" style="color: #3ec63e;">const</span> global <span class="synType" style="color: #3ec63e;">float</span> * lidar_points_z, <span class="synType" style="color: #3ec63e;">const</span> global <span class="synType" style="color: #3ec63e;">float</span> * map_points_x, <span class="synType" style="color: #3ec63e;">const</span> global <span class="synType" style="color: #3ec63e;">float</span> * map_points_y, <span class="synType" style="color: #3ec63e;">const</span> global <span class="synType" style="color: #3ec63e;">float</span> * map_points_z, <span class="synType" style="color: #3ec63e;">const</span> global <span class="synType" style="color: #3ec63e;">int</span> * node_indexes, __constant kdtree_node * root_node, <span class="synType" style="color: #3ec63e;">const</span> <span class="synType" style="color: #3ec63e;">int</span> n, <span class="synType" style="color: #3ec63e;">const</span> <span class="synType" style="color: #3ec63e;">int</span> limit, <span class="synType" style="color: #3ec63e;">const</span> <span class="synType" style="color: #3ec63e;">float</span> radius, global <span class="synType" style="color: #3ec63e;">int</span> * neighbor_candidate_indexes, global <span class="synType" style="color: #3ec63e;">float</span> * neighbor_candidate_dists) { <span class="synComment" style="color: #4f80e5;">// 1d range kernel for the point cloud</span> <span class="synType" style="color: #3ec63e;">int</span> item_index = get_global_id(<span class="synConstant" style="color: #ff6666;">0</span>); <span class="synStatement" style="color: #d88a17;">if</span> (item_index &gt;= n) <span class="synStatement" style="color: #d88a17;">return</span>; float4 reference_point = (float4)(lidar_points_x[item_index], lidar_points_y[item_index], lidar_points_z[item_index], <span class="synConstant" style="color: #ff6666;">0</span>); <span class="synStatement" style="color: #d88a17;">if</span> (item_index == <span class="synConstant" style="color: #ff6666;">0</span>) printf(<span class="synConstant" style="color: #ff6666;">"ref point (</span><span class="synSpecial" style="color: #c000c0;">%f</span><span class="synConstant" style="color: #ff6666;">, </span><span class="synSpecial" style="color: #c000c0;">%f</span><span class="synConstant" style="color: #ff6666;">, </span><span class="synSpecial" style="color: #c000c0;">%d</span><span class="synConstant" style="color: #ff6666;">), radius </span><span class="synSpecial" style="color: #c000c0;">%f</span><span class="synConstant" style="color: #ff6666;">, limit </span><span class="synSpecial" style="color: #c000c0;">%d\n</span><span class="synConstant" style="color: #ff6666;">"</span>, lidar_points_x[item_index], lidar_points_y[item_index], lidar_points_z[item_index], radius, limit); __constant kdtree_node *current_node = root_node; <span class="synType" style="color: #3ec63e;">int</span> neighbors_count = <span class="synConstant" style="color: #ff6666;">0</span>; <span class="synType" style="color: #3ec63e;">int</span> level = <span class="synConstant" style="color: #ff6666;">0</span>; <span class="synType" style="color: #3ec63e;">float</span> dist; float4 dist_square; <span class="synComment" style="color: #4f80e5;">// radius search</span> <span class="synStatement" style="color: #d88a17;">while</span> (<span class="synConstant" style="color: #ff6666;">true</span>) { <span class="synStatement" style="color: #d88a17;">if</span> ((current_node-&gt;child1 == <span class="synConstant" style="color: #ff6666;">NULL</span>) &amp;&amp; (current_node-&gt;child2 == <span class="synConstant" style="color: #ff6666;">NULL</span>)) { <span class="synComment" style="color: #4f80e5;">//reached to leaf node</span> <span class="synStatement" style="color: #d88a17;">for</span> (<span class="synType" style="color: #3ec63e;">int</span> i = current_node-&gt;left_index; i &lt; current_node-&gt;right_index; ++i) { <span class="synType" style="color: #3ec63e;">int</span> index = node_indexes[i]; float4 map_point = (float4)(map_points_x[index], map_points_y[index], map_points_z[index], <span class="synConstant" style="color: #ff6666;">0</span>); <span class="synStatement" style="color: #d88a17;">for</span> (<span class="synType" style="color: #3ec63e;">int</span> d = <span class="synConstant" style="color: #ff6666;">0</span>; d &lt; <span class="synConstant" style="color: #ff6666;">4</span>; d++) { dist_square[d] = (map_point[d] - reference_point[d]) * (map_point[d] - reference_point[d]); } <span class="synComment" style="color: #4f80e5;">//float4 dist_square = (map_point - reference_point) * (map_point - reference_point);</span> dist = sqrt(dist_square[<span class="synConstant" style="color: #ff6666;">0</span>] + dist_square[<span class="synConstant" style="color: #ff6666;">1</span>] + dist_square[<span class="synConstant" style="color: #ff6666;">2</span>]); <span class="synStatement" style="color: #d88a17;">if</span> (dist &lt; radius) { neighbor_candidate_indexes[limit*item_index + neighbors_count] = index; neighbor_candidate_dists[limit*item_index + neighbors_count] = dist; neighbors_count++; } <span class="synStatement" style="color: #d88a17;">if</span> (neighbors_count &gt;= limit){ <span class="synStatement" style="color: #d88a17;">break</span>; } } <span class="synStatement" style="color: #d88a17;">break</span>; } <span class="synStatement" style="color: #d88a17;">else</span> { <span class="synType" style="color: #3ec63e;">int</span> index = node_indexes[current_node-&gt;left_index + (current_node-&gt;right_index - current_node-&gt;left_index-<span class="synConstant" style="color: #ff6666;">1</span>) / <span class="synConstant" style="color: #ff6666;">2</span>]; float4 map_point = (float4)(map_points_x[index], map_points_y[index], map_points_z[index], <span class="synConstant" style="color: #ff6666;">0.0f</span>); <span class="synComment" style="color: #4f80e5;">//dist_square = (map_point - reference_point) * (map_point - reference_point);</span> <span class="synStatement" style="color: #d88a17;">for</span> (<span class="synType" style="color: #3ec63e;">int</span> d = <span class="synConstant" style="color: #ff6666;">0</span>; d &lt; <span class="synConstant" style="color: #ff6666;">4</span>; d++) { dist_square[d] = (map_point[d] - reference_point[d]) * (map_point[d] - reference_point[d]); } dist = sqrt(dist_square.x + dist_square.y + dist_square.z); <span class="synStatement" style="color: #d88a17;">if</span> (dist &lt; radius) { neighbor_candidate_indexes[limit*item_index + neighbors_count] = index; neighbor_candidate_dists[limit*item_index + neighbors_count] = dist; neighbors_count++; } <span class="synStatement" style="color: #d88a17;">if</span> (neighbors_count &gt;= limit){ <span class="synStatement" style="color: #d88a17;">break</span>; } <span class="synType" style="color: #3ec63e;">float</span> val = reference_point[current_node-&gt;axis]; <span class="synType" style="color: #3ec63e;">float</span> diff = val - current_node-&gt;axis_val; __constant kdtree_node * next; <span class="synStatement" style="color: #d88a17;">if</span> (diff &lt; <span class="synConstant" style="color: #ff6666;">0</span> &amp;&amp; current_node-&gt;child1) { next = current_node-&gt;child1; <span class="synComment" style="color: #4f80e5;">// printf("%d in (%d), select child1\n", item_index, n);</span> } <span class="synStatement" style="color: #d88a17;">else</span> { next = current_node-&gt;child2; <span class="synComment" style="color: #4f80e5;">// printf("%d in (%d), select child2\n", item_index, n);</span> } current_node = next; } } }</pre> <pre> </pre> <p><span style="color: #000000;">OpenCLの各スレッドは<span class="code" style="white-space: pre-wrap;" spellcheck="false">item_index</span>を用いて入力点群のうちの1つを取得してクエリ点とし、構築したKD木に対して近傍探索を行います。</span></p> <p><span style="color: #000000;"><a href="https://github.com/yuteno/kdtree_radius_search_opencl/blob/63997365128776dc189db8ba6da29da350f88b3e/src/kernel_radius_search.cl#L69" style="color: #000000;">L. 35</a> からのwhile文で近傍探索を行ないます。</span></p> <p><span style="color: #000000;">葉ノードに到達するまでは <a href="https://github.com/yuteno/kdtree_radius_search_opencl/blob/63997365128776dc189db8ba6da29da350f88b3e/src/kernel_radius_search.cl#L94" style="color: #000000;">L. 60</a> からのelse節が実行され、ノードの分割点とクエリ点の距離を計算し、近傍点かどうかの判定を行いつつ適切な子ノードに向かって木を降りていきます。</span></p> <p><span style="color: #000000;">葉ノードに到達すると <a href="https://github.com/yuteno/kdtree_radius_search_opencl/blob/63997365128776dc189db8ba6da29da350f88b3e/src/kernel_radius_search.cl#L70" style="color: #000000;">L. 36</a> のif節が実行されます。葉ノードには分割点以外にも複数の点が含まれる場合があるので、それら全てとクエリ点の距離を計算し、近傍判定を行います。</span></p> <p><span style="color: #000000;">また、前述の通り木を「登る」処理は行わないので、葉ノードに到達するか、あるいは取得した近傍点の数が<span class="code" style="white-space: pre-wrap;" spellcheck="false">limit</span>を超えた場合にwhile文からのbreakとなり、処理が終了します。</span></p> <h4 id="Host-Device間メモリについて"><span style="color: #000000;">Host-Device間メモリについて</span></h4> <p><span style="color: #000000;">KD木を用いたRadius Searchの処理を各点で並列化するためには、ホスト側で構築したKD木を各スレッドが参照できるメモリに配置する必要があります。そこで、<span class="code" style="white-space: pre-wrap;" spellcheck="false">__constant</span>修飾子を用いてコンスタントメモリに木構造を配置しますが、そのまま配置するとホスト側で、特に子ノードをポインタを使って表現されている木構造が、コンスタントメモリ上でも同様の構造を保つ保証がなくなってしまいます。</span></p> <p><span style="color: #000000;"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/j/james-murakami/20210430/20210430103111.png" alt="f:id:james-murakami:20210430103111p:plain" title="" class="hatena-fotolife" itemprop="image" />OpenCL 2.0から実装されたShared Virtual Memory (SVM) という機能を用いて上の問題を解決できます。名前の通り、ホストとデバイスで仮想メモリ空間を共有できる機能であり、今回の木構造のメモリのデバイス間共有に最適です。SVMについては<a href="/wiki/spaces/NA/pages/1284210938" __confluencemetadata="{&quot;spaceKey&quot;:&quot;NA&quot;,&quot;isRenamedTitle&quot;:true,&quot;linkType&quot;:&quot;page&quot;,&quot;contentTitle&quot;:&quot;性能解析WG ミーティング議事録&quot;,&quot;versionAtSave&quot;:&quot;2&quot;}" style="color: #000000;">Fixstars社のTech blog</a>でも詳しく紹介されています。また、OpenCLにおいてメモリ構造の記事は、<a href="https://www.mql5.com/ja/articles/407" style="color: #000000;">こちらの記事</a>が大変参考になります。</span></p> <h3 id="AutowareのTutorial-ROSBAGとMapを用いた動作"><span style="color: #000000;">AutowareのTutorial ROSBAGとMapを用いた動作</span></h3> <p><span style="color: #000000;">OpenCL実装したRadius Searchの動作確認を行うために、Autowareの動作確認に用いられているMapとLiDARのデータを使用します。しかし、LiDARのデータは、Autoware用のサンプルデータにおいてrosbagの中のtopic群として提供されていますし、何より座標変換の処理をしたり、複数のセンサーデータの統合もしなければなりません。動作確認だけのために、本実装にこの処理を追加するのは面倒なので、今回はAutowareを一部改変し、Scan Matching処理直前の点群を、外部ファイルに保存するという手段を取りましょう。</span></p> <p><span style="color: #000000;">再びAutowareでの実装である、<a href="https://github.com/tier4/AutowareArchitectureProposal.iv/blob/3461b8f28db76546ad81d0d6566a5eaa79b95305/localization/pose_estimator/ndt_scan_matcher/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp" style="color: #000000;">localization/pose_estimator/ndt_scan_matcher/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp</a> を見ていきます。</span></p> <p><span style="color: #000000;">LiDAR点群が到着するたびに、コールバック関数 <span class="code" style="white-space: pre-wrap;" spellcheck="false">callbackSensorPoints</span> が呼ばれ、それを入力としてScan Matching処理が行われます。そこで、この関数内で入力として使われている点群を外部ファイルに保存します。</span></p> <p><span style="color: #000000;">先に座標変換の話に触れましたが、rosbagの中に存在するLiDAR点群の座標は、あくまでLiDARセンサから見たものであり、Map点群とのMatching処理入力として有効であるためには、車体およびMapに対して座標変換を行っておく必要があります。</span></p> <p><span style="color: #000000;"><a href="https://github.com/tier4/AutowareArchitectureProposal.iv/blob/3461b8f28db76546ad81d0d6566a5eaa79b95305/localization/pose_estimator/ndt_scan_matcher/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L310" style="color: #000000;">ndt_scan_matcher_core.cpp の L.310</a> で <span class="code" style="white-space: pre-wrap;" spellcheck="false">setInputSource</span> 関数を用いて <span class="code" style="white-space: pre-wrap;" spellcheck="false">sensor_points_baselinkTF_ptr</span> という点群が入力として設定されていますが、この点群はまだ車体位置・姿勢に対しての座標変換が行われていません。車体位置・姿勢に対しての座標変換行列は、<a href="https://github.com/tier4/AutowareArchitectureProposal.iv/blob/3461b8f28db76546ad81d0d6566a5eaa79b95305/localization/pose_estimator/ndt_scan_matcher/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L346" style="color: #000000;">L. 346</a> で <span class="code" style="white-space: pre-wrap;" spellcheck="false">align</span> 関数の引数として使われている<span class="code" style="white-space: pre-wrap;" spellcheck="false">initial_pose_matrix</span> です。そこで、PCL (Point Cloud Libary) の <span class="code" style="white-space: pre-wrap;" spellcheck="false">pcl::transformPointCloud</span> 関数を用いて、<span class="code" style="white-space: pre-wrap;" spellcheck="false">sensor_points_baselikTF_ptr</span> を <span class="code" style="white-space: pre-wrap;" spellcheck="false">initial_pose_matrx</span> で座標変換を行います。このようにして変換した点群を <span class="code" style="white-space: pre-wrap;" spellcheck="false">pcl::io::savePCDFile</span> 関数でpcdファイルに保存することで、Autoware用サンプルデータ内の点群を、今回の実装の入力として適当な形に変換することができます。</span></p> <h3 id="ぜひティアフォーへ"><span style="color: #000000;">ぜひティアフォーへ!</span></h3> <p><span style="color: #000000;">今回の調査や再実装の動機は、採用できる計算システムの選択肢を広げたいところにあります。実証実験のソフトウェアは実証実験のシステムや環境からの影響を多大に受け、さらに使用しているライブラリ類の制限を多分に受けます。計算機側の立場は高速な開発/実証実験とは対極ではありますが、HW/SWの双方に高水準な性能が要求される自動運転開発の両軸です。</span></p> <p><span style="color: #000000;">移植性についても、あらゆるシステムに移植できることは幻想です。ただ、特定のシステムに依存することは、本質的に効率の悪い選択肢をとらざるを得なければならない危険性を抱えてしまいます。</span></p> <p>このようにティアフォーでは、自動運転技術の精度性能のチューニングはもちろん、計算システムでの性能のチューニングも行っております。計算機およびアルゴリズムは自信あり、でも自動運転は興味があるだけ...という、そこのお方!ぜひ一緒に完全自動運転を実現する計算機を探索しましょう!下記リンクからお問い合わせお待ちしています!<span style="color: #000000;"> </span></p> <p><a href="https://careers.tier4.jp/">TIER IV Careers</a></p> <p><span style="color: #000000;"><br /><cite class="hatena-citation"><a href="https://tier4.jp/careers/" style="color: #000000;">tier4.jp</a></cite></span></p> james-murakami 筑西市における小型自動搬送ロボットの実証実験 hatenablog://entry/26006613721500189 2021-04-28T16:00:00+09:00 2021-05-04T00:34:07+09:00 こんにちは、ティアフォーのフィールドインテグレーションチームに所属している帯津です。今回は2021年3月29日から4月13日の期間で、茨城県筑西市にある道の駅「グランテラス筑西」と周辺地域で実施しました、小型自動搬送ロボットの実証実験の概要と小型自動搬送ロボットならではの実証ポイントについてご紹介します。 なお、ティアフォーでは、自動運転の安心・安全を確保し「自動運転の民主化」をともに実現していく、様々なエンジニア・リサーチャーを募集しています。もしご興味があればカジュアル面談も可能ですので以下のページからコンタクトいただければと思います。 tier4.jp 実証実験概要 小型自動搬送ロボット… <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff;" data-renderer-start-pos="25">こんにちは、ティアフォーのフィールドインテグレーションチームに所属している帯津です。今回は2021年3月29日から4月13日の期間で、茨城県筑西市にある道の駅「グランテラス筑西」と周辺地域で実施しました、小型自動搬送ロボットの実証実験の概要と小型自動搬送ロボットならではの実証ポイントについてご紹介します。</p> <p data-renderer-start-pos="7448"><span style="font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial; float: none; display: inline !important;">なお、ティアフォーでは、自動運転の安心・安全を確保し「自動運転の民主化</span><span style="font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial; float: none; display: inline !important;">」をともに実現していく、様々なエンジニア・リサーチャーを募集しています。もしご興味があればカジュアル面談も可能ですので以下のページからコンタクトいただければと思います。</span></p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftier4.jp%2Fcareers%2F" title="Careers | 株式会社ティアフォー" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://tier4.jp/careers/">tier4.jp</a></cite></p> <h3>実証実験概要</h3> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="189">小型自動搬送ロボットの実証実験を行う背景には大きく分けて2つの理由があります。1つ目は、eコマースの普及にともなう物流量の増大や施設管理の大規模化が進み、対応する人手不足が深刻化しているため、2つ目は新型コロナウイルス感染症拡大にともない、新しい生活様式が広まる中、非接触型の配送ニーズが高まっているためです。そして将来的には自動配送ロボットを活用した新たな配送サービスの実現が期待されています。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="189">科学都市であるつくば市を擁する茨城県は、Society 5.0地域社会実装を強く推進、その茨城県配下の筑西市が手をあげ、本実証実験の支援を頂くこととなりました。</p> <h4>概要</h4> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="363">本実証実験では、仕様が異なる2台の小型自動搬送ロボット「Logiee」(以下、Logiee)で、下記2つの自動配送を実施しました。</p> <ol> <li><span style="font-size: 1em; letter-spacing: -0.005em; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; white-space: pre-wrap;">道の駅「グランテラス筑西」と周辺農家・民家を結ぶ公道の遠隔監視型配送</span></li> <li><span style="font-size: 1em; letter-spacing: -0.005em; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; white-space: pre-wrap;">「グランテラス筑西」施設敷地内における複数地点を結ぶ近接監視型配送</span></li> </ol> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="507">上記2のルートについては、株式会社オプティマインドの配送ルートを最適化する自動配車システム「Loogia」(以下、Loogia)と、ティアフォーの自動運転車両の運行管理サービスFMS(以下、FMS)との連携によるスケジュール配信の実験を行いました。</p> <h4>近接監視型と遠隔監視型</h4> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="734">小型自動搬送ロボットの運用では、自動運転システムの監視者はロボット近傍で常時監視するか、ロボットに搭載したカメラの映像を遠隔監視室で常時監視するかによって2つの監視型に分けられ、前者を近接監視型、後者を遠隔監視型としています。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="849">近接監視型は、近接監視者が車両近傍において、車両周囲の状況を目視で随時確認を行うとともに、自動運転OS Autoware(以下、Autoware)の稼働状況も随時確認します。また、システムの異常時や危険を感じた場合は、車両の緊急停止ボタンを押下、手動走行に切り替えての危険回避などを実施し、安全性を確保します。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="995">一方、遠隔監視型は、遠隔監視者が遠隔監視室よりモニターに映し出される車両のカメラ映像および各種情報より車両周囲の状況を確認するとともに、Autowareの稼働状況を監視し、異常が発生していないか監視します。また、必要に応じて緊急停止やシステムへの介入を行い、遠隔コントローラーを操作して危険回避などを実施し、安全性を確保します。</p> <h4>車両コンセプト</h4> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="1180">前述のとおり、私有地と公道をそれぞれが連携して走行させるため、異なる仕様のLogieeを使用しました。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="1233">1つは、公道走行が可能な高スペック自動搬送ロボット『LogieeS-TC』(以下、LogieeS-TC)、もう1つは、私有地での走行に限定した廉価版の自動搬送ロボット『LogieeSS』(以下、LogieeSS)です。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="1345">LogieeS-TCは一般消費者向けを想定しており、丸みを帯びたデザインとなっております。また、前後左右に搭載したカメラの映像が遠隔地からオペレータが監視可能であるほか、LogieeS-TCと遠隔室のオペレータ間に内蔵されたマイク、スピーカーを使うことで、通行する歩行者の方への呼びかけ、通話も可能となっています。さらに、商品の受け渡しの際に、オペレータと通話することで、初めて配送サービスを利用する方でも安心して利用することが可能です。事実、実証実験期間中に、地域の子どもたちとLogieeS-TC(このイベントでは「ろーじー」と称していました)が会話し、子どもたちの疑問を「ろーじー」が答えるなど、イメージキャラクターとしての役割も担いました。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="1633">一方、LogieeSSはビジネス向け用途を想定しており、今回の実証実験の場となったグランテラス筑西内を走行させるというよりも、一般には目にすることがないバックヤードでの走行を想定しているため、LogieeS-TCと比べて、LogieeSSでは遠隔監視機能、通話機能などはなく、デザインもシンプルです。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="1833">ただし、自動走行にフォーカスを当てると、LogieeS-TCとLogieeSSはコンセプト・外観は異なるものの、同一のパワーユニットを使用し、どちらもAutowareをコアアーキテクチャとした自動搬送ロボットです。なお、LogieeS-TCならびにLogieeSSの操舵方式は、後輪2輪の独立制御による差動2輪方式です。差動2輪方式は構造がシンプルである一方、2輪の駆動状況がパス追従性に大きく影響を及ぼします。例えば、2輪のタイヤエアー圧のバランスが異なると、タイヤ中心(回転軸)から接地面(地面)までの距離(タイヤ径)が変化し、直進指示を与えているにも関わらず、エアー圧が低いとタイヤ径が小さくなり、その結果、エアー圧が低い方へ曲がっていく挙動を示します。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="2192">そのため、実証実験期間中は、日々の車両点検で、外観チェック、カメラ・センサーの動作確認を実施するとともに、タイヤエアー圧の確認を実施し、安全な運行に努めました。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/T/TierIV/20210504/20210504003334.png" alt="f:id:TierIV:20210504003334p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <h4>走行ルート</h4> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="2284">走行ルートは、道の駅「グランテラス筑西」施設内と周辺の公道になります。今回、(A)施設内テナントの商品を地域住民へ配送する、(B)周辺農家から農産物をピックアップし、施設内テナントへ配送する、という2つのシナリオについて実証実験を実施しました。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="2408">(A)のルートは、以下の画像の緑のラインで示す道の駅「グランテラス筑西」施設敷地内のルートと、施設内から公道へ出て、周辺民家を周回するピンクのラインを走行するルートに分かれます。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="2514">一方、(B)のルートは、最初に公道を走行して農産物をピックアップし、施設へ戻り、その後、施設内テナントへ農産物を配送するルートです。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="2601">それぞれの走行ルートでLogieeが停車する箇所を便宜上「バス停」とし、FMSより次に向かうバス停までのルートを配信して各シナリオに即したルート指示を行いました。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/m/majestickou/20210419/20210419093925.png" alt="f:id:majestickou:20210419093925p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <h4>ODDアセスメント</h4> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="2873">Operational Design Domain(以下、ODD)とは、自動運転システムが安全に作動するための前提条件です。あらかじめ定められたODDの範囲内でのみ自動運転システムが作動するように設計することで、走行時の安全性を担保します。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="2873">Logieeが安全に走行するためには、上記よりODD設定が必要不可欠で、走行環境や運用方法を制限することで、事故などを未然に防ぎます。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="2873">ここで、設定した条件が欠けた場合などODD範囲外となった場合、安全な運行停止措置を行うか、手動運転への切り替えを行い、ODD範囲外となった原因を排除し、ODD範囲内での走行とします。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="2873">以下は、公道走行におけるODDです。道路条件では、決められたルートのみの走行であることや信号・横断歩道がないため、ODD範囲外となるケースでは、車両(自動車、自転車など)、人の接近がリスクとして挙げられます。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/m/majestickou/20210419/20210419095231.png" alt="f:id:majestickou:20210419095231p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="2980">このように、ODD範囲外となるケースを評価していく手法をODDアセスメントとして、事前に評価を実施しました。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="3034">走行ルートとODD道路条件が同一のルート区間(レーンのない道路、歩道、交差点など)をロードセクションと称し、ロードセクションごとにODD範囲外となるケースを割り出し、ODD範囲外となる確率が高いロードセクションに対し、Autowareの機能を維持・制限した状態でAutowareの稼働を継続させるフォールバックや、車両を一時停止させるミニマル・リスク・マヌーバー、手動運転への切り替えを行うなど、運行上の安全を担保する施策を行いました。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="3250">以下の図は、公道走行ルートの各ロードセクションにおけるODD範囲外ユースケースと全体に占める割合の評価結果です。(ロードセクションNo.1〜No.11は施設内のため、本稿では割愛致します。)評価結果として、車両接近によるODD外れが大きな割合を占めており、保安要員による監視が安全を担保する上で重要な役割を担うことになります。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="3418">そのため、監視・操作者と保安要員とのコミュニケーションプロトコルを定め、監視・操作者からは車両の状況を、保安要員からは接近する人・車情報を伝達することで、ODD範囲外を排除することができました。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/m/majestickou/20210419/20210419095424.png" alt="f:id:majestickou:20210419095424p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <h4>オペレーションイメージ</h4> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="3531">前述のシナリオ(A)、すなわち商品を地域住民へ配送するオペレーションイメージは以下の図のとおりです。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="3581">まずは、地域住民から電話orメールでカスタマーセンターへ注文が入ります(①)。カスタマーセンターのオペレータは、Loogiaへ情報を入力すると(②)、Loogiaは最適なルートを割り出し、画面に表示します(③)。オペレータは注文があった住民へ電話orメールで配達日時を連絡します(④)。また、該当商品を取り扱う店舗に対しては電話orメールにて集荷日時を連絡します(⑤)。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="3767">集荷先、配送先への連絡後、カスタマーセンターのオペレータは、Loogiaの画面よりルート配信を実行すると、Loogiaは、ティアフォーが開発している配車管理サービスのFMSへ、データインターフェース(API)を通してスケジュール登録を行います(⑥)。その後、FMSはLogieeへルート配信を行います(⑦)。ルート配信を受けたLogiee(今回、施設内走行はLogieeSS)は店舗前まで自動走行し、店舗スタッフより商品を受け取ります(⑧)。その後、商品を公道走行可能のLogieeS-TCへ載せ替えるため、施設内に設定したパーキングロットへ向かいます。向かった先にはLogieeS-TCが待機しているので、LogieeS-TCの隣に駐車し、そこにいる人が商品をLogieeS-TCへ載せ替えます(⑨)。商品を載せたLogieeS-TCは注文のあった住民宅まで公道を自動走行し、商品をお届けします(⑩)。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/T/TierIV/20210504/20210504002951.png" alt="f:id:TierIV:20210504002951p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="4192">上記は地域住民へ商品を配送するオペレーションイメージですが、周辺農家から農産物を受け取り、施設内テナントへお届けするオペレーションも同様のイメージです。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="4276">なお、FMSの詳細につきましては、以下の記事で紹介しています。<br /><span style="text-decoration-style: initial; text-decoration-color: initial;"><a href="https://tech.tier4.jp/entry/2019/04/05/165349">https://tech.tier4.jp/entry/2019/04/05/165349</a></span></p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftech.tier4.jp%2Fentry%2F2019%2F04%2F05%2F165349" title="ティアフォーにおける自動運転車両の運行管理サービスのご紹介 - Tier IV Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://tech.tier4.jp/entry/2019/04/05/165349">tech.tier4.jp</a></cite></p> <h3>小型自動搬送ロボットならではの実証ポイント</h3> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="4397">本実証実験では、2台の仕様が異なる小型自動搬送ロボットで行いましたが、自動運転システムとしてフォーカスすると、自動運転システムのコアアーキテクチャは、公道走行している車両のシステムと同様のAutowareです。このことは、市街地における公道走行が可能なアーキテクチャがLogieeにも採用されていることを指しており、高度な安全性、信頼性をもつ小型自動搬送ロボットとなっています。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="4591">一方、運用面のユースケースにフォーカスすると、2台の小型搬送ロボットが同じ場所に到着し、荷物の受け渡しをしやすいようにする必要があったり、公道を走行中に路肩に障害物があれば少し避けたり、遠隔監視走行から近接監視走行へ速やかに切り替え、近接操作者(ロボットの傍で監視を行っているオペレータ)によるマニュアル操作で障害物を回避したい、といった小型自動搬送システムとしての要求が発生します。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="4785">これら運用上の要求に対し、Autowareの機能となるパーキング、障害物回避を実証ポイントとして実験を行いましたので、以下にご紹介します。</p> <h4>パーキング</h4> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="4863">パーキングは、いわゆる駐車することを目的としているほか、LogieeSSが集荷してきた荷物をLogieeS-TCへ積み替えるためのポジショニングを主目的としています。物流業界において、トラックを荷積みのために出荷場所へ駐めるイメージです。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="4987">自動走行は地図情報にあるレーン上を走行しますが、パーキングは、レーン上で停止した位置(スタート位置)からパーキングロット(駐車エリア)上の目標位置(ゴール位置)まで移動することができるモード(シナリオ)です。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="5096">Autowareではレーン走行(lane driving)、パーキング(parking)の各シナリオを、Planningモジュール内のScenario selectorで、条件判定し切り替えを行います。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="5199">Scenario selectorは、レーン上からパーキングロットへ移動しようとした場合にパーキングへ切り替えを行います。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="5274">以下の図は、実際に施設内に設定したパーキングロット上まで移動するパス(赤色の線)です。スタートからゴールまでのパスは、Hybrid A*アルゴリズムによるパスプランニングを行うことで生成しています。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/m/majestickou/20210419/20210419100116.png" alt="f:id:majestickou:20210419100116p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="5369">パスプランニングでは、スタート、ゴールの位置、姿勢から横列、縦列の判断、さらに右折、左折、スイッチバック、方向転換などの動作を算出します。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="5450">以下の図は、シミュレーターを使用して、さまざまなスタート、ゴールの位置、姿勢に対するパスプランニングを行った結果です。なお、Vehicle model付近にある白い矢印は車両の向き、赤線は算出されたパス、ピンクの矢印は走行方向、青の点がゴール位置で、赤の線がゴール時の車両の向きを示します。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/m/majestickou/20210419/20210419100213.png" alt="f:id:majestickou:20210419100213p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <p data-renderer-start-pos="3418"><span style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: -0.08px; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial; float: none; display: inline !important;">下の写真は、パーキングロットにパーキングさせたLogieeSSとLogieeS-TCで、スタッフが農産物が入った箱の積み替えを行っているデモ風景です。</span></p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/m/majestickou/20210419/20210419100340.png" alt="f:id:majestickou:20210419100340p:plain" title="" class="hatena-fotolife" itemprop="image" width="434" /></p> <h4>障害物回避</h4> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="5696">小型自動搬送ロボットLogieeが障害物回避するユースケースとして、ロボットが走行するレーンに侵入している”もの”の回避があります。ここでいう”もの”とは、駐輪場から少しはみ出した自転車の車輪、置き去りにされたスーパーのカートなど、生活空間における無作為にレーンにはみ出しているものを差します。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="5845">これらの”もの”がレーン上にある場合、Logieeは障害物として認識し停止し、近接監視者、あるいは遠隔監視者がLogieeSを手動介入して障害物を回避しますが、Logieeがレーンをはみ出すことなく、ほんの少し避けるだけで”もの”を回避しても走行可能領域内にあると判断できる場合、Autowareは回避動作にともなうパスプランニングを行い、その結果、Logieeは障害物を自動回避します。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="6040">このことは、複数台の運行を鑑みた場合、ほんの少し避けるだけで自動走行が可能なケースではLogieeは自動で回避し、レーンを逸脱しなければ回避できない場合のみ手動介入して回避することで手動介入率を下げ、効率的な運行が可能となります。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="6160">今回、公道でのレーン幅は1.5mとしており、車両幅が0.75mであるため、左右のマージンは0.375m、理論上では30cmほどレーンに侵入している”もの”を回避できることになります。それ以上の侵入がある場合は、障害物停止となります。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="6278">また、物体認識にはLiDARの点群からクラスタリングを行う”Euclidean Clustering”を使用していますが、この手法では、物体全体の形状推定は行っていないことから、1つの物体を複数と認識したり、複数の物体を1つの物体と認識してしまいます。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="6406">そのため、走行する場のユースケースにあったパラメータチューニングが必要ですが、今回は、障害物回避の有効性について検証を進めました。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="6476">以下の動画は、県道に隣接した歩道で行った障害物(しゃがみこんだ人)の回避の様子です。</p> <p><iframe width="420" height="315" src="https://www.youtube.com/embed/qyH2xf_3cTw?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" id="widget2"></iframe><cite class="hatena-citation"><a href="https://youtu.be/qyH2xf_3cTw">youtu.be</a></cite></p> <h3> 実証実験の様子<button class="sc-bsbRJL dyppDQ" style="font-family: inherit; display: inline; outline: none; background-color: transparent; border: none; color: #42526e; cursor: pointer; right: 0px; padding-left: 0px; padding-right: 0px; opacity: 0; transform: translate(-8px, 0px); transition: opacity 0.2s ease 0s, transform 0.2s ease 0s;"><svg width="24" height="24" viewbox="0 0 24 24" role="presentation"><g fill="currentColor" fill-rule="evenodd"><path d="M12.856 5.457l-.937.92a1.002 1.002 0 000 1.437 1.047 1.047 0 001.463 0l.984-.966c.967-.95 2.542-1.135 3.602-.288a2.54 2.54 0 01.203 3.81l-2.903 2.852a2.646 2.646 0 01-3.696 0l-1.11-1.09L9 13.57l1.108 1.089c1.822 1.788 4.802 1.788 6.622 0l2.905-2.852a4.558 4.558 0 00-.357-6.82c-1.893-1.517-4.695-1.226-6.422.47"></path><path d="M11.144 19.543l.937-.92a1.002 1.002 0 000-1.437 1.047 1.047 0 00-1.462 0l-.985.966c-.967.95-2.542 1.135-3.602.288a2.54 2.54 0 01-.203-3.81l2.903-2.852a2.646 2.646 0 013.696 0l1.11 1.09L15 11.43l-1.108-1.089c-1.822-1.788-4.802-1.788-6.622 0l-2.905 2.852a4.558 4.558 0 00.357 6.82c1.893 1.517 4.695 1.226 6.422-.47"></path></g></svg></button></h3> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="6536">3/29(月)から現地での実証実験準備を進め、4/2(金)が近接監視走行の警察審査、4/9(金)が遠隔監視走行の警察審査と進めていき、4/12(月)、4/13(火)の2日間がお本番というスケジュールで進めていく中、期間中に多くの方々にお越し頂きました。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="6659">以下は実証実験の様子の動画です。<span style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; font-size: 14px; letter-spacing: normal;"> </span></p> <p><iframe width="560" height="315" src="https://www.youtube.com/embed/QCl9IuIRVog?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" id="widget4"></iframe><cite class="hatena-citation"><a href="https://www.youtube.com/watch?v=QCl9IuIRVog">www.youtube.com</a></cite></p> <p><span style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: -0.08px; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial; float: none; display: inline !important;">リハーサル、ならびに実証実験本番で、LogieeS-TCは、およそ30回、距離にして30kmの集荷・搬送を、LogieeSSでは、およそ30回、距離にして10kmの配送を実施し、実用化へ向けた課題などを洗い出すことができました。</span></p> <h3>今後の小型自動搬送ロボットによる実証実験について</h3> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="6710">冒頭でも触れましたが、昨今の新型コロナウィルス感染症拡大により、宅配サービスが急増し、それにともない、非接触型の配送ニーズが高まっています。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="6782">また、政府の成長戦略実行計画(令和2年7月)における低速・小型自動配送ロボットの社会実装に向けて「遠隔監視・操作」型の公道走行実証を実施するとの方針により、宅配ロボット事業へ参入する企業が増加し、実証実験も各地域でさかんに実施されています。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="6906">小型自動搬送ロボットにおける配送サービスの実用化には、法整備、インフラ整備など課題は山積みですが、その課題を解決すべく、国が動き出しています。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="6979">自動走行では、私たちティアフォー以外にも、大手メーカーが限定的ではあるものの公道での自動運転レベル3、あるいはレベル4の実用化に向け開発を進めていますが、法規制の敷居が高いのが現状です。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="7074">一方、小型自動搬送ロボットによる自動走行では、小型、低速(歩行レベル)で、歩道をメインに走行することから、リスクレベルが低く、国内における自動走行の実用化、ビジネスとして収益を得る土壌ができつつあります。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="7178">2021年度は、普及へ向けたさらなる拡大が予想されており、私たちティアフォーもパイロット企業となるべく技術改革を進めていきます。</p> <h3> 実証実験を終えて・・・<button class="sc-bsbRJL dyppDQ" style="font-family: inherit; display: inline; outline: none; background-color: transparent; border: none; color: #42526e; cursor: pointer; right: 0px; padding-left: 0px; padding-right: 0px; opacity: 0; transform: translate(-8px, 0px); transition: opacity 0.2s ease 0s, transform 0.2s ease 0s;"><svg width="24" height="24" viewbox="0 0 24 24" role="presentation"><g fill="currentColor" fill-rule="evenodd"><path d="M12.856 5.457l-.937.92a1.002 1.002 0 000 1.437 1.047 1.047 0 001.463 0l.984-.966c.967-.95 2.542-1.135 3.602-.288a2.54 2.54 0 01.203 3.81l-2.903 2.852a2.646 2.646 0 01-3.696 0l-1.11-1.09L9 13.57l1.108 1.089c1.822 1.788 4.802 1.788 6.622 0l2.905-2.852a4.558 4.558 0 00-.357-6.82c-1.893-1.517-4.695-1.226-6.422.47"></path><path d="M11.144 19.543l.937-.92a1.002 1.002 0 000-1.437 1.047 1.047 0 00-1.462 0l-.985.966c-.967.95-2.542 1.135-3.602.288a2.54 2.54 0 01-.203-3.81l2.903-2.852a2.646 2.646 0 013.696 0l1.11 1.09L15 11.43l-1.108-1.089c-1.822-1.788-4.802-1.788-6.622 0l-2.905 2.852a4.558 4.558 0 00.357 6.82c1.893 1.517 4.695 1.226 6.422-.47"></path></g></svg></button></h3> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="7258">仕様が異なる2種類の小型自動搬送ロボットを私有地、公道を連携して走行させる今回の実証実験は国内初であることから、非常に多くの方々が訪問、見学に来られました。これは、自動配送ロボットを活用した配送サービスに対する地域住民の方々の期待の表れと感じとることができました。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="7398">また、地域住民の方々の声を直接聞くことで、自動配送サービスに対する気づきを得ることができました。</p> <p style="margin: 0.75rem 0px 0px; padding: 0px; font-size: 16px; line-height: 1.714; font-weight: 400; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-style: initial; text-decoration-color: initial;" data-renderer-start-pos="7448">実証実験を通して得られた新たな課題は、社内へフィードバックし、より良いサービスの提供、ならびに小型自動搬送ロボットにおける自動運転レベル4の実用化にむけ、さらなる検証・評価を進めていく所存です。</p> majestickou 自動運転データの検索システムを爆速で作った話 hatenablog://entry/26006613715133861 2021-04-14T16:30:00+09:00 2021-04-14T16:47:58+09:00 みんなデータを探せなくて困ってるということがわかりました。課題は見つけた人が解決する精神で、私が自分で検索システムを作ることにしました。 <h3 id="はじめに"><span style="font-weight: 400;">はじめに</span></h3> <p><span style="font-weight: 400;">こんにちは、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%B5%A1%B3%A3%B3%D8%BD%AC">機械学習</a>の活用を加速させるために学習インフラの開発やワークフロー自動化に取り組むチームに所属している澁井です。今回は自動運転のためのデータ検索基盤を自作した話を書きます。</span></p> <p>なお、ティアフォーでは「自動運転の<a class="keyword" href="http://d.hatena.ne.jp/keyword/%CC%B1%BC%E7%B2%BD">民主化</a>」をともに実現していくエンジニアを募集しています。今回ご紹介する<a class="keyword" href="http://d.hatena.ne.jp/keyword/%B5%A1%B3%A3%B3%D8%BD%AC">機械学習</a>だけではなく、様々なバックグラウンドをお持ちの方と開発を進めていく必要があります。下記ページから募集職種のリストをご覧いただき、興味を持った方はぜひお気軽にご連絡ください!</p> <p style="margin: 0px 0px 1em; color: #111111; font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftier4.jp%2Fcareers%2F" title="Careers | 株式会社ティアフォー" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="max-width: 500px; display: block; width: 500px; height: 155px; margin: 10px 0px;"></iframe></p> <ul class="table-of-contents"> <li><a href="#はじめに">はじめに</a></li> <li><a href="#課題">課題</a></li> <li><a href="#検索システムをどのように作るか">検索システムをどのように作るか</a></li> <li><a href="#どのくらいの期間で作ったか">どのくらいの期間で作ったか</a></li> <li><a href="#もっと検索できるようにしたいデータがあった">もっと検索できるようにしたいデータがあった</a></li> <li><a href="#まとめ">まとめ</a></li> </ul> <p><span style="font-weight: 400;">さて、ティアフォーでは自動運転に<a class="keyword" href="http://d.hatena.ne.jp/keyword/%B5%A1%B3%A3%B3%D8%BD%AC">機械学習</a>を活用しています。主な<a class="keyword" href="http://d.hatena.ne.jp/keyword/%B5%A1%B3%A3%B3%D8%BD%AC">機械学習</a>の用途は画像や動画データを扱った認識技術への応用です。</span></p> <p><span style="font-weight: 400;"><a class="keyword" href="http://d.hatena.ne.jp/keyword/%B5%A1%B3%A3%B3%D8%BD%AC">機械学習</a>では意味づけ(<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A2%A5%CE%A5%C6%A1%BC%A5%B7%A5%E7%A5%F3">アノテーション</a>)されたデータが大量に必要となります。<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A2%A5%CE%A5%C6%A1%BC%A5%B7%A5%E7%A5%F3">アノテーション</a>とはネコの画像には「ネコ」、イヌの画像には「イヌ」と画像に意味を付与することです。</span></p> <p><span style="font-weight: 400;">自動運転で扱うデータは主に実証実験で各地を走ったデータになり、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%B5%A1%B3%A3%B3%D8%BD%AC">機械学習</a>の学習データも実証実験で得たデータになります。しかし実証実験のデータは<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A2%A5%CE%A5%C6%A1%BC%A5%B7%A5%E7%A5%F3">アノテーション</a>されておらず、自動運転を動かしているROS(Robot Operating System)特有のrosbagという<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C7%A1%BC%A5%BF%B7%C1%BC%B0">データ形式</a>になっているため、人間が生データを見て理解することはできません。データを分析して学習データを作るためにはrosbagを画像や動画形式に変換し、人間に読めるようにする必要があります。</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="自動運転からROS経由でデータを得る"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/c/cvusk/20210412/20210412082703.png" alt="f:id:cvusk:20210412082703p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">自動運転からROS経由でデータを得る</figcaption> </figure> <p><span style="font-weight: 400;">実証実験で収集するデータ量は<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%D3%A5%C3%A5%B0%A5%C7%A1%BC%A5%BF">ビッグデータ</a>と呼ぶに相応しく、一日に数TBを超える非構造化データが集まります。実証実験の価値を<a class="keyword" href="http://d.hatena.ne.jp/keyword/%B5%A1%B3%A3%B3%D8%BD%AC">機械学習</a>にフィードバックするためには収録したデータの中から有益なデータを探索し、学習データに加えられるようにする必要がありました。</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="自動運転のデータ規模"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/c/cvusk/20210412/20210412082956.png" alt="f:id:cvusk:20210412082956p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">自動運転のデータ規模</figcaption> </figure> <p><span style="font-weight: 400;">社内のデータ活用の状況を確認するため、社内コミュニケーションツールで下記のような質問をしてみました。</span></p> <blockquote> <p><span style="font-weight: 400;">質問:rosbagのデータを活用してる方々にオープンに質問なのですが、必要なデータはどうやって検索していますか? たとえば緯度経度や地名による検索とか、年月日、時間帯とか、どういう条件で検索できると便利でしょうか?</span></p> <p> </p> <p><span style="font-weight: 400;">回答:ほしい!</span></p> </blockquote> <figure class="figure-image figure-image-fotolife mceNonEditable" title="社内取引はネコ画像"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/c/cvusk/20210412/20210412083253.png" alt="f:id:cvusk:20210412083253p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">社内取引はネコ画像</figcaption> </figure> <p><span style="font-weight: 400;">その結果、みんなデータを探せなくて困っているものの、データを整備する<a class="keyword" href="http://d.hatena.ne.jp/keyword/%B9%A9%BF%F4">工数</a>が取れない、ということがわかりました。課題は見つけた人が解決する精神で、私が自分で検索システムを作ることにしました。</span></p> <h3 id="課題"><span style="font-weight: 400;">課題</span></h3> <p><span style="font-weight: 400;">まず、ティアフォー社内のデータ活用には3つの課題がありました。</span></p> <ol> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">データを探せない:実証実験で得たデータは社内に大量に貯まっているが、開発者が目的のデータを簡単に見つけられない。</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">保管先がまばら:データは社内ストレージにアップロードされている一方、「どこ」に「いつ」の「どの」データが保管されているのか、統一して整理されていない。</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;"><a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%AF%A5%E9%A5%A6%A5%C9">クラウド</a>を使わない:データが<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%AF%A5%E9%A5%A6%A5%C9">クラウド</a>に貯まっているのにローカルの開発端末にダウンロードして使おうとする。</span></li> </ol> <p><span style="font-weight: 400;">他にも細かい課題は多々ありますが、データ活用を加速して<a class="keyword" href="http://d.hatena.ne.jp/keyword/%B5%A1%B3%A3%B3%D8%BD%AC">機械学習</a>開発を効率化するためにはデータが探しづらい状態です。ほしいデータを得るためには社内ドキュメントに書かれた実験記録(自動運転で走った場所、日時、天気など)を元に、社内ストレージからrosbagファイルを探してダウンロードし、開発者の端末でrosbagを解凍して必要なデータを探さなければいけませんでした。rosbagは1ファイルで1GB以上のサイズの中に、自動運転中の5、6分程度を記録しています。<a class="keyword" href="http://d.hatena.ne.jp/keyword/%B5%A1%B3%A3%B3%D8%BD%AC">機械学習</a>に必要なバラエティのあるデータを得るためには5、6分程度では足りません。漏れのないデー<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%BF%A5%BB%A5%C3%A5%C8">タセット</a>を作るためには、年間通して場所や明るさ、天気、被写体の位置、大きさ、カメラの方向、自動運転の速度などを組み合わせた多様なデータパターンを用意する必要があります。rosbagファイルをいちいちダウンロードして確認するのはあまりにも非効率です。</span></p> <p><span style="font-weight: 400;">そこで、rosbagで収集したデータを検索できるシステムを<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%AF%A5%E9%A5%A6%A5%C9">クラウド</a>上に作ることにしました。検索システムのゴールは社内に散らばったデータを同じ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A4%A5%F3%A5%BF%A1%BC%A5%D5%A5%A7%A5%A4%A5%B9">インターフェイス</a>で検索し、すぐ利用できるようにすることです。</span></p> <h3 id="検索システムをどのように作るか"><span style="font-weight: 400;">検索システムをどのように作るか</span></h3> <p><span style="font-weight: 400;">検索<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B7%A5%B9%A5%C6%A5%E0%B3%AB%C8%AF">システム開発</a>で立てた目標の一つは、最速で作ってすぐ使える状態にすることです。データは貯まれば貯まるほど整理し使えるようにすることが難しくなります。データベースに登録するだけでも長時間かかりますし、バラエティが増えれば属性の整理やテーブル設計が困難になります。日々数TBの非構造化データが貯まる状況で放っておくことは良策ではありません。もちろんこれまでティアフォーでは検索システムがなくても開発できていたので、自動運転に検索システムは必要ないのかもしれません。しかし、ツールを導入することで仕事が楽になるかどうかは導入してみないとわかりません。検索の有用性(または無用性)を証明するため、スピーディに作ってPoCを進めることも目標としました。</span></p> <p><span style="font-weight: 400;">スピード優先で開発するため、検索システムのソフトウェアスタックには下記のすぐ簡単に使えるものを選びました。</span> </p> <ul> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">インフラ:<a class="keyword" href="http://d.hatena.ne.jp/keyword/Kubernetes">Kubernetes</a>(<a class="keyword" href="http://d.hatena.ne.jp/keyword/Amazon">Amazon</a> EKS『</span><a href="https://tech.tier4.jp/entry/reconstruct-eks"><span style="font-weight: 400;">2020年でKubernetesクラスターを3回再構築した話</span></a><span style="font-weight: 400;">』参照)</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">データベース:<a href="https://aws.amazon.com/jp/rds/aurora/postgresql-features/">Amazon PostgreSQL Aurora</a></span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">バックエンド<a class="keyword" href="http://d.hatena.ne.jp/keyword/API">API</a>:<a class="keyword" href="http://d.hatena.ne.jp/keyword/Python">Python</a>、<a href="https://fastapi.tiangolo.com/ja/">FastAPI</a>、<a href="https://www.sqlalchemy.org/">SQL Alchemy</a></span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">画面:<a class="keyword" href="http://d.hatena.ne.jp/keyword/Python">Python</a>、<a href="https://streamlit.io/">Streamlit</a></span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">データパイプラインとデータの意味づけ:<a class="keyword" href="http://d.hatena.ne.jp/keyword/Python">Python</a>、<a href="https://tfhub.dev/google/efficientnet/b1/classification/1">COCOデータセット学習済みEfficientDetの物体検知</a>、TensorFlow Serving</span> </li> </ul> <p><span style="font-weight: 400;">全体像は以下のようになります。</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="検索システム(α版)"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/c/cvusk/20210412/20210412083517.png" alt="f:id:cvusk:20210412083517p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">検索システム(α版)</figcaption> </figure> <p><span style="font-weight: 400;">ソフトウェアスタックと全体像からわかるとおり、主な開発言語は<a class="keyword" href="http://d.hatena.ne.jp/keyword/Python">Python</a>です。検索のレスポンス速度を上げるならば<a class="keyword" href="http://d.hatena.ne.jp/keyword/Java">Java</a>や<a class="keyword" href="http://d.hatena.ne.jp/keyword/Golang">Golang</a>を使ったほうが性能が改善されますが、短い期間で作り切ることを優先して<a class="keyword" href="http://d.hatena.ne.jp/keyword/Python">Python</a>を選びました。<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C7%A5%A3%A1%BC%A5%D7%A5%E9%A1%BC%A5%CB%A5%F3%A5%B0">ディープラーニング</a>でデータに意味づけするためには<a class="keyword" href="http://d.hatena.ne.jp/keyword/Python">Python</a>がより扱いやすいという理由もあります。</span></p> <p><span style="font-weight: 400;">インフラは以前構築した<a class="keyword" href="http://d.hatena.ne.jp/keyword/Amazon">Amazon</a> EKSの<a class="keyword" href="http://d.hatena.ne.jp/keyword/Kubernetes">Kubernetes</a><a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%AF%A5%E9%A5%B9%A5%BF">クラスタ</a>ーを使っています。個人的に<a class="keyword" href="http://d.hatena.ne.jp/keyword/Kubernetes">Kubernetes</a>が最も楽に使えるインフラになっているからです。データベースは私の好みでAurora <a class="keyword" href="http://d.hatena.ne.jp/keyword/PostgreSQL">PostgreSQL</a>を使っています。</span></p> <p><span style="font-weight: 400;">バックエンド<a class="keyword" href="http://d.hatena.ne.jp/keyword/API">API</a>はFastAPIと<a class="keyword" href="http://d.hatena.ne.jp/keyword/SQL">SQL</a> Alchemyで作っています。</span><a href="https://fastapi.tiangolo.com/tutorial/sql-databases/">SQL (Relational) Databases - FastAPI</a><span style="font-weight: 400;">で書かれているデータ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A4%A5%F3%A5%BF%A1%BC%A5%D5%A5%A7%A5%A4%A5%B9">インターフェイス</a>設計をそのまま参考にしています。<a class="keyword" href="http://d.hatena.ne.jp/keyword/Python">Python</a>側のデータ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B9%A5%AD%A1%BC%A5%DE">スキーマ</a>はPydanticで定義することで、関数間のデータ受け渡しで型がわからなくなって実装に迷うことを避けました。型が定まっているとコーディングの手戻りが減ります。</span></p> <p><span style="font-weight: 400;">バックエンド<a class="keyword" href="http://d.hatena.ne.jp/keyword/API">API</a>は<a class="keyword" href="http://d.hatena.ne.jp/keyword/Python">Python</a>+FastAPI+<a class="keyword" href="http://d.hatena.ne.jp/keyword/SQL">SQL</a> Alchemyで手早く済ませた<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%DD%A1%BC%A5%CD%A5%F3%A5%C8">コンポーネント</a>です。機能とデータが増えてパフォーマンス劣化してきたら、他の言語かgRPCで作り変えてORMも排除すると思います。</span></p> <p><span style="font-weight: 400;">画面はStreamlitという<a class="keyword" href="http://d.hatena.ne.jp/keyword/Python">Python</a>をベースにWeb画面を作ってデータを可視化するライブラリを使います。通常はHTML + <a class="keyword" href="http://d.hatena.ne.jp/keyword/JavaScript">JavaScript</a>で作る部分ですが、<a class="keyword" href="http://d.hatena.ne.jp/keyword/JavaScript">JavaScript</a>を書きたくないという個人的な理由でStreamlitを選びました。次はFlutterで作りたいと考えています。</span></p> <p><span style="font-weight: 400;">以下の公式の動画のように、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%DD%A1%BC%A5%CD%A5%F3%A5%C8">コンポーネント</a>を<a class="keyword" href="http://d.hatena.ne.jp/keyword/Python">Python</a>コードで書くことで画面表示を定義できてとても便利です。</span></p> <p><iframe width="560" height="315" src="https://www.youtube.com/embed/QjccJl_7Jco?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" id="widget2"></iframe><cite class="hatena-citation"><a href="https://youtu.be/QjccJl_7Jco">youtu.be</a></cite></p> <p><span style="font-weight: 400;">Streamlitであれば<a class="keyword" href="http://d.hatena.ne.jp/keyword/Python">Python</a>のグラフ作成ライブラリのMatplotlibやSeabornと組み合わせてデータのグラフを簡単に画面に表示できるため、良い選択だったと思います。</span> </p> <p><span style="font-weight: 400;">データパイプラインとデータの意味づけではrosbagから画像を抽出し、データベースとストレージに登録します。抽出するデータは主に一般道を走る自動運転車のカメラで撮影する画像になります。</span></p> <p><span style="font-weight: 400;">意味づけのために物体検知を使い、映っている被写体を判定しています。自動運転の<a class="keyword" href="http://d.hatena.ne.jp/keyword/%B5%A1%B3%A3%B3%D8%BD%AC">機械学習</a>では、認識のためにカメラに映っている歩行者や対向車、バイク、信号機等を検知します。学習済みの物体検知(EfficientDet)で簡易的に被写体を検知し、検索時に被写体の数で絞り込みできるようにしています。データの意味づけには物体検知以外にも、画像の明るさや逆光、緯度経度と住所、日時と場所をベースにした天気、気温による検索を可能にしています。</span></p> <p><span style="font-weight: 400;">データパイプラインは<a class="keyword" href="http://d.hatena.ne.jp/keyword/Kubernetes">Kubernetes</a> Jobで定期的にデータを収集、解凍し、意味づけしてデータベースに登録します。</span></p> <p><span style="font-weight: 400;">意味づけのおかげで、たとえば以下のように「信号機」が映っている逆光画像を検索できるようにしています。</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="逆光画像"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/c/cvusk/20210412/20210412083656.png" alt="f:id:cvusk:20210412083656p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable"><a class="keyword" href="http://d.hatena.ne.jp/keyword/%A4%A6%A4%AA%A4%C3%A4%DE%A4%D6%A4%B7%A4%C3">うおっまぶしっ</a></figcaption> </figure> <p><span style="font-weight: 400;">別の例として、天気は「雪」で「自転車」が映っている画像です。</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="雪の日の自転車"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/c/cvusk/20210412/20210412083737.png" alt="f:id:cvusk:20210412083737p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">雪の日の自転車</figcaption> </figure> <h3 id="どのくらいの期間で作ったか"><span style="font-weight: 400;">どのくらいの期間で作ったか</span></h3> <p><span style="font-weight: 400;">上記の構成と機能で検索システムを作りました。</span></p> <p><span style="font-weight: 400;">ところどころ再開発するつもりで、さっさと使えるようにすることを優先して開発しています。以下に各<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%DD%A1%BC%A5%CD%A5%F3%A5%C8">コンポーネント</a>の開発所要時間をまとめます。</span></p> <ul> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;"><a class="keyword" href="http://d.hatena.ne.jp/keyword/Kubernetes">Kubernetes</a>は構築済みの<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%AF%A5%E9%A5%B9%A5%BF">クラスタ</a>ーにノードグループを追加し、各<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%DD%A1%BC%A5%CD%A5%F3%A5%C8">コンポーネント</a>を動かす<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%DE%A5%CB%A5%D5%A5%A7%A5%B9%A5%C8">マニフェスト</a>を書きました。所要時間は1時間以内です。</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">バックエンド<a class="keyword" href="http://d.hatena.ne.jp/keyword/API">API</a>とテーブル設計は最低限の機能と正規化にとどめ、2週間程度で開発しています。</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">画面はStreamlitのおかげで3日くらいで作れました。マークダウンやテーブル、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C1%A5%A7%A5%C3%A5%AF%A5%DC%A5%C3%A5%AF%A5%B9">チェックボックス</a>等Web画面に必要な<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%DD%A1%BC%A5%CD%A5%F3%A5%C8">コンポーネント</a>を<a class="keyword" href="http://d.hatena.ne.jp/keyword/Python">Python</a>のコード数行で書くことができるため、とても楽に作れました。</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">データパイプラインはrosbagを解凍しデータベースとストレージに登録するコードをシングルプロセスで書いています。今後収集するデータ量が増えたら並列処理を検討します。データの意味づけは学習済みの物体検知モデルや簡易的な明るさ評価を活用しています。データの意味づけは開発者の要望を聞きながらオンデマンドで追加していったため所要時間はまちまちですが、1機能1週間程度です。</span></li> </ul> <p><span style="font-weight: 400;">作ったものを適宜リリースしていく方式で、最初はバックエンド<a class="keyword" href="http://d.hatena.ne.jp/keyword/API">API</a>と画面だけを用意し、オリジナルのrosbagデータを取得した日時や場所だけで検索できる状態で社内公開しました。ここまで大体3週間で第1弾をリリースしています。</span></p> <p><span style="font-weight: 400;">そこから毎週1機能追加を目標としました。1週間ごとに物体検知、天気や気温による検索、画像の明るさや逆光検索を追加していきました。</span></p> <p><span style="font-weight: 400;">他の作業をこなしながら検索システムを作っていたのですが、1ヶ月強で作ったわりには便利なものが作れたと思います。</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="大体3週間ちょっとで作る"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/c/cvusk/20210412/20210412083828.png" alt="f:id:cvusk:20210412083828p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">大体3週間ちょっとで作る</figcaption> </figure> <p><span style="font-weight: 400;">機能追加時は最初にモック画面と動画を作り、機能のイメージを利用者に共有してから実物を作る流れを取りました。検索の仕様を言葉で要件定義する作業を減らし、見えて使えるものを作ることにこだわっています("Working software over comprehensive documentation"または"Done is better than perfect")。これもスピード優先で作るための工夫です。</span></p> <h3 id="もっと検索できるようにしたいデータがあった"><span style="font-weight: 400;">もっと検索できるようにしたいデータがあった</span></h3> <p><span style="font-weight: 400;">ここまで2021年3月中に開発とリリースを進めてきました。社内でデータ検索システムを作っていることを宣伝したおかげで、当初は存在を知らなかったデータや、課題が不明確だったデータ活用のシーンが判明しました。</span></p> <p><span style="font-weight: 400;">その一例が<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A2%A5%CE%A5%C6%A1%BC%A5%B7%A5%E7%A5%F3">アノテーション</a>されたデータの検索です。<a class="keyword" href="http://d.hatena.ne.jp/keyword/%B5%A1%B3%A3%B3%D8%BD%AC">機械学習</a>で使うデータは外注して<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A2%A5%CE%A5%C6%A1%BC%A5%B7%A5%E7%A5%F3">アノテーション</a>しているのですが、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A2%A5%CE%A5%C6%A1%BC%A5%B7%A5%E7%A5%F3">アノテーション</a>されたデータも画像と<a class="keyword" href="http://d.hatena.ne.jp/keyword/JSON">JSON</a>形式でストレージに貯まったままで、データベース管理や検索可能化はされていません。<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A2%A5%CE%A5%C6%A1%BC%A5%B7%A5%E7%A5%F3">アノテーション</a>されたデータが貯まれば貯まるほど、学習条件に合うデータを探すのに人手と時間を要するようになります。そこで、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A2%A5%CE%A5%C6%A1%BC%A5%B7%A5%E7%A5%F3">アノテーション</a>されたデータを元データの意味と<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A2%A5%CE%A5%C6%A1%BC%A5%B7%A5%E7%A5%F3">アノテーション</a>を組み合わせて検索する機能を開発しました。</span></p> <p><span style="font-weight: 400;">信号機の<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A2%A5%CE%A5%C6%A1%BC%A5%B7%A5%E7%A5%F3">アノテーション</a>された画像(以下は「黄色信号」の含まれる画像)を検索できるようにしています。</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="小さくて見えないけど黄信号が写っています"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/c/cvusk/20210412/20210412083926.png" alt="f:id:cvusk:20210412083926p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">小さくて見えないけど黄信号が写っています</figcaption> </figure> <p><span style="font-weight: 400;">この過程で<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A2%A5%CE%A5%C6%A1%BC%A5%B7%A5%E7%A5%F3">アノテーション</a>されたデータを整理し数量をまとめることになりました。そこで判明したことは、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A2%A5%CE%A5%C6%A1%BC%A5%B7%A5%E7%A5%F3">アノテーション</a>は特定のカテゴリに偏っており、本来考慮すべきだが、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A2%A5%CE%A5%C6%A1%BC%A5%B7%A5%E7%A5%F3">アノテーション</a>が少ないデータカテゴリが存在することです。日々扱っているデータでも、整理、集計しないと実態を知ることはできないということです。</span></p> <p><span style="font-weight: 400;">今回は画像データをターゲットに検索データを作りましたが、その他にもポイント<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%AF%A5%E9%A5%A6%A5%C9">クラウド</a>のデータ等、自動運転には欠かせないデータが残っています。また、社内ストレージから発掘された未知のデータを検索できるようにしたいという要望が出てきています。</span></p> <p><span style="font-weight: 400;">個人的には「類似した状況」を条件に検索できるようにしたいと思っています。自動運転では運転中の周囲の状況が運転の判断を左右することがあります。左を並走している自動車が車線変更して先方に入ってきたり、先行している自動車が右折したり、道路幅が狭くなっていたり、周囲に建物があったり、林の中を走っていたり、自転車が並走していたり・・・。多種多様な状況を認識して自動運転するため、こうした「状況」を検索できるようにすることで、状況に応じた運転ロジックの開発を効率化することができると思います。画像や動画を入力にして似ている状況を検索する類似状況検索のようなシステムを作りたいです。</span></p> <h3 id="まとめ"><span style="font-weight: 400;">まとめ</span></h3> <p><span style="font-weight: 400;">データは貯めるだけでも<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B7%A5%B9%A5%C6%A5%E0%B3%AB%C8%AF">システム開発</a>とコストが必要となりますが、貯めるだけでなく使える状態にするためにはデータの意味づけと検索が必須になります。データは容量が増えれば増えるほど整理し管理する難しさが増します。加えてデータを使えていない状態では、データを使えない不便さに気づけない事態が頻繁に発生します。データ検索のあり方はデータの使い方や目的次第で千差万別です。今回の開発では素早く作って直しながら、本当に必要なものを目指していく方針がうまくハマりました。</span></p> <p>最後に1つだけご紹介させてください。</p> <p>4月21日にティアフォー初の【Tier IV SUMMIT 2021】をオンラインで開催します!</p> <p>参加は無料で自動運転の最前線を語ります!ぜひご登録ください!</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftier4summit.com%2F" title="Tier IV SUMMIT 2021 - ティアフォー初の公式サミット" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://tier4summit.com/">tier4summit.com</a></cite></p> cvusk 自動運転の実証実験を「安全」に進めるためのリスクアセスメントの活用について hatenablog://entry/26006613709839708 2021-04-07T16:00:00+09:00 2021-04-07T16:00:02+09:00 こんにちは、ティアフォーで安全に関して担当している新宅と申します。今回は、全国で進めている実証実験を「安全」に進めるためのリスクアセスメントの活用についてご紹介します。実証実験に限らず、安全を担保することは自動運転車両を開発する上で必要不可欠であり、社会受容性を高めていくための最も重要な要素の1つとなります。 なお、ティアフォーでは「自動運転の民主化」をともに実現していくエンジニアを募集しています。今回ご紹介する安全だけではなく、様々なバックグラウンドをお持ちの方と開発を進めていく必要があります。下記ページから募集職種のリストをご覧いただき、興味を持った方はぜひお気軽にご連絡ください! 安全に… <p style="margin: 0px 0px 1em; color: #111111; font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">こんにちは、ティアフォーで安全に関して担当している新宅と申します。今回は、全国で進めている実証実験を「安全」に進めるための<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%EA%A5%B9%A5%AF%A5%A2%A5%BB%A5%B9%A5%E1%A5%F3%A5%C8">リスクアセスメント</a>の活用についてご紹介します。実証実験に限らず、安全を担保することは自動運転車両を開発する上で必要不可欠であり、社会受容性を高めていくための最も重要な要素の1つとなります。</p> <p>なお、ティアフォーでは「自動運転の<a class="keyword" href="http://d.hatena.ne.jp/keyword/%CC%B1%BC%E7%B2%BD">民主化</a>」をともに実現していくエンジニアを募集しています。今回ご紹介する安全だけではなく、様々なバックグラウンドをお持ちの方と開発を進めていく必要があります。下記ページから募集職種のリストをご覧いただき、興味を持った方はぜひお気軽にご連絡ください!</p> <p style="margin: 0px 0px 1em; color: #111111; font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftier4.jp%2Fcareers%2F" title="Careers | 株式会社ティアフォー" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="max-width: 500px; display: block; width: 500px; height: 155px; margin: 10px 0px;"></iframe></p> <ul class="table-of-contents"> <li><a href="#安全に関わる最近のデータや動き">安全に関わる最近のデータや動き</a><ul> <li><a href="#年間の交通事故死者数">年間の交通事故死者数</a></li> <li><a href="#自動走行の実現に向けた国の直近の動き">自動走行の実現に向けた国の直近の動き</a></li> </ul> </li> <li><a href="#ティアフォーの実証実験の安全をリスクアセスメントで担保">ティアフォーの実証実験の安全をリスクアセスメントで担保</a><ul> <li><a href="#ODDアセスメントとは">ODDアセスメントとは?</a><ul> <li><a href="#ODDアセスメントの実施方法">ODDアセスメントの実施方法</a></li> </ul> </li> <li><a href="#走行ルートサーベイとは">走行ルートサーベイとは?</a><ul> <li><a href="#走行環境条件の設定のパターン化参照モデルの活用">走行環境条件の設定のパターン化参照モデルの活用</a></li> <li><a href="#保険会社の事故データの活用">保険会社の事故データの活用</a></li> </ul> </li> </ul> </li> <li><a href="#まとめ">まとめ</a></li> </ul> <h3 id="安全に関わる最近のデータや動き">安全に関わる最近のデータや動き</h3> <p><span style="color: #111111; font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; float: none; display: inline !important;"><a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%EA%A5%B9%A5%AF%A5%A2%A5%BB%A5%B9%A5%E1%A5%F3%A5%C8">リスクアセスメント</a>についてお話する前に、安全に関わる最近のデータや動きについてご紹介します。</span></p> <h4 id="年間の交通事故死者数">年間の交通事故死者数</h4> <p>2021年1月4日、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%B7%D9%BB%A1%C4%A3">警察庁</a>が2020年の交通事故死者数は前年よりも376人少ない2,839人だったことを発表しました。この数字は、4年連続で戦後最小を更新し、かつ初めて3,000人を下回ったとのことです。</p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="交通事故死者数の推移"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/y/yst4/20210322/20210322103308.png" alt="f:id:yst4:20210322103308p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">出典:<a class="keyword" href="http://d.hatena.ne.jp/keyword/%B7%D9%BB%A1%C4%A3">警察庁</a>ウェブサイト</figcaption> </figure> <p>この数字を見て、本記事を読んでいただいている皆さまは多いと思うでしょうか?それとも戦後最小を更新し続けているのだから少ないと思うでしょうか?おそらく皆さまそれぞれの感覚があるかと思います。しかし、1つはっきりしていることは、交通事故の数が限りなくゼロに近づけば同時に交通事故死者数も減っていきます。自動運転が普及することの意義の1つには、交通事故の数が限りなくゼロに近づいていくことにあります。一方で、仮に全て自動運転車になれば事故の数はゼロになるのでしょうか?不慮の事態を考慮すると、残念ながら自動運転が実現しても事故の数がゼロになるとは言えません。それでも、事故の数を限りなくゼロにすることを目指すべく、自動運転車の開発を進めています。これをエンジニアリング観点で言えば、許容可能なリスクの発生確率や損害の程度を<a class="keyword" href="http://d.hatena.ne.jp/keyword/%C4%EA%CE%CC">定量</a>的に定め、総合的に許容可能な範囲を決めながら安全な設計を行っています。</p> <h4 id="自動走行の実現に向けた国の直近の動き">自動走行の実現に向けた国の直近の動き</h4> <p> 3月はじめに、「自動走行ビジネス検討会」から「自動走行の実現及び普及に向けた<br />取組報告と方針」Version5.0の概要案が示されたのでこちらも簡単にご紹介します。</p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="出典:経済産業省・自動走行ビジネス検討会ウェブサイト"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/y/yst4/20210322/20210322162229.png" alt="f:id:yst4:20210322162229p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">出典:<a class="keyword" href="http://d.hatena.ne.jp/keyword/%B7%D0%BA%D1%BB%BA%B6%C8%BE%CA">経済産業省</a>・自動走行ビジネス検討会ウェブサイト</figcaption> </figure> <p><span style="color: #111111; font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; float: none; display: inline !important;">特に(1)では、本記事の主題である安全に関する記載があります。ここでは、米国NHTSA(<a class="keyword" href="http://d.hatena.ne.jp/keyword/%B1%BF%CD%A2%BE%CA">運輸省</a>道路交通安全局)の項目を参照しながら日本版セーフティレポート(仮称)と称して情報発信することの重要性を示し、さらに「走行環境・運行条件で想定されるリスクを網羅的に評価し、その安全対策をあらかじめ十分に行う、セーフティアセスメント(仮称)がきわめて重要」<a href="#f-d8e37bbf" name="fn-d8e37bbf" title="https://www.meti.go.jp/shingikai/mono_info_service/jido_soko/pdf/012_s01_00.pdf">*1</a>と判断しており、今年度を目途にセーフティアセスメント(仮称)に係る<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%AC%A5%A4%A5%C9%A5%E9%A5%A4%A5%F3">ガイドライン</a>が作成される予定となっています。また本概要案では、2025年度までに40か所以上で自動運転レベル4の<a class="keyword" href="http://d.hatena.ne.jp/keyword/%CC%B5%BF%CD">無人</a>自動運転サービスを実現する旨の記載もあり、今後5年以内に自動運転レベル4の普及が進んでいくことが考えられます。</span></p> <p>米国NHTSAの項目について興味のある方は、<a href="https://www.nhtsa.gov/document/automated-driving-systems-20-voluntary-guidance">https://www.nhtsa.gov/document/automated-driving-systems-20-voluntary-guidance</a>をご参照ください。<span style="color: #111111; font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; float: none; display: inline !important;">また、エンジニアリング観点での「安全」については、</span><a href="https://tech.tier4.jp/entry/2020/11/25/160000">安全への取り組み:②自動運転の安心・安全について - Tier IV Tech Blog</a>でご紹介しているので是非ご覧ください。</p> <h3 id="ティアフォーの実証実験の安全をリスクアセスメントで担保">ティアフォーの実証実験の安全を<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%EA%A5%B9%A5%AF%A5%A2%A5%BB%A5%B9%A5%E1%A5%F3%A5%C8">リスクアセスメント</a>で担保</h3> <p>さて、昨年の交通事故死者数から自動運転車開発の意義の1つを、そして国でも安全に自動運転車を普及・実現させていくために様々な動きがあることを見てきました。さらに「自動走行ビジネス検討会」では、セーフティアセスメント(仮称)に係る<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%AC%A5%A4%A5%C9%A5%E9%A5%A4%A5%F3">ガイドライン</a>作成が予定されている旨お話しましたが、ここからは全国で進めている実証実験を「安全」に進めるためにティアフォーが既に活用している「<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%EA%A5%B9%A5%AF%A5%A2%A5%BB%A5%B9%A5%E1%A5%F3%A5%C8">リスクアセスメント</a>」についてご紹介します。現在ティアフォーでは、異なる観点から「ODDアセスメント」と「走行ルート<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B5%A1%BC%A5%D9%A5%A4">サーベイ</a>」という2種類の「<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%EA%A5%B9%A5%AF%A5%A2%A5%BB%A5%B9%A5%E1%A5%F3%A5%C8">リスクアセスメント</a>」を行っています。</p> <p>※ODD:「Operational Design Domain」の略で、「運行設計領域」と呼ばれる自動運転システムが作動する前提となる走行環境条件のことです。</p> <h4 id="ODDアセスメントとは">ODDアセスメントとは?</h4> <p>まず、なぜODDアセスメントが必要なのでしょうか?ティアフォーでは下記のような理由からODDアセスメントを実施しています。</p> <ul> <li>走行ルートを決める際、車両を走行させることなく自動走行の可否を事前に把握するため</li> <li>走行限界を超えている箇所について、事前の対策を行うことが出来るため</li> <li>アセスメントの結果をドライバーやオペレータに周知することで、より安心・安全な走行を実現するため</li> <li>アセスメントの結果を活用し、運用面でのリスクを可視化するため</li> </ul> <p>実施にあたっては地図・走行経路、ODD<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E6%A1%BC%A5%B9%A5%B1%A1%BC%A5%B9">ユースケース</a>、Pilot.Auto性能仕様、シミュレータ実施結果を使用します。それでは、ここからODDアセスメントの実施方法をご説明します。</p> <h5 id="ODDアセスメントの実施方法">ODDアセスメントの実施方法</h5> <ol> <li><strong>コースの細分化</strong><br />下図のように、コースをODDカテゴリに分割してロードセクション番号を付加し、ロードセクション単位で評価を実施していきます。<br /> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/y/yst4/20210323/20210323160102.png" alt="f:id:yst4:20210323160102p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> </li> <li><strong>各ロードセクションごとに<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E6%A1%BC%A5%B9%A5%B1%A1%BC%A5%B9">ユースケース</a>定義を割当</strong><br />次に、各ロードセクションにおける<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E6%A1%BC%A5%B9%A5%B1%A1%BC%A5%B9">ユースケース</a>分析を行います。例えば、下図のように大枠として発車、同一車線内走行、右折、左折などとし、そこから同一車線内走行-通常走行(対向車線なし)や、左折-T字路交差点(信号なし)などの<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E6%A1%BC%A5%B9%A5%B1%A1%BC%A5%B9">ユースケース</a>に当てはめていきます。<br /> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/y/yst4/20210324/20210324104932.png" alt="f:id:yst4:20210324104932p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> </li> <li><strong>シナリオによる検証確認</strong><br />ロードセクションごとに<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E6%A1%BC%A5%B9%A5%B1%A1%BC%A5%B9">ユースケース</a>定義を割り当てたら、ロードセクションの<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E6%A1%BC%A5%B9%A5%B1%A1%BC%A5%B9">ユースケース</a>におけるシナリオのシミュレーション・<a class="keyword" href="http://d.hatena.ne.jp/keyword/%BC%C2%BC%D6">実車</a>での検証結果の確認を行います。</li> <li><strong>各ロードセクションの評価</strong><br />そして各ロードセクションの評価をしていきます。下図のように、これまで行ってきたシナリオ総数とそのシナリオを検証した結果のNG数の割合である「性能限界率」を算出します。さらにそれだけでなく、「ODD範囲(=人的介入が必要なのか、もしくは誘導員を配置するなど運用面の対策やそもそもソフトウェアの調整が必要なのかといったもの)」、「限界要因(=性能限界に達している要因が自車両によるものなのか、もしくはカットインしてきた車両や工事中の場所を走行する場合など、外部のものなのかといった要因をより細かく見ていくもの)」をそれぞれ4段階に分けた点数付けを行い、合計点数を算出します。<br /> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/y/yst4/20210323/20210323162643.png" alt="f:id:yst4:20210323162643p:plain" title="" class="hatena-fotolife" itemprop="image" /><br />合計点数を算出したら、下表にしたがってリスク評価を行います。点数が高ければよりリスクが高いことを示しており、運行計画の変更を検討していきます。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/y/yst4/20210323/20210323172456.png" alt="f:id:yst4:20210323172456p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> </li> <li><strong>評価結果からリスク軽減策の検討・実施</strong><br /> <p>最後に、4.で出てきた結果から安全余裕を確保するよう自動運転計画を修正し、リスクの軽減を図ります。リスク軽減策には、例えば車速の低減やより車間距離を取るなど、性能限界内での運用可能な手段を講じる場合もあれば、オーバーライド(=自動運転から手動運転に切り替えること)により、ルートの一部は必ず手動運転とすることで安全を担保するといった対策があります。下図がその一例となります。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/y/yst4/20210324/20210324104424.png" alt="f:id:yst4:20210324104424p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> </li> </ol> <p>このような一連の流れを経て、ODDアセスメント行っています。リスク軽減策を実施した場合には、改めて評価を行うことでより安全に実証実験が進められるようにしています。</p> <h4 id="走行ルートサーベイとは">走行ルート<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B5%A1%BC%A5%D9%A5%A4">サーベイ</a>とは?</h4> <p>次に、走行ルート<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B5%A1%BC%A5%D9%A5%A4">サーベイ</a>についてご紹介します。既にご紹介したODDアセスメントと似たようなものではありますが、アプローチの仕方でいくつか異なる点が存在します。異なる2点を中心に走行ルート<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B5%A1%BC%A5%D9%A5%A4">サーベイ</a>についてお話します。</p> <h5 id="走行環境条件の設定のパターン化参照モデルの活用">走行環境条件の設定のパターン化参照モデルの活用</h5> <p>これは、「自動走行に係る官民協議会」で日本経済再生総合事務局が策定したもので、「<a class="keyword" href="http://d.hatena.ne.jp/keyword/%CC%B5%BF%CD">無人</a>自動運転移動サービスの導入を検討している企業・団体等向けに、導入の検討段階において参考となる導入地域の環境や条件についてパターンを整理した」<a href="#f-ef3ad405" name="fn-ef3ad405" title="https://www.kantei.go.jp/jp/singi/keizaisaisei/jidousoukou/pdf/model.pdf">*2</a>ものになっています。<a class="keyword" href="http://d.hatena.ne.jp/keyword/%CC%B5%BF%CD">無人</a>自動運転移動サービスの実施に向けて「共通言語」として使用することで、より導入の検討が進むことを意図しています。</p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="出典:https://www.kantei.go.jp/jp/singi/keizaisaisei/jidousoukou/index.html"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/y/yst4/20210322/20210322172341.png" alt="f:id:yst4:20210322172341p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">出典:<a href="https://www.kantei.go.jp/jp/singi/keizaisaisei/jidousoukou/index.html">https://www.kantei.go.jp/jp/singi/keizaisaisei/jidousoukou/index.html</a></figcaption> </figure> <p>このモデルを参照し、順番に実証実験実施予定地域の走行ルート<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B5%A1%BC%A5%D9%A5%A4">サーベイ</a>を行います。例えば、1番目の時間については、実施予定地域・場所の日の出・日の入り時刻を調べることで、実証実験を安全に行うための開始・終了時間設定の参考にします。また8番目の交通量については、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%BC%AB%BC%A3">自治</a>体から情報提供いただき、その道路の交通量を可視化(例:〇〇台/24時間など)することで、安全に実証実験を進めていくルートを策定する参考にします。自動運転の技術力を上げていくため、時にはチャレンジングなルートを策定することもありますが、先ほどご紹介したODDアセスメントと合わせて確認していくことで、チャレンジングでありながらも、安全を最優先して実証実験を行っています。</p> <h5 id="保険会社の事故データの活用">保険会社の事故データの活用</h5> <p>さらに、保険会社の事故データを活用して「事故多発地点」と「うっかり運転地点」を本<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B5%A1%BC%A5%D9%A5%A4">サーベイ</a>の中に含めています。「過去5年間で3回以上事故が起こった地点」を「事故多発地点」、「直近半年間で一時不停止、踏切不停止、速度超過、一方通行違反が起こった地点」を「うっかり運転地点」と定義して「リスクの高い地点」を割り出しています。ご参考までに、「うっかり運転地点」の例を下図に示しています。一時不停止や一方通行違反があることが見て取れます。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/y/yst4/20210324/20210324103510.png" alt="f:id:yst4:20210324103510p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <p>実際に起こった事故だけでなく、「うっかり運転地点」まで加えている理由ですが、「<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%CF%A5%A4%A5%F3%A5%EA%A5%C3%A5%D2%A4%CE%CB%A1%C2%A7">ハインリッヒの法則</a>」では「1つの重大事故の背後には29の軽微な事故があり、その背景には300の異常(ヒヤリ・ハット)が存在する」<a href="#f-df31ca19" name="fn-df31ca19" title="https://ja.wikipedia.org/wiki/%E3%83%8F%E3%82%A4%E3%83%B3%E3%83%AA%E3%83%83%E3%83%92%E3%81%AE%E6%B3%95%E5%89%87">*3</a>と言われており、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%D2%A5%E4%A5%EA%A5%CF%A5%C3%A5%C8">ヒヤリハット</a>をきちんと分析し、対策を立てることが安全を担保するのに重要であると言われています。これを今回の「うっかり運転地点」に置き換えると、「うっかり運転地点」が発生している場所は「重大事故が起こる可能性がある」ことを示していると言えるので、これらの情報も本<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B5%A1%BC%A5%D9%A5%A4">サーベイ</a>に活用しています。なお、事故データの活用にあたり、ティアフォーがともに「自動運転の<a class="keyword" href="http://d.hatena.ne.jp/keyword/%CC%B1%BC%E7%B2%BD">民主化</a>」を実現するために連携している<a class="keyword" href="http://d.hatena.ne.jp/keyword/%C2%BB%B3%B2%CA%DD%B8%B1%A5%B8%A5%E3%A5%D1%A5%F3">損害保険ジャパン</a>株式会社様から提供いただいています。このように、ティアフォーだけでは提供出来ない情報を含めてご案内することで、より安全に対する優先度が高いことをおわかりいただけるのではないでしょうか。</p> <h3 id="まとめ">まとめ</h3> <p>今回は、「安全」というキーワードをもとに直近のデータや国の動きをお話し、安全を実現するための「<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%EA%A5%B9%A5%AF%A5%A2%A5%BB%A5%B9%A5%E1%A5%F3%A5%C8">リスクアセスメント</a>」についてご紹介しました。ティアフォーでは、安全を担保しながら自動運転の社会受容性を高めていけるよう引き続き開発を進めていきます。</p><div class="footnote"> <p class="footnote"><a href="#fn-d8e37bbf" name="f-d8e37bbf" class="footnote-number">*1</a><span class="footnote-delimiter">:</span><span class="footnote-text"><a href="https://www.meti.go.jp/shingikai/mono_info_service/jido_soko/pdf/012_s01_00.pdf">https://www.meti.go.jp/shingikai/mono_info_service/jido_soko/pdf/012_s01_00.pdf</a></span></p> <p class="footnote"><a href="#fn-ef3ad405" name="f-ef3ad405" class="footnote-number">*2</a><span class="footnote-delimiter">:</span><span class="footnote-text"><a href="https://www.kantei.go.jp/jp/singi/keizaisaisei/jidousoukou/pdf/model.pdf">https://www.kantei.go.jp/jp/singi/keizaisaisei/jidousoukou/pdf/model.pdf</a></span></p> <p class="footnote"><a href="#fn-df31ca19" name="f-df31ca19" class="footnote-number">*3</a><span class="footnote-delimiter">:</span><span class="footnote-text"><a href="https://ja.wikipedia.org/wiki/%E3%83%8F%E3%82%A4%E3%83%B3%E3%83%AA%E3%83%83%E3%83%92%E3%81%AE%E6%B3%95%E5%89%87">https://ja.wikipedia.org/wiki/%E3%83%8F%E3%82%A4%E3%83%B3%E3%83%AA%E3%83%83%E3%83%92%E3%81%AE%E6%B3%95%E5%89%87</a></span></p> </div> yst4 Autowareにおける狭路走行のための走行経路計画 hatenablog://entry/26006613707495087 2021-03-31T16:00:00+09:00 2021-03-31T16:00:03+09:00 こんにちは。ティアフォーで自動運転システムを開発している渡邉です。今回は、Autowareで使われている車両の走行経路の計画について簡単にご紹介したいと思います。 なお、ティアフォーでは「自動運転の民主化」をともに実現していくエンジニアを募集しております。今回ご紹介するような計画・制御に関わる分野だけでなく、様々なバックグラウンドをお持ちの方と開発を進めていく必要があります。下記ページから募集職種のリストをご覧いただき、興味を持った方はぜひお気軽にご連絡ください! tier4.jp 走行経路計画とは 走行経路計画とは、読んで字のごとく、車両が走行してほしい経路を計画することです。走行経路を計画… <p>こんにちは。ティアフォーで自動運転システムを開発している渡邉です。<br />今回は、Autowareで使われている車両の走行経路の計画について簡単にご紹介したいと思います。</p> <p>なお、ティアフォーでは「自動運転の<a class="keyword" href="http://d.hatena.ne.jp/keyword/%CC%B1%BC%E7%B2%BD">民主化</a>」をともに実現していくエンジニアを募集しております。今回ご紹介するような計画・制御に関わる分野だけでなく、様々なバックグラウンドをお持ちの方と開発を進めていく必要があります。下記ページから募集職種のリストをご覧いただき、興味を持った方はぜひお気軽にご連絡ください!</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftier4.jp%2Fen%2Fcareers%2F" title="Careers | Tier IV, Inc." class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://tier4.jp/en/careers/">tier4.jp</a></cite></p> <h3><strong>走行経路計画とは</strong></h3> <p><span style="font-weight: 400;">走行経路計画とは、読んで字のごとく、車両が走行してほしい経路を計画することです。</span><span style="font-weight: 400;">走行経路を計画するときには、道路の形状や道路上の障害物といったものを考慮しながら、車両が実際に走行できるように目標経路を計画する必要があります。走行経路の計画で必要な要件としては、次のようなものが考えられます。</span></p> <ul> <li>走行可能なエリアからはみ出さないこと</li> <li>障害物に衝突しないこと</li> <li>必要以上の蛇行といった不自然な挙動をしないこと</li> </ul> <p><span style="font-weight: 400;">人間が運転している場合、無意識のうちに走行したい経路を考えながらステアを切るといった操作をすると思います。しかし、自動運転では走行する経路を明示的に算出する必要があり、どのような曲線を描けば車両は安全に走行できるのか、を考える必要があります。また、車両が通れるかどうかの狭い道を通るようなシーンでは、車両の挙動を考えながら通過できる経路を考える必要があります。このようなシーンは人間でも難しい場合があると思います。</span></p> <p><span style="font-weight: 400;">今回は、狭い道を通るシーンを例に取り上げながら、Autowareの走行経路の計画方法についてご紹介したいと思います。</span></p> <h3><strong>狭路走行の難しさ</strong></h3> <p><span style="font-weight: 400;">狭い道を走行するシーンでは、単純に道路の中央を走行するような経路を計画すれば良いわけではありません。なぜならば、車両の大きさによってはうまく曲がりきれずに走行可能なエリアをはみ出してしまうからです。狭い道を走行するために考慮しなければならないことは、大きく分けて</span></p> <ul> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">道路の道幅、走行可能なエリア</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">車両の形状</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">車両の運動</span></li> </ul> <p><span style="font-weight: 400;">の3つになります。道路や車両の形状を考慮する必要があることは明らかだと思いますが、走行経路を決める上では車両の運動の特性も考える必要があります。例えば一般的な4輪の自動車の場合、その場で旋回して姿勢を変えるといった運動はできません。自動車の向きを変えたいときにはステアを切って前後に走行することで徐々に自動車の向きを変える必要があります。このように、一般に自動車は空間を自由に動くことはできず、自動車が動くことが可能な範囲は限定されています。そのため、自動車の運動の制限を考慮しながら走行経路の計画を行う必要があります。</span></p> <h3><strong>車両運動を考慮した走行経路計画</strong></h3> <p><span style="font-weight: 400;">車両運動を考慮した走行計画を考えるためには、車両の運動がどのように記述されるかを事前に求めておく必要があります。Autowareでは、ある速度で走行しながらステアを切ったときに、そのステア角に対する車両の位置・姿勢の変化量を数式ベースで取り扱っています。このように、ある入力に対する車両挙動の変化を表す数式を車両運動の<a class="keyword" href="http://d.hatena.ne.jp/keyword/%BF%F4%CD%FD%A5%E2%A5%C7%A5%EB">数理モデル</a>と呼びます。車両運動の<a class="keyword" href="http://d.hatena.ne.jp/keyword/%BF%F4%CD%FD%A5%E2%A5%C7%A5%EB">数理モデル</a>を用いると、与えられたステア角に対して車両が走行する経路をシミュレートすることができるようになります。これにより、車両が走行可能な範囲を考慮することができるようになります。</span></p> <p><span style="font-weight: 400;">走行経路を計画するとき、多くの場合通過可能なパターンは多数存在します。走行経路をひとつ決めるためには、何かの評価基準を与えて一番良いものを選ぶということを考えます。今回は、必要以上の蛇行や不自然な挙動を抑えたいため、ステアの角度や角速度、角加速度といったものをできる限り小さくするような走行経路を選択すると良さそうです。</span></p> <p><span style="font-weight: 400;">ここまでをまとめると、走行経路を計画するための目標と条件は次のようになります。</span> </p> <p><strong>目標:</strong></p> <ol> <li><span style="font-weight: 400;">ステアを切る角度・角速度・角加速度をできる限り小さくする</span></li> <li><span style="font-weight: 400;">道路の中央からできる限り離れないようにする</span></li> </ol> <p><strong>条件:</strong></p> <ol> <li><span style="font-weight: 400;">車両は<a class="keyword" href="http://d.hatena.ne.jp/keyword/%BF%F4%CD%FD%A5%E2%A5%C7%A5%EB">数理モデル</a>で記述された運動の法則に従って動く</span></li> <li><span style="font-weight: 400;">車両は走行可能なエリアからはみ出さない</span> </li> </ol> <p><span style="font-weight: 400;">これらの目標や条件が数式として定式化できれば、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%C4%EA%CE%CC">定量</a>的に走行経路の計画を行うことができるようになります。このように、目標や条件を数式として定式化して何かを計画する問題を数理<a class="keyword" href="http://d.hatena.ne.jp/keyword/%BA%C7%C5%AC%B2%BD%CC%E4%C2%EA">最適化問題</a>と呼びます。数理<a class="keyword" href="http://d.hatena.ne.jp/keyword/%BA%C7%C5%AC%B2%BD%CC%E4%C2%EA">最適化問題</a>は工学の分野だけでなく金融・経済など広い分野で登場するもので、その解き方は広く研究・開発されています。数理<a class="keyword" href="http://d.hatena.ne.jp/keyword/%BA%C7%C5%AC%B2%BD%CC%E4%C2%EA">最適化問題</a>の形で定式化することができれば、適切なソルバを用いることで条件を満たしつつできるだけ目標に近い解を得ることができます。上述した目標1にあるステア角度・角速度・角加速度や目標2にある道路中央からの距離はその数値そのものを扱えば良く、条件1の車両運動については<a class="keyword" href="http://d.hatena.ne.jp/keyword/%BF%F4%CD%FD%A5%E2%A5%C7%A5%EB">数理モデル</a>として定式化されています。したがって、走行経路計画を数理<a class="keyword" href="http://d.hatena.ne.jp/keyword/%BA%C7%C5%AC%B2%BD%CC%E4%C2%EA">最適化問題</a>として扱うためには、条件2の車両が走行可能なエリアからはみ出さないことを数式的に表現する必要があります。</span></p> <h3><strong>車両形状と走行可能領域</strong></h3> <p><span style="font-weight: 400;">車両が走行可能エリア内にいるかどうかの判定は様々な表現方法がありますが、表現の仕方によっては数理<a class="keyword" href="http://d.hatena.ne.jp/keyword/%BA%C7%C5%AC%B2%BD%CC%E4%C2%EA">最適化問題</a>の形式が難しくなってしまう場合があります。 そのため、Autowareではできる限り解きやすい形式で走行可能領域に関する条件を与えられるように工夫しています。</span></p> <p><span style="font-weight: 400;">Autowareでは、車両の中心線(図1の破線)と道路の中心線(図1の赤線)との距離を計算し、その距離と車両幅の半分の和が道路中心線から道路の端までの距離より小さいときに車両が走行可能エリア内にいると判定します。この判定を車両の前端・中央・後端に対して行うことで、車両全体が走行可能領域の中にいるかどうかを判定しています。</span></p> <p><span style="font-weight: 400;">この判定方法を用いることで、走行経路の計画問題を<a class="keyword" href="http://d.hatena.ne.jp/keyword/%C6%F3%BC%A1%B7%D7%B2%E8%CC%E4%C2%EA">二次計画問題</a>と呼ばれるクラスの数理<a class="keyword" href="http://d.hatena.ne.jp/keyword/%BA%C7%C5%AC%B2%BD%CC%E4%C2%EA">最適化問題</a>へ帰着することができます。<a class="keyword" href="http://d.hatena.ne.jp/keyword/%C6%F3%BC%A1%B7%D7%B2%E8%CC%E4%C2%EA">二次計画問題</a>は数理最適化のなかでも頻出の形式で、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%AA%A1%BC%A5%D7%A5%F3%A5%BD%A1%BC%A5%B9">オープンソース</a>のソルバもあります。Autowareでは<a class="keyword" href="http://d.hatena.ne.jp/keyword/%C6%F3%BC%A1%B7%D7%B2%E8%CC%E4%C2%EA">二次計画問題</a>を解くためにOSQP<a href="#f-39ab0bb7" name="fn-39ab0bb7" title="https://osqp.org/">*1</a>というソルバを利用しています。</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="図1:走行可能領域の表現方法"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/f/fwatanabe-t4/20210323/20210323154240.png" alt="f:id:fwatanabe-t4:20210323154240p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">図1:走行可能領域の表現方法</figcaption> </figure> <h3><strong>Autowareでの適用例</strong></h3> <p><span style="font-weight: 400;">では、実際に狭い道を走行している例をご紹介します。ここでは、S字カーブを走行するシーンを想定して走行経路を計画してみましょう。計画した結果を図2に示します。図中の赤線が道路中心線、白線が実際に計画された(後方車輪軸中心が通る)走行経路、黄色の四角い枠が白線に沿って走行したときの車両の外形(footprint)になります。まず、カーブ入口で中心に沿って走行すると走行可能エリアを逸脱してしまうため、カーブ内側を走行するような経路が引かれていることがわかります。また、S字カーブ内では車両が走行可能エリアを逸脱しないように計画されているだけでなく、中心線よりやや内側を走行して走行経路の曲率をできるだけ小さくしており、人間が見ても自然な経路が計画されていると思います。この結果から、走行可能エリアの逸脱を避けつつ、必要以上に大きくステアを動かさないような走行経路の計画が達成できていることがわかります。</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="図2:S字カーブの走行経路計画結果"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/f/fwatanabe-t4/20210326/20210326131049.png" alt="f:id:fwatanabe-t4:20210326131049p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">図2:S字カーブの走行経路計画結果</figcaption> </figure> <h3><strong>まとめ</strong></h3> <p><span style="font-weight: 400;">今回は、狭路走行を例に取り上げて走行経路の計画方法についてご紹介しました。Autowareでは、この<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A2%A5%EB%A5%B4%A5%EA%A5%BA%A5%E0">アルゴリズム</a>の導入により走行できるようになったシーンが増えました。しかし、経路計画にはまだ様々な課題が残っており、引き続き有効な手法の研究および開発が必要だと考えております。経路計画に限らず自動運転には難しい課題が多数ありますが、問題解決したときの喜びは大きいです。自動運転技術の発展に興味のある方は、ぜひ本記事冒頭のリンクからコンタクトしていただければと思います!</span></p><div class="footnote"> <p class="footnote"><a href="#fn-39ab0bb7" name="f-39ab0bb7" class="footnote-number">*1</a><span class="footnote-delimiter">:</span><span class="footnote-text"><a href="https://osqp.org/">https://osqp.org/</a></span></p> </div> fwatanabe-t4 The Challenges of Making Decisions in Autonomous Driving hatenablog://entry/26006613707184287 2021-03-24T16:00:00+09:00 2021-03-24T16:00:03+09:00 Autonomously controlling a car is challenging and requires solving a number of subproblems. If perception, which understands information from sensors, corresponds to the eyes or our system while control, which turns the wheel and adjusts the velocity, corresponds to the body having a physical impact… <p><span style="font-weight: 400;">Autonomously controlling a car is challenging and requires solving a number of subproblems. If perception, which understands information from sensors, corresponds to the eyes or our system while control, which turns the wheel and adjusts the velocity, corresponds to the body having a physical impact on the car, then decision making is the brain. It must connect what is perceived with how the car is controlled.</span></p> <p><span style="font-weight: 400;">In this blog post, we discuss the challenges in designing the brain of an autonomous car that can drive safely in a variety of situations. First, we introduce the scope and motivation for decision making before presenting how it is currently implemented in Autoware. We then <a class="keyword" href="http://d.hatena.ne.jp/keyword/talk">talk</a> about the trends observed in recent autonomous driving conferences and briefly introduce a few works that propose interesting new directions of research.</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" style="width: 60%;" title="Typical sense-plan-act paradigm for autonomous agents"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/T/TierIV/20210322/20210322212536.png" alt="f:id:TierIV:20210322212536p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">Figure 1 - Typical sense-plan-act paradigm for autonomous agents</figcaption> </figure> <p style="margin: 0px 0px 1em; color: #111111; font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">By the way, at Tier Ⅳ, we are looking for various engineers and researchers to ensure the safety and security of autonomous driving and to realise sharing technology for safe intelligent vehicles. Anyone who is interested in joining us, please contact us from the web page below. </p> <p style="margin: 0px 0px 1em; color: #111111; font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;"><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftier4.jp%2Fcareers%2F" title="Careers | 株式会社ティアフォー" class="embed-card embed-webcard" scrolling="no" style="max-width: 500px; display: block; width: 500px; height: 155px; margin: 10px 0px;" frameborder="0"></iframe><cite class="hatena-citation" style="font-style: normal; font-size: 14.4px; opacity: 0.75; display: block;"><a href="https://tier4.jp/careers/" style="background: transparent; color: #395b74; transition: color 0.3s ease 0s; overflow-wrap: break-word;">tier4.jp</a></cite></p> <h3><strong>Introduction to Decision Making</strong></h3> <p><span style="font-weight: 400;">We spend our life making decisions, carefully weighing the pros and cons of multiple options before choosing the one we deem best. Some decisions are easy to make, while others can involve more parameters than can be considered by a single human. Many works in artificial intelligence are concerned with such difficult problems. From deciding the best path in a graph, like the famous <a class="keyword" href="http://d.hatena.ne.jp/keyword/Dijkstra">Dijkstra</a> or A* algorithms, to finding the best sequence of actions for an autonomous robot.</span></p> <p><span style="font-weight: 400;">For autonomous vehicles, decision making usually deals with high level decisions and can also be called behavior planning, high-level planning, or tactical decision making. These high level decisions will then be used by a motion planner to create the trajectory to be executed by the controller. Other approaches consider planning as a whole, directly outputting the trajectory to execute. Finally, end-to-end approaches attempt to perform all functions in a single module by using machine learning techniques trained directly on sensor inputs. While planning is one of the functions handled by end-to-end techniques, we will not discuss them in this blog post as they <a class="keyword" href="http://d.hatena.ne.jp/keyword/tend">tend</a> to make decision making indistinguishable from perception and control.</span></p> <p><span style="font-weight: 400;">The common challenge unique to decision making systems comes from the open-endedness of the problem, even for humans. For perception, a human can easily identify the different objects in an image. For control, a human can follow a trajectory without too many issues. But for decision making, two drivers might make very different decisions in the same situation and it is almost never clear what is the </span><em><span style="font-weight: 400;">best </span></em><span style="font-weight: 400;">decision at any given time. The goals of an autonomous car at least seem clear: reach the <a class="keyword" href="http://d.hatena.ne.jp/keyword/destination">destination</a>, avoid collisions, respect the regulations, and offer a comfortable ride. The challenge then comes from finding decisions that best comply with these goals. The famous “freezing robot problem” illustrates this well: once a situation becomes too complex, not doing anything becomes the only safe decision to make and the robot “freezes”. Similarly, the best way for a car to avoid collisions is not to drive. A decision system must thus often deal with conflicting goals. Challenges also arise from uncertainties in the perception and in the other agents. Sensors are not perfect and perception systems can make mistakes, which needs to be carefully taken into account as making decisions based on wrong information can have catastrophic consequences. Moreover, cars or pedestrians around the autonomous vehicle can act in unpredictable ways, adding to the uncertainty. Dedicated prediction modules are sometimes used and focus on generating predictions for other agents. The final challenge we want to mention here comes from dealing with occluded space. It is common while driving not to be able to perfectly perceive the space around the car, especially in urban areas. We might be navigating small streets with <a class="keyword" href="http://d.hatena.ne.jp/keyword/sharp">sharp</a> corners or obstacles might be blocking the view (parked trucks for example), potentially hiding an incoming vehicle.</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="Schwarting, Wilko, Javier Alonso-Mora, and Daniela Rus. &quot;Planning and decision-making for autonomous vehicles.&quot; Annual Review of Control, Robotics, and Autonomous Systems (2018)."> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/T/TierIV/20210322/20210322212939.png" alt="f:id:TierIV:20210322212939p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable"> <p>Figure 2 - Standard autonomous driving architecture</p> <p>Schwarting, Wilko, Javier Alonso-Mora, and Daniela Rus. "Planning and decision-making for autonomous vehicles." Annual Review of Control, Robotics, and Autonomous Systems (2018)</p> </figcaption> </figure> <p><span style="font-weight: 400;">To summarize, we are concerned with the problem of making decisions on the actions of the car based on perceptions from sensors and the main challenging points are:</span></p> <ul> <li style="font-weight: 400;" aria-level="1"><strong>conflicting goals</strong><span style="font-weight: 400;"> that require trade-offs;</span></li> <li style="font-weight: 400;" aria-level="1"><strong>uncertainties</strong><span style="font-weight: 400;"> from perception, localization, and from the other agents;</span></li> <li style="font-weight: 400;" aria-level="1"><strong>occluded</strong><span style="font-weight: 400;"> parts of the environment.</span></li> </ul> <p><span style="font-weight: 400;">In the rest of this post we will try to introduce methods to make decisions and to tackle the aforementioned challenges.</span></p> <h3><strong>Decision Making in Autoware</strong></h3> <figure class="figure-image figure-image-fotolife mceNonEditable" title="Autoware architecture"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/T/TierIV/20210322/20210322213104.png" alt="f:id:TierIV:20210322213104p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">Figure 3 - Autoware architecture</figcaption> </figure> <p><span style="font-weight: 400;">Autoware is an open source project providing a full stack software platform for autonomous driving including modules for perception, control and decision making. In the spirit of open source, its architecture is made to have each function be an independent module, making it easy to add, remove, or modify functionalities based on everyone’s own needs.</span></p> <p><span style="font-weight: 400;">In this architecture, decision making occurs at two stages. At the </span><em><span style="font-weight: 400;">Planning</span></em><span style="font-weight: 400;"> stage, various planning algorithms such as A* or the Model Predictive Control are used to plan and modify trajectories. Before that, at the </span><em><span style="font-weight: 400;">Decision</span></em><span style="font-weight: 400;"> stage, the output of perception modules is used to select which planning algorithms to use for the current situation. For example, it can be decided that the car should perform a parking maneuver, in which case a specific parking module will be used (</span><a href="https://tech.tier4.jp/entry/2021/02/24/160000">Motion Planning Under Various Constraints - Autonomous Parking Case - Tier IV Tech Blog</a><span style="font-weight: 400;">). This </span><em><span style="font-weight: 400;">Decision </span></em><span style="font-weight: 400;">stage is implemented using a Finite State Machine (FSM), a common model used in rule-based systems. A state machine is basically a graph representing possible states of the system as nodes and the conditions to transition between these states as edges. State machines are easily designed by humans and offer decisions that are easy to understand and explain, which is very desirable in autonomous driving systems.</span></p> <p><span style="font-weight: 400;">While the decision and planning modules of Autoware offer state-of-the-art driving in nominal cases, they are not well suited to deal with uncertainties or occluded space. There are no classical approaches to deal with these challenges but they are studied by a lot of ongoing research, which we will discuss in the next part.</span></p> <h3><strong>Current Trends</strong></h3> <p><span style="font-weight: 400;">We now introduce some of the <a class="keyword" href="http://d.hatena.ne.jp/keyword/most">most</a> popular approaches for decision making seen in recent autonomous driving conferences (the </span><a href="https://2020.ieee-iv.org/">IEEE Intelligent Vehicles Symposium</a> <span style="font-weight: 400;">and the </span><a href="https://www.ieee-itsc2020.org"><span style="font-weight: 400;">International Conference on Intelligent Transportation Systems</span></a><span style="font-weight: 400;">). <br /></span></p> <p><strong>Deep <a class="keyword" href="http://d.hatena.ne.jp/keyword/Reinforcement%20Learning">Reinforcement Learning</a></strong><span style="font-weight: 400;"> (DRL) is an application of deep neural networks to the <a class="keyword" href="http://d.hatena.ne.jp/keyword/Reinforcement%20Learning">Reinforcement Learning</a> framework where the goal is to learn what action works best at each state of the system, corresponding to a policy <em>Π</em></span><em><span style="font-weight: 400;">(s) = a</span></em><span style="font-weight: 400;"> representing the decision </span><em><span style="font-weight: 400;">a</span></em><span style="font-weight: 400;"> to take at state </span><em><span style="font-weight: 400;">s</span></em><span style="font-weight: 400;">. This usually requires learning a function </span><em><span style="font-weight: 400;">Q(s,a)</span></em><span style="font-weight: 400;"> which estimates the reward we can obtain when performing action </span><em><span style="font-weight: 400;">a</span></em><span style="font-weight: 400;"> at state </span><em><span style="font-weight: 400;">s</span></em><span style="font-weight: 400;">. In simple environments, this function can be computed by completely exploring the search space but when the state and action spaces become too large, like in autonomous driving problems, more advanced techniques must be used. DRL leverages the power of deep neural networks to approximate the function </span><em><span style="font-weight: 400;">Q(s,a)</span></em><span style="font-weight: 400;">, allowing the use of RL in very complex situations. This requires training on a large number of example situations, which are usually obtained using a simulator. The biggest issue with using these techniques on real vehicles is the difficulty to guarantee the safety of the resulting policy <em>Π</em><em>(s)</em></span><span style="font-weight: 400;">. With large state spaces, it is difficult to ensure that there does not exist a state where the policy will take an unsafe action.</span></p> <p><strong>Mixed-Integer Programming</strong><span style="font-weight: 400;"> (MIP) is an optimization technique which maximizes a linear function of variables that are under some constraints. Some of these variables must be restricted to integer values (e.g., 0 or 1) and can be used to represent decisions (e.g., whether a lane change is performed or not). The problem of an autonomous vehicle following a route can be represented with MIP by including considerations like collisions and rules of the road as constraints. Using commonly available solvers, the problem can then be solved for an optimal solution, corresponding to the best values to assign to the variables while satisfying the constraints. </span><span style="font-weight: 400;">Many approaches applying MIP to autonomous driving have been proposed and while they can solve many complex situations, they cannot handle uncertain or partial information and require accurate models of the agents and of the environment, making them difficult to apply to real-life situations.</span></p> <p><strong>Monte-Carlo Tree Search</strong><span style="font-weight: 400;"> (<a class="keyword" href="http://d.hatena.ne.jp/keyword/MCTS">MCTS</a>) is an algorithm from game-theory which is used to model multiplayer games. It is <a class="keyword" href="http://d.hatena.ne.jp/keyword/most">most</a> famous for being used in AlphaGo, the first program able to defeat a human professional at the game of Go. The <a class="keyword" href="http://d.hatena.ne.jp/keyword/MCTS">MCTS</a> algorithm assumes a turn-based game where agents act in succession and builds a tree where each node is a state and where a child is the expected result from an action. If complete, the tree represents the whole space of possible future states of the game. Because building a complete tree is impossible for <a class="keyword" href="http://d.hatena.ne.jp/keyword/most">most</a> real problems, algorithms use trial-and-error, similar to <a class="keyword" href="http://d.hatena.ne.jp/keyword/reinforcement%20learning">reinforcement learning</a>, to perform sequences of actions before simulating the resulting outcome. This approach has the advantage of considering the actions of other agents in relation to our own decisions, making it useful in collaborative scenarios where the autonomous vehicle must negotiate with other vehicles (e.g., in highway merges). The main issue with <a class="keyword" href="http://d.hatena.ne.jp/keyword/MCTS">MCTS</a> is their computational complexity. As the tree must be sufficiently explored in order to confidently choose actions, it can be hard to use in real-time situations.</span></p> <p><span style="font-weight: 400;">In the next section, we will present some recent works related to each of these trends.</span></p> <h3><strong>Interesting Works</strong></h3> <h5><strong>Graph Neural Networks and <a class="keyword" href="http://d.hatena.ne.jp/keyword/Reinforcement%20Learning">Reinforcement Learning</a> for Behavior Generation in Semantic Environments</strong></h5> <blockquote> <p><span style="font-weight: 400;">Patrick Hart(</span><span style="font-weight: 400;">1)</span><span style="font-weight: 400;"> and Alois Knoll(</span><span style="font-weight: 400;">2)</span></p> <p><span style="font-weight: 400;">1- fortiss <a class="keyword" href="http://d.hatena.ne.jp/keyword/GmbH">GmbH</a>, An-Institut Technische Universität München, Munich, Germany.</span></p> <p><span style="font-weight: 400;">2- Chair of Robotics, Artificial Intelligence and Real-time Systems, Technische Universität München, Munich, Germany.</span></p> <p><a class="keyword" href="http://d.hatena.ne.jp/keyword/IEEE">IEEE</a> Intelligent Vehicles Symposium (2020) <a href="https://arxiv.org/abs/2006.12576"><span style="font-weight: 400;">https://arxiv.org/abs/2006.12576</span></a><a href="https://arxiv.org/abs/2006.12576"> </a></p> </blockquote> <figure class="figure-image figure-image-fotolife mceNonEditable" title="Graph representation of the vehicles"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/T/TierIV/20210322/20210322213643.png" alt="f:id:TierIV:20210322213643p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">Figure 4 - Vehicles of a scene represented as a graph</figcaption> </figure> <p><span style="font-weight: 400;">An issue with <a class="keyword" href="http://d.hatena.ne.jp/keyword/reinforcement%20learning">reinforcement learning</a> is that their input is usually a <a class="keyword" href="http://d.hatena.ne.jp/keyword/vector">vector</a> of fixed size. This causes issues when tackling situations with varying numbers of other agents. This paper proposes to use Graphic Neural Networks (GNNs) to learn the policy of a <a class="keyword" href="http://d.hatena.ne.jp/keyword/reinforcement%20learning">reinforcement learning</a> problem. GNNs are a neural network architecture that uses graphs as inputs instead of vectors, offering a solution that is more flexible and more general than previous works.</span></p> <p><span style="font-weight: 400;">The graph used in this paper represents vehicles with the nodes containing state information (coordinates and velocities) and the edges containing the distance between two vehicles. Experiments on a highway lane change scenario are used to compare the use of GNNs against the use of traditional neural networks. It shows that while results are similar in situations close to the ones used at training time, the use of GNNs generalizes much better to variations in the input without a significant loss of performance.</span></p> <h5><strong>Autonomous Vehicle Decision-Making and Monitoring based on Signal Temporal Logic and Mixed-Integer Programming</strong></h5> <blockquote> <p><span style="font-weight: 400;">Yunus Emre Sahin, Rien Quirynen, and Stefano Di Cairano<br /></span></p> <p><span style="font-weight: 400;"><a class="keyword" href="http://d.hatena.ne.jp/keyword/MITSUBISHI">MITSUBISHI</a> ELECTRIC RESEARCH LABORATORIES</span></p> <p>American Control Conference (2020) <a href="https://www.merl.com/publications/TR2020-095">https://www.merl.com/publications/TR2020-095</a></p> </blockquote> <figure class="figure-image figure-image-fotolife mceNonEditable" title="illustration of where this technique fits within the global architecture - illustration of the MIP solution space"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/T/TierIV/20210322/20210322213823.png" alt="f:id:TierIV:20210322213823p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">Figure 5 - (a) modules targeted by this work  (b) illustration of the MIP solution space</figcaption> </figure> <p><span style="font-weight: 400;">This work uses Mixed-Integer Programming to represent the problem of finding intermediate waypoints along a given route. The interesting parts of this work are its use of Signal Temporal Logic (<a class="keyword" href="http://d.hatena.ne.jp/keyword/STL">STL</a>) to represent some of the constraints, and a monitoring system that can identify if the environment changes in ways that deviate from the models used.</span></p> <p><span style="font-weight: 400;">Temporal Logic is a language used to write rules which include some time information. In this work for example, intersections are regulated by a first-in-first-out rule, which in <a class="keyword" href="http://d.hatena.ne.jp/keyword/STL">STL</a> is written as <img src="https://cdn-ak.f.st-hatena.com/images/fotolife/m/mclement/20210323/20210323100344.png" alt="f:id:mclement:20210323100344p:plain" title="" class="hatena-fotolife" itemprop="image" width="179" />, which means “the car must not be at the intersection until it is clear”. The paper proposes an efficient way to encode <a class="keyword" href="http://d.hatena.ne.jp/keyword/STL">STL</a> rules as constraints, reducing the solution space of the problem (like in Figure </span>5b<span style="font-weight: 400;">) and ensuring that they are satisfied by the solution of the MIP.</span></p> <p><span style="font-weight: 400;">The paper tackles a simulated scenario with intersections and curved roads and shows that their solution can navigate a number of situations in real-time. They also show that their monitoring system can correctly detect unexpected changes in the environment, for example when another vehicle suddenly brakes. It is then possible to fall back to another algorithm or to solve the MIP problem again but with the new information added. This alleviates the main issue of MIP which is to depend on very good models of the environment as it is now possible to detect when these models make a mistake.</span></p> <h5><strong>Accelerating Cooperative Planning for Automated Vehicles with Learned Heuristics and Monte Carlo Tree Search</strong></h5> <blockquote> <p><span style="font-weight: 400;">Karl Kurzer(</span><span style="font-weight: 400;">1)</span><span style="font-weight: 400;">, Marcus Fechner(</span><span style="font-weight: 400;">1),</span><span style="font-weight: 400;"> and J. Marius Zöllner(</span><span style="font-weight: 400;">1,2)</span></p> <p><span style="font-weight: 400;">1- Karlsruhe Institute of Technology, Karlsruhe, Germany</span></p> <p><span style="font-weight: 400;">2- FZI Research Center for Information Technology, Karlsruhe, Germany</span></p> <p><a class="keyword" href="http://d.hatena.ne.jp/keyword/IEEE">IEEE</a> Intelligent Vehicles Symposium (2020) <a href="https://arxiv.org/abs/2002.00497"><span style="font-weight: 400;">https://arxiv.org/abs/2002.00497</span></a></p> </blockquote> <figure class="figure-image figure-image-fotolife mceNonEditable" title="image from https://angusturner.github.io/generative_models/2017/11/03/pytorch-gaussian-mixture-model.html"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/T/TierIV/20210322/20210322214141.png" alt="f:id:TierIV:20210322214141p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable"> <p>Figure 6 - (a) Use of the Gaussian mixture to select actions in the <a class="keyword" href="http://d.hatena.ne.jp/keyword/MCTS">MCTS</a> (b) Gaussian mixture</p> <p>(b) taken from <a href="https://angusturner.github.io/generative_models/2017/11/03/pytorch-gaussian-mixture-model.html">https://angusturner.github.io/generative_models/2017/11/03/pytorch-gaussian-mixture-model.html</a></p> </figcaption> </figure> <p><span style="font-weight: 400;">As discussed in the previous section, <a class="keyword" href="http://d.hatena.ne.jp/keyword/MCTS">MCTS</a> are great to model interactions with other agents but are very hard to sufficiently explore. In order to make exploring the tree more efficient, this paper learns Gaussian mixture models that associate each state (i.e., node of the <a class="keyword" href="http://d.hatena.ne.jp/keyword/MCTS">MCTS</a>) some probabilities on the action space. These probabilities are used to guide the exploration of the tree.</span></p> <p><span style="font-weight: 400;">A Gaussian mixture is a combination of several Gaussian probability distributions, allowing multiple peaks with different means and covariances (Figure 6b</span><span style="font-weight: 400;">). In this paper, the actions modeled by these probabilities are pairs of changes in longitudinal velocity and in lateral position. This means that for a given state, the mixture must contain as many peaks as there are possible maneuvers such that their mean will correspond to the typical trajectory for that maneuver. On the highway for example, mixtures with 2 components can be used to learn the 2 typical maneuvers of keeping or changing lanes (Figure </span>6a<span style="font-weight: 400;">).</span></p> <p><span style="font-weight: 400;">This technique is interesting to make the exploration faster but the experiments of the paper do not show any performance improvements once enough exploring time is given. Having to fix the number of components can also be an issue when trying to generalize to various situations.</span></p> <h3><strong>Conclusion</strong></h3> <p><span style="font-weight: 400;">Decision making for autonomous driving remains a very important topic of research with many exciting directions currently being investigated.</span></p> <p><span style="font-weight: 400;">Researchers and engineers at Tier IV are working to bring the results of this progress to Autoware as well as to develop new techniques to help make autonomous driving safer and smarter.</span></p> mclement Intelのad-rss-libを大解剖!RSSのライブラリのアーキテクチャと中身を解説する! hatenablog://entry/26006613703524778 2021-03-17T16:00:00+09:00 2021-03-17T16:11:53+09:00 こんにちは、ティアフォーでAutowareのSimulator開発を担当している片岡と申します。 弊社ではSimulationや実車評価を通して様々な側面からAutowareの性能評価と開発へのフィードバックを行っております。 今回はその一環でIntelのRSS(Responsibility Sensitive Safety)という安全評価基準のライブラリを読み解きましたのでその中身について解説したいと思います。 また、ティアフォーでは「自動運転の民主化」をともに実現していく、Simulation EngineerやSafety Engineerを募集しています。 自動運転を実現するためには、… <p>こんにちは、ティアフォーでAutowareのSimulator開発を担当している片岡と申します。</p> <p>弊社ではSimulationや<a class="keyword" href="http://d.hatena.ne.jp/keyword/%BC%C2%BC%D6">実車</a>評価を通して様々な側面からAutowareの性能評価と開発へのフィードバックを行っております。</p> <p>今回はその一環で<a class="keyword" href="http://d.hatena.ne.jp/keyword/Intel">Intel</a>の<a class="keyword" href="http://d.hatena.ne.jp/keyword/RSS">RSS</a>(Responsibility Sensitive Safety)という安全評価基準のライブラリを読み解きましたのでその中身について解説したいと思います。</p> <p><span style="color: #111111; font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none;">また、ティアフォーでは「自動運転の</span><a class="keyword" href="http://d.hatena.ne.jp/keyword/%CC%B1%BC%E7%B2%BD" style="background: #ffffff; color: inherit !important; transition: color 0.3s ease 0s; overflow-wrap: break-word; text-decoration: none; border-bottom: 1px dotted #dddddd; font-size: 16px; font-weight: 400; font-style: normal; pointer-events: auto !important; cursor: pointer !important; font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-variant-ligatures: normal; font-variant-caps: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px;">民主化</a><span style="color: #111111; font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none;">」をともに実現していく、Simulation EngineerやSafety Engineerを募集しています。</span></p> <p><span style="color: #111111; font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none;">自動運転を実現するためには、極めて幅広い分野に対する研究開発や安全担保への取り組みを進めていく必要があります。もしご興味があれば以下のページからコンタクトいただければと思います。</span></p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftier4.jp%2Fcareers%2F" title="Careers | 株式会社ティアフォー" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://tier4.jp/careers/">tier4.jp</a></cite></p> <ul class="table-of-contents"> <li><a href="#Intel-RSSとは"> Intel RSSとは?</a><ul> <li><a href="#RSSの概要">RSSの概要</a></li> </ul> </li> <li><a href="#RSSと自動運転システムのIntegration">RSSと自動運転システムのIntegration</a><ul> <li><a href="#ad-rss-lib">ad-rss-lib</a></li> </ul> </li> <li><a href="#ad-rss-libのパッケージ構成">ad-rss-libのパッケージ構成</a><ul> <li><a href="#ad_rssの中身">ad_rssの中身</a></li> <li><a href="#ad_rss_map_integrationの中身">ad_rss_map_integrationの中身</a></li> </ul> </li> <li><a href="#ad-rss-libの使い方"> ad-rss-libの使い方</a><ul> <li><a href="#ApolloにおけるRSSのIntegration">ApolloにおけるRSSのIntegration</a></li> <li><a href="#CARLAにおけるRSSのIntegration">CARLAにおけるRSSのIntegration</a><ul> <li><a href="#RSS-Sensor">RSS Sensor</a></li> <li><a href="#RSS-Restrictor">RSS Restrictor</a></li> </ul> </li> </ul> </li> <li><a href="#まとめ">まとめ</a></li> </ul> <h3 id="Intel-RSSとは"> <a class="keyword" href="http://d.hatena.ne.jp/keyword/Intel">Intel</a> <a class="keyword" href="http://d.hatena.ne.jp/keyword/RSS">RSS</a>とは?</h3> <p><iframe width="560" height="315" src="https://www.youtube.com/embed/ObACNv3ejpE?start=18&amp;feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe><cite class="hatena-citation"><a href="https://youtu.be/ObACNv3ejpE?t=18">youtu.be</a></cite></p> <p><cite class="hatena-citation"></cite><a class="keyword" href="http://d.hatena.ne.jp/keyword/Intel">Intel</a> <a class="keyword" href="http://d.hatena.ne.jp/keyword/RSS">RSS</a>は<a class="keyword" href="http://d.hatena.ne.jp/keyword/Intel">Intel</a> (Mobileye) が提唱している自動運転車両の安全性を評価する基準です。評価基準の詳細な計算ロジックが記述されている論文は<a class="keyword" href="http://d.hatena.ne.jp/keyword/arXiv">arXiv</a>において公開されております。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Farxiv.org%2Fabs%2F1708.06374" title="On a Formal Model of Safe and Scalable Self-driving Cars" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://arxiv.org/abs/1708.06374">arxiv.org</a></cite></p> <h4 id="RSSの概要"><a class="keyword" href="http://d.hatena.ne.jp/keyword/RSS">RSS</a>の概要</h4> <p><span style="color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: -0.08px; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none;"><a class="keyword" href="http://d.hatena.ne.jp/keyword/RSS">RSS</a>はHD Mapと周囲のオブジェクトの動きから、自動運転車が取ってよい動作コマンド(縦方向、横方向加速度)の範囲を計算します。</span></p> <p>公道において自動運転車両が出会う状況を数式で表現することで自動運転車両が取った行動の危険度を数値化することが可能になります。この機能は「この危険な状況は道路上にいる誰のせいで発生したのか」を表現することができるため、公道走行ログから危険なシナリオを抽出したり、様々なパラメータで実行されたSimulation Testの結果を分析するのに使うことができます。</p> <p>このロジックは本質的にはAutoware等の自動運転システムに含まれるプランナーと等価なものであり、後述するad-<a class="keyword" href="http://d.hatena.ne.jp/keyword/rss">rss</a>-libのサポート対象からは外れているものの、障害物回避等の動きを行うことも可能なようです。</p> <p>下の動画(CARLA 0.9.10のNew Feature紹介動画)においては実際に<a class="keyword" href="http://d.hatena.ne.jp/keyword/RSS">RSS</a>に基づいて計算された制御入力を使ってUnstructuredな環境での障害物回避が行われています。</p> <p><iframe width="560" height="315" src="https://www.youtube.com/embed/7jej46ALVRE?start=164&amp;feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe><cite class="hatena-citation"><a href="https://youtu.be/7jej46ALVRE?t=164">youtu.be</a></cite></p> <p><a class="keyword" href="http://d.hatena.ne.jp/keyword/RSS">RSS</a>は内部に状態機械を持っており、様々なシチュエーションに対して適切な評価関数を選択することで自動運転システムからの出力が適切かを評価することができます。</p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="https://intel.github.io/ad-rss-lib/images/ad-rss-map-situation_analysis.png"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/m/masaya-kataoka/20210315/20210315164514.png" alt="f:id:masaya-kataoka:20210315164514p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable"><a href="https://intel.github.io/ad-rss-lib/images/ad-rss-map-situation_analysis.png">https://intel.github.io/ad-rss-lib/images/ad-rss-map-situation_analysis.png</a></figcaption> </figure> <h3 id="RSSと自動運転システムのIntegration"><a class="keyword" href="http://d.hatena.ne.jp/keyword/RSS">RSS</a>と自動運転システムのIntegration</h3> <figure class="figure-image figure-image-fotolife mceNonEditable" title="https://intel.github.io/ad-rss-lib/images/ad-rss-lib-Integrate_Into_Sense-Plan-Act.png"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/m/masaya-kataoka/20210315/20210315164013.png" alt="f:id:masaya-kataoka:20210315164013p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable"><a href="https://intel.github.io/ad-rss-lib/images/ad-rss-lib-Integrate_Into_Sense-Plan-Act.png">https://intel.github.io/ad-rss-lib/images/ad-rss-lib-Integrate_Into_Sense-Plan-Act.png</a></figcaption> </figure> <p><a class="keyword" href="http://d.hatena.ne.jp/keyword/RSS">RSS</a>は自動運転のサブシステムとして実装することを考慮して設計されており、認識結果からワールドモデルを構築して自動運転システムからの出力を制限するといった使い方が想定されています。</p> <p>また、後述するad-<a class="keyword" href="http://d.hatena.ne.jp/keyword/rss">rss</a>-libは様々な外部ツールとインテグレーションされており、インテグレーションもやりやすい仕様になっていることが伺えます。</p> <h4 id="ad-rss-lib">ad-<a class="keyword" href="http://d.hatena.ne.jp/keyword/rss">rss</a>-lib</h4> <p>今回紹介しますのは、この論文に有る内容を<a class="keyword" href="http://d.hatena.ne.jp/keyword/C%2B%2B">C++</a>で実装した<a class="keyword" href="http://d.hatena.ne.jp/keyword/OSS">OSS</a>です。</p> <p>ライセンスはLGPL2.1となっていて、Ubuntu16.04、18.04、20.04で動作します。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fgithub.com%2Fintel%2Fad-rss-lib" title="intel/ad-rss-lib" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://github.com/intel/ad-rss-lib">github.com</a></cite></p> <p>CARLAやBaiduの<a class="keyword" href="http://d.hatena.ne.jp/keyword/Apollo">Apollo</a>といった自動運転業界で有名な<a class="keyword" href="http://d.hatena.ne.jp/keyword/OSS">OSS</a>でもこのライブラリはインテグレーションされており、その使いやすさと注目度の高さが伺えます。</p> <p>現在のversion(4.4.0)においては以下の内容がサポートされています。</p> <ul class="ak-ul" style="margin: 12px 0px 0px; padding: 0px 0px 0px 24px; box-sizing: border-box; list-style-type: disc; display: flow-root; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;" data-indent-level="1"> <li><span style="font-size: 1em; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; white-space: pre-wrap;">複数のマップバージョンをサポート(Map Integration)</span></li> <li>構造化されていない道路や歩道も扱える</li> <li>複数車線の道路、すなわち縦方向および横方向の安全距離と適切な対応の決定</li> <li>交差点、つまり、異なるジオメトリの2つ以上のルート、ルートの交差点のルール、優先権/通行権、および縦方向と横方向の適切な応答の決定</li> </ul> <p>逆にサポート範囲外となっているのは以下の内容になります。</p> <ul class="ak-ul" style="margin: 12px 0px 0px; padding: 0px 0px 0px 24px; box-sizing: border-box; list-style-type: disc; display: flow-root; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;" data-indent-level="1"> <li><span style="font-size: 1em; letter-spacing: -0.005em; color: #172b4d; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Noto Sans', Ubuntu, 'Droid Sans', 'Helvetica Neue', sans-serif; white-space: pre-wrap;">オクルージョンの考慮</span></li> <li>回避動作を生成するロジック</li> <li>横方向の衝突がない交差点の対応</li> </ul> <h3 id="ad-rss-libのパッケージ構成">ad-<a class="keyword" href="http://d.hatena.ne.jp/keyword/rss">rss</a>-libのパッケージ構成</h3> <p>ad-<a class="keyword" href="http://d.hatena.ne.jp/keyword/rss">rss</a>-libは<a class="keyword" href="http://d.hatena.ne.jp/keyword/C%2B%2B">C++</a>とCMakeで書かれており、<a class="keyword" href="http://d.hatena.ne.jp/keyword/Python">Python</a>のC <a class="keyword" href="http://d.hatena.ne.jp/keyword/API">API</a>を使用して<a class="keyword" href="http://d.hatena.ne.jp/keyword/Python">Python</a> Bindingsも製作されています。</p> <p>ad-<a class="keyword" href="http://d.hatena.ne.jp/keyword/rss">rss</a>-libのコアライブラリは以下の2つの<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C7%A5%A3%A5%EC%A5%AF%A5%C8">ディレクト</a>リに格納されています。</p> <p><a href="https://github.com/intel/ad-rss-lib/tree/master/ad_rss">https://github.com/intel/ad-rss-lib/tree/master/ad_rss</a></p> <p><a href="https://github.com/intel/ad-rss-lib/tree/master/ad_rss_map_integration">https://github.com/intel/ad-rss-lib/tree/master/ad_rss_map_integration</a></p> <h4 id="ad_rssの中身">ad_<a class="keyword" href="http://d.hatena.ne.jp/keyword/rss">rss</a>の中身</h4> <p>ad_<a class="keyword" href="http://d.hatena.ne.jp/keyword/rss">rss</a>は以下のような<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C7%A5%A3%A5%EC%A5%AF%A5%C8">ディレクト</a>リ構造になっています。</p> <blockquote> <p>ad_<a class="keyword" href="http://d.hatena.ne.jp/keyword/rss">rss</a></p> <p>├── CMakeLists.txt<br />├── doc<br />├── generated<br />├── gtest-cmake.txt.in<br />├── impl</p> <p>│   ├── ad_<a class="keyword" href="http://d.hatena.ne.jp/keyword/rss">rss</a>.cmake<br />│   ├── include<br />│   ├── src</p> <p>│   │   ├── core<br />│   │   ├── situation<br />│   │   ├── unstructured<br />│   │   └── world<br />│   └── test<br />└── <a class="keyword" href="http://d.hatena.ne.jp/keyword/python">python</a></p> </blockquote> <p> CMakeLists.txtはCMakeの設定ファイルであり、ビルド手順が記述されています。</p> <p>doc<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C7%A5%A3%A5%EC%A5%AF%A5%C8">ディレクト</a>リには<a class="keyword" href="http://d.hatena.ne.jp/keyword/Doxygen">Doxygen</a>の設定ファイルが入っており、こちらのドキュメントを生成するのに使われています。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fintel.github.io%2Fad-rss-lib%2Fdoxygen%2Fad_rss%2Findex.html" title="ad_rss: Main Page" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://intel.github.io/ad-rss-lib/doxygen/ad_rss/index.html">intel.github.io</a></cite></p> <p>generated<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C7%A5%A3%A5%EC%A5%AF%A5%C8">ディレクト</a>リには<a href="https://github.com/intel/ad-rss-lib/blob/master/ad_rss/generated/src/ad/rss/state/LateralResponse.cpp">縦方向の反応時間</a>といった<a class="keyword" href="http://d.hatena.ne.jp/keyword/RSS">RSS</a>の計算で使われるデータ型を文字列等から作成するためのユーティリティが含まれています。</p> <p>impl<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C7%A5%A3%A5%EC%A5%AF%A5%C8">ディレクト</a>リは更に4つの<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C7%A5%A3%A5%EC%A5%AF%A5%C8">ディレクト</a>リに整理されており、それぞれ</p> <ul> <li>core : 下に記した<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C7%A5%A3%A5%EC%A5%AF%A5%C8">ディレクト</a>リ群の中の関数を使うための関数群を収録</li> <li>situation:各situationにおいて実行されるロジックを収録</li> <li>unstructured:構造化されていないシーンでのロジックを収録</li> <li>world:レーン座標系への変換や現在のsituationの認識等のロジックを収録</li> </ul> <p>に分割されています。</p> <p>レーン座標系への変換等は特に加速度の連続性を維持するためにかなり工夫がなされているようです。このあたりの綺麗に実装するのが難しいロジックをオープンにしてくれるのは非常にありがたいですね!</p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="https://intel.github.io/ad-rss-lib/images/lanes_with_different_width.svg"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/m/masaya-kataoka/20210315/20210315165258.png" alt="f:id:masaya-kataoka:20210315165258p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable"><a href="https://intel.github.io/ad-rss-lib/images/lanes_with_different_width.svg">https://intel.github.io/ad-rss-lib/images/lanes_with_different_width.svg</a></figcaption> </figure> <p><a class="keyword" href="http://d.hatena.ne.jp/keyword/Python">Python</a><a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C7%A5%A3%A5%EC%A5%AF%A5%C8">ディレクト</a>リには<a class="keyword" href="http://d.hatena.ne.jp/keyword/Python">Python</a>のC <a class="keyword" href="http://d.hatena.ne.jp/keyword/API">API</a>を利用して<a class="keyword" href="http://d.hatena.ne.jp/keyword/Python">Python</a>からad-<a class="keyword" href="http://d.hatena.ne.jp/keyword/rss">rss</a>-libのロジックをラップして使えるようにするための関数が入っています。</p> <h4 id="ad_rss_map_integrationの中身">ad_<a class="keyword" href="http://d.hatena.ne.jp/keyword/rss">rss</a>_map_integrationの中身</h4> <p>ad_<a class="keyword" href="http://d.hatena.ne.jp/keyword/rss">rss</a>_map_integrationは以下のような<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C7%A5%A3%A5%EC%A5%AF%A5%C8">ディレクト</a>リ構造になっています。</p> <blockquote> <p>ad_<a class="keyword" href="http://d.hatena.ne.jp/keyword/rss">rss</a>_map_integration</p> <p>├── CMakeLists.txt<br />├── doc<br />├── generated<br />├── impl<br />└── <a class="keyword" href="http://d.hatena.ne.jp/keyword/python">python</a></p> </blockquote> <p>impl<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C7%A5%A3%A5%EC%A5%AF%A5%C8">ディレクト</a>リ以外はad_<a class="keyword" href="http://d.hatena.ne.jp/keyword/rss">rss</a><a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C7%A5%A3%A5%EC%A5%AF%A5%C8">ディレクト</a>リと同様のコードが入っています。</p> <p>implには<a class="keyword" href="http://d.hatena.ne.jp/keyword/RSS">RSS</a>の内部で使われているHD Mapに関連するコードが収録されています。</p> <h3 id="ad-rss-libの使い方"> ad-<a class="keyword" href="http://d.hatena.ne.jp/keyword/rss">rss</a>-libの使い方</h3> <h4 id="ApolloにおけるRSSのIntegration"><a class="keyword" href="http://d.hatena.ne.jp/keyword/Apollo">Apollo</a>における<a class="keyword" href="http://d.hatena.ne.jp/keyword/RSS">RSS</a>のIntegration</h4> <p><a class="keyword" href="http://d.hatena.ne.jp/keyword/Apollo">Apollo</a>は自動運転車の行動計画部分に<a class="keyword" href="http://d.hatena.ne.jp/keyword/RSS">RSS</a>のモジュールをインテグレーションしています。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fjapan.cnet.com%2Farticle%2F35121963%2F" title="バイドゥの自動運転プロジェクト「Apollo」、自律運転機能の強化でMobileyeと提携" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://japan.cnet.com/article/35121963/">japan.cnet.com</a></cite></p> <p>具体的な実装箇所は以下のものになります。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fgithub.com%2FApolloAuto%2Fapollo%2Ftree%2Fa29a563e95944b603ab9be338cce46e6486a89be%2Fmodules%2Fplanning%2Ftasks%2Fdeciders%2Frss_decider" title="ApolloAuto/apollo" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://github.com/ApolloAuto/apollo/tree/a29a563e95944b603ab9be338cce46e6486a89be/modules/planning/tasks/deciders/rss_decider">github.com</a></cite></p> <p>この<a href="https://github.com/ApolloAuto/apollo/raw/master/docs/specs/images/class_architecture_planning/image008.png">ドキュメント</a>によると<a class="keyword" href="http://d.hatena.ne.jp/keyword/Apollo">Apollo</a>のEMプランナー(<a class="keyword" href="http://d.hatena.ne.jp/keyword/Apollo">Apollo</a>のプランニング<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A2%A5%EB%A5%B4%A5%EA%A5%BA%A5%E0">アルゴリズム</a>)は3つのカテゴリーのタスクが交錯する反復的なアプローチをとっており、この中のタスクの一種として<a class="keyword" href="http://d.hatena.ne.jp/keyword/RSS">RSS</a>のタスクが実装されているようです。</p> <p><a href="https://github.com/ApolloAuto/apollo/raw/master/docs/specs/images/class_architecture_planning/image008.png" class="http-image"><img src="https://github.com/ApolloAuto/apollo/raw/master/docs/specs/images/class_architecture_planning/image008.png" class="http-image" alt="https://github.com/ApolloAuto/apollo/raw/master/docs/specs/images/class_architecture_planning/image008.png" /></a></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="https://raw.githubusercontent.com/intel/ad-rss-lib/master/doc/images/apollo_integration.png"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/m/masaya-kataoka/20210315/20210315130447.png" alt="f:id:masaya-kataoka:20210315130447p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable"><a href="https://raw.githubusercontent.com/intel/ad-rss-lib/master/doc/images/apollo_integration.png">https://raw.githubusercontent.com/intel/ad-rss-lib/master/doc/images/apollo_integration.png</a></figcaption> </figure> <p>実装されている内容としては</p> <ol> <li><a href="https://github.com/ApolloAuto/apollo/blob/master/docs/specs/Class_Architecture_Planning.md">認識系からきた情報とHD Mapの情報を合わせてWorld Modelを構築</a></li> <li><a href="https://github.com/ApolloAuto/apollo/blob/master/docs/specs/Class_Architecture_Planning.md">World Modelから現在のSituationを判断</a></li> <li><a href="https://github.com/ApolloAuto/apollo/blob/master/docs/specs/Class_Architecture_Planning.md">RSSの計算式に基づいて適切な応答を計算</a></li> <li><a href="https://github.com/ApolloAuto/apollo/blob/a29a563e95944b603ab9be338cce46e6486a89be/modules/planning/tasks/deciders/rss_decider/rss_decider.cc#L277">実際の制御入力における適切な応答を計算</a></li> <li><a href="https://github.com/ApolloAuto/apollo/blob/a29a563e95944b603ab9be338cce46e6486a89be/modules/planning/tasks/deciders/rss_decider/rss_decider.cc#L277">安全な車間距離を取っているかを評価</a></li> </ol> <p>というロジックになります。</p> <h4 id="CARLAにおけるRSSのIntegration">CARLAにおける<a class="keyword" href="http://d.hatena.ne.jp/keyword/RSS">RSS</a>のIntegration</h4> <p>CARLAにおいては<a class="keyword" href="http://d.hatena.ne.jp/keyword/RSS">RSS</a> Sensorと<a class="keyword" href="http://d.hatena.ne.jp/keyword/RSS">RSS</a> Restrictorの2種類のIntegrationがされています。</p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="https://carla.readthedocs.io/en/latest/img/rss_carla_integration_architecture.png"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/m/masaya-kataoka/20210315/20210315130404.png" alt="f:id:masaya-kataoka:20210315130404p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable"><a href="https://carla.readthedocs.io/en/latest/img/rss_carla_integration_architecture.png">https://carla.readthedocs.io/en/latest/img/rss_carla_integration_architecture.png</a></figcaption> </figure> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fcarla.readthedocs.io%2Fen%2Flatest%2Fadv_rss%2F" title="RSS - CARLA Simulator" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://carla.readthedocs.io/en/latest/adv_rss/">carla.readthedocs.io</a></cite></p> <h5 id="RSS-Sensor"><a class="keyword" href="http://d.hatena.ne.jp/keyword/RSS">RSS</a> Sensor</h5> <p><a class="keyword" href="http://d.hatena.ne.jp/keyword/RSS">RSS</a> Sensorは自車両の制御コマンドが<a class="keyword" href="http://d.hatena.ne.jp/keyword/RSS">RSS</a>の基準を満たしているかをチェックするセンサーです。</p> <ol> <li><a href="https://github.com/carla-simulator/carla/blob/fe3cb6863a604f5c0cf8b692fe2b6300b45b5999/LibCarla/source/carla/rss/RssSensor.cpp#L292">SimulatorのAPIを使用してActorの一覧を取得</a></li> <li><a href="https://github.com/carla-simulator/carla/blob/fe3cb6863a604f5c0cf8b692fe2b6300b45b5999/LibCarla/source/carla/rss/RssSensor.cpp#L300">RSSに基づいて適切な制御コマンドの範囲を計算、その値に自車両の入力が入っているかを確認</a></li> </ol> <p><iframe width="560" height="315" src="https://www.youtube.com/embed/UxKPXPT2T8Q?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe><cite class="hatena-citation"><a href="https://www.youtube.com/watch?v=UxKPXPT2T8Q">www.youtube.com</a></cite></p> <p>上記の動画に有るとおり、様々な状況下で<a class="keyword" href="http://d.hatena.ne.jp/keyword/RSS">RSS</a>をメトリクスとして自車両の危険な行動をチェックできています。</p> <p>CARLAのver 9.10.0からはUnstructuredな環境での実行もサポートされており、市街地環境における本格的なSimulationの実現に向けて着々と進んでいる様子が見て取れます。</p> <p><iframe width="560" height="315" src="https://www.youtube.com/embed/7jej46ALVRE?start=165&amp;feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe><cite class="hatena-citation"><a href="https://youtu.be/7jej46ALVRE?t=165">youtu.be</a></cite></p> <h5 id="RSS-Restrictor"><a class="keyword" href="http://d.hatena.ne.jp/keyword/RSS">RSS</a> Restrictor</h5> <p><a class="keyword" href="http://d.hatena.ne.jp/keyword/RSS">RSS</a> Restrictorは<a class="keyword" href="http://d.hatena.ne.jp/keyword/RSS">RSS</a>のメトリクスを使い、<a class="keyword" href="http://d.hatena.ne.jp/keyword/NPC">NPC</a>車両にその場面において危険な状況をうむ制御入力を入れないようにするためのモジュールです。</p> <p>具体的な実装箇所はこちらになります。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fgithub.com%2Fcarla-simulator%2Fcarla%2Fblob%2F5bd3dab1013df554c0198662e0ceb50b7857feba%2FLibCarla%2Fsource%2Fcarla%2Frss%2FRssRestrictor.cpp%23L30" title="carla-simulator/carla" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://github.com/carla-simulator/carla/blob/5bd3dab1013df554c0198662e0ceb50b7857feba/LibCarla/source/carla/rss/RssRestrictor.cpp#L30">github.com</a></cite></p> <p>この関数は<a class="keyword" href="http://d.hatena.ne.jp/keyword/Python">Python</a>から呼び出せるようになっており、CARLAの<a class="keyword" href="http://d.hatena.ne.jp/keyword/Python">Python</a> <a class="keyword" href="http://d.hatena.ne.jp/keyword/API">API</a>で呼び出すことによって<a class="keyword" href="http://d.hatena.ne.jp/keyword/NPC">NPC</a>が適切に振る舞うことができるようになるようです。</p> <h3 id="まとめ">まとめ</h3> <p>今回は自動運転システムを支える評価基準の一種である<a class="keyword" href="http://d.hatena.ne.jp/keyword/Intel">Intel</a>の<a class="keyword" href="http://d.hatena.ne.jp/keyword/RSS">RSS</a>とその<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%AA%A1%BC%A5%D7%A5%F3%A5%BD%A1%BC%A5%B9">オープンソース</a>実装について解説しました。今後はこのツールを活用しAutowareの性能評価をさらに加速させ、安全安心で<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%AA%A1%BC%A5%D7%A5%F3%A5%BD%A1%BC%A5%B9">オープンソース</a>な自動運転<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B7%A5%B9%A5%C6%A5%E0%B3%AB%C8%AF">システム開発</a>を強力に押し進めていきたいと思います。</p> masaya-kataoka eBPFやLD_PRELOADを利用した共有ライブラリの関数フック hatenablog://entry/26006613698711806 2021-03-10T16:00:00+09:00 2022-07-02T18:16:39+09:00 こんにちは、ティアフォーでパートタイムエンジニアをしている石川です。 本記事では、楽に「動的ライブラリ(及び実行バイナリ)の特定の関数をフックして何かしらの処理をする」手法について紹介していきます。 この記事は、同じくパートタイムエンジニアの西村さんによる作業の成果を元にして、石川が執筆したものです。ソースコードや図のいくつかも西村さんによる貢献です。 また、ティアフォーでは「自動運転の民主化」をともに実現していく、学生パートタイムエンジニアを常時募集しています。自動運転を実現するためには、Softwareに関してはOSからMiddlewareそしてApplicationに至るまで、Hardw… <p>こんにちは、ティアフォーでパートタイムエンジニアをしている石川です。</p> <p>本記事では、楽に「動的ライブラリ(及び実行バイナリ)の特定の関数をフックして何かしらの処理をする」手法について紹介していきます。</p> <p>この記事は、同じくパートタイムエンジニアの西村さんによる作業の成果を元にして、石川が執筆したものです。ソースコードや図のいくつかも西村さんによる貢献です。</p> <p>また、ティアフォーでは「自動運転の民主化」をともに実現していく、学生パートタイムエンジニアを常時募集しています。自動運転を実現するためには、Softwareに関してはOSからMiddlewareそしてApplicationに至るまで、Hardwareに関してはSensorからECUそして車両に至るまで異なるスキルを持つ様々な人々が不可欠です。もしご興味があれば以下のページからコンタクトいただければと思います。 <a href="https://tier4.jp/careers/">https://tier4.jp/careers/</a><cite class="hatena-citation"><a href="https://tier4.jp/careers/">tier4.jp</a></cite></p> <ul class="table-of-contents"> <li><a href="#この記事の主題">この記事の主題</a></li> <li><a href="#eBPFを利用した方法">eBPFを利用した方法</a></li> <li><a href="#LD_PRELOADを利用した方法">LD_PRELOADを利用した方法</a></li> <li><a href="#まとめ">まとめ</a></li> <li><a href="#参照">参照</a></li> </ul> <h3 id="この記事の主題">この記事の主題</h3> <p>この記事の主題は、楽に「動的ライブラリ(及び実行バイナリ)の特定の関数をフックして何かしらの処理をする」( ≒ ソースコードを改変したりビルドしなおしたりしない) ことです。</p> <p>ティアフォーを中心として開発されているAutowareは、ROS (Robot Operating System) という通信ミドルウェアに依存しています。今回はAutowareの性能解析という業務を進める上で、ROS1内部の特定区間の処理時間(実時間)を計測したくなり、上記目的を達成する手段を用意することになりました。</p> <p>手段としては、eBPF(extended Berkeley Packet Filter) を利用した方法と、LD_PRELOADを利用した方法の2種類を紹介します。</p> <h3 id="eBPFを利用した方法">eBPFを利用した方法</h3> <p>まず、eBPFとは何かについて説明します。 eBPFとは、Linux kernel内部で実行される独自の命令セットを持つ仮想マシンにおいて、ユーザ空間から実行プログラムを送り込み、指定したevent (下図におけるkprobes, uprobes, tracepoints, perf_events に対応)にフックするなどして実行することができる機能のことです。</p> <p>eBPFのユーザは、BPF bytecodeをbpf(2)によってkernelに送りこみ、安全なコードであるかのverifyとコンパイル/実行をkernelが行います。eBPFのユーザがBPF bytecodeを直接書くのは稀で、通常はC言語likeな高級言語で記述することができます。eBPFのユーザプログラムとのデータのやりとりは、“maps” と呼ばれるデータ構造を通して容易に行うようになっています。</p> <p><figure class="figure-image figure-image-fotolife" title="eBPF internal (http://www.brendangregg.com/ebpf.html より引用)"><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/s/sykwer/20210303/20210303121516.png" width="1200" height="440" loading="lazy" title="" class="hatena-fotolife" itemprop="image"></span><figcaption>eBPF internal (<a href="http://www.brendangregg.com/ebpf.html">http://www.brendangregg.com/ebpf.html</a> より引用)</figcaption></figure></p> <p>今回は、「動的ライブラリ(及び実行バイナリ)の特定の関数をフックして何かしらの処理をする」ことを実現したかったので、フックイベントとしてuprobesを使用します。uprobesとは、eBPFとは独立した概念であり、ユーザアプリケーションにbreakpointを仕込んで、kernelでハンドリングするための仕組みです。</p> <p>uprobesにフックしてeBPFのコードを実行するためのAPIなどについては、iovisor/bccリポジトリにおいてある <a href="https://github.com/iovisor/bcc/blob/master/docs/reference_guide.md">bcc Reference Guide</a> を見ればよいです。今回は、ユーザコードの関数の開始地点にフックを仕込む <a href="https://github.com/iovisor/bcc/blob/master/docs/reference_guide.md#4-attach_uprobe">attach_uprobe()</a> を利用します。</p> <p>例として、ROS1内部の ros::Publication::publish(ros::SerializedMessage const&amp;) をフックして文字列をprintするだけのコードを示します。</p> <pre class="code lang-python" data-lang="python" data-unlink><span class="synPreProc">from</span> __future__ <span class="synPreProc">import</span> print_function <span class="synPreProc">from</span> bcc <span class="synPreProc">import</span> BPF libroscpp_path = <span class="synConstant">&quot;/path/to/libroscpp.so&quot;</span> bpf_text = <span class="synConstant">&quot;&quot;&quot;</span> <span class="synConstant">#include &lt;uapi/linux/ptrace.h&gt;</span> <span class="synConstant">#include &lt;linux/sched.h&gt;</span> <span class="synConstant">int publish(struct pt_regs *ctx) {</span> <span class="synConstant"> uint64_t pid = bpf_get_current_pid_tgid();</span> <span class="synConstant"> bpf_trace_printk(&quot;publish() called: msg addr - %p :pid/tid %d&quot;, (void *)ctx-&gt;di, pid);</span> <span class="synConstant"> return 0;</span> <span class="synConstant">}</span> <span class="synConstant">&quot;&quot;&quot;</span> b = BPF(text=bpf_text) b.attach_uprobe(name=libroscpp_path, sym=<span class="synConstant">&quot;_ZN3ros11Publication7publishERNS_17SerializedMessageE&quot;</span>, fn_name=<span class="synConstant">&quot;publish&quot;</span>) <span class="synStatement">while</span> <span class="synConstant">1</span>: <span class="synStatement">try</span>: (task, pid, cpu, flags, ts, msg) = b.trace_fields() <span class="synStatement">except</span> <span class="synType">ValueError</span>: <span class="synStatement">continue</span> <span class="synIdentifier">print</span>(<span class="synConstant">&quot;%s&quot;</span> % msg) </pre> <p>以上のスクリプトを実行することにより、libroscpp.so を動的リンクして実行されている全てのROS1プログラムにおける、指定した関数をフックすることができます。</p> <p>ところで、libroscpp.soはC++によって書かれたライブラリなので、関数名がマングリングされており (上のコードにおけるattach_uprobe()の第二引数に渡している “_ZN3ros11Publication7publishERNS_17SerializedMessageE”)、面倒なことにビルド済みのバイナリからマングリングされた関数名を調べなくてはなりません。</p> <pre class="code bash" data-lang="bash" data-unlink># Get offset address of the specified function $ nm -D /path/to/binary_file | c++filt | grep &lt;function_name&gt; # Get the mangled function name $ nm -D /path/to/binary_file | grep &lt;offset&gt;</pre> <p>さて、このようにすることで実行バイナリや動的リンクされるsoファイルに変更を加えることなく、Pythonスクリプトを実行するのみでユーザ空間の関数をフックすることに成功しましたが、計測のオーバーヘッドの面でデメリットがあります。</p> <p>関数にフックしてeBPFのコードを実行する際には、毎回ユーザ空間からカーネル空間へのコンテキストスイッチが生じるため、高い頻度で呼ばれる関数のフックに対して無視できないオーバーヘッドが生じてしまうという点です(eBPFはkprobesに対するフックやkernel eventなどの、kernel空間で発生するイベントに対するフックに適している選択肢と言えます)。</p> <p>これを解決するため、次はユーザ空間のみで完結するLD_PRELOADを用いた方法を検討します。</p> <h3 id="LD_PRELOADを利用した方法">LD_PRELOADを利用した方法</h3> <p>LD_PRELOADとは、/lib/ld-linux.so.2 の動作を制御する環境変数の一つであり、環境変数LD_PRELOADに共有オブジェクトを指定して実行することによって先にLD_PRELOADで指定した共有オブジェクトがリンクされます。</p> <p>したがって、その共有オブジェクトに同名の関数を定義しておくことによって、元の共有ライブラリに定義されている関数の代わりにLD_PRELOADで指定した共有オブジェクトの関数を実行させることが可能になります。</p> <p>さて、今回実現したいのは「特定の関数の開始時にフックして、ある処理を挟む」ことなので、LD_PRELOADで置き換えた関数の実行後に元の関数に処理を戻します。これを実現する方法はいくつかありますが、一番簡単な方法はRTLD_NEXTハンドルを引数に指定して、dlsym(3)を呼びだすことです (LD_PRELOADで置き換えた後の関数内でその関数を呼び出しても、置き換えた後の関数を再帰的に呼びだすだけなので無限ループしてしまいます)。</p> <p>RTLD_NEXTハンドルとはGNU拡張による特殊なハンドルであり、現在の共有オブジェクトの次の共有オブジェクト以降で発見されるシンボルの値を取ってきます。つまり今回の場合では、LD_PRELOADで置き換える前の本来の共有ライブラリにて定義されている関数のシンボルを取ってくることができます。ちなみにRTLD_NEXTハンドルを利用するためには、GNU拡張を有効にするためにdlfcn.h をincludeする前に #define _GNU_SOURCE する必要があります。</p> <p>さて、eBPFを使用したときと同様にros::Publication::publish(ros::SerializedMessage const&amp;) が呼び出された際にフックして特定の処理を挟むことをしてみます。以下のコードを共有ライブラリとしてコンパイルし、LD_PRELOADに指定しつつROS1のプログラムを実行します。</p> <pre class="code lang-cpp" data-lang="cpp" data-unlink><span class="synPreProc">#define _GNU_SOURCE</span> <span class="synPreProc">#include</span><span class="synConstant">&lt;dlfcn.h&gt;</span> <span class="synPreProc">#include</span><span class="synConstant">&lt;iostream&gt;</span> <span class="synStatement">using</span> publish_type = <span class="synType">bool</span> (*)(<span class="synType">void</span>* ,<span class="synType">void</span>*); <span class="synType">extern</span> <span class="synConstant">&quot;C&quot;</span> <span class="synType">bool</span> <span class="synIdentifier">_ZN3ros11Publication7publishERNS_17SerializedMessageE</span>(<span class="synType">void</span> *p, <span class="synType">void</span> *q) { <span class="synType">void</span> *orig_pub = <span class="synIdentifier">dlsym</span>(RTLD_NEXT, <span class="synConstant">&quot;_ZN3ros11Publication7publishERNS_17SerializedMessageE&quot;</span>); <span class="synConstant">std</span>::<span class="synIdentifier">cout</span> &lt;&lt; <span class="synConstant">&quot;call detect: publish 1st arg: &quot;</span> &lt;&lt; p &lt;&lt; <span class="synConstant">&quot; 2nd arg: &quot;</span> &lt;&lt; q &lt;&lt; <span class="synConstant">std</span>::<span class="synIdentifier">endl</span>; <span class="synStatement">return</span> ((publish_type)orig_pub)(p,q); } </pre> <p>マングリングされたそれぞれの関数を再定義し (マングリングされた関数名を調べる方法は前章のとおり)、再定義した関数の内部から dlsym(3)にRTLD_NEXTハンドルを渡して元の関数のシンボルを取得し、その元の関数を呼びだしています。</p> <h3 id="まとめ">まとめ</h3> <p>本記事では、楽に「動的ライブラリ(及び実行バイナリ)の特定の関数をフックして何かしらの処理をする」ことを目的とし、eBPFによる方法とLD_PRELOADによる方法を紹介しました。本記事において紹介した手法は、動的ライブラリをリンクして実行するアプリケーション全般(やアプリケーションの実行バイナリ自体)に使用できるものですので、幅広く応用先があると思います。</p> <h3 id="参照">参照</h3> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fgithub.com%2Fros%2Fros_comm" title="GitHub - ros/ros_comm: ROS communications-related packages, including core client libraries (roscpp, rospy, roslisp) and graph introspection tools (rostopic, rosnode, rosservice, rosparam)." class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://github.com/ros/ros_comm">github.com</a></cite></p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Febpf.io%2F" title="eBPF - Introduction, Tutorials &amp; Community Resources" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://ebpf.io/">ebpf.io</a></cite></p> <p><iframe src="https://hatenablog-parts.com/embed?url=http%3A%2F%2Fwww.brendangregg.com%2Febpf.html" title="Linux eBPF Tracing Tools" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="http://www.brendangregg.com/ebpf.html">www.brendangregg.com</a></cite></p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.amazon.co.jp%2F-%2Fen%2F%25E9%25AB%2598%25E6%259E%2597-%25E5%2593%25B2%2Fdp%2F4873112885" title="Amazon.co.jp: Binary Hacks ―ハッカー秘伝のテクニック100選 : 高林 哲, 鵜飼 文敏, 佐藤 祐介, 浜地 慎一郎, 首藤 一幸: Japanese Books" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://www.amazon.co.jp/-/en/%E9%AB%98%E6%9E%97-%E5%93%B2/dp/4873112885">www.amazon.co.jp</a></cite></p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.amazon.co.jp%2F-%2Fen%2Fdp%2FB081ZDXNL3%2Fref%3Ddp_kinw_strp_1" title="Amazon.co.jp: BPF Performance Tools (Addison-Wesley Professional Computing Series) (English Edition) eBook : Gregg, Brendan: Foreign Language Books" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://www.amazon.co.jp/-/en/dp/B081ZDXNL3/ref=dp_kinw_strp_1">www.amazon.co.jp</a></cite></p> sykwer Autoware開発におけるrvizの活用ついて  hatenablog://entry/26006613696628851 2021-03-03T16:00:00+09:00 2021-03-04T12:15:32+09:00 こんにちは、ティアフォーで自動運転システムを開発している高木です。今回はROS開発の心強い味方、「rviz」についてのちょっとしたお話を紹介していきたいと思います。主に開発者向けのノウハウについて書いていくので実装に踏み込んだ話が多くなりますが、そうでない方も画像だけ見れば概要は伝わると思いますので、こういった機能があることを知っていただき、ぜひ率直な感想をお聞かせください。 なお、ティアフォーでは「自動運転の民主化」をともに実現していく仲間を様々な分野から募集しています。下記ページから募集職種のリストをご覧いただき、興味を持った方はぜひコンタクトをお願いします。 tier4.jp 可視化につ… <p><span style="color: #111111; font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none;">こんにちは、ティアフォーで自動運転システムを開発している高木です。今回はROS開発の心強い味方、「r</span><span style="color: #111111; font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none;">viz」についてのちょっとしたお話を紹介していきたいと思います。主に開発者向けのノウハウについて書いていくので実装に踏み込んだ話が多くなりますが、そうでない方も画像だけ見れば概要は伝わると思いますので、こういった機能があることを知っていただき、ぜひ率直な感想をお聞かせください。</span></p> <p>なお、ティアフォーでは「自動運転の<a class="keyword" href="http://d.hatena.ne.jp/keyword/%CC%B1%BC%E7%B2%BD">民主化</a>」をともに実現していく仲間を様々な分野から募集しています。下記ページから募集職種のリストをご覧いただき、興味を持った方はぜひコンタクトをお願いします。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftier4.jp%2Fen%2Fcareers%2F" title="Careers | Tier IV, Inc." class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://tier4.jp/en/careers/">tier4.jp</a></cite></p> <h3>可視化について</h3> <p>Autowareは多数のプロセスが組み合わさって動作する複雑なシステムであり、最終的な出力となる車両の挙動のみを見て動作状況を把握するのは容易なことではありません。特にAutowareは<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%AA%A1%BC%A5%D7%A5%F3%A5%BD%A1%BC%A5%B9">オープンソース</a>であるため、第<a class="keyword" href="http://d.hatena.ne.jp/keyword/%BB%B0%BC%D4">三者</a>が作成したプログラムとの連携が前提となります。そのため、それぞれの処理でどのような判断が行われており、どういった出力がなされているかを把握することは開発の効率や品質に大きな影響を与えます。</p> <p>プログラムの動作を把握する方法としてはログ出力やデバッガなどが汎用的ですが、AutowareはROS上で動作するためrqtやrvizといった強力な周辺ツールを利用することができます。私達人間にとって視覚情報は極めて相性が高く、適切な可視化は、詳細な説明をせずとも直感的に動作を理解させるほどの効果を発揮します。というわけで、今回は可視化を行う際に大活躍するrvizについて語っていこうと思います。</p> <h3>rvizとは</h3> <p>ROSが提供しているデータの可視化を行うツールがrvizで、センサーから取得した映像や点群、各プログラムの出力結果を簡単に表示することができます。ティアフォーのデモ映像でもよく登場していて、例えばこの動画でもrvizを使っています。</p> <div style="position: relative; width: 100%; padding-top: 56.25%;"><iframe style="position: absolute; top: 0; right: 0; width: 100% !important; height: 100% !important;" src="https://www.youtube.com/embed/GjxEvmbtDPA?feature=oembed" frameborder="0" allowfullscreen=""></iframe></div> <p><cite class="hatena-citation"><a href="https://www.youtube.com/watch?v=GjxEvmbtDPA">www.youtube.com</a></cite></p> <p>それでは、ここから先はrvizの機能の細かいところについてお話していきます。</p> <h3>Marker/MarkerArray</h3> <p>恐らくrvizで何らかの表示を行いたいと考えた時、真っ先に思い浮かぶのがこれでしょう。ROS標準のメッセージ型(visualization_msg)の中で定義されており、typeを指定して様々な図形を描画することができます。</p> <h4>poseとpoints</h4> <p>知ってる方にとっては当たり前かもしれませんが、POINTSやLINE_LISTなどpointsを使用する図形ではposeとpointsが併用できます。挙動はpointsの全座標をpose.positionだけ平行移動してから、pose.positionを中心にしてpose.orientationの回転を行います。私はなぜかposeが無視されてpointsだけ使われると勘違いしていたのでpointsの時点で座標変換をしていました。同じ作業に煩わされている方がいるかもしれないのでメモとして残しておきます。</p> <h4>LINE_LISTとLINE_STRIP</h4> <p>Markerで線を描くにはLINE_LISTかLINE_STRIPを使います。LINE_LISTは頂点を2個ごとに使用して独立した直線を描き、LINE_STRIPは頂点を順番に繋いだ連続する直線を描きます。単に頂点の指定方法が違うだけかと思いきや、実は連続した直線を描く場合に微妙に挙動が異なります。下の画像は星形をそれぞれの方法で描いた結果なのですが、右のLINE_STRIPで描いた方は線の幅が均等になっていません。これは線と言いつつも内部的には四角形になっているからで、頂点で折り曲げるときに線の幅が縦に配置されてしまうためです。なので見た目を気にする場合はLINE_LISTを使ったほうが綺麗になります。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/i/isamu-takagi/20210223/20210223175854.png" alt="LINE_LISTとLINE_STRIPで描いた星形" title="" class="hatena-fotolife" itemprop="image" /></p> <h3>透過度の罠</h3> <p>まずはこちらの画像をご覧ください。これは手前(Z=+1.0)に緑の三角形を、奥(Z=-1.0)に赤の三角形を配置したときの描画結果です。両方の図形で透明度は1.000に設定しています。</p> <div class="images-row mceNonEditable"> <div class="images-row-item"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/i/isamu-takagi/20210223/20210223192750.png" alt="" title="" class="hatena-fotolife" itemprop="image" /></div> <div class="images-row-item"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/i/isamu-takagi/20210223/20210223192757.png" alt="" title="" class="hatena-fotolife" itemprop="image" /></div> </div> <p> 続いて透過度を0.999にした結果がこちらです。再表示するたびにランダムで左右のどちらかの結果になります。赤の三角形が奥に配置されていて、Z座標は緑の三角形と2.0も離れているのにもかかわらず、手前に赤の三角形が表示されてしまう場合があります。</p> <div class="images-row mceNonEditable"> <div class="images-row-item"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/i/isamu-takagi/20210223/20210223193211.png" alt="" title="" class="hatena-fotolife" itemprop="image" /></div> <div class="images-row-item"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/i/isamu-takagi/20210223/20210223193216.png" alt="" title="" class="hatena-fotolife" itemprop="image" /></div> </div> <p>原因はMarker表示時に透過度に応じて以下のような設定が行われるためで、透過度を0.9998以上に設定した時にしか前後関係が正しく処理されません。</p> <table> <tbody> <tr> <th>透過度</th> <th>深度バッファ</th> <th><a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A2%A5%EB%A5%D5%A5%A1%A5%D6%A5%EC%A5%F3%A5%C7%A5%A3%A5%F3%A5%B0">アルファブレンディング</a></th> </tr> <tr> <td>0.9998以上</td> <td>有効 (前後関係が正しく表示される)</td> <td>無効 (上書きする)</td> </tr> <tr> <td>0.9998未満</td> <td>無効 (前後関係が正しく表示されない)</td> <td>有効 (合成する)</td> </tr> </tbody> </table> <p>両方有効にすれば良いのではないかと思ったかもしれませんが、そう簡単にはいかない事情があります。深度バッファは描画の順序によらず前後関係を正しく表示する方法であるのに対し、透過度を考慮するには背景色が必要なので奥の物体から処理しなければならないためです。残念なことに順序はMarkerで制御できないので、透過度をどちらが上になっても判別できるように調整するのが最も簡単な対応となるでしょう。</p> <h3>Display Plugin</h3> <p>Displayは主にrviz中央の3D画面に何かを表示する目的で使用します。特殊な用途でなければMarkerで十分表現可能だと思いますが、より高度な処理をしたければ自作のpluginを作成することになります。Markerに似た図形を描画するならogre_helpersにあるこれらのクラスが役立ちます。</p> <ul> <li>Arrow</li> <li>Axes</li> <li>BillboardLine</li> <li>Line</li> <li>PointCloud</li> <li>Shape</li> </ul> <p>それでも満足できないという方はOgreという3D描画ライブラリを調べてみてください。ここから先はrvizというよりもOgreの領域になります。詳細は省きますが、大まかには次の手順で自由に図形を描画できるようになり、TRIANGLE_STRIPといったMarkerにはない描画方法の指定も行えるようになります。先ほどのogre_helpers内にあるline.cppの実装が分かりやすいです。</p> <ol> <li>親となるSceneNodeから新しいSceneNodeを作成する</li> <li>ManualObjectを作成して新しいSceneNodeに関連付ける</li> <li>Materialを作成する</li> <li>Materialを使用してManualObjectの描画関数一式を実行する</li> </ol> <h3> Panel Plugin</h3> <p>Panelはrvizの上下左右に<a class="keyword" href="http://d.hatena.ne.jp/keyword/GUI">GUI</a>を追加できます。Qtというライブラリで実装されており、純粋なQtアプリケーションと似たような感覚で開発できるでしょう。固有の機能としてrvizが内部で管理しているデータにアクセスできるほか、設定をrviz本体と一緒に管理するための機能が用意されています。</p> <p>個人的にはrvizと同じウィンドウでまとめて情報を表示できるのがメリットだと思っています。特段rviz固有の機能を使うわけではないのですが、使用頻度の高いデータを表示しておけば別途端末を立ち上げてrostopic echoする手間が省けます(rqtにもtopicを表示するpluginがありますが、自作する場合は最小限の情報を適切に配置できるのが強み)。このような感じでQGridLayoutとQLabelを組み合わせ、簡単に情報表示を行うpluginを作ってみたのですが、これだけでもかなり印象が変わってくるのではないでしょうか。</p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/i/isamu-takagi/20210226/20210226030837.png" alt="f:id:isamu-takagi:20210226030837p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <p>特に情報が常に視界に入っているというのが大きいです。能動的にデータを見に行く場合、気にすべきデータがどれなのかを把握し、適切なタイミングで確認しなければなりません。意外とこの作業の負担は大きく、確認し忘れなどヒューマンエラーが起こる頻度も高いです。しかし、このような表示があれば「何かエラーの部分が赤くなっているんだけど大丈夫なのだろうか」といった具合で疑問を抱かせ、迅速な対応を取ることが可能となります。</p> <p>また、現地で実験を行っているスタッフを開発者が遠隔からサポートする際も役立ち、確認用のコマンドを細かく指示せずとも画面の表示を読み上げてもらうだけで大まかに状況を理解することができます。実際、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B9%A5%AF%A5%EA%A1%BC%A5%F3%A5%B7%A5%E7%A5%C3%A5%C8">スクリーンショット</a>を一枚送ってもらうだけで問題を解決できたこともありました。今後は自動運転のサービス化を目指して車両の台数を増やしていかなければなりませんから、現地で活動するスタッフの規模も拡大していくと予想されます。そのとき、個人のスキルレベルに大きく依存せず、技術者と容易にコミュニケーションがとれるかどうかは、プログラムの重要な要素となっているはずです。</p> <h3>Tool Plugin</h3> <p>Toolはrviz上部に配置され、主に中央の3D画面を使った操作を作成できます。その性質上マウスとキーボードのイベントを処理するためのコールバック関数が提供されていて、素晴らしいことにマウスの座標と任意の平面の交点を計算する関数(getPointOnPlaneFromWindowXY)まで用意されています。もちろん、rvizにはInteractive Markerが用意されているので基本的にこちらを使えば良いのですが、例えば点群を任意の場所に出して障害物検知のテストを行いたい場合に便利だったりします。 </p> <p>本来の使い方ではないような気もしますが(Tool内で処理を完結させた方が良いと思っています)、画面上でクリックされた座標をtopicとしてpublishするToolを作って利用しています。マウスがクリックされた時だけ処理を行ったり、ドラッグの始点と終点を取得したりと大抵は同じような操作が欲しくなるので該当部分をToolで実装しておき、利用したいプログラムでは結果をsubscribeすればお手軽にrvizとの連携が可能となるわけです。あくまで<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C7%A5%D0%A5%C3%A5%B0">デバッグ</a>の範囲に限りますが、作っておくとそこそこ便利に使えます。</p> <div style="position: relative; width: 100%; padding-top: 56.25%;"><iframe style="position: absolute; top: 0; right: 0; width: 100% !important; height: 100% !important;" src="https://www.youtube.com/embed/DcoOhjSLxyY?feature=oembed" frameborder="0" allowfullscreen=""></iframe></div> <p><cite class="hatena-citation"><a href="https://youtu.be/DcoOhjSLxyY">youtu.be</a></cite></p> <p>この動画では歩行者に見立てた点群をマウスで動かせるようにして<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C7%A5%D0%A5%C3%A5%B0">デバッグ</a>をしています。任意のタイミングで急に飛び出したり、車両に合わせて速度を調整するといった動きを用意するのはなかなか難しいのですが、マウスで歩行者の位置を操作すれば複雑なケースも自由自在にテストできます。突き詰めていくとやはり専用のツールには敵いませんが、基本的にrvizには<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C7%A5%D0%A5%C3%A5%B0">デバッグ</a>用の情報を色々と出しているはずですので、同じ画面から空間を共有して操作できるというメリットは非常に大きいです。</p> <h3>まとめ</h3> <p>普段の開発では可視化まわりの処理にそこまで力を入れることはないと思います。しかし、ちょっとした工夫で効率が大きく変わったり、気づきにくいミスを防止できたりと大きな可能性を秘めている部分なので、余裕があればひと手間かけてみると良いかもしれません。</p> isamu-takagi Motion Planning Under Various Constraints - Autonomous Parking Case hatenablog://entry/26006613694966754 2021-02-24T16:00:00+09:00 2021-02-24T20:44:27+09:00 Introduction to the Motion Planning Autonomous vehicles (robots, agents) are requested to move around in an environment, executing complex, safe maneuvers without human interference and to make thousands of decisions in a split second. How can we endow autonomous vehicles with these properties? By t… <h3>Introduction to the Motion Planning</h3> <p><span style="font-weight: 400;">Autonomous vehicles (robots, agents) are requested to move around in an environment, executing complex, safe maneuvers without human interference and to make thousands of decisions in a split second. How can we endow autonomous vehicles with these properties?  </span></p> <p>By the way, at Tier Ⅳ, we are looking for various engineers and researchers to ensure the safety and security of autonomous driving and to realise sharing technology for safe intelligent vehicles. Anyone who is interested in joining us, please contact us from the web page below. </p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftier4.jp%2Fcareers%2F" title="Careers | 株式会社ティアフォー" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://tier4.jp/careers/">tier4.jp</a></cite></p> <p><span style="font-weight: 400;">Then, the key to answering this question is “Motion Planning”. Autonomous vehicles should be able to quickly generate motion plans and choose the best among many or the optimal plan defined by some optimization criteria. </span></p> <p><span style="font-weight: 400;">Motion planning modules for autonomous driving might serve for three different objectives [1]:</span></p> <ul> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">Producing a trajectory to track,</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">Producing a path to follow,</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">Producing a path and trajectory with a definite final configuration. </span></li> </ul> <p><span style="font-weight: 400;">In a trajectory tracking task, agents execute time-stamped commands to satisfy the spatial coordinates with the prescribed velocities. In the path tracking, only positions are tracked. </span></p> <p><br /><span style="font-weight: 400;">Vehicle motion is formally defined using a couple of differential equations. These differential equations propagate the state variables such as velocities (Longitudinal and lateral velocities; </span><em><span style="font-weight: 400;">V</span></em><em><span style="font-weight: 400;">x</span></em><em><span style="font-weight: 400;">, V</span></em><em><span style="font-weight: 400;">y</span></em> <span style="font-weight: 400;">and Heading Rate </span><span style="font-weight: 400;">) in the chosen coordinate system. The resultant integral curves </span><span style="font-weight: 400;">define the configuration space of the robots (see Figure 1.). If we are controlling robots by velocities, the motion equations are called kinematic model equations.</span></p> <p> </p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="Figure 1. Configuration space (x, y and heading rate) for a car-like robot motion"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/b/boyali/20210222/20210222170034.png" alt="f:id:boyali:20210222170034p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">Figure 1. Configuration space (x, y and heading rate) for a car-like robot motion</figcaption> </figure> <p><span style="font-weight: 400;">The <a class="keyword" href="http://d.hatena.ne.jp/keyword/most">most</a> difficult task in the objectives list is the last one: to generate a trajectory or a path while satisfying the endpoint configuration. We are familiar with this kind of planning tasks from our daily life. You can probably remember how frustrating it was to park a vehicle within a parking slot the first time and execute a couple of maneuvers without hitting <a class="keyword" href="http://d.hatena.ne.jp/keyword/the%20cars">the cars</a> or walls around (Figure 2).</span></p> <p> </p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="Figure 2. Parallel parking"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/b/boyali/20210222/20210222170443.png" alt="f:id:boyali:20210222170443p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">Figure 2. Parallel parking</figcaption> </figure> <h3> <strong>Why is planning with the endpoint configuration a difficult task even for cases without any obstacle in the environment?</strong></h3> <p><span style="font-weight: 400;">When considering the parking maneuver, notice that a car can only move forward-backward directions. If we also turn the steering wheel, the vehicle follows a circular path. Cars cannot move in their sideway direction as it is impossible due to the fixed rear wheel orientation. On the other hand, while executing a parking maneuver, we need to be able to move the car in the sideway directions to properly park the vehicle. That is why we drive the car, backward-forward and steer to move the car’s position in parallel to the starting position (Figure 3).</span></p> <p> </p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="Figure 3. To move the car in the sideway direction parallel to the starting configuration, we need at least two maneuvers. "> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/b/boyali/20210222/20210222170651.png" alt="f:id:boyali:20210222170651p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">Figure 3. To move the car in the sideway direction parallel to the starting configuration, we need at least two maneuvers.</figcaption> </figure> <p> </p> <p><span style="font-weight: 400;">In physics, the prohibited sideway directions mean zero velocity in these directions. Although there are no environmental obstacles or physical constraints in these directions, the velocity is constrained to be zero. We can not integrate these velocities to convert them to path constraints which are relatively simpler to deal with. These velocity constraints are called "</span><em>non-holonomic" </em><span style="font-weight: 400;">motion constraints. </span></p> <p><span style="font-weight: 400;">Since we have three motion direction (x, y and heading angle) </span>and two controls (Speed V and steering δ), these kinds of systems are called under-actuated. Non-holonomic systems are in general under-actuated. Finding a path given two configuration positions respecting the velocity constraint is difficult due to the missing control direction.</p> <p><span style="font-weight: 400;">Almost five decades of research effort has been put into finding a solution for non-holonomic motion planning. There has been no general solution proposed so far to the problem. Although it is possible to move a car position in parallel with a couple of maneuvers, such as zigzagging (Figure 3), the resultant paths and trajectories are discontinuous and generally have some cusp and breakpoints.  This makes the solutions more difficult to find smooth trajectories mathematically. The nonholonomic motion planning problem becomes even more difficult when there are constraints in the environment (such as parking a vehicle in between the other vehicles).  What is more, the motion equations are usually nonlinear and nonlinear differential equations do not have a direct solution except in a few cases. </span></p> <p><span style="font-weight: 400;">In the robotics literature, approximate solutions have been proposed. These solutions are based on the notion of local controllability and the geometry of the configuration space. In principle, a global motion between two endpoints is divided into small motion trajectories. The small motion intervals are then connected using various algorithms.</span></p> <p><span style="font-weight: 400;">When there are no obstacles in the environment, we can use Reed &amp; Shepp Curves (R&amp;S Curves) to generate a direct path given two endpoints [2]. The R&amp;S curves fit a path for the given endpoint configurations using some motion primitives; Straight (Backward-Forward), Left - Right Turns (Forward-Backward). </span></p> <p> </p> <p><span style="font-weight: 400;">A couple of examples of R&amp;S curves are shown in the following figures [3].  </span></p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/b/boyali/20210222/20210222182247.png" alt="f:id:boyali:20210222182247p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="Figure 4. Reeds and Shepp curves for two different endpoint conditions."> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/b/boyali/20210222/20210222182307.png" alt="f:id:boyali:20210222182307p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">Figure 4. Reeds and Shepp curves for two different endpoint conditions.</figcaption> </figure> <p><span style="font-weight: 400;">Even though the R&amp;S curves produce time-optimal and pleasing curves, they cannot provide a solution when there are environmental constraints. Their use is limited to unconstrained cases. </span></p> <p><span style="font-weight: 400;">The <a class="keyword" href="http://d.hatena.ne.jp/keyword/most">most</a> recent literature focuses on two-staged nonlinear optimization-based </span><span style="font-weight: 400;">solutions for constrained environments.   Nonlinear Optimization (Nonlinear Programming techniques - <a class="keyword" href="http://d.hatena.ne.jp/keyword/NLP">NLP</a>) can deal with nonlinear motion equations and constraints. However, the nonlinear optimization methods require a good feasible solution to start with. This difficulty is what diversifies the proposals in the literature. We can list these methods under four categories. These are;</span></p> <ul> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">Optimization-based (bi-level or multi-staged optimization)</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">Heuristic algorithms (particle swarm optimization, genetic algorithm)</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">Sampling-based algorithms (RRT, Hybrid-A*) and, </span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">Machine learning. </span></li> </ul> <p><span style="font-weight: 400;">The proposed algorithms have advantages and disadvantages relative to each other. The common theme of these algorithms is having a two-stage solution that contributes to the implementation complexity.</span></p> <p><span style="font-weight: 400;">At Tier IV, we have proposed a new algorithm for autonomous vehicle parking maneuvers inspired by an optimization method trending in the aerospace industry for designing spacecraft trajectories. The Successive Convexification Algorithm (SCvx) is capable of returning a feasible trajectory under a wide range of initial conditions, removing the need for a two stage approach, and has been proven to converge to the solution of the original nonlinear problem without compromising accuracy. In the next section, we explain what kind of problems we can encounter in the numerical solution of optimization problems, and how the successive convexification methods offer a solution to constrained nonholonomic motion planning. </span></p> <h3><strong>Solving Nonlinear Problems by Successive Convexification Algorithms</strong></h3> <p><span style="font-weight: 400;">Apart from a very demanding feasible initial solution in nonlinear programs, a design engineer can experience infeasible solution error messages raised by the solvers used in the numerical problem although the original problem is feasible. This kind of infeasibility is called artificial infeasibility. Solvers in numerical optimization have a mechanism to check beforehand whether the problem is feasible or not. The cause of infeasibility can be attributed to the results of implicit or explicit unrealistic linearization. </span></p> <p><span style="font-weight: 400;">Furthermore, linear functions might not have a lower bound in the search space. This could be another reason for the solvers to halt. The lack of a lower bound in a minimization problem is called “artificial unboundedness” [see 3, 4, 5 and references therein]. </span></p> <p><span style="font-weight: 400;">The SCvx algorithm is a kind of sequential quadratic optimization. In the sequential solutions, the nonlinear motion and constraint equations are linearized starting from an initial trajectory. Almost in all mathematical problems, one of the best strategies for the solution is to convert complex problems into a series of linear problems. </span></p> <p><span style="font-weight: 400;">The solution of a linear problem yields a feasible trajectory which is then used as an initial trajectory for the next solution (Figure 5).</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="Figure 5. A nonlinear trajectory can be solved by creating linear sub-problems which can be solved iteratively. "> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/b/boyali/20210222/20210222182708.png" alt="f:id:boyali:20210222182708p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">Figure 5. A nonlinear trajectory can be approximated by linear sub-problems which can be solved iteratively.</figcaption> </figure> <p><span style="font-weight: 400;">The SCvx algorithm operates in the same manner with two additional mechanisms to prevent artificial infeasibility and artificial unboundedness error messages. </span></p> <p><span style="font-weight: 400;">The artificial unboundedness problem is addressed by introducing a trust region that restricts the search space (Figure 6). The <a class="keyword" href="http://d.hatena.ne.jp/keyword/radius">radius</a> of the thrust region is adjusted by checking if our linearization reasonably approximates the nonlinear cost. If the linearization approximates the nonlinearity well enough, the <a class="keyword" href="http://d.hatena.ne.jp/keyword/radius">radius</a> of the trust region is increased, and <a class="keyword" href="http://d.hatena.ne.jp/keyword/vice%20versa">vice versa</a>. </span></p> <p> </p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="Figure 6. Trust regions are used to restrict the search space of the optimization algorithm. The minimum or maximum is sought within the circles specified by the trust region radius. "> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/b/boyali/20210222/20210222182925.png" alt="f:id:boyali:20210222182925p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">Figure 6. Trust regions are used to restrict the search space of the optimization algorithm. The minimum or maximum is sought within the circles specified by the trust region <a class="keyword" href="http://d.hatena.ne.jp/keyword/radius">radius</a>.</figcaption> </figure> <p><span style="font-weight: 400;">The artificial infeasibility problem is addressed by adding a virtual force pushing all the infeasible states into a feasible region. However, the amount of virtual force we apply is penalized in the cost function with a very high weighting factor (i.e 1e</span><span style="font-weight: 400;">5</span><span style="font-weight: 400;">). One of the objectives is to make the contribution of the virtual force to the cost zero in the optimization. </span></p> <p><span style="font-weight: 400;">These two additional mechanisms to prevent artificial infeasibility and unboundedness prevent the solvers from stopping due to the numerical problems and allow the solvers to seek the solution. The SCvx algorithms have been proved to converge to the original nonlinear solution. When a solution of the linear counterpart of a nonlinear problem is equivalent, the solution is called lossless (no feasible region is removed from the problem, [5]). </span></p> <h3><strong>How Does the Successive Convexification Algorithm (SCvx) Help in Solving the Autonomous Parking (Nonholonomic Motion Planning) Problem? </strong></h3> <p><span style="font-weight: 400;">So far, we alluded that the SCvx algorithm could give us a solution for a nonlinear optimization problem by solving sequential linear sub-problems. We also emphasised a virtual force that pushes infeasible states into the feasible state-space regions, and later on, this force is driven to zero. These two properties eliminate the need for a feasible initial trajectory, therefore reducing the two-stage solutions into one. The SCvx algorithm does not require an initial feasible trajectory. This is a highly desirable property since it is generally a hard problem to come with an initial trajectory in nonlinear optimization problems. </span> </p> <p><span style="font-weight: 400;">Although we are now closer to the solution for an autonomous parking problem, we need to overcome the other continuity issues afflicted.  When we have a look at the R&amp;S curves, point-to-point trajectories might require forward-backward - full stop motion. The vehicle moves a bit forward, stops fully, makes a full steering turn and moves back. There are both input and output discontinuities. The solvers and optimization algorithms operate on the continuity assumption. The second issue is the discontinuities in the environmental constraints. </span></p> <p><span style="font-weight: 400;">Inspired by the shape of R&amp;S curves, we divide a whole parking maneuver into a minimum of three curve sections. <a class="keyword" href="http://d.hatena.ne.jp/keyword/Most">Most</a> of the trajectories that the R&amp;S method produces consists of a maximum of four or five connected curves. Dividing a whole trajectory into three sections captures <a class="keyword" href="http://d.hatena.ne.jp/keyword/most">most</a> of the solution families. In this proposal, we can imagine three separate vehicles trying to reach each other similar to the situation we see in a flag race (Figure 7).</span></p> <p> </p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="Figure 7. Three separate curve sections on which each vehicle travels. "> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/b/boyali/20210222/20210222183507.png" alt="f:id:boyali:20210222183507p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">Figure 7. Three separate curve sections on which each vehicle travels.</figcaption> </figure> <p> </p> <p><span style="font-weight: 400;">The three separate-curve-approach  can be formulated with boundary conditions for each curve. The start and endpoint of the whole trajectory must be fixed. The curve connections (light blue circles) are the free boundary conditions for each of the curves that are needed to be connected by the optimization algorithm. In this way, we can obtain any arbitrary trajectory with cusps and breakpoints </span></p> <p><span style="font-weight: 400;">A solution to a nonholonomic motion planning problem without environmental constraints using the SCvx algorithm is shown in Figure 8.</span></p> <p> </p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="Figure 8. A trajectory with two cusps solved by SCvx for an unconstrained case. The arrows with red-hats show the direction of the vehicle. "> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/b/boyali/20210222/20210222183538.png" alt="f:id:boyali:20210222183538p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">Figure 8. A trajectory with two cusps solved by SCvx for an unconstrained case. <a class="keyword" href="http://d.hatena.ne.jp/keyword/The%20arrows">The arrows</a> with red-hats show the direction of the vehicle.</figcaption> </figure> <p><span style="font-weight: 400;">For the second issue; discontinuities in the environmental constraints, we used a state-triggered constraint formulation offered by the same authors of SCvx algorithms [5]. The authors formulate the keep-out zone for the spacecraft landing regions using the state-triggered constraints. The keep-out zone formulation resembles parking situations. In some optimization problems, we need to define the regions where  some constraints could be active or inactive. This requires logical constraints or binary decisions such that, if some conditions occur, then some constraints are activated [if the triggering “condition &lt; 0” ⇒ constraints &lt; 0]. In mathematical optimization theory, these kinds of logical constraints are solved by mixed integer programming which is equally as hard as nonlinear optimization. We show an example of triggering and constraint conditions in Figure 9.</span></p> <p> </p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="Figure 9. State-triggered constraint condition for a parking lot. Here the triggering conditions are xw &lt; - b OR xw &gt; b. When these conditions are triggered, the vehicle’s position value in yw direction must be yw&gt;2 meters. "> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/b/boyali/20210222/20210222183628.png" alt="f:id:boyali:20210222183628p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">Figure 9. State-triggered constraint condition for a parking lot. Here the triggering conditions are x<span style="font-size: 80%;">w</span> &lt; - b OR x<span style="font-size: 80%;">w</span> &gt; b. When these conditions are triggered, the vehicle’s position <a class="keyword" href="http://d.hatena.ne.jp/keyword/value">value</a> in y<span style="font-size: 80%;">w</span> direction must be y<span style="font-size: 80%;">w</span>&gt;2 meters.</figcaption> </figure> <p> </p> <p><span style="font-weight: 400;">As you may notice, the solutions obtained at each iteration becomes an initial trajectory for the subsequent problem and hints us the regions where the logical constraints become active or inactive.  This allows us to inject discontinuous environmental constraints when the iterated trajectory triggers the condition. </span></p> <p><span style="font-weight: 400;">Using the state-triggers eliminates the use of complicated collision checking algorithms and alleviates the load of the solvers.</span></p> <h3><strong>Complete Solution for Parking Maneuvers</strong></h3> <p><span style="font-weight: 400;">We applied the strategies we have mentioned to a couple of tight parking scenarios: parallel and perpendicular parking, which are shown in figures 10 and 11 respectively and with an animation in Figure 12. In these figures, we compare the SCvx solutions to the R&amp;S curve solutions that are not aware of any constraints in the environment. </span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="Figure 10. A parallel parking case. The vehicle starts in a random position and direction in the green shaded area and is requested to park in between two obstacles parallel to the X-axis. "> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/b/boyali/20210222/20210222183816.png" alt="f:id:boyali:20210222183816p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">Figure 10. A parallel parking case. The vehicle starts in a random position and direction in the green shaded area and is requested to park in between two obstacles parallel to the X-axis.</figcaption> </figure> <figure class="figure-image figure-image-fotolife mceNonEditable" title="Figure 11. A reverse parking case. The vehicle is requested to park perpendicular to the X-axis in between two obstacles. "> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/b/boyali/20210222/20210222183835.png" alt="f:id:boyali:20210222183835p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">Figure 11. A reverse parking case. The vehicle is requested to park perpendicular to the X-axis in between two obstacles.</figcaption> </figure> <p> </p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="Figure 12. An animation for a reverse parking maneuver. "> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/b/boyali/20210222/20210222183853.gif" alt="f:id:boyali:20210222183853g:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">Figure 12. An animation for a reverse parking maneuver.</figcaption> </figure> <p> </p> <h3><strong>Final Remarks</strong></h3> <p><span style="font-weight: 400;">In this blog article, we summarized one of our publications presented at ITSC 2020; “Autonomous Parking by Successive Convexification and Compound State Triggers”. The detailed algorithms, equations and procedures and the related literature review and references can be found in our paper. We are planning to put the application of SCvx solutions into Autoware.</span></p> <p> </p> <h5><span style="font-weight: 400;">References:</span></h5> <ol> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">Latombe, J.C., 2012. </span><em><span style="font-weight: 400;">Robot motion planning</span></em><span style="font-weight: 400;"> (Vol. 124). Springer Science &amp; Business Media.</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">LaValle, S.M., 2006. </span><em><span style="font-weight: 400;">Planning algorithms</span></em><span style="font-weight: 400;">. Cambridge <a class="keyword" href="http://d.hatena.ne.jp/keyword/university%20press">university press</a>.</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">Boyali, A. and Thompson, S., 2020, September. Autonomous Parking by Successive Convexification and Compound State Triggers. In </span><em><span style="font-weight: 400;">2020 <a class="keyword" href="http://d.hatena.ne.jp/keyword/IEEE">IEEE</a> 23rd International Conference on Intelligent Transportation Systems (ITSC)</span></em><span style="font-weight: 400;"> (pp. 1-8). <a class="keyword" href="http://d.hatena.ne.jp/keyword/IEEE">IEEE</a>.</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">Mao, Y., Szmuk, M. and Açıkmeşe, B., 2016, December. Successive convexification of non-convex optimal control problems and its convergence properties. In </span><em><span style="font-weight: 400;">2016 <a class="keyword" href="http://d.hatena.ne.jp/keyword/IEEE">IEEE</a> 55th Conference on Decision and Control (CDC)</span></em><span style="font-weight: 400;"> (pp. 3636-3641). <a class="keyword" href="http://d.hatena.ne.jp/keyword/IEEE">IEEE</a>.</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">Szmuk, M., 2019. </span><em><span style="font-weight: 400;">Successive Convexification &amp; High-Performance Feedback Control for <a class="keyword" href="http://d.hatena.ne.jp/keyword/Agile">Agile</a> Flight</span></em><span style="font-weight: 400;"> (Doctoral dissertation).</span></li> </ol> <p><a href="http://larsblackmore.com/losslessconvexification.htm"><span style="font-weight: 400;">http://larsblackmore.com/losslessconvexification.htm</span></a></p> <p> </p> boyali 大規模非構造データ(Point Cloud)のリアルタイム通信 hatenablog://entry/26006613692264232 2021-02-17T16:30:00+09:00 2021-02-17T16:30:00+09:00 こんにちは、ティアフォーでフロントエンド開発を担当している田上です。 ティアフォーでは先日ご紹介したSREの信頼性への取り組みの一つとして、少人数でも信頼性が高く、効率的な開発ができるように技術選定会を実施しています。 今回は、最近技術選定会で取り上げた「Point cloud data(PCD)のように大きなサイズのデータを含んだROS TopicをAWS CloudからWebブラウザに転送する」仕組みと技術選定会の様子についてお話したいと思います。 なお、今回ご紹介するようにティアフォーには新しい技術や技術的なチャレンジを良しとする雰囲気、エンジニアの興味や好奇心を満たせる環境があります。… <p><span style="font-weight: 400;">こんにちは、ティアフォーでフロントエンド開発を担当している田上です。</span></p> <p>ティアフォーでは<a href="https://tech.tier4.jp/entry/2021/01/20/160000" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;">先日ご紹介したSREの信頼性への取り組み</a><span style="font-weight: 400;">の一つとして、少人数でも信頼性が高く、効率的な開発ができるように技術選定会を実施しています。</span></p> <p><span style="font-weight: 400;">今回は、最近技術選定会で取り上げた「Point cloud data(<a class="keyword" href="http://d.hatena.ne.jp/keyword/PCD">PCD</a>)のように大きなサイズのデータを含んだROS Topicを<a class="keyword" href="http://d.hatena.ne.jp/keyword/AWS">AWS</a> Cloudから<a class="keyword" href="http://d.hatena.ne.jp/keyword/Web%A5%D6%A5%E9%A5%A6%A5%B6">Webブラウザ</a>に転送する」仕組みと技術選定会の様子についてお話したいと思います。</span></p> <p>なお、今回ご紹介するようにティアフォーには新しい技術や技術的なチャレンジを良しとする雰囲気、エンジニアの興味や好奇心を満たせる環境があります。ぜひ以下のページから募集職種のリストを見ていただき、興味を持った方は応募をしていただければと思います。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fherp.careers%2Fv1%2Ftier4" title="株式会社ティアフォー 求人一覧" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://herp.careers/v1/tier4">herp.careers</a></cite></p> <h3><span style="font-weight: 400;">背景</span></h3> <p><span style="font-weight: 400;">Autowareを使った自動運転車両は車両に搭載したLiDARを用いて、周囲の物体の形状を点群データ(<a class="keyword" href="http://d.hatena.ne.jp/keyword/PCD">PCD</a>: Point Cloud Data)の形式で取得します。<a class="keyword" href="http://d.hatena.ne.jp/keyword/PCD">PCD</a>は、自動運転を行う上で非常に重要なデータです。例えば、自動運転車両が地図上のどこを走行しているかの推定(自己位置推定)に用いられたり、障害物の物体認識に用いられたりします。自動運転開発者は、自動運転時に発生した問題の原因を特定するために、<a class="keyword" href="http://d.hatena.ne.jp/keyword/PCD">PCD</a>が適切に取得されたかどうか、あるいは<a class="keyword" href="http://d.hatena.ne.jp/keyword/PCD">PCD</a>をもとに障害物が適切に認識されたかどうかを確認します。そのため、<a class="keyword" href="http://d.hatena.ne.jp/keyword/PCD">PCD</a>自体や<a class="keyword" href="http://d.hatena.ne.jp/keyword/PCD">PCD</a>をもとに認識した結果を可視化する仕組みは、自動運転開発においてとても重要です。</span></p> <p><iframe width="560" height="315" src="https://www.youtube.com/embed/3Mrm0Wy7TqE?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe><cite class="hatena-citation"><a href="https://youtu.be/3Mrm0Wy7TqE">youtu.be</a></cite></p> <p><span style="font-weight: 400;">AutowareはROSをベースに構築されていますが、ROSにはRosbagと呼ばれるROS Topicをファイル(bagファイル)に保存する仕組みがあります。Autowareを使った自動運転車両は<a class="keyword" href="http://d.hatena.ne.jp/keyword/PCD">PCD</a>や物体の認識結果、その他さまざまな自動運転時に用いたデータをRosbagを用いてbagファイルに保存しています。保存されたbagファイルは</span><span style="font-weight: 400;">自動運転走行後に、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%AF%A5%E9%A5%A6%A5%C9">クラウド</a>にアップロードされます。自動運転開発者は<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%AF%A5%E9%A5%A6%A5%C9">クラウド</a>上のbagファイルをダウンロードし、手元のPCでbagファイルの中身を可視化して自動運転時のセンサーのデータやAutowareの動作などを確認することができます。</span></p> <p><span style="font-weight: 400;">通常、bagファイルの可視化にはRVizというソフトウェアが用いられます。RVizは優れた可視化ツールであり、ROSの開発者にとって一般的なソフトウェアです。ティアフォーでもRVizは当然のように使われていますが、問題点もあります。</span></p> <p><span style="font-weight: 400;">RVizを使う上での問題点の一つは、可視化ツールとして<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%AF%A5%E9%A5%A6%A5%C9">クラウド</a>上の大量のデータを扱うのに適さないという点です。一台の自動運転車両は実証実験の際に一日あたり数百GByteを超えるbagデータを生成し、そのデータを<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%AF%A5%E9%A5%A6%A5%C9">クラウド</a>に保存します。<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%AF%A5%E9%A5%A6%A5%C9">クラウド</a>上のデータストアに存在する大量のデータのうち、どのデータが自分の興味のあるデータか探索したり、大きなサイズのファイルをダウンロードして手元のツールで表示するのは開発者にとってストレスのかかる作業です。</span></p> <p><iframe width="560" height="315" src="https://www.youtube.com/embed/5_YOr-P_-IU?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe><cite class="hatena-citation"><a href="https://youtu.be/5_YOr-P_-IU">youtu.be</a></cite></p> <p><span style="font-weight: 400;">そのような問題に対処するため、現在ティアフォーではウェブブラウザ上で<a class="keyword" href="http://d.hatena.ne.jp/keyword/PCD">PCD</a>を含んだbagファイルを可視化する仕組み(Webアプリ)を開発中です。可視化ツールをWebアプリにすることで複数のOS上でインストールレスで使用することができます。また車両の運行管理システムやbagファイルの管理システムと連携することで、開発者が可視化したいデータをより容易に見つけられるようになると期待できます。</span></p> <h3><span style="font-weight: 400;">課題</span></h3> <p><span style="font-weight: 400;">bagファイルの可視化をWebアプリで実現する際に気をつけるべき点があります。それは表示するデータ(<a class="keyword" href="http://d.hatena.ne.jp/keyword/PCD">PCD</a>を含んだROS Topic)のサイズが大きく、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%AF%A5%E9%A5%A6%A5%C9">クラウド</a>からウェブブラウザに対してデータを転送する際にそれなりのネットワーク帯域を必要とすることです。1台のLiDARが取得する点群データの数は数万ポイントに及び、その点群の位置は常に変化します。そのため<a class="keyword" href="http://d.hatena.ne.jp/keyword/PCD">PCD</a>のサイズは動画像データに匹敵する大きさになります。</span></p> <p><span style="font-weight: 400;">ROSにはROS Bridgeと呼ばれる仕組みがあり、WebSocketを用いてROSのTopicをウェブブラウザに送信することができます。ROS Bridgeは便利な仕組みではありますが、WebSocket上で<a class="keyword" href="http://d.hatena.ne.jp/keyword/JSON">JSON</a>フォーマット(テキスト形式)を用いてROS Topicを転送しているため、<a class="keyword" href="http://d.hatena.ne.jp/keyword/PCD">PCD</a>のような大きなデータを転送する場合には必要以上に転送量が大きくなってしまいます。</span></p> <p><span style="font-weight: 400;">そのため、帯域が制限された環境で使用しづらかったり、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%AF%A5%E9%A5%A6%A5%C9">クラウド</a>からのデータ転送量にかかる料金が増大することが懸念されます。</span></p> <p><span style="font-weight: 400;">そこで、ROS Bridgeではない別のデータ転送方法によって、可視化に必要なデータだけをバイナリ形式でウェブブラウザに転送することを検討しました。</span><span style="font-weight: 400;"><br /></span><span style="font-weight: 400;">(また、今回は未検討ではありますが、<a class="keyword" href="http://d.hatena.ne.jp/keyword/PCD">PCD</a>の転送には圧縮技術を適用することも求められると思います。)</span></p> <h3><span style="font-weight: 400;">実験システムの構築</span></h3> <p><span style="font-weight: 400;">ROS Bridgeに代わるデータの転送方法としてgRPC-webを使用できないか考えました。</span></p> <p><span style="font-weight: 400;">gRPC-webを選んだ理由は</span></p> <ul> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">バイナリ形式でデータを転送できること</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">転送するデータの型定義ができること</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">サーバを開発する際に選択できる<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%D7%A5%ED%A5%B0%A5%E9%A5%DF%A5%F3%A5%B0%B8%C0%B8%EC">プログラミング言語</a>が多いこと</span></li> </ul> <p><span style="font-weight: 400;">などがあげられます。(またバックエンドのサービス間で使われる仕組みをフロントエンドに適用できるのは、単純に面白そうだと思ったのもあります)</span></p> <p><span style="font-weight: 400;">実験のため<a class="keyword" href="http://d.hatena.ne.jp/keyword/AWS">AWS</a>上に構築したシステム構成の概要が下の図です。</span></p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/n/naokit00/20210215/20210215103453.png" alt="f:id:naokit00:20210215103453p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <p> </p> <p><span style="font-weight: 400;"><a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%AF%A5%E9%A5%A6%A5%C9">クラウド</a>側は構築するのが容易であるという理由でALBとECS(FARGATE)を組み合わせた構成にしました。Fargateのタスクとして二つのコンテナが動作しています。一つはEnvoyで、これは<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%D7%A5%ED%A5%C8%A5%B3%A5%EB">プロトコル</a>変換(gRPC-webとgRPCの変換)を行っています。もう一つはBag serverと呼ばれるサーバで、これはbagファイルのデータをクライアントに転送するgRPCサーバです。</span></p> <p><span style="font-weight: 400;">クライアント側は<a class="keyword" href="http://d.hatena.ne.jp/keyword/Web%A5%D6%A5%E9%A5%A6%A5%B6">Webブラウザ</a>上にThree.jsを使ったROS Topicの可視化アプリが動作しており、gRPC-webクライアントとしてBag serverと通信します。</span><span style="font-weight: 400;"><br /></span></p> <p><span style="font-weight: 400;">実験システムの大まかな動作は次のようなものです。</span></p> <ul> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;"><a class="keyword" href="http://d.hatena.ne.jp/keyword/Web%A5%D6%A5%E9%A5%A6%A5%B6">Webブラウザ</a>上の可視化アプリがgRPCのリク<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A8%A5%B9">エス</a>トをALB/Envoyを経由してBag serverに送信する</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">Bag serverは<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%AF%A5%E9%A5%A6%A5%C9">クラウド</a>上のマイクロサービス(図中の<a class="keyword" href="http://d.hatena.ne.jp/keyword/API">API</a> <a class="keyword" href="http://d.hatena.ne.jp/keyword/Gateway">Gateway</a>)を呼び出して、S3上のbagファイルのkeyを取得する</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">Bag server はS3上のbagファイル中のROS Topicを読み込んで、可視化に必要なデータをgRPCのServer streaming で<a class="keyword" href="http://d.hatena.ne.jp/keyword/Web%A5%D6%A5%E9%A5%A6%A5%B6">Webブラウザ</a>に送信する</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;"><a class="keyword" href="http://d.hatena.ne.jp/keyword/Web%A5%D6%A5%E9%A5%A6%A5%B6">Webブラウザ</a>上の可視化アプリがgRPCのServer streamingのデータを受信して3次元的に可視化する</span></li> </ul> <p><span style="font-weight: 400;">うまく動くとS3上のbagファイルのデータを<a class="keyword" href="http://d.hatena.ne.jp/keyword/Web%A5%D6%A5%E9%A5%A6%A5%B6">Webブラウザ</a>上で動画プレイヤーのような見せ方で表示できるというものです。</span></p> <p><span style="font-weight: 400;">実際に試したところ構築した実験システムは期待通り動作することがわかりました。そこでこの仕組みを利用して良いかどうかを社内の技術選定会で問うことにしました。</span></p> <h3><span style="font-weight: 400;">技術選定会とその準備</span></h3> <p><span style="font-weight: 400;">ティアフォーでは技術選定会を行うことで、課題解決のためにどの技術を選ぶべきか決定しています。まず、起案者はある課題を解決するための複数の手法について次のことを準備します。</span></p> <ul> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">あらかじめ分類されたさまざまな観点(開発生産性、技術信頼性、コスト、セキュリティなど)の比較表を作成する</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">議論すべき重要なトピックをリストアップする</span></li> </ul> <p><span style="font-weight: 400;">その上で社内の専門性の高いメンバーを集めて議論をすることで妥当な技術を選択する、といったやり方をしています。</span></p> <p><span style="font-weight: 400;">今回はROS Bridgeの代替技術として、「gRPC-webを用いた仕組み」と「WebSocketとprotobufを用いた仕組み」の二つについて比較表を作成しました。</span></p> <p><span style="font-weight: 400;">また重要なトピックとして次のような項目をリストアップしました。</span></p> <ul> <li><span style="font-weight: 400;"><a class="keyword" href="http://d.hatena.ne.jp/keyword/PCD">PCD</a>の転送効率</span></li> <li><span style="font-weight: 400;">開発生産性</span><span style="font-weight: 400;"><br /></span></li> <li><span style="font-weight: 400;"><a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%AF%A5%E9%A5%A6%A5%C9">クラウド</a>上のシステム構築の容易さ</span></li> </ul> <p><span style="font-weight: 400;">重要なトピックとして挙げた項目について、gRPC-webは比較対象の技術と比べて概ね同等か、あるいは優位なものもある</span><span style="font-weight: 400;">と私は考えました。</span></p> <p><span style="font-weight: 400;">会議はバックエンドエンジニア、フロントエンドエンジニア、SREエンジニアを含む6名程度のメンバーを集めてオンラインで行われました。</span></p> <p><span style="font-weight: 400;">1時間に満たない会議ではありましたが参加したメンバーから技術的な懸念や課題が示されて、追加で検討すべき項目がリストアップされました。</span></p> <h3><span style="font-weight: 400;">技術選定会後のFeedback</span></h3> <p><span style="font-weight: 400;">技術選定会で示された追加の検討項目は次のようなものでした。いくつかの項目は私が想定していなかったものもあり、技術的な検討を深める助けになりました。</span></p> <ul> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">gRPC-web自体は未成熟な技術であるから、やっぱり使えないとなる可能性は十分ある。その場合、代替技術に移行できるか?</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">データのアップロードに使用可能か?(Client streaming/Bi-directional streamingが可能か?)</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">想定される使用規模はどの程度か?<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E6%A1%BC%A5%B9%A5%B1%A1%BC%A5%B9">ユースケース</a>を明確にするべき</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">回線品質が悪い時の動作検証が必要。帯域を絞るなどして試すべき</span></li> <li style="font-weight: 400;" aria-level="1"><span style="font-weight: 400;">運用コストの見積もりが必要</span></li> </ul> <p><span style="font-weight: 400;">追加の検討項目のうち帯域制限された環境での動作検証を進めたところ、適切に動作させるためにはなんらかのフローコン<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C8%A5%ED%A1%BC%A5%EB">トロール</a>の仕組みを導入する必要があることがわかりました。実験システムに単純なフローコン<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C8%A5%ED%A1%BC%A5%EB">トロール</a>の仕組みを導入することで、帯域制限された環境下でも通信エラーを起こすことなく動作することが確認されました。</span></p> <p><span style="font-weight: 400;">また、運用コスト見積もりの結果、転送量にかかる料金が支配的であることがわかりました。<a class="keyword" href="http://d.hatena.ne.jp/keyword/PCD">PCD</a>の表示に限って言えば、点群の<a class="keyword" href="http://d.hatena.ne.jp/keyword/%C9%E2%C6%B0%BE%AE%BF%F4">浮動小数</a>点の精度を落としても問題ない(元データが単精度(4byte)であるのを半精度(2byte)に落としても表示上は問題ない)と考え、転送時にデータの精度を落とすことで転送量を削減するといった試みも行いました。</span><span style="font-weight: 400;"><br /></span><span style="font-weight: 400;"><br /></span><span style="font-weight: 400;">その他の追加の検討項目についても検討を進めたのち、後日再び技術選定会を開催しました。その会議においても新たに課題や懸念が示</span><span style="font-weight: 400;">されましたが、技術選定としては承認されました。また、社内のシステムで使用されることと、3ヶ月後に技術的な振り返りをすることが決定されました。</span></p> <h3><span style="font-weight: 400;">まとめ</span></h3> <p><span style="font-weight: 400;">「Point cloud data(<a class="keyword" href="http://d.hatena.ne.jp/keyword/PCD">PCD</a>)のように大きなサイズのデータを含んだROS Topicを<a class="keyword" href="http://d.hatena.ne.jp/keyword/AWS">AWS</a> Cloudから<a class="keyword" href="http://d.hatena.ne.jp/keyword/Web%A5%D6%A5%E9%A5%A6%A5%B6">Webブラウザ</a>に転送する」仕組みについて検討したことと、技術選定会の様子についてお話ししました。</span><span style="font-weight: 400;"><br /></span></p> <p><span style="font-weight: 400;">今回示した仕組みは、まずは社内の限定的な用途で使用される予定ですし、今後見直され使われなくなるかもしれません。ただし、検討や技術選定会をスピード感を持って進められたこと(他の業務を行いながら1ヶ月程度でできたこと)や、技術選定のプロセスを経験できたことは良かったと思います。</span></p> <p><span style="font-weight: 400;">技術選定の資料作成に多くの時間は取れなかったので、技術選定会のメンバーは少ない情報の中で判断をすることになりましたが、前向きに検討してくれたと思います。</span></p> <p><span style="font-weight: 400;">また、参加メンバーは技術的な懸念や課題を示しつつも、新しい技術や技術的なチャレンジを許容する姿勢を示していたと感じました。</span><span style="font-weight: 400;"><br /></span><span style="font-weight: 400;">今後、今回のような内容をテックブログだけでなく、以下の勉強会でも発表していきますのでこちらもぜひご覧ください。</span></p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftier4.connpass.com%2F" title="Tier IV/ティアフォー" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://tier4.connpass.com/">tier4.connpass.com</a></cite></p> naokit00 LinuxのSCHED_DEADLINEスケジューラについての話 hatenablog://entry/26006613689351727 2021-02-10T16:00:00+09:00 2021-02-12T15:24:52+09:00 こんにちは、ティアフォーでパートタイムエンジニアをしている佐々木です。 今回はLinuxに搭載されているスケジューラの一つ、SCHED_DEADLINEについて紹介していきたいと思います。自動運転には多数のクリティカルタスクがあり、自動運転の安心・安全をしっかりと確保するためにはこのスケジューラを上手に設定することでこれらのクリティカルタスクが効率的にまた互いにコンフリクトすることなくリアルタイムに処理されることを担保する必要があります。なお、この記事で紹介するコードはLinuxカーネル5.4.0 (Ubuntu 20.04 LTSのベースカーネル) を元としています。 また、ティアフォーでは… <p>こんにちは、ティアフォーでパートタイムエンジニアをしている佐々木です。</p> <p>今回は<a class="keyword" href="http://d.hatena.ne.jp/keyword/Linux">Linux</a>に搭載されているスケジューラの一つ、SCHED_DEADLINEについて紹介していきたいと思います。自動運転には多数のクリティカルタスクがあり、自動運転の安心・安全をしっかりと確保するためにはこのスケジューラを上手に設定することでこれらのクリティカルタスクが効率的にまた互いにコンフリクトすることなくリアルタイムに処理されることを担保する必要があります。なお、この記事で紹介するコードは<a class="keyword" href="http://d.hatena.ne.jp/keyword/Linux">Linux</a><a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%AB%A1%BC%A5%CD%A5%EB">カーネル</a>5.4.0 (<a class="keyword" href="http://d.hatena.ne.jp/keyword/Ubuntu">Ubuntu</a> 20.04 LTSのベース<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%AB%A1%BC%A5%CD%A5%EB">カーネル</a>) を元としています。</p> <p>また、ティアフォーでは「自動運転の<a class="keyword" href="http://d.hatena.ne.jp/keyword/%CC%B1%BC%E7%B2%BD">民主化</a>」をともに実現していく、学生パートタイムエンジニアを常時募集しています。自動運転を実現するためには、Softwareに関してはOSからMiddlewareそしてApplicationに至るまで、Hardwareに関してはSensorから<a class="keyword" href="http://d.hatena.ne.jp/keyword/ECU">ECU</a>そして車両に至るまで異なるスキルを持つ様々な人々が不可欠です。もしご興味があれば以下のページからコンタクトいただければと思います。 <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftier4.jp%2Fcareers%2F" title="Careers | 株式会社ティアフォー" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://tier4.jp/careers/">tier4.jp</a></cite></p> <h2><a class="keyword" href="http://d.hatena.ne.jp/keyword/Linux">Linux</a>のスケジューラについて</h2> <p>まず、スケジューラとはなんぞや?という話から始めると、CPU上で実行するタスク(<a class="keyword" href="http://d.hatena.ne.jp/keyword/Linux">Linux</a>ではスレッドがスケジュール単位)が複数あるとき、どのタスクから実行するかを決めるものです。 スケジュールの仕方のことをスケジューリングポリシーと呼び、<a class="keyword" href="http://d.hatena.ne.jp/keyword/Linux">Linux</a>には現在6つのスケジューリングポリシーが搭載されています。</p> <p>搭載されているポリシーは<code>kernel/sched/sched.h</code>で確認することができます。</p> <pre class="code lang-c" data-lang="c" data-unlink><span class="synPreProc">#define SCHED_NORMAL </span><span class="synConstant">0</span> <span class="synPreProc">#define SCHED_FIFO </span><span class="synConstant">1</span> <span class="synPreProc">#define SCHED_RR </span><span class="synConstant">2</span> <span class="synPreProc">#define SCHED_BATCH </span><span class="synConstant">3</span> <span class="synPreProc">#define SCHED_IDLE </span><span class="synConstant">5</span> <span class="synPreProc">#define SCHED_DEADLINE </span><span class="synConstant">6</span> </pre> <p>SCHED_NORMAL (SCHED_OTHER)は通常のタスクに使われるスケジューラで、現在<a class="keyword" href="http://d.hatena.ne.jp/keyword/Linux">Linux</a>だとCompletely Fair Scheduler (<a class="keyword" href="http://d.hatena.ne.jp/keyword/CFS">CFS</a>)という赤黒木を使用するできるだけ平等にタスクに実行時間を割り当てるスケジューラです。</p> <p>SCHED_<a class="keyword" href="http://d.hatena.ne.jp/keyword/FIFO">FIFO</a>とSCHED_RRは静的優先度を使うスケジューリングポリシーです。</p> <p>優先度が高いタスクが低いタスクより優先的にスケジュールされ、高優先度のタスクでコアが占有されている時、低優先度のタスクは実行されません。 逆に、低優先度のタスクが実行開始後に高優先度のタスクが来たら低優先度のタスクは直ちに中断し、高優先度のタスクが実行開始します。</p> <p>SCHED_<a class="keyword" href="http://d.hatena.ne.jp/keyword/FIFO">FIFO</a>とSCHED_RRは0~99の優先度を持ち、双方この優先度に従ってスケジューリングを行いますが、挙動の違いは同じ優先度を持つタスクが複数存在する時、SCHED_<a class="keyword" href="http://d.hatena.ne.jp/keyword/FIFO">FIFO</a>はFirst-In-First-Out (<a class="keyword" href="http://d.hatena.ne.jp/keyword/FIFO">FIFO</a>)キューを用いて逐次実行し、SCHED_RRはRound-Robin (RR)を用いて設定したtime slice事に実行タスクを切り替えます。</p> <p>SCHED_NORMALのタスクは優先度が100以上なので、SCHED_<a class="keyword" href="http://d.hatena.ne.jp/keyword/FIFO">FIFO</a>とSCHED_RRは任意のSCHED_NORMALタスクより優先され、SCHED_NORMALのタスクと比較してSCHED_<a class="keyword" href="http://d.hatena.ne.jp/keyword/FIFO">FIFO</a>/SCHED_RR/SCHED_DEADLINEのタスクをリアルタイムタスクと呼んだりします。</p> <p>また、SCHED_<a class="keyword" href="http://d.hatena.ne.jp/keyword/FIFO">FIFO</a>/SCHED_RRは<a class="keyword" href="http://d.hatena.ne.jp/keyword/POSIX">POSIX</a>.1-2001で規程されているので、<a href="https://linuxjm.osdn.jp/html/glibc-linuxthreads/man3/pthread_setschedparam.3.html"><code>pthread_setschedparam(3)</code></a>を使って設定することが可能です。</p> <p>SCHED_BATCH, SCHED_IDLEについては本記事では省略します。</p> <h2>Earliest Deadline First (<a class="keyword" href="http://d.hatena.ne.jp/keyword/EDF">EDF</a>)</h2> <p>さて、本題のSCHED_DEADLINEについて説明していきます。</p> <p>SCHED_DEADLINEは<a class="keyword" href="http://d.hatena.ne.jp/keyword/Linux">Linux</a> 3.14以降に標準搭載されたEarliest Deadline First (<a class="keyword" href="http://d.hatena.ne.jp/keyword/EDF">EDF</a>)というスケジューリングポリシーをベースとしたスケジューラで、設定されたデッドラインが一番近いものから実行していきます。</p> <p><a class="keyword" href="http://d.hatena.ne.jp/keyword/EDF">EDF</a>の例を見てみましょう。</p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/twertho/20210209/20210209113837.png" alt="f:id:twertho:20210209113837p:plain" title="" class="hatena-fotolife" itemprop="image"></span></p> <ul> <li>まずt=0にタスク1がリリースされ、他のタスクはないのでそのままスケジュールされます。</li> <li>次にt=1にタスク2がリリースされますが、デッドラインがタスク1のデッドラインより後ろなのでタスク1が終わるまで待機キューに入れられます。</li> <li>t=2になりタスク1が実行終了するので、タスク2が実行を開始します。</li> <li>t=3ではタスク3がリリースされ、今度はタスク3のデッドラインの方が近いので、タスク2は中断(プリエンプション)されます。</li> <li>t=4でタスク3が終了するので、中断されていたタスク2が実行を再開します。</li> </ul> <p>よって実行結果は図の最下部のようになります。 例はシングルコアでのスケジューリング例ですが、マルチコアでも同様のスケジューリングポリシーが使えます。</p> <h2>SCHED_DEADLINEの使用方法</h2> <p>ここではSCHED_DEADLINEの使い方を簡単に説明していきます。 基本は公式ドキュメント<a href="https://www.kernel.org/doc/html/latest/scheduler/sched-deadline.html">Deadline Task Scheduling</a>を参照してください。</p> <p>SCHED_DEADLINEポリシーは<a class="keyword" href="http://d.hatena.ne.jp/keyword/POSIX">POSIX</a>規格ではないので<code>pthread_setschedparam(3)</code>ではなく<a href="https://linuxjm.osdn.jp/html/LDP_man-pages/man2/sched_setattr.2.html"><code>sched_setattr(2)</code></a>を使います。(<a href="https://linuxjm.osdn.jp/html/LDP_man-pages/man2/sched_setscheduler.2.html"><code>sched_setscheduler(2)</code></a>と<a href="https://linuxjm.osdn.jp/html/LDP_man-pages/man2/sched_setparam.2.html"><code>sched_setparam(2)</code></a>の組み合わせでも同様の設定ができます)</p> <p><code>sched_setattr(2)</code>の引数を説明していきます。</p> <pre class="code" data-lang="" data-unlink>int sched_setattr(pid_t pid, const struct sched_attr *attr, unsigned int flags);</pre> <ul> <li><code>pid</code>:ポリシーを設定する対象のpid/0の時は呼び出しスレッドが設定対象になる。</li> <li><code>attr</code>:スケジューリング属性(attribute)後述</li> <li><code>flags</code>:現状では何も意味がないので0を設定(ドキュメントには将来の機能拡張のために確保となっている)</li> </ul> <p>さてスケジューリング属性<code>attr</code>の構造体である<code>struct sched_attr</code>は以下のようになっています。</p> <pre class="code lang-c" data-lang="c" data-unlink><span class="synType">struct</span> sched_attr { __u32 size; __u32 sched_policy; __u64 sched_flags; <span class="synComment">/* SCHED_NORMAL, SCHED_BATCH */</span> __s32 sched_nice; <span class="synComment">/* SCHED_FIFO, SCHED_RR */</span> __u32 sched_priority; <span class="synComment">/* SCHED_DEADLINE (nsec) */</span> __u64 sched_runtime; __u64 sched_deadline; __u64 sched_period; }; </pre> <p>コメントにも書かれている通り<code>sched_nice</code>と<code>sched_priority</code>はSCHED_DEADLINEでは使いません。</p> <p><code>sched_priority</code>は0を設定するものの、内部ではSCHED_DEADLINEタスクは優先度が-1に設定されており、任意のSCHED_<a class="keyword" href="http://d.hatena.ne.jp/keyword/FIFO">FIFO</a>,SCHED_RRタスクよりも優先されます。</p> <p>SCHED_DEADLINEでは実行時間<code>sched_runtime</code>、デッドライン<code>sched_deadline</code>、周期<code>sched_period</code>を使います。</p> <p>実際にSCHED_DEADLINEを使って実行時間10ms/デッドライン30ms/周期40msのタスクの設定してみると以下のようになります。</p> <pre class="code lang-c" data-lang="c" data-unlink>sched_attr attr; attr.size = <span class="synStatement">sizeof</span>(attr); attr.sched_flags = <span class="synConstant">0</span>; attr.sched_nice = <span class="synConstant">0</span>; attr.sched_priority = <span class="synConstant">0</span>; attr.sched_policy = SCHED_DEADLINE; attr.sched_runtime = <span class="synConstant">10</span> * <span class="synConstant">1000</span> * <span class="synConstant">1000</span>; attr.sched_deadline = <span class="synConstant">30</span> * <span class="synConstant">1000</span> * <span class="synConstant">1000</span>; attr.sched_period = <span class="synConstant">40</span> * <span class="synConstant">1000</span> * <span class="synConstant">1000</span>; <span class="synType">unsigned</span> <span class="synType">int</span> flags = <span class="synConstant">0</span>; sched_setattr(<span class="synConstant">0</span>, &amp;attr, flags); </pre> <p>なお、<code>sched_period</code>は必須ではなく、設定しない場合<code>sched_deadline</code>が周期として使われます。</p> <h2>SCHED_DEADLINEを使用する際の注意点</h2> <p>SCHED_DEADLINEを使うには<code>sched.h</code>をインクルードして前セクションの通りに設定すれば基本的に動きます。(環境によっては<code>linux/sched.h</code>)</p> <p>が、環境によっていくつかハマりポイントがあるので、いくつか紹介していきます。</p> <h3>sched.hがない/インクルードしてもsched_setattrが見つからない</h3> <p>環境によって<code>sched.h</code>が見つからない/インクルードしても<code>sched_setattr</code>が<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%D1%A5%A4%A5%EB">コンパイル</a>されない場合があります。(<a class="keyword" href="http://d.hatena.ne.jp/keyword/Ubuntu">Ubuntu</a> 18.04 LTS等)</p> <p>自分の環境では以下のように<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B7%A5%B9%A5%C6%A5%E0%A5%B3%A1%BC%A5%EB">システムコール</a>を直打ち/構造体を直接宣言することで使用できました。</p> <pre class="code" data-lang="" data-unlink>#include &lt;unistd.h&gt; #include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; #include &lt;string.h&gt; #include &lt;time.h&gt; #include &lt;linux/unistd.h&gt; #include &lt;linux/kernel.h&gt; #include &lt;linux/types.h&gt; #include &lt;sys/syscall.h&gt; #include &lt;pthread.h&gt; #define SCHED_FLAG_DL_OVERRUN 0x04 #define gettid() syscall(__NR_gettid) #define SCHED_DEADLINE 6 #ifdef __x86_64__ #define __NR_sched_setattr 314 #endif #ifdef __i386__ #define __NR_sched_setattr 351 #endif #ifdef __arm__ #define __NR_sched_setattr 380 #endif #ifdef __aarch64__ #define __NR_sched_setattr 274 #endif struct sched_attr { __u32 size; __u32 sched_policy; __u64 sched_flags; /* SCHED_NORMAL, SCHED_BATCH */ __s32 sched_nice; /* SCHED_FIFO, SCHED_RR */ __u32 sched_priority; /* SCHED_DEADLINE (nsec) */ __u64 sched_runtime; __u64 sched_deadline; __u64 sched_period; }; int sched_setattr(pid_t pid, const struct sched_attr *attr, unsigned int flags){ return syscall(__NR_sched_setattr, pid, attr, flags); }</pre> <h3>SCHED_DEADLINEが設定されない</h3> <p><code>sched_setattr</code>を使っているのにSCHED_DEADLINEポリシーが適用されていないという場合は<code>sched_setattr</code>の返り値をみてみます。 正しく設定されている場合は0、失敗した場合は-1を返します。</p> <p><code>sched_setattr</code>にはいくつかのerrnoが設定されてますがSCHED_DEADLINEを使う場合、以下の3つがよく遭遇します。</p> <ul> <li><code>EPERM</code>:root権限で実行していない。SCHED_DEADLINEはユーザー権限では動きません。</li> <li><code>EINVAL</code>:パラメータが正しく設定されてない、または周期等の値が2<sup>10</sup>~2<sup>63</sup>の間にない時にこのエラーがでます。</li> <li><code>EBUSY</code>:<code>sched_setattr</code>でSCHED_DEADLINEを設定する際、使用率=実行時間/周期の計算が行われます。この使用率をスケジューラが受け入れるだけの余裕があるかを計算し、無理な場合EBUSYを返します。これにより最低限のデッドライン保証をチェックしています。</li> </ul> <p>特に複数のタスクをSCHED_DEADLINEポリシーで動かす場合EBUSYエラーが起こり易いので、可能ならデッドラインを長めに見積もると良いでしょう。</p> <p>詳しくここのvalidationを知りたい方は<a href="https://elixir.bootlin.com/linux/v5.4/source/kernel/sched/deadline.c#L2463">ここ</a>に実装があります。 まだRC版である最新の5.11系ではこのvalidationが高速化されるみたいです(<a href="https://elixir.bootlin.com/linux/v5.11-rc1/source/kernel/sched/deadline.c#L2582">参照</a>)。</p> <h3>tasksetでCPU制限した場合に失敗する</h3> <p>SCHED_DEADLINEと<code>taskset</code>を併用するとエラーを起こすケースがあります。</p> <p>これはSCHED_DEADLINEのCPUハンドリングが<code>taskset</code>によるマスキングに対応していないためと思われます。</p> <p>実行するコアを限定したい場合は<code>cgroup</code>の<code>cpuset</code>で設定することで上手く動きます。</p> <h2>Constant Bandwidth Server (<a class="keyword" href="http://d.hatena.ne.jp/keyword/CBS">CBS</a>) について</h2> <p>さて、SCHED_DEADLINEは<a class="keyword" href="http://d.hatena.ne.jp/keyword/EDF">EDF</a>ポリシーに従ってスケジューリングしてくれますが、適切なdeadlineとruntimeを設定するのはユーザーの責任となっています。</p> <p>設定が適切でなければ、仮にプロセスが無限loopなどで実行し続けてdeadlineを超過したとしても、何も起こらずCPUリソースが占有され続けることになります。</p> <p>これを防ぐためにLinux4.16以降ではConstant Bandwidth Server (<a class="keyword" href="http://d.hatena.ne.jp/keyword/CBS">CBS</a>)という機能がついています。</p> <p><a class="keyword" href="http://d.hatena.ne.jp/keyword/CBS">CBS</a>は実行時間を制限するもので、SCHED_DEADLINEでは設定されたスレッドの実行時間がsched_runtimeを超えた場合、シグナルを送るように設定することができます。</p> <p><code>attr.sched_flags=SCHED_FLAG_DL_OVERRUN</code>と設定することで超過時に<code>SIGXCPU</code>というシグナルをスレッドに送ります。 このシグナルをハンドリングすることで超過対策を行うことができます。</p> <p>また<a class="keyword" href="http://d.hatena.ne.jp/keyword/CBS">CBS</a>にはreplenishというもう一つの機能があります。</p> <p>例えばタスクAの実行中にデッドラインが近いタスクBがリリースされたことによりAは中断(プリエンプション)され、Bが終了しAを再開しようとしたときにAのデッドラインを過ぎていて本来ならばAを実行できないといったケースがあります。</p> <p>このような中断はユーザが関知することができない以上、<a class="keyword" href="http://d.hatena.ne.jp/keyword/Linux">Linux</a>の実装ではタスク自体は実行時間が設定されたruntimeを超えない限り、デッドラインを超過していても最後まで実行させるというポリシーを取っています。</p> <p>この最後まで実行させるために追加の実行時間を確保する仕組みがreplenishになります。</p> <p>内容としては残りの実行時間(runtime-中断するまでに実行した時間)をruntimeとし1周期後のデッドラインをデッドラインと変更し、再度スケジューリングされます。</p> <p>この<a class="keyword" href="http://d.hatena.ne.jp/keyword/CBS">CBS</a>があるため厳密な<a class="keyword" href="http://d.hatena.ne.jp/keyword/EDF">EDF</a>通りの実行にならないことを考慮した上でSCHED_DEADLINEを使う必要があります。</p> <h2>SCHED_DEADLINEの実装</h2> <p>最後にSCHED_DEADLINEの実装を簡単にみてみましょう。</p> <p>実装は主に<code>kernel/sched/deadline.c</code>に記述されています。</p> <p>まず、SCHED_DEADLINEのランキューをみてみます。</p> <pre class="code c " data-lang="c " data-unlink>struct dl_rq { struct rb_root_cached root; unsigned long dl_nr_running; struct dl_bw dl_bw; u64 running_bw; u64 this_bw; u64 extra_bw; u64 bw_ratio; };</pre> <ul> <li><code>root</code>:ランキューを管理する構造体</li> <li><code>dl_nr_running</code>:デッドラインクラスのスレッドで実行可能な数</li> <li><code>*_bw</code>:このbwはbandwidthの略で使用率とほぼ同義で、先ほどのスケジューリング可能性のチェック等で使われます。</li> </ul> <p>次にデッドラインクラスをみてみます。 デッドラインクラスはRTクラス(SCHED_<a class="keyword" href="http://d.hatena.ne.jp/keyword/FIFO">FIFO</a>/SCHED_RR)より上、最上位クラスのSTOPクラスより下になっています。</p> <pre class="code c " data-lang="c " data-unlink>const struct sched_class dl_sched_class = { .next = &amp;rt_sched_class, .enqueue_task = enqueue_task_dl, .dequeue_task = dequeue_task_dl, .yield_task = yield_task_dl, .check_preempt_curr = check_preempt_curr_dl, .pick_next_task = pick_next_task_dl, .put_prev_task = put_prev_task_dl, .set_next_task = set_next_task_dl, .task_tick = task_tick_dl, .task_fork = task_fork_dl, .prio_changed = prio_changed_dl, .switched_from = switched_from_dl, .switched_to = switched_to_dl, .update_curr = update_curr_dl, };</pre> <p>ここで重要なメンバを3つほどみていきます。</p> <ul> <li><code>enqueue_task</code>:タスク追加時の処理</li> <li><code>dequeue_task</code>:タスク削除時の処理</li> <li><code>pick_next_task</code>:次に実行するタスクの選択処理</li> </ul> <h3>タスク追加時の処理</h3> <pre class="code c " data-lang="c " data-unlink>static void enqueue_dl_entity(struct sched_dl_entity *dl_se, struct sched_dl_entity *pi_se, int flags) { BUG_ON(on_dl_rq(dl_se)); //省略 __enqueue_dl_entity(dl_se); } static void enqueue_task_dl(struct rq *rq, struct task_struct *p, int flags) { struct task_struct *pi_task = rt_mutex_get_top_task(p); struct sched_dl_entity *pi_se = &amp;p-&gt;dl; //省略 enqueue_dl_entity(&amp;p-&gt;dl, pi_se, flags); if (!task_current(rq, p) &amp;&amp; p-&gt;nr_cpus_allowed &gt; 1) enqueue_pushable_dl_task(rq, p); }</pre> <p>DEADLINEタスク追加時の処理は、優先度継承、<a class="keyword" href="http://d.hatena.ne.jp/keyword/CBS">CBS</a>に関連する例外処理等がありますが、重要な追加時の関数は<code>__enqueue_dl_entity</code>であることがわかります。</p> <pre class="code c " data-lang="c " data-unlink>static void __enqueue_dl_entity(struct sched_dl_entity *dl_se) { struct dl_rq *dl_rq = dl_rq_of_se(dl_se); struct rb_node **link = &amp;dl_rq-&gt;root.rb_root.rb_node; struct rb_node *parent = NULL; struct sched_dl_entity *entry; int leftmost = 1; BUG_ON(!RB_EMPTY_NODE(&amp;dl_se-&gt;rb_node)); while (*link) { parent = *link; entry = rb_entry(parent, struct sched_dl_entity, rb_node); if (dl_time_before(dl_se-&gt;deadline, entry-&gt;deadline)) link = &amp;parent-&gt;rb_left; else { link = &amp;parent-&gt;rb_right; leftmost = 0; } } rb_link_node(&amp;dl_se-&gt;rb_node, parent, link); rb_insert_color_cached(&amp;dl_se-&gt;rb_node, &amp;dl_rq-&gt;root, leftmost); inc_dl_tasks(dl_se, dl_rq); }</pre> <p>この実装からデッドラインクラスのランキューには通常タスクの<a class="keyword" href="http://d.hatena.ne.jp/keyword/CFS">CFS</a>でも使われている<a href="https://ja.wikipedia.org/wiki/%E8%B5%A4%E9%BB%92%E6%9C%A8#:~:text=%E8%B5%A4%E9%BB%92%E6%9C%A8%EF%BC%88%E3%81%82%E3%81%8B%E3%81%8F%E3%82%8D%E3%81%8E,%E3%83%BB%E3%83%96%E3%83%A9%E3%83%83%E3%82%AF%E3%83%BB%E3%83%84%E3%83%AA%E3%83%BC%E3%81%A8%E3%82%82%E3%81%84%E3%81%86%E3%80%82">赤黒木</a>が使われていて、タスク構造体をデッドラインを基準に挿入していることがわかります。 赤黒木は安定した二分木なので、これによりデッドラインが一番近い(最小値)のタスクを選択しスケジュールすることが可能になっています。</p> <h3>タスク削除時の処理</h3> <p>削除に関する実装も同様に<code>__dequeue_dl_entity</code>を見ると赤黒木から終了したタスクの削除を行っていることがわかります。</p> <pre class="code lang-c" data-lang="c" data-unlink><span class="synType">static</span> <span class="synType">void</span> __dequeue_dl_entity(<span class="synType">struct</span> sched_dl_entity *dl_se) { <span class="synType">struct</span> dl_rq *dl_rq = dl_rq_of_se(dl_se); <span class="synStatement">if</span> (RB_EMPTY_NODE(&amp;dl_se-&gt;rb_node)) <span class="synStatement">return</span>; rb_erase_cached(&amp;dl_se-&gt;rb_node, &amp;dl_rq-&gt;root); RB_CLEAR_NODE(&amp;dl_se-&gt;rb_node); dec_dl_tasks(dl_se, dl_rq); } </pre> <h3>次に実行するタスクの選択処理</h3> <p>最後に次に実行するタスクの選択処理をみてみましょう。</p> <pre class="code lang-c" data-lang="c" data-unlink><span class="synType">static</span> <span class="synType">void</span> set_next_task_dl(<span class="synType">struct</span> rq *rq, <span class="synType">struct</span> task_struct *p) { p-&gt;se.exec_start = rq_clock_task(rq); dequeue_pushable_dl_task(rq, p); <span class="synStatement">if</span> (hrtick_enabled(rq)) start_hrtick_dl(rq, p); <span class="synStatement">if</span> (rq-&gt;curr-&gt;sched_class != &amp;dl_sched_class) update_dl_rq_load_avg(rq_clock_pelt(rq), rq, <span class="synConstant">0</span>); deadline_queue_push_tasks(rq); } <span class="synType">static</span> <span class="synType">struct</span> sched_dl_entity *pick_next_dl_entity(<span class="synType">struct</span> rq *rq, <span class="synType">struct</span> dl_rq *dl_rq) { <span class="synType">struct</span> rb_node *left = rb_first_cached(&amp;dl_rq-&gt;root); <span class="synStatement">if</span> (!left) <span class="synStatement">return</span> <span class="synConstant">NULL</span>; <span class="synStatement">return</span> rb_entry(left, <span class="synType">struct</span> sched_dl_entity, rb_node); } <span class="synType">static</span> <span class="synType">struct</span> task_struct * pick_next_task_dl(<span class="synType">struct</span> rq *rq, <span class="synType">struct</span> task_struct *prev, <span class="synType">struct</span> rq_flags *rf) { <span class="synType">struct</span> sched_dl_entity *dl_se; <span class="synType">struct</span> dl_rq *dl_rq = &amp;rq-&gt;dl; <span class="synType">struct</span> task_struct *p; WARN_ON_ONCE(prev || rf); <span class="synStatement">if</span> (!sched_dl_runnable(rq)) <span class="synStatement">return</span> <span class="synConstant">NULL</span>; dl_se = pick_next_dl_entity(rq, dl_rq); BUG_ON(!dl_se); p = dl_task_of(dl_se); set_next_task_dl(rq, p); <span class="synStatement">return</span> p; } </pre> <p>実装によると選択処理は5ステップから構成されています。</p> <ul> <li><code>sched_dl_runnable</code>でランキューを確認し、タスクが実行する可能か確認</li> <li><code>pick_next_dl_entity</code>で赤黒木からデッドラインが一番近いものを選択</li> <li><code>dl_task_of</code>で選択したスケジュールから実行するタスク構造体ポインタを抽出</li> <li><code>set_next_task_dl</code>で実行開始時間を記録</li> <li>次に実行するタスク構造体ポインタを返す</li> </ul> <p><a class="keyword" href="http://d.hatena.ne.jp/keyword/CBS">CBS</a>の処理が絡むとややこしいですが、それ以外の基本的な処理は赤黒木を使ったわかりやすい実装になっていることがわかります。</p> <h2>まとめ</h2> <p>今回は<a class="keyword" href="http://d.hatena.ne.jp/keyword/Linux">Linux</a>に搭載されている<a class="keyword" href="http://d.hatena.ne.jp/keyword/EDF">EDF</a>スケジューラのSCHED_DEADLINEを簡単にみてみました。 なお今回は簡単にまとめる関係上Symmetric Multi-Processing(SMP)の処理部分は省いています。</p> <p>リアルタイムに対応するために<a href="https://rt.wiki.kernel.org/index.php/Main_Page">RT_PREEMPT_PATCH</a>を導入する手法も知られてはいますが、SCHED_DEADLINEを使う分には何も変更することなく値を設定するだけで簡単に<a class="keyword" href="http://d.hatena.ne.jp/keyword/EDF">EDF</a>スケジューラが<a class="keyword" href="http://d.hatena.ne.jp/keyword/Linux">Linux</a>で使えるので、是非興味ある方はいじって見ると面白いと思います。</p> <h3>参照</h3> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.kernel.org%2Fdoc%2Fhtml%2Flatest%2Fscheduler%2Fsched-deadline.html" title="Deadline Task Scheduling — The Linux Kernel documentation" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://www.kernel.org/doc/html/latest/scheduler/sched-deadline.html">www.kernel.org</a></cite></p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Flinuxjm.osdn.jp%2Fhtml%2FLDP_man-pages%2Fman2%2Fsched_setattr.2.html" title="Man page of SCHED_SETATTR" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://linuxjm.osdn.jp/html/LDP_man-pages/man2/sched_setattr.2.html">linuxjm.osdn.jp</a></cite></p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Flinuxjm.osdn.jp%2Fhtml%2FLDP_man-pages%2Fman7%2Fsched.7.html" title="Man page of SCHED" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://linuxjm.osdn.jp/html/LDP_man-pages/man7/sched.7.html">linuxjm.osdn.jp</a></cite></p> twertho 西新宿における自動運転実証実験の振り返り hatenablog://entry/26006613684085493 2021-02-03T16:00:00+09:00 2021-02-05T11:59:18+09:00 こんにちは、ティアフォーで自動運転システムを開発している木村と斉藤です。今回は2020年11月から12月にかけて行った西新宿における自動運転の実証実験の概要と振り返りをご紹介します。 なお、ティアフォーでは、自動運転の安心・安全を確保し「自動運転の民主化」をともに実現していくため、様々なエンジニア・リサーチャーを募集しています。もしご興味があれば以下のページからコンタクトいただければと思います。 tier4.jp ティアフォーにおける自動運転の実証実験について 私たちが行う実証実験の目的は、お客様へのデモンストレーションから、新しい自動運転技術への挑戦、新たなオペレーション手法の検証などなど多… <p><span style="font-weight: 400;">こんにちは、ティアフォーで自動運転システムを開発している木村と斉藤です。今回は2020年11月から12月にかけて行った西新宿における自動運転の実証実験の概要と振り返りをご紹介します。</span></p> <p><span style="font-weight: 400;">なお、ティアフォーでは、自動運転の安心・安全を確保し「自動運転の<a class="keyword" href="http://d.hatena.ne.jp/keyword/%CC%B1%BC%E7%B2%BD">民主化</a></span><span style="font-weight: 400;">」をとも</span><span style="font-weight: 400;">に実現していくため、様々なエンジニア・リサーチャーを募集しています。もしご興味があれば以下のページからコンタクトいただければと思います。</span></p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftier4.jp%2Fcareers%2F" title="Careers | 株式会社ティアフォー" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://tier4.jp/careers/">tier4.jp</a></cite></p> <h3>ティアフォーにおける自動運転の実証実験について</h3> <p><span style="font-weight: 400;">私たちが行う実証実験の目的は、お客様へのデモンストレーションから、新しい自動運転技術への挑戦、新たなオペレーション手法の検証などなど多岐にわたりますが、いずれも実証実験毎にそれ</span><span style="font-weight: 400; font-size: 16px;">ぞれ具体的な目的を定めています。</span></p> <p><span style="font-weight: 400;">今回の実証実験はビジネス視点ではサービスとしての成り立ちを見るための観点から行われましたが、私たち自動運転エンジニアとしての視点では3つの目的を持って取り組みました。1つ目は都心での実運用されている5Gを活用した遠隔自動運転の性能評価、2つ目はMobility Technologies様のアプリケーションと弊社運行管理システムとの連携、3つ目は新しい<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A2%A1%BC%A5%AD%A5%C6%A5%AF%A5%C1%A5%E3">アーキテクチャ</a>となったAutowareの公道検証となります。今回は、私たちが主に担当していた新しい<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A2%A1%BC%A5%AD%A5%C6%A5%AF%A5%C1%A5%E3">アーキテクチャ</a>のAutowareを扱った自動運転システムを中心に振り返っていきたいと思います。ここでの新しい<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A2%A1%BC%A5%AD%A5%C6%A5%AF%A5%C1%A5%E3">アーキテクチャ</a>のAutowareというものはAutoware Architecture Proposalとして私たちがAutoware Foundationに提案しているもので、このAutowareを用いた自動運転システムによって走行する車両を社外の方に公道でお見せするのは今回行われた西新宿における実証が初めてとなります。</span> </p> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tkimura4/20210128/20210128143949.png" alt="f:id:tkimura4:20210128143949p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <h3>西新宿における実証実験について</h3> <h4>①11月の実証実験</h4> <p><span style="font-weight: 400;">11月に西新宿での自動運転実証実験を行いました。実験は2020年11月5日(木)から2020年11月8日(日)までの計4日間行われました。11月5日(木)は関係者試乗、他3日間は一般の試乗者を募集して乗車していただきました。</span></p> <p><span style="font-weight: 400;">11月の実証実験では</span><span style="font-weight: 400;"><a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B8%A5%E3%A5%D1%A5%F3%A5%BF%A5%AF%A5%B7%A1%BC">ジャパンタクシー</a>車両をベースにした自動運転車両を1台用いました。初日以外の3日間は京王プラザホテルから<a class="keyword" href="http://d.hatena.ne.jp/keyword/%BF%B7%BD%C9%C3%E6%B1%FB%B8%F8%B1%E0">新宿中央公園</a>までの1km程度のコースを走行しましたが、初日は京王プラザホテルから<a class="keyword" href="http://d.hatena.ne.jp/keyword/KDDI">KDDI</a>新宿ビル内を経由し、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%BF%B7%BD%C9%C3%E6%B1%FB%B8%F8%B1%E0">新宿中央公園</a>の前を通って京王プラザホテルに戻る2km程度のコースを走行しました。</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="11月の実証実験で使用した走行ルート"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tkimura4/20210128/20210128143952.png" alt="f:id:tkimura4:20210128143952p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">11月の実証実験で使用した走行ルート</figcaption> </figure> <p><span style="font-weight: 400;">実験中は安全のためドライバーとオペレーター(助手席)<a href="#f-8b1d0f47" name="fn-8b1d0f47" title="オペレーターというのは、自動運転システムで対応が困難かつ緊急性が求められる際に、自動運転システムに対する緊急停止などのソフトウェア的な介入や、ドライバーに対するオーバーライド指示を出す役割を指します">*1</a>が乗り込んで非遠隔監視での自動運転走行を実施しました</span><span style="font-weight: 400;">。それに加え、初日には運転席は<a class="keyword" href="http://d.hatena.ne.jp/keyword/%CC%B5%BF%CD">無人</a>で遠隔のドライバーが映像を通して監視しながら走行を行う遠隔型自動走行も行いました。</span></p> <p><span style="font-weight: 400;">実証実験では東京都の宮坂副<a class="keyword" href="http://d.hatena.ne.jp/keyword/%C5%D4%C3%CE%BB%F6">都知事</a>にもご乗車いただき、「違和感のない乗り心地だった」という大変ありがたいコメントもいただきました。多くの関係者・一般試乗者の方に乗車いただきながら、西新宿という交通量の多い環境の中での実証実験を無事終えることが出来ました。</span></p> <p><span style="font-weight: 400;">なお、11月の実証実験に関するより詳しい情報はこちらのプレスリリースをご覧ください。</span></p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftier4.jp%2Fmedia%2Fnews%2F20201009nishi-shinjuku%2F" title="西新宿エリアで5Gを活用した自動運転タクシーの実証実験(フェーズⅡ)を始動 〜環境改善委員会と西新宿版スマートシティ推進に向けた連携協定を締結します〜 | 株式会社ティアフォー" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://tier4.jp/media/news/20201009nishi-shinjuku/">tier4.jp</a></cite></p> <p><span style="font-weight: 400;">また、実証実験の様子は以下の動画をご覧ください。</span></p> <p><iframe width="560" height="315" src="https://www.youtube.com/embed/3Mrm0Wy7TqE?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe><cite class="hatena-citation"><a href="https://www.youtube.com/watch?v=3Mrm0Wy7TqE">www.youtube.com</a></cite></p> <p><iframe width="560" height="315" src="https://www.youtube.com/embed/KMZeVfXjRvE?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe><cite class="hatena-citation"><a href="https://www.youtube.com/watch?v=KMZeVfXjRvE">www.youtube.com</a></cite></p> <h4>②12月の実証実験</h4> <p><span style="font-weight: 400;">こちらの実証実験は西新宿にて</span><span style="font-weight: 400;">2020年12月8日(火)から2020年12月23日(水)までの平日計12日間で行われ、そのうち7日間は関係者試乗、5日間は一般者試乗という形で試乗</span><span style="font-weight: 400;">者</span><span style="font-weight: 400;">を乗せての自動運行を行いました。</span></p> <p><span style="font-weight: 400;">11月の実証実験と同様に西新宿で実施しましたが、12月の実証実験では最大3台の<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B8%A5%E3%A5%D1%A5%F3%A5%BF%A5%AF%A5%B7%A1%BC">ジャパンタクシー</a>車両を同時稼働させ、試乗者が京王プラザホテル/<a class="keyword" href="http://d.hatena.ne.jp/keyword/%C5%EC%B5%FE%C5%D4%C4%A3">東京都庁</a>第二庁舎ロータリー/<a class="keyword" href="http://d.hatena.ne.jp/keyword/%BF%B7%BD%C9%C3%E6%B1%FB%B8%F8%B1%E0">新宿中央公園</a>の3か所から出発地・目的地を選択可能という形での運行を行いました。そのため11月に行った実証実験と比較して、多数台の稼働や複数ルートの走行などの要素が加わり、更に難易度を上げての実施となりました。</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="12月の実証実験で使用した走行ルート"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tkimura4/20210128/20210128144000.png" alt="f:id:tkimura4:20210128144000p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">12月の実証実験で使用した走行ルート</figcaption> </figure> <figure class="figure-image figure-image-fotolife mceNonEditable" title="三台のJapanTaxi"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/t/tkimura4/20210128/20210128143955.png" alt="f:id:tkimura4:20210128143955p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">三台の<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B8%A5%E3%A5%D1%A5%F3%A5%BF%A5%AF%A5%B7%A1%BC">ジャパンタクシー</a></figcaption> </figure> <p><span style="font-weight: 400;">本実証実験には12日間で計100名を超える試乗者の方に参加いただき、多くの方に自動運転を体験していただく機会となりました。西新宿という難しい環境かつ難しい条件での実験を通し、ありがたい事に多くの課題も見つかりました。そうしたことを踏まえながら実証実験の振り返りをしていきたいと思います。</span></p> <p><span style="font-weight: 400;">なお、12月の実証実験に関するより詳しい情報はこちらのプレスリリースをご覧ください。</span></p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftier4.jp%2Fmedia%2Fnews%2Ftokyo-autonomous-project%2F" title="東京都『自動運転技術を活用したビジネスモデル構築に関するプロジェクト』にて 5Gを活用した自動運転タクシーの実証実験を実施 ~事業化に向けて複数車両の同時走行と目的地に応じたルート判別機能を実装~ | 株式会社ティアフォー" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://tier4.jp/media/news/tokyo-autonomous-project/">tier4.jp</a></cite></p> <p><span style="font-weight: 400;">また、実証実験の様子は以下の動画をご覧ください。 </span></p> <p><iframe width="560" height="315" src="https://www.youtube.com/embed/-CPNvUTfhaA?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe><cite class="hatena-citation"><a href="https://www.youtube.com/watch?v=-CPNvUTfhaA">www.youtube.com</a></cite></p> <h3>振り返り</h3> <p><span style="font-weight: 400;">実証実験では、西新宿という交通量も多く難しい環境の中で、多くの右左折を含むコースの走行、遠隔監視型自動走行、同時の複数台運行などの難しい条件が複合した実験となり、私たち開発者としても不安の尽きない日々でした。そのような中でも、自動運転をする上で特に難しかった/大変だったケースをいくつか紹介いたします。</span></p> <h4><strong>障害物の誤検知</strong></h4> <p><span style="font-weight: 400;">今回の実証実験でかなり悩まされたのが障害物を適切に検知することです。その中でも特に悩まされたのが歩道の段差や落ち葉です。</span></p> <p><span style="font-weight: 400;">Autowareは、センサ情報から自動車・歩行者といった検出したいものを認識して結果を出力する「<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%DB%A5%EF%A5%A4%A5%C8%A5%EA%A5%B9%A5%C8">ホワイトリスト</a>形式」、地面や雨・落ち葉といった検出したくないものを検出対象から除いて結果を出力する「<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%D6%A5%E9%A5%C3%A5%AF%A5%EA%A5%B9%A5%C8">ブラックリスト</a>形式」の両方のアプローチで動作しています。この様に「<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%DB%A5%EF%A5%A4%A5%C8%A5%EA%A5%B9%A5%C8">ホワイトリスト</a>形式」と「<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%D6%A5%E9%A5%C3%A5%AF%A5%EA%A5%B9%A5%C8">ブラックリスト</a>形式」の両方を採用している理由は、例えば前方のトラックから急に荷物が落ちてくる、といったイレギュラーな事象にも対応するためです。</span></p> <p><span style="font-weight: 400;">例えば今回の実証実験では、車道から新宿公園に入る際には20~30cmほどの段差がある歩道を通過する必要がありますが、その様な大きい段差がある場所では適切に地面除去できず、段差を障害物として認識してしまうことが起きていました。また、今回は秋の実験ということもあり落ち葉が非常に落ちやすい環境だったので、大量の落ち葉がまとまって落ちて来たり落ち葉が舞い上がったりすると大きな障害物としてみなされ、適切に除去出来ず障害物として認識されてしまうことが起きていました。今回の実証実験で明らかとなったこれらの課題を踏まえ、認識技術をより高精度な手法へと発展させていく取組を現在行っています。</span></p> <h4><strong>交差点での素早い判断とスピーディな加速</strong></h4> <p><span style="font-weight: 400;">西新宿で自動運転を行う上で、最も難しいことと言えばやはり交通量の多さが挙げられると思います。このような交通量が多い環境の中、今回の実証実験のコースには多くの右折が含まれていました。右折の中でも、特に難しい場所は右折信号のない交差点での右折です。右折信号がある場所では対向車両の流れが完全に途切れてから右折をすることが可能ですが、そうでない場所ではかなりシビアなタイミング判断が求められます。</span></p> <p><span style="font-weight: 400;">ティアフォーの自動運転システムでは、安全のために前方車との衝突余裕時間(Time to Collision)を計算し、前方車との衝突がまず起きないコンサバティブな見積もりをして右折をします。これに加え今回の実証実験では、快適な乗り心地を実現するため車両の発進時には紳士的な加速を行う様に設定していました。</span><span style="font-weight: 400;">しかしながら、このコンサバティブな見積もりに加えてこのような紳士的な加速を意識していては、交通量の多い西新宿の一部の交差点で時間帯によっては曲がるタイミングがなかなか得られないことがあり、信号の変わり目では乗り心地よりも素早い加速が求められるシーンがありました</span><span style="font-weight: 400;">。このことから、西新宿のような交通量の多い交差点でもより自動運転サービスの可用性を高めることができるよう、</span>人間の様にシーンに応じてコンサバティブさやアグレッシブさの加減を切り替えられるように今後取り組んでいきます。</p> <h4><strong>複数の走行経路</strong></h4> <p><span style="font-weight: 400;">ティアフォーが行ったこれまでの実験では走行経路</span><span style="font-weight: 400;">が固定された1つに限られていました</span><span style="font-weight: 400;">。</span><span style="font-weight: 400;">しかし、</span><span style="font-weight: 400;">今回の12月の実証実験では</span><span style="font-weight: 400;">より実サービスに近い設計となっており</span><span style="font-weight: 400;">、3か所から出発地・目的地を選択可能となっていたことから、当日選ばれた組み合わせに応じて計6つの経路を走るという大変チャレンジングな取組を行いました。</span></p> <p><span style="font-weight: 400;">Autowareでは信号や交差点、横断歩道、道路の優先関係などが紐付いた地図情報を用いて</span><span style="font-weight: 400;">交通ルールを認識・判断して</span><span style="font-weight: 400;">いるため、実験で使用するコースを実際に走行してみて、問題なく走れるかどうか、地図情報が正しく現実と合っているかどうかなど</span><span style="font-weight: 400;">様々</span><span style="font-weight: 400;">なことを確認する必要があります。そのため、これまでの実証実験と同様の手法で全てを確認していたら、単純計算で6倍の時間がかかってしまいます。</span></p> <p><span style="font-weight: 400;">そこで、今回は今まで以上にシミュレータをフルに活用することで、可能な限り現地に行かずに地図の検証等を行うことで時間を短縮し実証実験を乗り切りました。今後シミュレータの活用範囲をさらに広げていき、開発スピードもより効率化していきます。</span></p> <h4><strong>車両個体差</strong></h4> <p><span style="font-weight: 400;">最後に、大きな技術課題とまでは言えないものの地味に悩まされたのが車両個体差です。同じ種類の車両とはいえ、同じアクセルペダル、ブレーキペダルを踏んでも個体によって加減速の具合は全然異なりますし、同じハンドル操作をしても個体によってカーブの具合も全く異なります。また、タイヤ空気圧やブレーキパッドの経年劣化といった事象によっても車両の制御性は変わります。そういった個体差を吸収するためにそれぞれパラメタチューニングする必要があるのですが、どうしても実際に車両を動かす必要があるため、必要以上に時間が取られます。少し加減速の具合が違うだけでも思った以上に運転の滑らかさに影響するため、精細なチューニングが求められるのも中々難しいところでした。</span></p> <p><span style="font-weight: 400;">今回の実証実験では台数も少なかったので<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%DE%A5%F3%A5%D1%A5%EF%A1%BC">マンパワー</a>で乗り切ることが出来ましたが、これが100台、1000台となってくると流石にワークしません。こちらの実証実験を通して、走っているうちに段々走行具合が滑らかになっていく様な自動チューニングの必要性を実感し、ティアフォーでも自動チューニングの仕組みを取り入れ始めています。</span></p> <h3><strong>まとめ</strong> </h3> <p><span style="font-weight: 400;">今回は西新宿の実証実験の概要と振り返りをご紹介しました。今回ご紹介したように、私たちの開発している自動運転ソフトウェアにはまだまだ課題が多くあります。これからも引き続きより良い自動運転のために精進していこうと思います。</span></p> <h4>謝辞</h4> <p>今回の自動運転実証実験は株式会社Mobility Technologies、株式会社ティアフォー、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%C2%BB%B3%B2%CA%DD%B8%B1%A5%B8%A5%E3%A5%D1%A5%F3">損害保険ジャパン</a>株式会社、<a class="keyword" href="http://d.hatena.ne.jp/keyword/KDDI">KDDI</a>株式会社<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A2%A5%A4%A5%B5%A5%F3%A5%C6%A5%AF%A5%CE%A5%ED%A5%B8%A1%BC">アイサンテクノロジー</a>株式会社の5社の協業体制にて行いました。私たちが自動運転システムの開発に集中して取り組めたのも上記企業様の多大なご協力があってこそのことです。また、11月の実証実験は一般社団法人新宿副都心エリア環境改善委員会、12月の実証実験は東京都がそれぞれの実証実験の主催者として舞台を提供いただき実現しました。この場をお借りして深く感謝いたします。</p><div class="footnote"> <p class="footnote"><a href="#fn-8b1d0f47" name="f-8b1d0f47" class="footnote-number">*1</a><span class="footnote-delimiter">:</span><span class="footnote-text">オペレーターというのは、自動運転システムで対応が困難かつ緊急性が求められる際に、自動運転システムに対する緊急停止などのソフトウェア的な介入や、ドライバーに対するオーバーライド指示を出す役割を指します</span></p> </div> tkimura4 Visual SLAMの可能性と技術的チャレンジ hatenablog://entry/26006613683577649 2021-01-27T16:00:00+09:00 2021-02-05T12:01:00+09:00 こんにちは、ティアフォーでVisual SLAMの研究をしている石田です。今回は、自動運転における自己位置推定に関してVisual SLAMの重要性と課題についてお話ししたいと思います。 www.youtube.com Visual SLAMの要素技術であるVisual Odometryの例 Reference: Alismail et al., 2016Dataset: Computer Vision Group - Dataset Download 自動運転における自己位置推定 車両が地図上のどこを走っているかを推定する技術(自己位置推定)は自動運転において欠かせない要素のひとつです。自分… <p><span style="color: #111111; font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none;">こんにちは、ティアフォーでVisual SLAMの研究をしている石田です。今回は、自動運転における自己位置推定に関してVisual SLAMの重要性と課題についてお話ししたいと思います。</span></p> <div style="position: relative; width: 100%; padding-top: 56.25%;"><iframe style="position: absolute; top: 0; right: 0; width: 100% !important; height: 100% !important;" src="https://www.youtube.com/embed/z4RjYVU5s4o?feature=oembed" frameborder="0" allowfullscreen=""></iframe></div> <p><cite class="hatena-citation"><a href="https://youtu.be/z4RjYVU5s4o">www.youtube.com</a></cite></p> <figure class="figure-image figure-image-fotolife mceNonEditable"> <figcaption class="mceEditable"> <p>Visual SLAMの要素技術であるVisual Odometryの例</p> <p align="right"><span style="font-size: 80%;">Reference: <a href="https://arxiv.org/abs/1604.00990">Alismail et al., 2016</a><br />Dataset: <a href="https://vision.in.tum.de/data/datasets/rgbd-dataset/download">Computer Vision Group - Dataset Download</a></span></p> </figcaption> </figure> <h3>自動運転における自己位置推定</h3> <p>車両が地図上のどこを走っているかを推定する技術(自己位置推定)は自動運転において欠かせない要素のひとつです。自分がどこを走っているかを把握できなければ迷子になってしまいますし、自分が走っている場所の先に何があるかを把握することも難しくなってしまいます。</p> <p>現状のAutowareではレーザー光を用いたLiDARという巨大なセンサーを車両に搭載して自己位置推定を行っています。あらかじめ作っておいた地図の構造と、LiDARで得られた車両周囲の3次元構造を照らし合わせて自分がどこにいるのかを把握するというわけです。ジグソーパズルをはめ込むようにして位置推定をしていると考えるとイメージが湧きやすいかもしれません。</p> <p>しかしながらLiDARベースの位置推定手法には大きく2つの欠点があります。</p> <p>ひとつはLiDARそのものが非常に高価であることです。性能のいいものでは数千万円もするものがあります。これを世の中のクルマひとつひとつに取り付けて走らせることは現実的ではないため、なんらかの方法でコストを下げる必要があります。</p> <p>もうひとつは構造特徴に乏しい場所では性能を発揮できないことです。絵柄のないジグソーパズルをイメージしてみてください。ピースひとつひとつが異なる形をしていたら、それぞれのピースは特定の場所にはまります。しかし、もし全てのピースが正方形だったら... これはもはやジグソーパズルの意味を成しませんよね。全てのピースがどこにでもはまってしまいます。同じように、構造的な特徴に乏しい場所(平原やトンネルなど)では、LiDARはどこにでも”はまって”しまうため、位置を一意に定めることができません。</p> <p>これらの問題を解決するために現在私が取り組んでいるのがVisual SLAMという技術です。</p> <p>Visual SLAMとは、視覚情報を用いて地図を作成し、同時に地図内での自己位置を推定する技術です。 また、あらかじめ作成しておいた地図に対して、その地図内でどこにいるのかを推定する relocalization という技術も活発に研究されています。</p> <p>Visual SLAMの最大の利点は設備の安さです。Visual SLAMは基本的にカメラやIMU(物体の加速度や回転速度を測るセンサー)からの入力に基づいて動作します。これらのセンサーは安価に手に入るため、数万円で位置推定を始めることができます。また、Visual SLAMは視覚情報をもとに動作するため、構造特徴に乏しい場所であっても車の位置を推定することができます。さらに、カメラやIMUだけでなく、LiDARなどの他のセンサーと組み合わせることによって<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%ED%A5%D0%A5%B9%A5%C8">ロバスト</a>性を向上させ、さまざまな場所を走ることができるようになります。</p> <p>自動運転ではあらかじめ作成しておいた地図との照合による位置推定が基本となるため、通常走行の範囲では relocalization が主体となります。しかし、LiDARがうまく動かない場所ではLiDARで地図を作ることが難しいため、Visual SLAMによって車両の位置推定をしつつLiDARによって地図を作ることも想定されています。</p> <p> </p> <h3>Visual SLAMの技術的チャレンジ</h3> <p>自動運転におけるVisual SLAMの最大の課題は、なんといってもその<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%ED%A5%D0%A5%B9%A5%C8">ロバスト</a>性です。自動車はあらゆる環境のあらゆる場所を走ります。街中、ハイウェイ、峠、住宅街、晴れ、雨、雪、夜…</p> <p>現在はODD(運行設計領域)対象外の環境もあるとはいえ、トンネルや逆光など、日常生活でよく目にするシーンの中にもVisual SLAMにとっては難しいものがあります。こういった場所で安定して動作する手法を設計し実装するのは至難の業ですが、技術者の腕の見せどころでもあります。</p> <p>Visual SLAMにとって難しい環境は大きく分けて2つあります。ひとつは暗い場所、もうひとつは動く物体が多い場所です。</p> <p>Visual SLAMは画像の情報から地図の3次元構造を計算し、その地図に対して自分がどの程度動いたかを推定することによって位置を把握します。画像からどのような情報を抽出するのかは手法によって大きく異なりますが、画像の特徴がよく現れている点(特徴点)を用いるものが一般的です。カメラから得られた画像1枚1枚から特徴点を抽出し、それらの幾何関係を利用して3次元地図を作ったり、位置推定を行ったりします。しかし、暗い場所ではそもそも画像から得られる情報が大きく減ってしまいますし、画像から有用な特徴点を抽出することも難しくなります。露光時間が長くなってブレが大きくなってしまいますし、カメラの感度が高くなって明るいものは極端に明るく映ってしまうためです。暗い場所でVisual SLAMを安定して動作させるためにはカメラ本体も含めた包括的な設計が必要になるため、これは非常にチャレンジングな問題だと言えます。</p> <p>動く物体の扱いも大きな課題です。既存のVisual SLAMのほとんどは周囲の環境が動かないことを仮定しており、動く物体の扱いをあまり考慮できていません。このため、周囲に移動物体がたくさんあると、自分が動いているのか、それとも環境が動いているのかを判別できなくなってしまいます。自動車は周囲に動く物体がたくさんある場所をよく走るため、Visual SLAM単体で位置推定を行うことはせず、他のセンサーと組み合わせることが必須となります。</p> <p> </p> <figure class="figure-image figure-image-fotolife mceNonEditable"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/s/sonicair/20210127/20210127110704.png" alt="" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable"> <p>トンネル内で得られた画像の例<br /><span style="font-size: 80%;">カメラの感度が上がっている一方で対向車のライトは非常に明るいため<br /></span><span style="font-size: 80%;">カメラが扱える明るさを大きく超えてしまっている</span></p> </figcaption> </figure> <p>自動運転車にとって最も難しい環境のひとつがトンネルです。トンネル内部には<a class="keyword" href="http://d.hatena.ne.jp/keyword/GNSS">GNSS</a>(<a class="keyword" href="http://d.hatena.ne.jp/keyword/GPS">GPS</a>などの衛星測位システム)の信号が届きませんし、構造的な特徴に乏しいためLiDARの信頼性も低くなります。また、トンネルはVisual SLAMにとってもやはり課題のひとつです。</p> <p>トンネルの内部は暗いため有用な視覚情報を得ることが難しいですし、全体が暗いのに対して周囲の車のライトは明るいため、ひとつの環境の中で非常に激しい光量変化が起きてしまいます。また、トンネル出入口では視野全体の明るさが一気に変わるため、やはり極端な光量変化に対応できる機材および<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A2%A5%EB%A5%B4%A5%EA%A5%BA%A5%E0">アルゴリズム</a>が求められます。それに加えて、周囲の全ての車が移動物体なので、これらもうまく扱わなければなりません。</p> <p>こういった難しい環境でも安心して走れるよう、我々はハードウェアからソフトウェア、さらにはインフラまでも対象として、日々研究開発を行っています。</p> <p> </p> <h3>Visual SLAMの面白さ</h3> <p>Visual SLAMはコンピュータビジョンの<a class="keyword" href="http://d.hatena.ne.jp/keyword/%C1%ED%B9%E7%B3%CA%C6%AE%B5%BB">総合格闘技</a>です。画像処理に対する基礎的な知識はもちろんとして、エピポーラ幾何や数理最適化に対する深い理解が要求されますし、IMUなど他のセンサと組み合わせる場合はカルマンフィルタや制御理論の知識も必要になります。また、Visual SLAMはやや大規模なシステムになることが多いため、コードをきれいに管理したり、綿密にテストしたりする能力も求められます。特に自動運転では非常に高い安全性が求められるため、他のVisual SLAMのアプリケーションと比べると徹底したテストが必要となります。</p> <p>自動運転では、Visual SLAMは省電力デ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%D0%A5%A4%A5%B9">バイス</a>上で高速に動作することが要求されるため、コンピュータの能力をフルに発揮するための実装力も必要になります。車に数千ワットの巨大なコンピュータを載せるわけにはいきませんし、かといってゆっくり動作すると車の運行性能や安全性が犠牲になってしまいます。先ほども述べたように、Visual SLAMの多くは画像から特徴点を抽出し、それらの幾何関係を利用して地図作成と位置推定を行います。カメラは1秒間に何十枚もの画像を出力しますし、1画像から得られる特徴点の数は数百から数千にもなります。自動運転では、省電力デ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%D0%A5%A4%A5%B9">バイス</a>の上で、大量の特徴点から信頼できるものを選び出し、地図作成と位置推定をできるだけ高速に行う必要があるというわけです。また、地図を作っていくと誤差が蓄積してどんどん歪んでいってしまうため、この歪みを補正する処理も必要になります。小さなコンピュータで大量の情報を正確かつ高速に処理することがVisual SLAMの最大のチャレンジであり、これを徹底した安全管理と品質管理に基づいて自動車に載せていくことが私にとっての自動運転の面白さです。</p> <p>Visual SLAMを自動運転に活用するためには、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%BE%F0%CA%F3%B9%A9%B3%D8">情報工学</a>の理論から実装までありとあらゆる知識が必要とされます。自分がいままで学んできたことを全てつぎ込んでものをつくることが、この仕事の最大の面白さです。</p> <p>もしあなたが自動運転車に乗る日が来たら、車のまわりを細かくチェックしてみてください。もしかしたらカメラがたくさんついていて、そのうしろでは私が作ったシステムが動いているかもしれません。</p> <p>ティアフォーでは、自己位置推定に関するリサーチャーとエンジニアを絶賛募集しています!もしご興味ある方がいましたら、以下のURLからご応募ください!!</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftier4.jp%2Fcareers%2F" title="Careers | 株式会社ティアフォー" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://tier4.jp/careers/">tier4.jp</a></cite></p> sonicair 自動運転を支えるWeb技術 - 信頼性への取り組み (SRE編) hatenablog://entry/26006613679905520 2021-01-20T16:00:00+09:00 2021-01-23T19:45:05+09:00 こんにちは、ティアフォーでSREを担当している宇津井です。 2019年9月にSite Reliability Engineering(SRE)として入社して以来行ってきたことをざっと振り返った上で、自動運転の社会実装においてWeb系のエンジニアには何が求められるのかという答えを探っていきたいと思います。スタートアップ企業でどのようにSREの文化を作っていくのかという面でも何かの参考になるのではないかと考え筆を取っています。 と言いつつも重要なことなので最初に書いておきますが、ティアフォーのSREは私が一人目で入社して以来専任としてはずーっと一人でその役割を担ってきました。ようやく一緒に働く方を… <p>こんにちは、ティアフォーでSREを担当している宇津井です。</p> <p>2019年9月にSite Reliability Engineering(SRE)として入社して以来行ってきたことをざっと振り返った上で、自動運転の社会実装においてWeb系のエンジニアには何が求められるのかという答えを探っていきたいと思います。スタートアップ企業でどのようにSREの文化を作っていくのかという面でも何かの参考になるのではないかと考え筆を取っています。</p> <p>と言いつつも重要なことなので最初に書いておきますが、ティアフォーのSREは私が一人目で入社して以来専任としてはずーっと一人でその役割を担ってきました。ようやく一緒に働く方を募集できる状態になりました。そのような背景もあってこのエントリーを書いています。もしご興味がある方は以下のCareersページからご連絡をお待ちしております。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftier4.jp%2Fcareers%2F" title="Careers | 株式会社ティアフォー" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://tier4.jp/careers/">tier4.jp</a></cite></p> <p>※SRE編とタイトルに書きましたが続編が出てくるかは分かりません。</p> <ul class="table-of-contents"> <li><a href="#入社当時の状況">入社当時の状況</a></li> <li><a href="#SREとして整備した内容">SREとして整備した内容</a><ul> <li><a href="#システム把握">システム把握</a></li> <li><a href="#セキュリティ">セキュリティ</a></li> <li><a href="#モニタリングとログの統合管理">モニタリングとログの統合管理 </a></li> <li><a href="#テンプレート命名規則作り">テンプレート・命名規則作り</a></li> <li><a href="#マルチテナンシーへの取り組み">マルチテナンシーへの取り組み</a></li> </ul> </li> <li><a href="#法律法令ガイドライン基準への準拠">法律・法令・ガイドライン・基準への準拠</a></li> <li><a href="#信頼性に対する取り組み">信頼性に対する取り組み</a><ul> <li><a href="#SLI--SLO--SLA">SLI / SLO / SLA</a></li> <li><a href="#DevOps文化の醸成">DevOps文化の醸成</a></li> <li><a href="#Incident-Management">Incident Management</a></li> </ul> </li> <li><a href="#まとめ">まとめ</a></li> </ul> <p>まず、ティアフォーの場合は<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%AA%A1%BC%A5%D7%A5%F3%A5%BD%A1%BC%A5%B9">オープンソース</a>の自動運転OS「Autoware」を開発する部門とそのAutowareを用いた自動運転エコシステムの導入・運用・開発をサポートするWeb.Auto(MaaS, CI/CD)を開発する部門が存在します。私はWeb.Autoの開発・運用に従事しています。</p> <p>Web.Autoについてはサービスページ及び昨年行ったミートアップの発表資料をご覧ください。ミートアップ資料では組織・体制・採用している技術スタック等も垣間見えるようになっています。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fweb.auto%2F" title="Web.Auto" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://web.auto/">web.auto</a></cite></p> <p><iframe src="https://www.slideshare.net/slideshow/embed_code/key/htAtq7lwPVSTWu" width="427" height="356" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border: 1px solid #CCC; border-width: 1px; margin-bottom: 5px; max-width: 100%;" allowfullscreen=""> </iframe></p> <div style="margin-bottom: 5px;"><strong> <a href="https://www.slideshare.net/Tier_IV/tier-tech-meetup-2-cloud-238997099" title="Tier Ⅳ Tech Meetup #2 - 自動運転を作るのはCloudシステムの集合体?? 活用技術を大解剖 -" target="_blank">Tier Ⅳ Tech Meetup #2 - 自動運転を作るのはCloudシステムの集合体?? 活用技術を大解剖 -</a> </strong> from <strong><a href="https://www.slideshare.net/Tier_IV" target="_blank">Tier_IV</a></strong></div> <p><cite class="hatena-citation"><a href="https://www.slideshare.net/Tier_IV/tier-tech-meetup-2-cloud-238997099">www.slideshare.net</a></cite></p> <h3 id="入社当時の状況">入社当時の状況</h3> <p>当時のWeb.AutoはFMS「Fleet Management System / 配車管理プラットフォーム」、Maps「地図プラットフォーム」、Drive「遠隔監視・操作プラットフォーム」で構成されており、今考えると自動運転車両を走らせて遠隔監視ができるだけという非常にシンプルな構成でした。ざっくり表現すると<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%D1%A5%D6%A5%EA%A5%C3%A5%AF%A5%AF%A5%E9%A5%A6%A5%C9">パブリッククラウド</a>(主に<a class="keyword" href="http://d.hatena.ne.jp/keyword/AWS">AWS</a>)上にいくつかのマイクロサービスが展開されていました。</p> <p>システム構成・<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A2%A1%BC%A5%AD%A5%C6%A5%AF%A5%C1%A5%E3">アーキテクチャ</a>等については<a class="keyword" href="http://d.hatena.ne.jp/keyword/AWS">AWS</a> Summit 2019 (Tokyo) で発表された資料が参考になります<a href="#f-7fb0ce45" name="fn-7fb0ce45" title="https://pages.awscloud.com/rs/112-TZM-766/images/K3-03.pdf">*1</a>。発表されたのは2019年6月の事で私は入社前でしたが、9月に入社したら資料の最後に記載されている今後に向けてというページの内容が全て完了していました。そのスピード感にとても関心したのを今でも覚えています。</p> <p>また、私が入社した当時は実証実験を日本あるいは世界各地で行いつつもSREは不在で少数の開発部隊で運用・サービス実証を行なっていました。AutowareはStand-Aloneでも走行ができるのでWeb.Autoの主要機能のひとつであるFMS(Fleet Management System)が必要とされない実証実験さえ存在しました。</p> <div style="text-align: center;"> <figure class="figure-image figure-image-fotolife mceNonEditable" title="実証実験の風景 〜 某キャラクターに似ているというmillee"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/u/utsudai/20210119/20210119175407.jpg" alt="f:id:utsudai:20210119175407j:plain" title="" class="hatena-fotolife" itemprop="image" width="80%" /></p> <figcaption class="mceEditable">実証実験の風景 〜 某キャ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E9%A5%AF">ラク</a>ターに似ているというmilee</figcaption> </figure> </div> <p>システム監視だけを切り取って見ても<a class="keyword" href="http://d.hatena.ne.jp/keyword/Amazon">Amazon</a> CloudWatchでいくつかのMetrics Alertが設定されているだけでした。</p> <p>要はシステムを安定的に動かすとか、高い品質を維持し続ける事、堅牢である事、パフォーマンス、キャパシティプランニング、拡張性といった信頼性に対する取り組みよりも開発スピードが優先されている状況だったということです(組織がシステムの信頼性を重要視していないというわけではなく、何を優先しているかという話です。重要なフェーズに差し掛かったから私がジョインしたわけです)。</p> <h3 id="SREとして整備した内容">SREとして整備した内容</h3> <h4 id="システム把握">システム把握</h4> <p>そのような中で入社してまず取り掛かったのは<a class="keyword" href="http://d.hatena.ne.jp/keyword/AWS">AWS</a> Well-Architected Frameworkを参考に「運用の優秀性」、「セキュリティ」、「可用性」、「パフォーマンス効率」、「コスト最適化」の観点について現状どういった状態なのかを自己評価しそこからリスク分析を行いました。自分自身がどの様な状態でシステムが動いているのか知る良い機会になりましたし、上長にどのような順序で何を整備していくのかを説明するのにも客観的な視点が得られて大変役立ちました。</p> <h4 id="セキュリティ">セキュリティ</h4> <p>まず手を付けたのがセキュリティです。弊社は今も昔も<a class="keyword" href="http://d.hatena.ne.jp/keyword/AWS">AWS</a>をマルチアカウントで運用しています。アカウント数は入社当時で20個ほどあったと思います。スタートアップあるあるですがアクセス権は開発者が皆平等に強めの権限を持っていたりします。流石にrootアカウントは上長のみが<a class="keyword" href="http://d.hatena.ne.jp/keyword/%CA%DD%CD%AD">保有</a>していましたが、誰かが入社するとそれぞれの<a class="keyword" href="http://d.hatena.ne.jp/keyword/AWS">AWS</a>アカウントにIAM Userを手作りしているような状況でした(他の<a class="keyword" href="http://d.hatena.ne.jp/keyword/AWS">AWS</a>リソースは積極的にCloudFormationで作られていたけどなぜかここは手作業で微笑ましかったと記憶しています)。</p> <p>アクセス権の管理は重要です。 然るべき権限が然るべき人に割り当てられているべきですし、アクセス状況は監査できる必要があります。権限付与も低いコストで行える必要があるし、与えられた権限の利用状況が監査できる必要もあります。別途ICTセクションでSingle <a class="keyword" href="http://d.hatena.ne.jp/keyword/Sign">Sign</a>-On(SSO)環境を検討していた時期でID Providerが決め打ちできなかったので、<a class="keyword" href="http://d.hatena.ne.jp/keyword/AWS">AWS</a> OrganizationsをベースにしてIAMロールによるクロスアカウントアクセス環境を構築しました。少し古い資料ですが、2017年の<a class="keyword" href="http://d.hatena.ne.jp/keyword/AWS">AWS</a> Summitで発表された内容<a href="#f-b3e06ec7" name="fn-b3e06ec7" title="https://d0.awsstatic.com/events/jp/2017/summit/slide/D4T2-2.pdf">*2</a>に近いものが書かれています。</p> <p>監査・運用については<a class="keyword" href="http://d.hatena.ne.jp/keyword/AWS">AWS</a> CloudTrail / <a class="keyword" href="http://d.hatena.ne.jp/keyword/AWS">AWS</a> Config / <a class="keyword" href="http://d.hatena.ne.jp/keyword/Amazon">Amazon</a> GuardDutyがその役割をになっています。</p> <p><a class="keyword" href="http://d.hatena.ne.jp/keyword/AWS">AWS</a> OrganizationsのService Control Policy(SCP)で全<a class="keyword" href="http://d.hatena.ne.jp/keyword/AWS">AWS</a>アカウント共通の制限(上述のセキュリティ系設定を弄れないようにしたり)も実施しています。</p> <p>開発者の中に元々セキュリティエンジニアとして活躍されていた方がいたこともあり、互いに協力しあって抱えているセキュリティリスクを洗い出したりもしました。この方は<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%DA%A5%CD%A5%C8%A5%EC%A1%BC%A5%B7%A5%E7%A5%F3%A5%C6%A5%B9%A5%C8">ペネトレーションテスト</a>も実施していました、専門でやられている方が居たのは心強かったです。</p> <h4 id="モニタリングとログの統合管理">モニタリングとログの統合管理 </h4> <p>セキュリティと並行して手を付けたのはモニタリングです。<a class="keyword" href="http://d.hatena.ne.jp/keyword/Amazon">Amazon</a> CloudWatchが悪いわけではないですが、<a class="keyword" href="http://d.hatena.ne.jp/keyword/Amazon">Amazon</a> CloudWatchだけでモニタリング体制を敷くのは結構面倒です。何かのマイクロサービスを追加する度にCloudWatchの設定をチェックして回るのは<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%DE%A5%F3%A5%D1%A5%EF%A1%BC">マンパワー</a>的に無理があります。何かリソースが追加された時でもAuto Discoveryされ、手間なくモニタリングされる世界を作りたかったためDatadogを導入しました。</p> <div style="text-align: center;"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/u/utsudai/20210119/20210119153839.png" alt="f:id:utsudai:20210119153839p:plain" title="" class="hatena-fotolife" itemprop="image" width="200" /></div> <p>また、ログ解析にも手間がかかる状態でした。ログは全て<a class="keyword" href="http://d.hatena.ne.jp/keyword/Amazon">Amazon</a> CloudWatch Logsに出力されているまでは良かったのですが、マイクロサービス故にユーザーからは一つの<a class="keyword" href="http://d.hatena.ne.jp/keyword/API">API</a>をキックしているだけだったとしても、内部的にマイクロサービスがマイクロサービスを呼び出していたりしてログが分散してしまいます。何か問題が発生した時にこれらのログを見るのにも一苦労でしたし、<a class="keyword" href="http://d.hatena.ne.jp/keyword/AWS">AWS</a> <a class="keyword" href="http://d.hatena.ne.jp/keyword/CLI">CLI</a> v2の様にロググループをtailする機能もありませんでした。</p> <p>そこでDatadogをログの統合管理基盤としても用いることにしました。既にシステムモニタリングとしてDatadogを採用していたこともあり、ツールを新たに増やさす要件を満たしにいった形です。</p> <p>これで複数のマイクロサービスに跨がる処理もDatadogのFilterを駆使すれば処理の流れをリアルタイムに近い状態で追いかけれる状態になりました。</p> <div style="text-align: center;"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/u/utsudai/20210119/20210119154032.png" alt="f:id:utsudai:20210119154032p:plain" title="" class="hatena-fotolife" itemprop="image" width="200" /></div> <p>ここまで出来ると<a class="keyword" href="http://d.hatena.ne.jp/keyword/APM">APM</a>「Application Performance Management / Application Performance Monitoring」やマイクロサービス間の処理をTraceしたくなります。これもDatadogと<a class="keyword" href="http://d.hatena.ne.jp/keyword/AWS">AWS</a> <a class="keyword" href="http://d.hatena.ne.jp/keyword/X-Ray">X-Ray</a>を組み合わせることである程度実現できました。</p> <p>更には手取り早くE2Eテストを自動化したかったのでDatadogのSynthetics Testも導入しました。E2EテストはDatadogで行うよりもフロントエンドエンジニアが<a class="keyword" href="http://d.hatena.ne.jp/keyword/JavaScript">JavaScript</a>でアプリケーションコードと同じコードベースで記述した方が良いという話が当初からあり、限定的な利用に止まっています。</p> <p>ブラウザ上で発生したエラーのト<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E9%A5%C3%A5%AD%A5%F3%A5%B0">ラッキング</a>も重要です。いくつか候補が上がりましたが弊社ではSentryを採用しました。これで実証実験の場でエラーが発生したとしても開発者側でト<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E9%A5%C3%A5%AD%A5%F3%A5%B0">ラッキング</a>できる様になりました。</p> <h4 id="テンプレート命名規則作り">テンプレート・<a class="keyword" href="http://d.hatena.ne.jp/keyword/%CC%BF%CC%BE%B5%AC%C2%A7">命名規則</a>作り</h4> <p>何のテンプレートだよ、という声が聞こえてきそうですが様々なテンプレートを作成しました。</p> <p>テンプレートの例としては以下の様な物です。</p> <ul> <li><a class="keyword" href="http://d.hatena.ne.jp/keyword/AWS">AWS</a>リソースのタグ設計</li> <li>利用できるIP Subnet(CIDR)</li> <li>踏み台アカウントの作成方法をCFn化</li> <li><a class="keyword" href="http://d.hatena.ne.jp/keyword/AWS">AWS</a> Transit <a class="keyword" href="http://d.hatena.ne.jp/keyword/Gateway">Gateway</a>の作成基準</li> <li>各種<a class="keyword" href="http://d.hatena.ne.jp/keyword/Access">Access</a> Tokenを<a class="keyword" href="http://d.hatena.ne.jp/keyword/AWS">AWS</a> Secret Managerから取得する方法</li> <li>モニタリングツール導入のコードサンプル</li> <li>ログ管理のコードサンプル</li> <li><a class="keyword" href="http://d.hatena.ne.jp/keyword/AWS">AWS</a>リソースの<a class="keyword" href="http://d.hatena.ne.jp/keyword/%CC%BF%CC%BE%B5%AC%C2%A7">命名規則</a></li> <li>技術選定の基準</li> <li>etc</li> </ul> <p>一人で全てのマイクロサービスにルールを適用していくのは無理があるので何かルールを決めた際はどこかのサービスへ実装して、他のサービスは基本的にはそのコード化された方法を模倣してもらう作戦で凌いでいます。</p> <p>将来的にはSREが基盤を作って各マイクロサービスへ自動的に反映される様な仕組みにしていきたいです。</p> <p>技術選定は大きなトピックなのでこの記事では取り扱いません。</p> <h4 id="マルチテナンシーへの取り組み">マルチテナンシーへの取り組み</h4> <p><a class="keyword" href="http://d.hatena.ne.jp/keyword/AWS">AWS</a>がマルチアカウントで運用されていることは上述しましたが、弊社では実証実験の拠点ごとに<a class="keyword" href="http://d.hatena.ne.jp/keyword/AWS">AWS</a>アカウントを用意していました。この利点は拠点ごとに異なる要求・仕様に答えやすいし、とある拠点でのデプロイが他の拠点には影響しないという安全性がありました。自動運転業界の特色かもしれませんが、人・物を載せて運行することになるので多少コストがかかっても安全に倒すという傾向があります(ようやく自動運転が出てきた)。</p> <p>ですが、全国で行われている実証実験は拠点ごとに捉えると1ヶ月のうち毎日行われる物でもありません。拠点ごとに<a class="keyword" href="http://d.hatena.ne.jp/keyword/AWS">AWS</a>アカウントを作成して各々環境を作っていくとシステムリソースとコストの効率が非常に悪いのです。</p> <p>大規模に展開していくことを見据えて早いうちに移行した方が良かろうという意思決定をして現在はマルチテナンシーで稼働しています。単純に統合すれば動くというわけでもなく、主に権限管理の仕組みだったりが必要で<a class="keyword" href="http://d.hatena.ne.jp/keyword/AWS">AWS</a>側の基板だけではなく、<a class="keyword" href="http://d.hatena.ne.jp/keyword/API">API</a>からWeb画面まで色々な対応が必要でした(これは開発陣が尽力してくれました)。</p> <h3 id="法律法令ガイドライン基準への準拠">法律・法令・<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%AC%A5%A4%A5%C9%A5%E9%A5%A4%A5%F3">ガイドライン</a>・基準への準拠</h3> <p>自動運転という領域の特徴の一つとして日本国内だけで考えても<a class="keyword" href="http://d.hatena.ne.jp/keyword/%C6%BB%CF%A9%B8%F2%C4%CC%CB%A1">道路交通法</a>・<a class="keyword" href="http://d.hatena.ne.jp/keyword/%C6%BB%CF%A9%B1%BF%C1%F7%BC%D6%CE%BE%CB%A1">道路運送車両法</a>・<a class="keyword" href="http://d.hatena.ne.jp/keyword/%C6%BB%CF%A9%CB%A1">道路法</a>・<a class="keyword" href="http://d.hatena.ne.jp/keyword/%C6%BB%CF%A9%B1%BF%C1%F7%CB%A1">道路運送法</a>といった国内法規に準拠する必要があります。法令だけでなく各省庁から<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%AC%A5%A4%A5%C9%A5%E9%A5%A4%A5%F3">ガイドライン</a>も発行されます。</p> <p>また国際規格も目白押しで様々な規格を参照する必要があるのですが、この分野をSREが全て抑えるのは厳しいです。ティアフォーにはSafety Engineerが在籍しているので、彼らから必要とされた物を粛々と対応していくスタイルです(今後はもっと前のめりに対応する必要があります)。</p> <p>ティアフォーとしては2020年8月に「Tier IV Safety Report 2020」を公開しましたので興味のある方は参照していただければと。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftier4.jp%2Fmedia%2Fnews%2Fsafetyreport%2F" title="ティアフォー、国内初となる自動運転のセーフティレポートを公開 − Tier IV Safety Report 2020 | 株式会社ティアフォー" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://tier4.jp/media/news/safetyreport/">tier4.jp</a></cite></p> <p>テックブログにも安全への取り組みが連載されていますので合わせて紹介させていただきます。</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftech.tier4.jp%2Fentry%2F2020%2F05%2F08%2F163000" title="安全への取り組み: ①自動運転関連の法律・ガイドライン - Tier IV Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://tech.tier4.jp/entry/2020/05/08/163000">tech.tier4.jp</a></cite></p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftech.tier4.jp%2Fentry%2F2020%2F11%2F25%2F160000" title="安全への取り組み:②自動運転の安心・安全について - Tier IV Tech Blog" class="embed-card embed-blogcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://tech.tier4.jp/entry/2020/11/25/160000">tech.tier4.jp</a></cite></p> <h3 id="信頼性に対する取り組み">信頼性に対する取り組み</h3> <p>上記以外にも取り組みは色々ありましたがシステムの稼働状況は大部分が自動計測できている状態になってきたので、いよいよ信頼性自体を定義する運びとなりました。</p> <h4 id="SLI--SLO--SLA">SLI / SLO / <a class="keyword" href="http://d.hatena.ne.jp/keyword/SLA">SLA</a></h4> <p>最終的には高いService Level Agreement(<a class="keyword" href="http://d.hatena.ne.jp/keyword/SLA">SLA</a>)を定義してお客様に向けてシステムの稼働目標を提示できる様にしたいです。</p> <p><a class="keyword" href="http://d.hatena.ne.jp/keyword/SLA">SLA</a>は近日中に掲げる見込みですが、これに先立って自動運転車両が安全に運行している事を担保するためにもまずはService Level Indicator(SLI) / Service Level Objective(SLO)の設定を行いました。</p> <p>各マイクロサービスの開発者に<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%D2%A5%A2%A5%EA">ヒアリ</a>ングを行いつつ、開始当初は全社統一の基準を定めてスタートしました。最終プロダクトという状態ではないので自動運転で人命がかかっているとはいえ、99.999%の様なあまりにも高すぎる目標を掲げるのは理にかなっていません。自動運転の安全性は色々な側面で総当たり的に担保しています。この辺りは4半期毎にSLI / SLOの設定内容をレビューし、月毎に結果を取り纏め共有しあっています。</p> <p>DatadogのSLO機能はリアルタイムでエラーバジェットの残り時間まで表示してくれるので重宝しています。</p> <div style="text-align: center;"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/u/utsudai/20210119/20210119153300.png" alt="f:id:utsudai:20210119153300p:plain" title="" class="hatena-fotolife" itemprop="image" width="80%" /></div> <h4 id="DevOps文化の醸成">DevOps文化の醸成</h4> <p>自動運転の実証実験にはアカデミックな側面も見え隠れします。開発者の中には大学からティアフォーに入社して活躍されている方もいます。そうなるとResearch&amp;Developmentはやってきたけど企業でのOperations経験に乏しいみたいな方も在籍しています。</p> <p>入社して2ヶ月後程度経過した時に「皆んなSREになろう」というサブタイトルでDevOpsとは何か、SLI / SLO / <a class="keyword" href="http://d.hatena.ne.jp/keyword/SLA">SLA</a>の各指標の説明、モニタリングツールの説明等を行いました。SREを増員する時期ではなかったため開発者を全員巻き込むスタイルを敢行したわけです。</p> <p>それ以外にも所属する全てのメンバーが共通認識を持つために社内勉強会、会議、実際の業務を通じて、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%C8%A5%E9%A5%D6%A5%EB%A5%B7%A5%E5%A1%BC%A5%C6%A5%A3%A5%F3%A5%B0">トラブルシューティング</a>、キャパシティプランニング等を行ってきています。</p> <p>私自身の取り組みではないですがWeb.Autoに閉じず全社一丸となってDevOpsに取り組もうというムーブメントを上長がぶち上げたりもしています。自動運転の走行車両、各地で行われる実証実験までターゲットを拡げているので一筋縄ではいかない面もあると思います。Web.Autoは自動運転システムの導入・運用・開発の全てをサポートするサービスで、DevOpsを推進するサービスという側面を持っているのです。この活動には大きく期待しています。</p> <h4 id="Incident-Management">Incident Management</h4> <p>各地で行われている実証実験ですがその目的は様々です。自動運転業界においては一昨年、昨年まではまだPoCの域に収まった実験が多かったと感じます。ですが、最近ではPoC「Proof of Concept」はある程度こなしてきたから今度はPoB「Proof of Business」だよというシーンが増えてきました。</p> <p>そうなると自動運転のシステムでクリティカルな問題が発生した場合に組織として対処できる状態が求められます。これまではSlackに飛んできたアラートを緩く心地の良い温度感でSREと開発者が取り扱ってきました。これだとアラートに対してお見合いが発生してしまう事もあります。また、アラートへの対処方法が属人的になってしまったり、そもそもアラートに対応する人に偏りが出てきてしまう側面もあります。</p> <p>そこでOn-Call、アラート発生後の対応・連絡フロー、ポストモーテムまで<a class="keyword" href="http://d.hatena.ne.jp/keyword/%B0%EC%B5%A4%C4%CC%B4%D3">一気通貫</a>した管理プロセスを構築しました。</p> <p>ツールとしてはOpsGenieを導入しました。単位時間を区切ってSREと開発者全員が均等にOn-Callに対処する体制へ移行しています。<a class="keyword" href="http://d.hatena.ne.jp/keyword/OSS">OSS</a>のグローバル企業という特色を活かし、いずれは24x365のOn-Call体制をFollow the Sunで実現したいと考えています。夜中の対応とかきついですからね。</p> <div style="text-align: center;"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/u/utsudai/20210119/20210119152730.png" alt="f:id:utsudai:20210119152730p:plain" title="" class="hatena-fotolife" itemprop="image" width="80%" /></div> <h3 id="まとめ">まとめ</h3> <p><a class="keyword" href="http://d.hatena.ne.jp/keyword/OSS">OSS</a>によって「自動運転の<a class="keyword" href="http://d.hatena.ne.jp/keyword/%CC%B1%BC%E7%B2%BD">民主化</a>」実現を目論むスタートアップにSREが入社してSREとして整備してきた事を振り返ってみました。スタートアップでは個人の業務範囲が広くなりがちなので、それこそエンジニアの仕事ではない様な事も取り組んだ気がします。ここに書いた事以外の事にも多くの時間を使ってきたと思いますがそれはそれで楽しい時間でした。</p> <p>SREとして信頼性を武器に自動運転の社会実装を行いたいという方がいれば是非ともそのお力をお貸しください。業界自体が謎めいていると思うのでMeetup等を活用していただけると幸いです。</p> <p>直近では1/29(金)19:00より「Tier IV 自動運転Web&amp;Dataミートアップ」というタイトルで開催予定です!</p> <p><iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftier4.connpass.com%2Fevent%2F198897%2F" title="Tier IV 自動運転Web&amp;Dataミートアップ (2021/01/29 19:00〜)" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;"></iframe><cite class="hatena-citation"><a href="https://tier4.connpass.com/event/198897/">tier4.connpass.com</a></cite></p> <p> </p><div class="footnote"> <p class="footnote"><a href="#fn-7fb0ce45" name="f-7fb0ce45" class="footnote-number">*1</a><span class="footnote-delimiter">:</span><span class="footnote-text"><a href="https://pages.awscloud.com/rs/112-TZM-766/images/K3-03.pdf">https://pages.awscloud.com/rs/112-TZM-766/images/K3-03.pdf</a></span></p> <p class="footnote"><a href="#fn-b3e06ec7" name="f-b3e06ec7" class="footnote-number">*2</a><span class="footnote-delimiter">:</span><span class="footnote-text"><a href="https://d0.awsstatic.com/events/jp/2017/summit/slide/D4T2-2.pdf">https://d0.awsstatic.com/events/jp/2017/summit/slide/D4T2-2.pdf</a></span></p> </div> utsudai 自動運転システムの性能限界検知と環境センシングに関する取組み hatenablog://entry/26006613674051227 2021-01-13T16:00:00+09:00 2021-01-13T16:14:59+09:00 こんにちは、ティアフォーで自動運転システムを開発している川端です。今回はシステムの性能限界検知と環境センシングに関する取り組みの一部をご紹介します。 1、自動運転レベルとODDによる走行条件定義 【自動運転レベル】 自動運転のレベルはSAEの定義に沿う形で0から5までの6段階に分けられることが主流となっています*1。そのうち、レベル3以上の定義は以下のようになっています。 レベル3(条件付運転自動化) 運転自動化システムが全ての動的運転タスクを限定領域において持続的に実行。この際、作動継続が困難な場合への応答準備ができている利用者は、他の車両のシステムにおける動的運転タスクの実行システムに関… <p>こんにちは、ティアフォーで自動運転システムを開発している川端です。<br />今回はシステムの性能限界検知と環境センシングに関する取り組みの一部をご紹介します。</p> <h3>1、自動運転レベルとODDによる走行条件定義</h3> <h4>【自動運転レベル】</h4> <p>自動運転のレベルは<a href="https://www.sae.org/">SAE</a>の定義に沿う形で0から5までの6段階に分けられることが主流となっています<a href="#f-82663f05" name="fn-82663f05" title="日本では公益社団法人 自動車技術会発行の資料において日本語で定義されています。">*1</a>。そのうち、レベル3以上の定義は以下のようになっています。</p> <p> </p> <p>レベル3(条件付運転自動化)</p> <blockquote> <p>運転自動化システムが全ての動的運転タスクを限定領域において持続的に実行。この際、<span style="text-decoration: underline;"><strong>作動継続が困難な場合への応答準備ができている利用者は、他の車両のシステムにおける動的運転タスクの実行システムに関連するシステム故障だけでなく、自動運転システムが出した介入の要求を受け容れ、適切に応答することが期待される</strong></span></p> </blockquote> <p> </p> <p>レベル4(高度運転自動化)</p> <blockquote> <p>運転自動化システムが全ての動的運転タスク及び作動継続が困難な場合への応答を限定領域において持続的に実行。<span style="text-decoration: underline;"><strong>作動継続が困難な場合、利用者が介入の要求に応答することは期待されない</strong></span></p> </blockquote> <p> </p> <p>レベル5(完全運転自動化)</p> <blockquote> <p><span style="text-decoration: underline;">運転自動化システムが全ての動的運転タスク及び作動継続が困難な場合への応答を持続的かつ無制限に(すなわち、限定領域内ではない)実行<strong>。</strong></span><span style="text-decoration: underline;"><strong>作動継続が困難な場合、利用者が介入の要求に応答することは期待されない</strong></span></p> </blockquote> <p> </p> <p>すなわち、レベル4以上の自動運転の実現には、<strong>作動継続が困難な場合でも利用者による介入を求めず、自動運転システムが周囲環境やシステムの状態を検知し安全に運行停止措置へ移行する</strong>、等の応答が求められます。</p> <p>では<strong>「作動継続が困難な場合」</strong>とはどのような場合でしょうか?ここでODDという概念が登場します。</p> <p> </p> <h4>【ODDによる走行条件定義】</h4> <p>ODD<a href="#f-ef075cc5" name="fn-ef075cc5" title="Operational design domain、運行設計領域">*2</a>とは、自動運転システムが作動する前提となる走行環境条件のことで、以下のようにいくつかのカテゴリに分けて考えることができます(参考:<a href="https://assets.ctfassets.net/rfp71c5fx4wl/2qucBNStIcWMHdv66s6l9k/218c33211025606924da8ace946b6fd7/Safety-Report-Jpn-8_11-master_compressed.pdf">Tier IV Safety Report 2020</a>、<a href="https://jidounten-lab.com/u_autonomous-odd">自動運転LAB</a>)</p> <ol> <li>道路条件:高速/一般道路、車線数、車線や歩道の有無など走行する道路に関わる条件</li> <li>地理条件:都市部/山間部/ジオフェンス内など周辺環境も含んで設定する条件</li> <li>環境条件:天候/日照/昼夜/温度など環境に関わる条件</li> <li>その他:速度制限/インフラ協調の有無/オペレータの乗車要否/連続運行時間などの運行に関わる1〜3以外の条件 </li> </ol> <p>ODDは<strong>全ての条件を満たす場合に自動運転システムが正常に作動するように定義されます</strong>。例として、先日<a class="keyword" href="http://d.hatena.ne.jp/keyword/%B9%F1%C5%DA%B8%F2%C4%CC%BE%CA">国土交通省</a>からリリースされた<a href="https://www.mlit.go.jp/report/press/content/001371535.pdf">自動運転車(レベル3)に関する発表資料</a>の主な走行環境条件で以下のような記載がありました。</p> <blockquote> <p>環境条件(気象状況)</p> <p><a class="keyword" href="http://d.hatena.ne.jp/keyword/%B6%AF%A4%A4%B1%AB">強い雨</a>や降雪による<a class="keyword" href="http://d.hatena.ne.jp/keyword/%B0%AD%C5%B7%B8%F5">悪天候</a>、視界が著しく悪い濃霧又は日差しの強い日の逆光等により自動運行装置が周辺の車両や走路を認識できない状況でないこと</p> </blockquote> <p>すなわち、上で登場した<strong>「作動継続が困難な場合」</strong>とは<strong>「走行環境が事前に定義されたODDの条件を満たさなくなった場合」</strong>と解釈することができます。このようにODDを事前に定義し、その条件の中でシステムを作動させることで、走行時の安全性を担保することが可能となります。</p> <p>一方で、ODDの極端な例として<strong>「<a class="keyword" href="http://d.hatena.ne.jp/keyword/%B0%AD%C5%B7%B8%F5">悪天候</a>(雨、雪)や霧、逆光を含まない明るい環境」</strong>と定義することもできますが、そのような場合には少しでも雨が降ったり、日が傾いて逆光になると(走行条件から外れて)システムが作動できなくなり、自動運転による本来のメリットを得ることが難しくなってしまいます。そのため自動運転システムの設計には、<span style="text-decoration: underline;"><strong>安全性を確保しつつ、同時に<span style="color: #333333; text-decoration: underline;">システムの可用性(Availability)も高めていくことが</span>求められています</strong></span>。</p> <p> </p> <p>以上を簡単にまとめますと、レベル4以上の自動運転を多くの環境で使えるものとしていくためには、システムに対して、</p> <ul> <li><strong>時々刻々と変化する走行環境に対してODD条件の評価を行い、外れた場合には縮退運転やMRM<a href="#f-dbc70012" name="fn-dbc70012" title="Minimal Risk Maneuver">*3</a>などの応答を安全に実施できること<br /></strong></li> <li><strong>雨、霧、逆光などを含む様々な走行環境で安全に走行できること</strong></li> </ul> <p>といった要素が求められます。</p> <p> </p> <h3>2、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%B0%AD%C5%B7%B8%F5">悪天候</a>環境下で生じる課題と環境センシング </h3> <p>日々の実証実験の中で様々な環境や気象条件に遭遇し課題が発生します。<br />特に<span style="text-decoration: underline;">日本の平均年間降水量は世界平均の約2倍</span>と言われており、雨や霧に関連した課題に遭遇するケースが少なくありません。</p> <p>例として、図1は急な降雨による気温低下と湿度上昇によってカメラのレンズ付近に水滴(結露)が付着し、光が回折することでカメラの画像にゴーストが生じている例です。</p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="水滴(結露)により生じたゴースト"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/K/Kaz0227/20201224/20201224090759.png" alt="f:id:Kaz0227:20201224090759p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">図1:水滴(結露)により生じたゴースト</figcaption> </figure> <p>図2はLiDARが発する赤外線が空気中の水滴によって反射されることで、あたかも障害物が存在するように見えている例です。</p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="図2:霧により生じたゴースト"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/K/Kaz0227/20201224/20201224094021.png" alt="f:id:Kaz0227:20201224094021p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">図2:空気中の水滴により生じたゴースト(点群の色は地面からの高さに相当)</figcaption> </figure> <p>これらの課題は日中の晴れた環境において生じることはほとんど無く、自然の環境変化によって偶発的に生じるため、<strong>対策の効果や再現性の確認、また体系的な評価を行うことが難しい</strong>領域となっています。</p> <p>そのような状況を解決するための一つのアプローチとして、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%CB%C9%BA%D2%B2%CA%B3%D8%B5%BB%BD%D1%B8%A6%B5%E6%BD%EA">防災科学技術研究所</a>(<a class="keyword" href="http://d.hatena.ne.jp/keyword/%B0%F1%BE%EB%B8%A9">茨城県</a><a class="keyword" href="http://d.hatena.ne.jp/keyword/%A4%C4%A4%AF%A4%D0%BB%D4">つくば市</a>)との共同研究を通して、<strong>制御された<a class="keyword" href="http://d.hatena.ne.jp/keyword/%B0%AD%C5%B7%B8%F5">悪天候</a>環境下での技術開発</strong>を進めています。 </p> <p>本共同研究では図3に示すような車両を用いて、降雨強度、視程、照度といった環境パラメタのセンシング技術の開発と、環境パラメタとシステム性能の関係のモデル化にトライしています。 </p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="図3:R&amp;D車両(通常の自動走行用のセンサに加えて、環境センシング用に照度計や降雨強度計などを搭載)"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/K/Kaz0227/20201224/20201224100525.png" alt="f:id:Kaz0227:20201224100525p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">図3:R&amp;D車両(通常の自動走行用のセンサに加えて、環境センシング用に照度計やディスドロメータ、降雨強度計などを搭載)</figcaption> </figure> <p> </p> <h3>3、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%CB%C9%BA%D2%B2%CA%B3%D8%B5%BB%BD%D1%B8%A6%B5%E6%BD%EA">防災科学技術研究所</a>との共同研究における実験内容の紹介 </h3> <p><a class="keyword" href="http://d.hatena.ne.jp/keyword/%CB%C9%BA%D2%B2%CA%B3%D8%B5%BB%BD%D1%B8%A6%B5%E6%BD%EA">防災科学技術研究所</a>の<a href="https://www.bosai.go.jp/study/rain.html">大型降雨実験施設</a>は、天井に配置された直径の異なる4種類のノズルからの流量を個別に制御することで、雨粒の分布を制御しながら、降雨強度15(mm/h)から最大約300(mm/h)までの範囲 <a href="#f-db814d40" name="fn-db814d40" title="300(mm/h)は日本の過去のゲリラ豪雨でも最も強いクラスに相当">*4</a> で人工的に雨を降らせたり、霧を発生させることができます。また、地面からノズルまで約20(m)の高さがあるため、ノズルから吐出された水滴が落下に伴って拡散し、局在の少ないより自然の雨に近い環境を再現できるように設計されています。図4に降雨実験の様子を示しました。</p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="図4:降雨実験の様子"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/K/Kaz0227/20201224/20201224102344.jpg" alt="f:id:Kaz0227:20201224102344j:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">図4:降雨実験の様子(細かい雨粒で降雨強度50mm/hを再現)</figcaption> </figure> <p>図5に降雨強度を変更しながら取得したLiDAR点群(最上段、上面図)とカメラ画像の例を示します。今回実験に用いたLiDARは波長903nmの赤外線を周囲に向けて発し、物体からの反射光の位置と強度の情報を<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%DE%A5%C3%A5%D4%A5%F3%A5%B0">マッピング</a>することで3次元の情報を得ています。今回の例では降雨強度の値が大きい50(mm/h)よりも、細かい雨粒をより多く発生させた30(mm/h)の方がLiDARでの周囲認識の性能やカメラの視界が悪化する傾向が定性的に確認できました。また、図3に示した車両に搭載された計測機器で雨粒の落下速度や大きさの分布等も計測することができているため、上記の傾向を<a class="keyword" href="http://d.hatena.ne.jp/keyword/%C4%EA%CE%CC">定量</a>的に把握してモデル化するためのデータを蓄積することができています。</p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="図5:降雨強度によるとLiDAR点群・カメラ画像の変化(点群の色は反射強度をに対応)"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/K/Kaz0227/20201224/20201224115459.png" alt="f:id:Kaz0227:20201224115459p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">図5:降雨強度によるLiDAR点群分布・カメラ画像の変化(点群の色は反射光強度に対応)</figcaption> </figure> <p> </p> <h3>4、LiDAR点群による降雨強度推定</h3> <p>環境センシングの応用例として、自動運転車両で一般に使用されているLiDARの点群情報を用いて降雨強度を推定するモデルの開発事例を紹介します。雨粒の大きさや分布と赤外線の吸収や散乱強度の間には相関があることが知られており(参考文献1)、その相関を利用してBayesian<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%E2%A5%C7%A5%EA%A5%F3%A5%B0">モデリング</a>の手法(参考文献2)に基づいてLiDAR点群(雨粒や周囲物体からの反射光の強度分布)と実測した降雨強度との関係をあらわす確率モデルを開発しています。Bayesianベースのモデルを用いることで推論結果の不確かさも同時に見積もることができるようになっています。 </p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="図6:今回開発したモデルをによる推論結果"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/K/Kaz0227/20201224/20201224160548.png" alt="f:id:Kaz0227:20201224160548p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable"> <p>図6:開発中のモデルによる推論結果の例(プロットの色は真値が予め定めた±5%のエラー範囲の外に存在する可能性の大きさを示しています)</p> </figcaption> </figure> <p>このように、制御された<a class="keyword" href="http://d.hatena.ne.jp/keyword/%B0%AD%C5%B7%B8%F5">悪天候</a>環境での系統的な評価やデータ収集を行うことで、自動運転で一般的に利用されているセンサを用いて環境パラメタの推定が行える例を示しました。このようにして得られる情報を用いて、自動運転システムを安全に運行させるために必須となる自己位置推定や物体認識といった機能の性能との対応を確認しながら、システム性能のモデル化を進めております。</p> <p>今後は降雨強度だけでなく視程(MOR)、環境照度、路面の摩擦係数などODDを定義する上で重要な様々な環境パラメタに関して研究開発を進めていきます。 </p> <p> </p> <h3>5、まとめ</h3> <p>以上、性能限界検知に関する環境センシングの開発事例をご説明させて頂きました。<br />ここまでで述べましたように、自動運転の技術開発はソフトウェアに関する部分だけではなく、自然現象に関するセンシング技術や物理解析といった分野でも多くの知見が必要となりますし、不確かさを<a class="keyword" href="http://d.hatena.ne.jp/keyword/%C4%EA%CE%CC">定量</a>的に扱うための数理的な素養なども必要になります(確率的な推論モデルの構築に関してはティアフォーのリサーチャーと共同で実施しています)。ロボットやソフトウェア開発がご専門でない方でも、我々と一緒に新しい技術開発にチャレンジしたいというパッションをお持ちの方は下のリンクより是非ご連絡頂ければ幸いです。カジュアル面談も随時受け付けております。</p> <p><iframe class="embed-card embed-webcard" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" title="Careers | 株式会社ティアフォー" src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftier4.jp%2Fcareers%2F" frameborder="0" scrolling="no"></iframe><cite class="hatena-citation"><a href="https://tier4.jp/careers/">tier4.jp</a></cite></p> <p> </p> <h3>6.謝辞</h3> <p>この報告は、国立研究開発法人<a class="keyword" href="http://d.hatena.ne.jp/keyword/%CB%C9%BA%D2%B2%CA%B3%D8%B5%BB%BD%D1%B8%A6%B5%E6%BD%EA">防災科学技術研究所</a>との共同研究「<a class="keyword" href="http://d.hatena.ne.jp/keyword/%B0%AD%C5%B7%B8%F5">悪天候</a>環境における自立移動体の外界センシング性能の検証および向上等に関する研究」(令和2年度)の成果の一部です。特に、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%BC%F2%B0%E6%C4%BE%BC%F9">酒井直樹</a>主任研究員、小林政美専門員には、降雨や実験に関する多くのご知見を共有頂きました。この場をお借りして深く感謝致します。 </p> <p>以上</p> <p> </p> <p>(参考文献)</p> <p>1: A First course in Atmospheric Radiation, Grant W.<a class="keyword" href="http://d.hatena.ne.jp/keyword/Petty">Petty</a>, Sundog Publishing,p.346-, 2006</p> <p>2: Pattern recognition and machine learning, Christpher M. Bishop, Springer, 2006</p><div class="footnote"> <p class="footnote"><a href="#fn-82663f05" name="f-82663f05" class="footnote-number">*1</a><span class="footnote-delimiter">:</span><span class="footnote-text">日本では<a class="keyword" href="http://d.hatena.ne.jp/keyword/%B8%F8%B1%D7%BC%D2%C3%C4%CB%A1%BF%CD">公益社団法人</a> <a class="keyword" href="http://d.hatena.ne.jp/keyword/%BC%AB%C6%B0%BC%D6%B5%BB%BD%D1%B2%F1">自動車技術会</a>発行の<a href="https://www.jsae.or.jp/08std/data/DrivingAutomation/jaso_tp18004-18.pdf">資料</a>において日本語で定義されています。</span></p> <p class="footnote"><a href="#fn-ef075cc5" name="f-ef075cc5" class="footnote-number">*2</a><span class="footnote-delimiter">:</span><span class="footnote-text">Operational design domain、運行設計領域</span></p> <p class="footnote"><a href="#fn-dbc70012" name="f-dbc70012" class="footnote-number">*3</a><span class="footnote-delimiter">:</span><span class="footnote-text"></strong>Minimal Risk Maneuver<strong></span></p> <p class="footnote"><a href="#fn-db814d40" name="f-db814d40" class="footnote-number">*4</a><span class="footnote-delimiter">:</span><span class="footnote-text">300(mm/h)は日本の過去の<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B2%A5%EA%A5%E9%B9%EB%B1%AB">ゲリラ豪雨</a>でも最も強いクラスに相当</span></p> </div> Kaz0227 Unity for Industryでお話した事と紹介しきれなかった事 hatenablog://entry/26006613668061895 2021-01-06T16:00:00+09:00 2021-01-06T16:00:01+09:00 皆さんこんにちは、ティアフォーでSimulationチームに所属している織田です。 先日、「Unity for Industry」と言うウェビナーで、人生初の大勢の前(?)で話す実績を解除しました。 今回のTech Blogでは、その際にお話した事と紹介しきれなかった部分を書こうかと思います。 Unityだから出来た自動運転車両の設計を加速させた話 Unity for Industryではこのタイトルでお話をしました。 お話をかいつまみますと 自動運転で使用するセンサの構成の検証が大変。 検証が可能な場所の用意や、取れるデータを推測しながら構成しなければならなかった。 上記の点を調整して、目的… <p><span style="font-weight: 400;">皆さんこんにちは、ティアフォーでSimulationチームに所属している織田です。</span></p> <p><span style="font-weight: 400;">先日、「<a href="https://www.borndigital.co.jp/seminar/19937.html">Unity for Industry</a>」と言うウェビナーで、人生初の大勢の前(?)で話す実績を解除しました。</span></p> <p><span style="font-weight: 400;">今回のTech Blogでは、その際にお話した事と紹介しきれなかった部分を書こうかと思います。</span></p> <p> </p> <h3><span style="font-weight: 400;">Unityだから出来た自動運転車両の設計を加速させた話</span></h3> <p><span style="font-weight: 400;">Unity for Industryではこのタイトルでお話をしました。</span></p> <p><span style="font-weight: 400;">お話をかいつまみますと</span></p> <ul> <li><span style="font-weight: 400;">自動運転で使用するセンサの構成の検証が大変。</span></li> <li>検証が可能な場所の用意や、取れるデータを推測しながら構成しなければならなかった。</li> <li>上記の点を調整して、目的のデータが取れなければ再度構成の見直しを行う。</li> <li>Unity/LGSVL-Simulatorを使用すれば、場所もデータ取りもシミュレーション可能になる。</li> <li>作ってみた。Unityだったので割と早めに実現できた。</li> <li>センサ構成を検討する際に、このシミュレータを使用する事で事前に構成の検証が出来る様になった。</li> <li>良かったね。</li> </ul> <p><span style="font-weight: 400;">上の様なお話をいたしました。</span></p> <p> </p> <h3><span style="font-weight: 400;">ウェビナーで紹介しきれなかった部分</span></h3> <p><span style="font-weight: 400;">下記の様な環境をシミュレーターで検証</span><span style="font-weight: 400;">しました。</span></p> <h4><span style="font-weight: 400;">10m/30m/50m/100m先に人が立っていている場合、LiDARはどの様に人が立っているのを検知出来るか?</span></h4> <p><span style="font-weight: 400;">100m先まで人がいる状態</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="100m先迄全員"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/o/odaka_tier4/20201221/20201221135021.png" alt="f:id:odaka_tier4:20201221135021p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">100m先まで人が並んでます</figcaption> </figure> <p><span style="font-weight: 400;">この時の50m地点の人のLiDARの当たり具合</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="50m先だと2line位当ってますね"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/o/odaka_tier4/20201221/20201221135148.png" alt="f:id:odaka_tier4:20201221135148p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">50m先だと2lineくらい当たってますね</figcaption> </figure> <p><span style="font-weight: 400;">同様に、この時の30m地点の人々</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="30m先では6line位当ってますね"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/o/odaka_tier4/20201221/20201221135317.png" alt="f:id:odaka_tier4:20201221135317p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">30m先では6lineくらい当たってますね</figcaption> </figure> <p><span style="font-weight: 400;">やはり100m先を見通せる広くて平らな環境と言うのは現実環境ではすぐに用意できないのでこの環境の様な検証はシミュレーターが向いていますね。<br /><br /></span></p> <p><span style="font-weight: 400;">30m先の人々と50m先の人々を比較してみると、</span><span style="font-weight: 400;">50m先の人々の方がLiDARのスキャンの間隔が開いてしまい、</span><span style="font-weight: 400;">検知可能な点が少なくなってしまう事が判別できます。</span></p> <p> </p> <h4><span style="font-weight: 400;">10%の勾配で30〜35m先の坂の上に立っている人はLiDARでどの様に検知されるか?<br /></span></h4> <figure class="figure-image figure-image-fotolife mceNonEditable" title="10%勾配で30mと35mに人々が立っています"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/o/odaka_tier4/20201221/20201221135757.png" alt="f:id:odaka_tier4:20201221135757p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">10%勾配で30〜34mに人々が立っています</figcaption> </figure> <p><span style="font-weight: 400;">30〜34m付近にいる人々</span></p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="30mから1m毎、34m迄並んで立っています"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/o/odaka_tier4/20201221/20201221140122.png" alt="f:id:odaka_tier4:20201221140122p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">30mから1m毎、34mまで並んで立っています</figcaption> </figure> <p><span style="font-weight: 400;">こちらのケースも、実世界では10%勾配に見事にマッチする環境を探すのは難しいですが、</span><span style="font-weight: 400;">シミュレーターでは勾配を変更した場合のケースも値を変更することですぐに用意できます。<br /><br /></span></p> <p><span style="font-weight: 400;">30〜34m先の人々には勾配の先にいると言う事もあってか、</span><span style="font-weight: 400;">先の平地での30m先の人に比べると全くと言って良い程LiDARのスキャンが届かない様に見えます。</span></p> <p> </p> <h4><span style="font-weight: 400;">LiDARを車両のどの位置に、どの様な角度で設置するとどの範囲を測定できるのか?</span></h4> <figure class="figure-image figure-image-fotolife mceNonEditable" title="計測範囲を可視化"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/o/odaka_tier4/20201221/20201221140459.png" alt="f:id:odaka_tier4:20201221140459p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">計測範囲を可視化した図</figcaption> </figure> <p><span style="font-weight: 400;">ここでは、追加で作成したLiDARが測位する範囲を可視化させた物を設定する事で</span><span style="font-weight: 400;">測定範囲を可視化しています。</span><span style="font-weight: 400;">緑、黄、青の範囲の外側だと、車両が停止している場合に計測できない領域となる箇所が</span><span style="font-weight: 400;">一目瞭然ですね。</span><span style="font-weight: 400;"><br /></span></p> <p> </p> <h3><span style="font-weight: 400;">課題</span></h3> <p><span style="font-weight: 400;"><a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B2%A1%BC%A5%E0%A5%A8%A5%F3%A5%B8%A5%F3">ゲームエンジン</a>/センサシミュレーションでもまだ解決出来ない問題はあるのです。</span></p> <h4><span style="font-weight: 400;"><a class="keyword" href="http://d.hatena.ne.jp/keyword/%B0%AD%C5%B7%B8%F5">悪天候</a></span></h4> <p><span style="font-weight: 400;">雨/霧等、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B2%A1%BC%A5%E0%A5%A8%A5%F3%A5%B8%A5%F3">ゲームエンジン</a>では画面上のビジュアルに向けた実装は多いですが、</span><span style="font-weight: 400;">センサで取れるデータと言うものに関しての考慮はやはりされていないので、</span><span style="font-weight: 400;">どの様に実装するのかは現状の課題になっています。</span></p> <p><span style="font-weight: 400;"><br /></span><span style="font-weight: 400;">とは言え、何も手が無い訳ではなくて例えば<a class="keyword" href="http://d.hatena.ne.jp/keyword/Uber">Uber</a> Advanced Technology Groupが</span><span style="font-weight: 400;">LiDARsimと言う形で、現実的なセンサのデータに近付けるといった研究をされていたりします<a href="#f-8a6a0e82" name="fn-8a6a0e82" title="https://arxiv.org/pdf/2006.09348.pdf">*1</a>。</span></p> <p><span style="font-weight: 400;">こちらを応用したりすれば、解決していける課題になっていくのではないかと今は考えてます。</span></p> <p> </p> <h4><span style="font-weight: 400;">データを効率良く捌く</span></h4> <p><span style="font-weight: 400;">センサシミュレーションで取るデータは現状</span></p> <ul> <li><span style="font-weight: 400;">LiDARによる点群計測</span></li> </ul> <p><span style="font-weight: 400;">が主なのですが、計測する為の点群のデータ量はかなり膨大で、</span><span style="font-weight: 400;">且つ高頻度で</span><span style="font-weight: 400;">効率良く処理する方法も課題となっています。</span></p> <p> </p> <h3><span style="font-weight: 400;">まとめ</span></h3> <p><span style="font-weight: 400;">現実では用意が難しい環境でもシミュレータによって検証出来るようになり、</span><span style="font-weight: 400;">事前にどの様なデータが取れそうか?等が容易に検証できる様になりました。</span></p> <p><span style="font-weight: 400;">この辺は<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B2%A1%BC%A5%E0%A5%A8%A5%F3%A5%B8%A5%F3">ゲームエンジン</a>の面目躍如です。</span></p> <p><span style="font-weight: 400;">又、新たなセンサの構成を検証する際にもリアルタイム且つ柔軟に</span><span style="font-weight: 400;">センサの確認が出来るのも<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B2%A1%BC%A5%E0%A5%A8%A5%F3%A5%B8%A5%F3">ゲームエンジン</a>だから可能になったと言えるでしょう。</span></p> <p>ティアフォーでは、自動運転の安心・安全を確保し「自動運転の<a class="keyword" href="http://d.hatena.ne.jp/keyword/%CC%B1%BC%E7%B2%BD">民主化</a>」をともに実現してくため、様々なエンジニア・リサーチャーを募集しています。もしご興味があればカジュアル面談も可能ですので以下のページからコンタクトいただければと思います。</p> <p> </p> <p><iframe class="embed-card embed-webcard" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" title="Careers | 株式会社ティアフォー" src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftier4.jp%2Fcareers%2F" frameborder="0" scrolling="no"></iframe><cite class="hatena-citation"><a href="https://tier4.jp/careers/">tier4.jp</a></cite></p> <p> </p> <p>又、2020年1月29日(金)の夕方にはTech Meetupを開催する予定ですので、もしお時間が合う方はご参加下さい。</p> <p><iframe class="embed-card embed-webcard" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" title="Tier IV 自動運転Web&amp;Dataミートアップ (2021/01/29 19:00〜)" src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftier4.connpass.com%2Fevent%2F198897%2F" frameborder="0" scrolling="no"></iframe><cite class="hatena-citation"><a href="https://tier4.connpass.com/event/198897/">tier4.connpass.com</a></cite></p><div class="footnote"> <p class="footnote"><a href="#fn-8a6a0e82" name="f-8a6a0e82" class="footnote-number">*1</a><span class="footnote-delimiter">:</span><span class="footnote-text"></span><a href="https://arxiv.org/pdf/2006.09348.pdf"><span style="font-weight: 400;">https://arxiv.org/pdf/2006.09348.pdf</span></a><span style="font-weight: 400;"></span></p> </div> odaka_tier4 ROS2 rmwを切り替えてpub/sub通信しよう hatenablog://entry/26006613662299848 2020-12-23T16:00:00+09:00 2021-01-04T09:27:49+09:00 こんにちは、ティアフォーエンジニアの村上です。今回は、ROS 2の通信機能に関するお話をしたいと思います。 自動運転OSSの「Autoware」は、ROS 2の上に構築されており*1、ROS 2はその通信 (出版/購読) backendとしてDDS (Data Distribution Service) を採用しています。多くのプロセスからなるAutowareにおいて、通信は注目すべき要素です。安心・安全な自動運転の実現のためには、Autowareの機能自体はもちろんのこと、通信のようなbackendについて、各systemに対するtuningをすることは不可欠です。 今回はそのROS 2/D… <article> <section> <p><span style="color: #111111; font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, 'Hiragino Kaku Gothic Pro', Meiryo, 'MS PGothic', sans-serif; font-size: 15.2px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none;">こんにちは、ティアフォーエンジニアの村上です。今回は、ROS 2の通信機能に関するお話をしたいと思います。</span></p> <p>自動運転OSSの「Autoware」は、ROS 2の上に構築されており<a href="#f-38eb314c" name="fn-38eb314c" title="Autoware.AIはROSで動くように設計されていたがAutoware.AutoはROS 2上で動くように設計されている">*1</a>、ROS 2はその通信 (出版/購読) backendとしてDDS (Data Distribution Service) を採用しています。多くのプロセスからなるAutowareにおいて、通信は注目すべき要素です。安心・安全な自動運転の実現のためには、Autowareの機能自体はもちろんのこと、通信のようなbackendについて、各systemに対するtuningをすることは不可欠です。 今回はそのROS 2/DDSについて調査した時のreportです。</p> <section> <h2>ROS 2のProtocol Stack</h2> <p>従来のROS (便宜上ROS 1と呼称します) においては、独自の出版/購読の仕組みを実装していましたが、ROS 2ではDDSのAPI等をinterfaceとして、具体的な出版/購読の実装をROS本体から分離しました。このlayerこそがrmw (ROS MiddleWare)です。我々は各DDS実装に対するrmwを使用することで、application側でコードを変更することなく、各DDS実装を切り替えて使用することができます。</p> <p>下記の図は、ROS 2の、特に通信に着目したProtocol Stackです。</p> <center><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/j/james-murakami/20201208/20201208113128.png" alt="f:id:james-murakami:20201208113128p:plain" title="" class="hatena-fotolife" itemprop="image" /></center> <p><br /> backendは様々なものを考えることが可能で、layerというものではありません。例えばPOSIXで提供されているある種のprocess間通信、RTPSのような通信protocol、RTOS (Realtime OS) でサポートされている特殊な通信API、直接Network-on-Chipなどのhardwareを扱うなんてことも考えられるでしょう。<br /> このように、rmwやrclcによって、個別の実装は隠蔽されており、各backendに適したrmwを使いわけることで、tuningを行うことができます。</p> <p>ここまでの用語を整理しておきましょう。</p> <dl> <dt><span style="text-decoration: underline;"><strong>RMW (ROS Middleware)</strong></span></dt> <dd>各DDS実装あるいは各backendの差を吸収、あるいは最適化を施している層。rclcに対して共通のinterfaceを提供する。</dd> <dd></dd> <dt></dt> <dt><span style="text-decoration: underline;"><strong>DDS (Data Distribution Service)</strong></span></dt> <dd>publish/subscribe programmingを実現するAPIを規定する。同じ立ち位置のAPIとしては、例えばSocketやMPIがある。</dd> <dd></dd> <dd></dd> <dt><span style="text-decoration: underline;"><strong>RTPS (Real Time Publish-Subscribe)</strong></span></dt> <dd>transport-layerよりも上層に位置する通信protocolの一つ。同じ立ち位置の仲間としてはHTTPなど。protocolの位置関係は、DDS API over [RTPS/UDP/IP/Ethernet]のようになる。</dd> </dl> </section> <section> <h2>共有メモリを使用するrmw</h2> <p>Autowareの通信を考えるとき、いかにも最適化できそうなものとして、例えば以下のような特徴があります。</p> <ul> <li>高性能sensor群からの大きなdataの通信が存在するが、出版者と購読者が1対1で、dataを出版後に参照することはない</li> <li>GPGPUを活用している認識以外の大部分の処理は、1 hostで処理されている計算機systemである</li> </ul> <p>帯域量を求めるROS node間通信と応答時間を求めるROS node間通信は、Autowareにおいて混在していますが、今回は後者の応答時間を考えたいと思います。</p> <p>応答時間に対するROS 1での最適化については、nodeletを積極的に使用していました。<br /> nodeletは1 processの中で複数のnodeを実行する仕組みであり、その通信はpointer passing、所謂参照渡しとして実装できます。ROS 2においてもこの仕組みはexecutorという、より発展した形として提供されておりますが、これらが共通して抱えている課題点はapplication levelでの変更が必要な点です。nodeletを使用しない場合、ROS 1では、たとえ1 hostの計算機で閉じていようが、socket API over [TCP or UDP]経由の通信しかできません。</p> <p>対してROS 2では、先に触れたrmwより下層の切り替えのみで最適化を行うことができ、applicationへの変更は一切必要ありません。</p> <p>それでは実際に、今回の条件に適しているであろう、rmw_iceoryxを使用してみたいと思います。iceoryxはshared memory上でのdata転送を効率よく行う仕組みを提供しており、今回のようなlocalhost上限定の状況では、よい選択肢となります。このような転送はiceoryxの専売特許というわけではありませんので、実際にrmwの選定を行うときには、より広い選択肢があるでしょう。<br /> (するどい方は、DDSのAPI等と濁したことに気がついているかもしれませんが、iceoryxはDDSのAPIを提供しているわけではありません。今回はrmwをI/Fとしますので、DDSに類する機能を内包さえしてしまえば、stackは厳密に積まれる必要はないのです。)</p> </section> <section> <h2>rmw_iceoryxの応答時間評価</h2> <h3>rmw_iceoryxのbuild</h3> 環境は、Ubuntu 18.04 <a href="https://index.ros.org/doc/ros2/Installation/Eloquent/">ROS 2 Eloquent</a>です。<br /> rmw_iceoryxは<a href="https://github.com/ros2/rmw_iceoryx/tree/eloquent">github</a>からcloseしてきてください。<br /> <p>基本的には、rwm_icoryxのreadmeのInstallationを参考にしますが、最後のcolcon buildにおいて、下記2点に注意してください。</p> <ul> <li>sys/acl.hがない場合; <per><code>apt install libacl1-dev</code></per></li> <li>rosidl_runtime_cのcmake用のconfigがない場合; rmw_iceoryxがmaster(foxy用)かもしれません。eloquent用のbranchに切り替えてください。 <pre><code>cd src/rmw_iceoryx; git checkout -b eloquent origin/eloquent</code></pre> </li> </ul> <h3>サンプルプログラム</h3> <p>今回使用する<a href="https://github.com/harihitode/pubsub">pub/sub サンプルプログラム</a>は、2MB/100msのtopicをpublish/subscribeさせ、その間のlatencyを出力するprogramです。この2MB/100msの数字は、高性能なsensor一つの出力を模しています。</p> <h2>実行</h2> <ol> <li>まず、shared memory及びその上のpub/subを監督する処理を立ち上げます。<br /> <pre><code>./iceoryx_ws/install/iceoryx_posh/bin/iox-roudi</code></pre> </li> <li>次に、以下のようにRMW_IMPLEMENTATIONを指定して、sample programを起動します。<br /> <pre><code>source /opt/ros/eloquent/setup.bash source iceoryx_ws/install/setup.bash source pubsub/install/setup.bash RMW_IMPLEMENTATION=rmw_iceoryx_cpp ros2 launch comm inter_process_pubsub.launch.py</code></pre> </li> </ol> <p>環境変数RMW_IMPLEMENTATIONを特に設定しなければ、default(fastrtps)による通信が行われます。また、latencyの出力については、launcherの設定で~/.ros/log/[日時]/launch.log以下に出すようにしています。</p> </section> <section> <h2>動作比較</h2> <p>応答速度としては、Fast RTPS &gt; Ice Oryx &gt; executorが予想されます。それぞれ応答速度と引き換えに制限が発生します。それは1 hostの制限であったり、単一障害点の発生であったり、published dataを参照するnode数 etc…であったりです。 また、使用したrmwはそれぞれdefaultの設定を使用しており、tuningの余地は十分にあります。</p> <h2>Fast RTPS (Default DDS)</h2> 上述の通り、何も設定しない状態でのpubl/subです。 <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/j/james-murakami/20201208/20201208163417.png" alt="f:id:james-murakami:20201208163417p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <h3>Process内 (executor)</h3> rmw層下の話からは逸れる話ですが、先に触れたprocess内のpubsubでは、実装やコーディング制限が伴う可能性はあるものの、それに見あうだけの非常に高速な応答性があります。今回はsingle thread executorを使用しました。起動方法としては<code>ros2 launch comm intra_process_pubsub.launch.py</code>で起動できます。 <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/j/james-murakami/20201208/20201208163522.png" alt="" title="" class="hatena-fotolife" itemprop="image" /></p> <h3>Ice Oryx (固定長message)</h3> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/j/james-murakami/20201208/20201208163537.png" alt="" title="" class="hatena-fotolife" itemprop="image" /></p> <h3>Ice Oryx (可変長messega)</h3> 上述のサンプルプログラムの<code>variable_message</code>ブランチで計測ができます。固定長との違いは、message typeで<code>std_msgs/ByteMultiArray</code>を指定している点です。 <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/j/james-murakami/20201208/20201208163552.png" alt="" title="" class="hatena-fotolife" itemprop="image" /></p> </section> <section> <h4>最後に</h4> <p>今回は実験として、rmwを切り替えた時の応答速度の変化を見てみました。話を簡単にするため、Autowareではなくsample programの上で観測しましたが、Autowareにおいても十分期待ができる結果です。また、rmwの切り替えだけという、非常に簡単な方法でtuningができるということも実感できました。ただし、観測結果については通信以外の部分の考慮をしていないため、厳密な評価ではないでしょう。それでも、大雑把にこれだけの差が出ることは、大変に興味深い結果です。</p> <p>ティアフォーでは、今回ご紹介したように、自動運転ソフトウェアの開発だけでなく、自動運転という最先端のApplicationに対するECU/Middlewareの設計開発も行っており、自動運転の安心・安全を確保し「自動運転の民主化」をともに実現してくため、様々なエンジニア・リサーチャーを募集しています。もしご興味があればカジュアル面談も可能ですので以下のページからコンタクトいただければ幸いです。</p> <p><iframe class="embed-card embed-webcard" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" title="Careers | 株式会社ティアフォー" src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftier4.jp%2Fcareers%2F" frameborder="0" scrolling="no"></iframe><cite class="hatena-citation"><a href="https://tier4.jp/careers/">tier4.jp</a></cite></p> </section> <section> <h4>補遺、参照</h4> <ol> <li><a href="https://design.ros2.org/articles/ros_on_dds.html">ROS on DDS</a> (ROS本家tech. blog)</li> <li>ECU; 車載向けのcontroller(計算機)の意味。完全自動運転が要求するspecは、通常の車載system、自動運転支援systemと比べても幾分か高い。性能及び組み込み的な安全性を考慮する点は、非常に挑戦的である</li> <li>rmw-[implementationの名前]; 各DDS/RTPSに対するrmw側実装。<a href="https://github.com/ros2">github</a>上に存在はしても、Full Supportか否かは別途確認が必要がある点に注意</li> <li>ゼロコピー転送; 通信時にコピーが発生しない転送。process間のshared memory上を介した実装がIce-Oryx。process内のpointer passingによる転送もゼロコピー転送。転送先のみがそのデータを使用する場合に有効で、応答速度やメモリ消費量が改善する。そうでない一般の通信はコピーが必要だが、大きいデータを扱う時は注意が必要。以下の例では700MBほどの地図データが何重にもコピーされてしまっている<br /> <img src="https://cdn-ak.f.st-hatena.com/images/fotolife/j/james-murakami/20201208/20201208165755.png" alt="" title="" class="hatena-fotolife" itemprop="image" /></li> </ol> </section> </section> </article><div class="footnote"> <p class="footnote"><a href="#fn-38eb314c" name="f-38eb314c" class="footnote-number">*1</a><span class="footnote-delimiter">:</span><span class="footnote-text">Autoware.AIはROSで動くように設計されていたがAutoware.AutoはROS 2上で動くように設計されている</span></p> </div> james-murakami Web.Auto 全体チーム社内開発レビュー会を開催しました hatenablog://entry/26006613661646885 2020-12-09T16:00:00+09:00 2020-12-16T15:20:19+09:00 こんにちは、ティアフォーでWebサービス開発を行っている桑原です。 今回はティアフォーが開発をリードしている自動運転ソフトウェア「Autoware」の開発・実証実験を支え、自動運転サービスのために必要なWebの基盤を開発しているチームの活動と開発しているWebアプリケーションの概要を紹介します。 Web.Auto 全体チーム開発レビュー会 ティアフォーが開発しているWeb.Autoは、IoT・Cloud技術を用いて、様々な組織・個人が迅速かつ簡単に自動運転テクノロジーにアクセス可能となり、自動運転サービスに関する幅広い課題を解決できる基盤となることを目指しているサービスです。自動運転サービスを… <p><span style="font-weight: 400;">こんにちは、ティアフォーで<a class="keyword" href="http://d.hatena.ne.jp/keyword/Web%A5%B5%A1%BC%A5%D3%A5%B9">Webサービス</a>開発を行っている桑原です。</span></p> <p><span style="font-weight: 400;">今回はティアフォーが開発をリードしている自動運転ソフトウェア「Autoware」の開発・実証実験を支え、自動運転サービスのために必要なWebの基盤を開発しているチームの活動と開発しているWebアプリケーションの概要を紹介します。</span></p> <h2><span style="font-weight: 400;">Web.Auto 全体チーム開発レビュー会</span></h2> <p> </p> <p>ティアフォーが開発している<a href="https://web.auto/ja/"><strong>Web.Auto</strong></a><span style="font-weight: 400;">は、IoT・Cloud技術を用いて、様々な組織・個人が迅速かつ簡単に自動運転テク<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%CE%A5%ED">ノロ</a><a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B8%A1%BC">ジー</a>にアクセス可能となり、自動運転サービスに関する幅広い課題を解決できる基盤となることを目指しているサービスです。自動運転サービスを導入・運用するための多くのWebアプリケーションを開発しています。</span></p> <p> </p> <p class="center"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/k/kuwabara_tier4/20201207/20201207132552.png" alt="f:id:kuwabara_tier4:20201207132552p:plain" title="" class="hatena-fotolife, center" itemprop="image" width="441" /></p> <p> </p> <p><span style="font-weight: 400;">今回 Web.Autoチームではこれらのサービスが顧客に届ける価値をより高めるために、自動運転ソフトウェアの開発から実際に自動運転サービスが届けられるまでのWebアプリケーションの利用例をユーザーストーリーとして作成して、各アプリケーションが実際に使われるイメージ全体を共有するチーム横断の開発レビュー会を行いました。</span></p> <p> </p> <p><span style="font-weight: 400;">この会の目的としては以下の通りです。</span> </p> <ul> <li style="font-weight: 400;"><span style="font-weight: 400;">チームで閉じた開発であったり、機能ベースの開発ではなく、どのようなものが顧客に取って価値になるか考え、プロダクトを市場に届けるところまで考えれるようになる</span></li> <li style="font-weight: 400;"><span style="font-weight: 400;">自分の担当するシステムやチームの中での<a class="keyword" href="http://d.hatena.ne.jp/keyword/%C9%F4%CA%AC%BA%C7%C5%AC">部分最適</a>な開発ではなく、横断的な開発ができるようになる</span></li> </ul> <p> </p> <p><span style="font-weight: 400;">自動運転技術においては専門的な知識が多く、Webアプリケーションの開発でも多角的な観点から開発するのが難しくなってしまうので、この会を通して目指しているビジョンを再認識して、開発が促進できるように開催されました。</span></p> <p> </p> <h3><span style="font-weight: 400;">Web.Auto サービスの全体ユーザーストーリー</span></h3> <p> </p> <p><span style="font-weight: 400;">実際に自動運転のサービスを提供する場合、大きく分けて以下のフローを踏んで自動走行が可能であることを確認します。実際にはもっと多くの細かい手順がありますが、ここではWebアプリケーションで補助できる部分に限った大まかなユーザーストーリーとなっています。</span></p> <p> </p> <ol> <li style="font-weight: 400;"><span style="font-weight: 400;">自動運転ソフトウェアの開発とテスト</span></li> <li style="font-weight: 400;"><span style="font-weight: 400;">自動運転サービスのための事前準備</span></li> <li style="font-weight: 400;"><span style="font-weight: 400;"><a class="keyword" href="http://d.hatena.ne.jp/keyword/%BC%C2%BC%D6">実車</a>試験</span></li> <li style="font-weight: 400;"><span style="font-weight: 400;">自動運転サービスの運用と監視</span></li> <li style="font-weight: 400;"><span style="font-weight: 400;">自動運転の走行分析</span></li> </ol> <p> </p> <p><span style="font-weight: 400;">次に各手順に沿ってストーリーの詳細を紹介します。</span></p> <h4><span style="font-weight: 400;">1. 自動運転ソフトウェアの開発とテスト - Testbed &amp; CI/CD Pipeline</span></h4> <p> </p> <p><span style="font-weight: 400;">自動運転ソフトウェア「Autoware」の開発・評価を、安全を担保しながら信頼性高くかつ効率的に行えるようにするための開発者向けのテスト評価フローです。</span></p> <p><span style="font-weight: 400;">自動運転ソフトウェアの開発者が機能の改良を加え、テストを実行・評価して、<a class="keyword" href="http://d.hatena.ne.jp/keyword/%BC%C2%BC%D6">実車</a>テストまで行う作業の障壁を軽減するためのユーザーストーリーです。このセッションのレビュー会の内容は以下になります。</span></p> <ul> <li><span style="font-weight: 400;">自動運転車に取り付けるセンサーのシミュレーション</span></li> <li style="font-weight: 400;"><span style="font-weight: 400;">自動運転ソフトウェア「Autoware」のシミュレーションテスト</span></li> </ul> <ol> <li style="font-weight: 400;"><span style="font-weight: 400;">車両の構成などをまとめたファイルの作成</span></li> <li style="font-weight: 400;"><span style="font-weight: 400;">テストの要件からテストシナリオを作成</span></li> <li style="font-weight: 400;"><span style="font-weight: 400;">テストの実行</span></li> <li style="font-weight: 400;"><span style="font-weight: 400;">テスト結果の確認・リプレイ</span></li> <li style="font-weight: 400;"><span style="font-weight: 400;">Web.Auto基盤から接続車両に配信可能状態なパッケージを生成</span></li> </ol> <p> </p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="シミュレーションのリプレイ画像"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/k/kuwabara_tier4/20201207/20201207133102.png" alt="f:id:kuwabara_tier4:20201207133102p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">シミュレーションのリプレイ画像</figcaption> </figure> <p><span style="font-weight: 400;">Webアプリケーションでこれらを確認することで、早く安全に<a class="keyword" href="http://d.hatena.ne.jp/keyword/%BC%C2%BC%D6">実車</a>テストを行うことを可能にします。</span></p> <p><span style="font-weight: 400;">より詳細な内容は以下の記事で紹介しています。</span></p> <p><iframe class="embed-card embed-blogcard" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" title="ティアフォーにおけるシミュレーションを用いたCIの取り組み - Tier IV Tech Blog" src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftech.tier4.jp%2Fentry%2F2020%2F09%2F09%2F160000" frameborder="0" scrolling="no"></iframe><cite class="hatena-citation"><a href="https://tech.tier4.jp/entry/2020/09/09/160000">tech.tier4.jp</a></cite></p> <p> </p> <p> </p> <h4><span style="font-weight: 400;">2. 自動運転サービスのための事前準備 - Setup for Self-driving Services </span></h4> <p> </p> <p><span style="font-weight: 400;">自動運転車サービスには配車管理コンソールへの車両の登録と接続の設定、自動運転ソフトウェアや車両アプリケーションのインストール、地図の設定が必要です。ユーザーストーリーとしては自動運転車サービスを運用する管理者のサービスの準備となります。このセッションのレビュー会の内容は以下の通りです。</span></p> <ul> <li style="font-weight: 400;"><span style="font-weight: 400;">配車管理コンソールでプロジェクトと走行環境の設定</span></li> <li style="font-weight: 400;"><span style="font-weight: 400;">車両と配車管理コンソールが接続できるように車両の証明書を発行し、車両に設定</span></li> <li style="font-weight: 400;"><span style="font-weight: 400;">自動運転車両で使用する地図を<a href="https://tools.tier4.jp/">地図ツール</a>から配車管理コンソールにアップロード</span></li> <li style="font-weight: 400;"><span style="font-weight: 400;">配車管理コンソールから車両へ「1. 自動運転ソフトウェアの開発とテスト - Testbed &amp; CI/CD Pipeline」の手順で生成したパッケージを配信</span></li> </ul> <p> </p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="地図ツール画面"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/k/kuwabara_tier4/20201207/20201207133431.png" alt="f:id:kuwabara_tier4:20201207133431p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">地図ツール画面</figcaption> </figure> <p><span style="font-weight: 400;">これらのIoT・Cloud技術で車両の管理やサービスを扱う準備を一層簡単にすることで、自動運転サービスをより早くまた安全性高く提供することができます。</span></p> <p> </p> <h4><span style="font-weight: 400;">3. <a class="keyword" href="http://d.hatena.ne.jp/keyword/%BC%C2%BC%D6">実車</a>試験 - Operation for Self-driving Vehicles</span></h4> <p> </p> <p><span style="font-weight: 400;">自動運転車の現地試験運用を迅速かつ安全に行えることを目指した、車両オペレーターによる開発車両運用中のフローです。現在は自動運転車の車両が安全に運行できるように車両オペレーターが実際に自動運転車両が正常に動いているかどうかを監視しているので、ここでは車両オペレータが監視して<a class="keyword" href="http://d.hatena.ne.jp/keyword/%BC%C2%BC%D6">実車</a>の走行をテストするユーザーストーリーになります。</span></p> <p><span style="font-weight: 400;">ティアフォーが行っている実証実験では、実際にオペレーターが以下の走行を監視しています。</span></p> <blockquote class="twitter-tweet"> <p dir="ltr" lang="ja">基準緩和申請を行えば時速20キロまでなら運転席<a class="keyword" href="http://d.hatena.ne.jp/keyword/%CC%B5%BF%CD">無人</a>の自動運転タクシーを運行できるようになりました。次回は時速30キロ、複数台、広域エリアでの運行を目指します。 <a href="https://t.co/1myurA3tBq">pic.twitter.com/1myurA3tBq</a></p> — <a class="keyword" href="http://d.hatena.ne.jp/keyword/Shinpei">Shinpei</a> Kato (加藤真平) (@ShinpeiKato) <a href="https://twitter.com/ShinpeiKato/status/1324726288163106816?ref_src=twsrc%5Etfw">November 6, 2020</a></blockquote> <p> <script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> </p> <p> </p> <p><span style="font-weight: 400;">オペレーターが自動運転の状態監視を行えることで安全に<a class="keyword" href="http://d.hatena.ne.jp/keyword/%BC%C2%BC%D6">実車</a>のテスト走行を実行することが可能になっています。</span></p> <p> </p> <h4><span style="font-weight: 400;">4. 自動運転サービスの運用と監視 - Management for Self-driving Services</span></h4> <p> </p> <p><span style="font-weight: 400;">自動運転車サービスの運用を迅速に、安全に、簡単に行えるようにする運用管理者・遠隔監視者・車両オペレーター・サービスユーザー向けのサービス運用中のフローです。自動運転の運行事業者が自動運転車両のサービスを提供するエリアに関して、走行の環境や地図を更新して、自動運転車両の配車サービスを運用するというユーザーストーリーになります。今回のレビュー会では<a class="keyword" href="http://d.hatena.ne.jp/keyword/%BC%C2%BC%D6">実車</a>ではなく、自動運転の走行を模擬するシミュレータを使って仮想的にサービスを確認しました。</span></p> <ul> <li style="font-weight: 400;"><span style="font-weight: 400;">運行管理コンソールから自動運転車両を配車リク<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A8%A5%B9">エス</a>ト</span></li> <li style="font-weight: 400;"><span style="font-weight: 400;">車載<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%BF%A5%D6%A5%EC%A5%C3%A5%C8">タブレット</a>から出発ボタンを押して走行</span></li> <li style="font-weight: 400;"><span style="font-weight: 400;">運行管理コンソールから自動運転の走行の状態を確認</span></li> <li style="font-weight: 400;"><span style="font-weight: 400;">運行管理コンソールから車両のカメラ映像を確認</span></li> </ul> <p> </p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="運行管理コンソール画面"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/k/kuwabara_tier4/20201207/20201207143756.png" alt="f:id:kuwabara_tier4:20201207143756p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">運行管理コンソール画面</figcaption> </figure> <p> </p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="車載タブレット画面"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/k/kuwabara_tier4/20201207/20201207133614.png" alt="f:id:kuwabara_tier4:20201207133614p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">車載<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%BF%A5%D6%A5%EC%A5%C3%A5%C8">タブレット</a>画面</figcaption> </figure> <p> </p> <p><span style="font-weight: 400;">運行管理に関しては以下の記事で紹介しています。</span></p> <p><iframe class="embed-card embed-blogcard" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" title="ドメイン駆動設計による運行管理システムのアーキテクチャの最適化 - Tier IV Tech Blog" src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftech.tier4.jp%2Fentry%2F2020%2F07%2F03%2F160000" frameborder="0" scrolling="no"></iframe><cite class="hatena-citation"><a href="https://tech.tier4.jp/entry/2020/07/03/160000">tech.tier4.jp</a></cite></p> <p> </p> <p> </p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="遠隔監視・運転システム画面"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/k/kuwabara_tier4/20201207/20201207142102.png" alt="f:id:kuwabara_tier4:20201207142102p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">遠隔監視・運転システム画面(※画面ははめ込みです)</figcaption> </figure> <p><br /><span style="font-weight: 400;">また遠隔からの操縦に関する取り組みは以下の記事で紹介しています。</span></p> <p><iframe class="embed-card embed-blogcard" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;" title="ティアフォーにおける自動運転車両の遠隔監視・操縦システムのご紹介 - Tier IV Tech Blog" src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftech.tier4.jp%2Fentry%2F2019%2F01%2F22%2F170032" frameborder="0" scrolling="no"></iframe><cite class="hatena-citation"><a href="https://tech.tier4.jp/entry/2019/01/22/170032">tech.tier4.jp</a></cite></p> <p> </p> <h4><span style="font-weight: 400;">5. 自動運転の走行分析 - Inspection for Self-driving Services </span></h4> <p> </p> <p><span style="font-weight: 400;">自動運転車サービスの運用や開発のフィードバックのための運用管理者・開発者向けのサービス監視・評価のフローです。運行事業者や自動運転ソフトウェアの開発者が蓄積された走行データを分析して、サービス運用および開発のフィードバックを行うことができるようになります。また、実際に走行したプローブデータを収集して蓄積し、分析しやすい形で走行ごとに車両の状態を振り返ることができます。運用管理者が走行テストや自動運転サービスが終了したのちに自動走行の安全性の分析をするユーザーストーリーなります。</span></p> <p> </p> <figure class="figure-image figure-image-fotolife mceNonEditable" title="走行履歴画面"> <p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/k/kuwabara_tier4/20201207/20201207144004.png" alt="f:id:kuwabara_tier4:20201207144004p:plain" title="" class="hatena-fotolife" itemprop="image" /></p> <figcaption class="mceEditable">走行履歴画面</figcaption> </figure> <p><br /> </p> <h2><span style="font-weight: 400;">まとめ</span></h2> <p> </p> <p><span style="font-weight: 400;">Web.Auto チームでは以上の他にも様々なシステムとアプリケーションを開発しています。今回は半日かけて自動運転のサービスを提供するまでのユーザーストーリーについてレビュー会を開催しました。本レビュー会は、テックカンファレンスのようにそれぞれのアプリケーションの担当が開発背景やシステムの概要を発表し、実際動くデモを発表する形で進めました。</span></p> <p><span style="font-weight: 400;">このレビュー会を通して、自分が担当するシステム以外の開発がどのようにユーザーまでつながっているかを一貫して全Web.Autoチームで見ることでより良い改善を進めることができています。いずれは勉強会やテックカンファレンスなどで「自動運転の<a class="keyword" href="http://d.hatena.ne.jp/keyword/%CC%B1%BC%E7%B2%BD">民主化</a>」に向かって、</span><span style="font-weight: 400;">今回説明したものよりさらに改善が進んだアプリケーション・システムを紹介していきたいと思います。</span></p> <p>ティアフォーでは、自動運転の安心・安全を確保し「自動運転の<a class="keyword" href="http://d.hatena.ne.jp/keyword/%CC%B1%BC%E7%B2%BD">民主化</a>」をともに実現してくため、様々なエンジニア・リサーチャーを募集しています。もしご興味があればカジュアル面談も可能ですので以下のページからコンタクトいただければと思います。</p> <p> </p> <p><iframe class="embed-card embed-webcard" style="display: block; width: 100%; height: 155px; max-width: 500px; margin: 10px 0px;" title="Careers | 株式会社ティアフォー" src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Ftier4.jp%2Fcareers%2F" frameborder="0" scrolling="no"></iframe><cite class="hatena-citation"><a href="https://tier4.jp/careers/">tier4.jp</a></cite></p> kuwabara_tier4