ETロボコン2020 競技会場システムのおはなし (フォローアップ)

毎年恒例イベントのオンライン化、ふたつ目の事例紹介です。

[前回の記事](https://qiita.com/tetsuya-ooooo/items/d62a983da9887050c6ca)は、筆者が所属する事業部のキックオフを動画配信することによってオンライン化したというお話でした。

今回は、[ETロボコン](https://www.etrobo.jp/)の試走会と競技会を「オンラインで開催」しました。[チャンピオンシップ大会のワークショップ (シミュレータ競技よもやま話)](https://www.jasa.or.jp/expo/event/robocon.html) で サラッとお話ししましたが持ち時間が短かったので、ここでフォローアップしてみようと思います。
※動画は[こちら](https://youtu.be/EWCLrX2mj6Q)
※スライドは[こちら](https://www2.slideshare.net/tetsuyaodashima/et2020)
※こちらの動画もどうぞ→[(1)](https://youtu.be/XJ3cE9BqdO8) [(2)](https://youtu.be/PjsamdGNVXo) [(3)](https://youtu.be/lNX-QjdOMnA)

# はじめに

筆者は、[ETロボコン](https://www.etrobo.jp/) を企画・運営する[実行委員会](https://www.etrobo.jp/staff/)に参画しています。毎年、[技術教育、試走会、地区大会、チャンピオンシップ大会](https://www.etrobo.jp/%e5%88%9d%e5%8f%82%e5%8a%a0%e3%81%ae%e6%89%8b%e5%bc%95%e3%81%8d/)と開催していました。

しかし、今年は新型コロナウイルスの影響ですべての集合形式のイベントを中止しましたが、**ETロボコンの目的である「技術教育の機会を提供する」という歩みを止めてはいけない**という強い思いから、[「オンラインモデリング教育＆シミュレーター競技」を提供しようと決断](https://www.etrobo.jp/et2020-enforcement-policy/)しました。

※ETロボコンの詳しい内容は、[チャンピオンシップ大会のパンフレット](https://docs.etrobo.jp/information/ET2020panf.pdf)をご覧ください。
※身内が言うのもアレですが、とても素敵なかんじにできています。(これ、実行委員の有志で作成しているんですよ)

筆者のミッションは、**「ETロボコンシミュレーター」を使って、ヴァーチャル試走会、ヴァーチャル競技会のプラットフォームを整えて実現させること**でした。プラットフォームはもちろん[「Microsoft Azure」](https://azure.microsoft.com/ja-jp/overview/what-is-azure/?WT.mc_id=AZ-MVP-5003113)です！

なお、Azure 上に展開した環境を**「ETロボコン2020 競技会場システム」**と名付けました。
そして、その「ETロボコン2020 競技会場システム」の全体像は :point_down: こんなかんじです。

![202011etrobotechws_p10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230264/b1de63e0-036b-9c57-64c6-e1965028246c.png)


# ETロボコンシミュレーターとは

試走会、競技会で使用するETロボコンシミュレーターは、TOPPERS プロジェクト[「箱庭WG」](https://github.com/toppers/hakoniwa)のメンバーが研究開発している組み込みマイコンシミュレーターと、実行委員の有志が開発した [「EV3/シミュレーター開発環境」](https://github.com/ETrobocon/etrobo/)から構成されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230264/761f6a6b-06f4-e9db-e214-81e7bf837d99.png)


# ヴァーチャル競技会って、どこでやるのよ？

ビビってしまうくらい:scream:、ものすごい勢いで開発が進められ、着々とアップデートを重ねていましたが、「そもそも、これ、どこで動かすのよ？」と有志メンバーには考える余裕はなかったと察します。

![202011etrobotechws_p5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230264/e4dc18a0-64b8-ac34-36a9-e14e9dad7114.png)


## シミュレーター環境はどこで動かすのよ？

なので、「EV3/シミュレーター開発環境」が快適に動作する環境を探しました。以下は、その調査記事です。参加チームのみなさんに「開発するために高スペックな高価な PC を購入する」以外の選択肢として、クラウド、「Azure」があることを示すつもりで記事にしました。

- [Azure VM で ET ロボコン EV3/シミュレータ開発環境を構築しよう (準備編)](https://qiita.com/tetsuya-ooooo/items/29aca6eb9587e501e033)
- [Azure VM で ET ロボコン EV3/シミュレータ開発環境を構築しよう (NV/NVv3 シリーズ編)](https://qiita.com/tetsuya-ooooo/items/dd640004f6fb23ed85fe)
- [Azure VM で ET ロボコン EV3/シミュレータ開発環境を構築しよう (NVv4 シリーズ編)](https://qiita.com/tetsuya-ooooo/items/4b05897128abd8109a05)

と調べた結果、「NVシリーズ」の仮想マシンが[スペック](https://docs.microsoft.com/ja-jp/azure/virtual-machines/nv-series?WT.mc_id=AZ-MVP-5003113)的にも[料金](https://azure.microsoft.com/ja-jp/pricing/details/virtual-machines/windows/?WT.mc_id=AZ-MVP-5003113)的[^1]にも最適だと判断しました。

![202011etrobotechws_p12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230264/37f044c0-ed7b-346b-96c7-a6cd1d3ba553.png)

NVシリーズの仮想マシンの GPU[「NVIDIA Tesla M60」](https://www.nvidia.com/ja-jp/data-center/graphics-cards-for-virtualization/)のドライバー[「NVIDIA GRID ドライバー」をインストール](https://docs.microsoft.com/ja-jp/azure/virtual-machines/windows/n-series-driver-setup?WT.mc_id=AZ-MVP-5003113)すると、[「NVIDIA コントロール パネル」](https://www.nvidia.com/content/Control-Panel-Help/vLatest/ja-jp/mergedProjects/nvcplJPN/Understanding_the_NVIDIA_Control_Panel_Interface.htm)も併せてインストールされます。
「NVIDIA コントロール パネル」は、グラフィックボードの基本設定や設定変更、調整を行うための専用ソフトウェアです。これを使えばグラフィックボードの 3D に関する設定項目の変更や調整が柔軟にできます。ここも採用したポイントですね。

これで「EV3/シミュレーター開発環境」が快適に動作する環境は無事見つかりました。

なお、ここが 2020 年大会の**「競技会場」**となります。

※Azure AD に仮想マシンをデバイス参加させているのは、Windows 10 ライセンスをアクティベートするためです。
[参考：Azure Windows 10 VM に Azure AD ユーザーで RDP 接続したい (主に接続元のはなし)](https://qiita.com/tetsuya-ooooo/items/5896b0f77b2cf3d685dc)


## 参加チームのみなさんにシミュレーター環境をどうやって使わせるのよ？

当初 API を用意しようとがんばっていたのですが時間的に余裕が無くなってしまい、Web サイトを設けることにしました。
※当初から API だけでなく UI も必要だろうという話もありました。
※結果的に SPA[^2] っぽい Web アプリになりました。

なお、ここは前述の競技会場の窓口的な役割を果たすので**「受付カウンター」**と名付けました。

ここでは、以下のようなことを行っています。

1. 参加チームから走行リクエスト (プログラム) を受け取り ※アップロード
2. そのリクエストを競技会場にパスして
3. 競技会場で、提出されたプログラムに従って走行体 (ロボット) を走行させ
4. 競技会場から走行結果 (走行動画やログなど) が返され
5. 参加チームに走行結果を返す ※ダウンロード

どこで時間がかかってしまったかというと、ちょっと目新しい [Microsoft Identity Web 認証ライブラリ](https://docs.microsoft.com/ja-jp/azure/active-directory/develop/microsoft-identity-web?WT.mc_id=AZ-MVP-5003113) (.NET Core 3.1 向け) をどうしても使いたくて勉強がてらチャレンジしてみましたが、ちょっと苦戦してしまいました。:disappointed_relieved:

その時、以下の記事などを参考にしていました。

[参考：Web Apps · AzureAD/microsoft-identity-web Wiki](https://github.com/AzureAD/microsoft-identity-web/wiki/web-apps)
[参考：Web APIs · AzureAD/microsoft-identity-web Wiki](https://github.com/AzureAD/microsoft-identity-web/wiki/web-apis)
[参考：How to build a Blazor web app with Azure Active Directory authentication and Microsoft Graph](https://developer.microsoft.com/en-us/identity/blogs/how-to-build-a-blazor-web-app-with-azure-active-directory-authentication-and-microsoft-graph/?WT.mc_id=AZ-MVP-5003113)

![202011etrobotechws_p13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230264/fe5312ca-8888-1e72-43f0-49ad9e046b6e.png)

アプリの認証は、Office 365 などでも使われている [Azure AD](https://docs.microsoft.com/ja-jp/azure/active-directory/fundamentals/active-directory-whatis?WT.mc_id=AZ-MVP-5003113) で認証しています。なぜ、Azure ADを使うのかというと、Office 365向けに完璧に実装されたセキュリティを活かすことができること、非機能要件の一部をAzure ADに任せられることなどによって、認証まわりの開発コスト、管理コストが下げられるというメリットがあるので、積極的に利用しています。

アプリに認証機能を実装するだけでひとつのアプリを開発するくらいたいへんなんです。認証機能を任せられるおかげで、アプリのことだけに集中できますね。

![202011etrobotechws_p14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230264/5749dd2a-817e-f09b-c53d-086c970ec96e.png)

ついでに言うと、参加チーム用に設けた「マイページ (kintone)」も Azure AD 連携して認証を任せられる (ID をひとつにする) こともできますよ。
※マイページ開設時は、こんな状況になるとは思っていなかったのでやっていない。

これで、参加チームのみなさんが「シミュレーター環境」利用できるようになりました。

※Azure AD では誰がいつサインインしたかなどの監査情報を確認することができます。試走会期間中にこのレポートを都度確認し、参加者に対してフォローを行っていました。
[参考：Azure AD ユーザーアカウントの棚卸しに便利なスクリプト](https://qiita.com/tetsuya-ooooo/items/02e66dd35a102792402c)

...で、ここまでだけで満足するのはちょっとモッタイナイので、もっともっとクラウドならではのメリットを魅せたいですねぇ :sunglasses: ...ということで、まだまだ続きます。


# 参加チームにたくさん試走させたい！

試走会は、9 月と 10 月にそれぞれ 1 週間程度の期間で実施しました。

試走会開始のタイミングでは、どんなものかと覗いてみるかんじでリクエストはバーンっと上がるんですが、しばらくするとシーンと静まり返ったように見受けられました。
せっかく「競技会場」を開放しているので、こちらとしてはもっと使って欲しいんですよ。

という思いから、(勝手に) **「試走会参加状況レポート」**を用意することにしました。はじめは、このレポートを実行委員会で共有して、実行委員から参加チームに対して~~煽って~~フォローしてもらおうと思っていましたが、もうちょっと加工 (チーム名などを伏せる) して参加チームに見せちゃおうということになりました。

![202011etrobotechws_p15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230264/7f668c5b-1cc2-625e-45e2-a6cb0004b636.png)

このレポートは、[Power BI](https://docs.microsoft.com/ja-jp/power-bi/fundamentals/power-bi-overview?WT.mc_id=AZ-MVP-5003113) で作成しています。レポートの元ネタは主に「受付カウンター」で管理している「リクエスト」データです。ただ、レポート下部の折れ線グラフ「時間帯ごとのリクエスト数」については、「リクエスト」データ (実績) だけでは表現することが難しいので、別途時系列データ (予定) を CSV ファイルで用意しました。

これらのデータを表やグラフを用いてイメージしやすい形に加工して、参加チームにバーンっと公開するだけで、「どれくらいのチームが走ったのかな」、「あるチームはこんなに走っているのか」、「この時間帯は空いてそうだ」とチーム内で作戦を練っていただろうと想像できます。(そうであって欲しい...:sweat_smile:)


# 異議申し立てボット！

試走会後、参加チームから「受付カウンター」に最終的なプログラムを提出してもらい、「競技会場」でそのプログラムを実行する「競技会」を 11 月初旬に催しました。
※そこから上位チームの競技は「チャンピオンシップ大会[^3]」でお披露目しました。

で。競技会の競技結果が参加チームに公開され、競技判定に対する異議申し立てを受け付けます。異議申し立ては ([Microsoft Forms](https://support.microsoft.com/ja-jp/office/bb1dd261-260f-49aa-9af0-d3dddcea6d69?WT.mc_id=AZ-MVP-5003113) などで) フォームを用意して、そこから送信してもらえば良いですが、送信されるたびに受付担当者が実行委員会に異議内容を速攻で共有する (すぐに審議したいために) のはとてもめんどくさいです。この作業を自動的にできたらラクちんだなーと思って、異議申し立てが送信されたら [Slack](https://slack.com/intl/ja-jp/) にメッセージ投稿する**「異議申し立てボット」**を作りました。

![202011etrobotechws_p16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230264/e5e7bf1e-fa9b-cf6b-a55e-1a3610726d0e.png)

このボットは [Azure Logic Apps](https://docs.microsoft.com/ja-jp/azure/logic-apps/logic-apps-overview?WT.mc_id=AZ-MVP-5003113) で作りました。[「Microsoft Forms」](https://docs.microsoft.com/ja-jp/connectors/microsoftforms/?WT.mc_id=AZ-MVP-5003113)、[「Slack」](https://docs.microsoft.com/ja-jp/connectors/slack/?WT.mc_id=AZ-MVP-5003113)、[「Azure SQL Database」](https://docs.microsoft.com/ja-jp/connectors/sql/?WT.mc_id=AZ-MVP-5003113)の[コネクタ](https://docs.microsoft.com/ja-jp/azure/connectors/apis-list?WT.mc_id=AZ-MVP-5003113)が揃っているので、数時間でパパっと出来上がりました。

どれくらいカンタンなのか、実際のワークフローを見てみましょう。

はじめに、[トリガー](https://docs.microsoft.com/ja-jp/connectors/microsoftforms/?WT.mc_id=AZ-MVP-5003113#when-a-new-response-is-submitted)で通知を受け取りたい Microsoft Forms のフォームを指定して、その[異議内容を取得](https://docs.microsoft.com/ja-jp/connectors/microsoftforms/?WT.mc_id=AZ-MVP-5003113#get-response-details)します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230264/c0e79a58-0560-b2f8-9e6f-009e50a21cc9.png)

次に、[Azure SQL Database](https://docs.microsoft.com/ja-jp/azure/azure-sql/database/sql-database-paas-overview?WT.mc_id=AZ-MVP-5003113) に格納してあるチーム情報を取得します。
チーム情報を取得するためには [SQL クエリ](https://docs.microsoft.com/ja-jp/connectors/sql/?WT.mc_id=AZ-MVP-5003113#execute-a-sql-query-(v2))を条件を指定して実行するのですが、異議申し立てフォームから受け取った異議内容の値をその SQL クエリに直接入れてしまうと、SQL インジェクションが通ってしまうおそれがあるのでちょっと対策しておきます。

まず、SQL クエリで `@id` を使用するように変更します。これは、[formalParameters オプション](https://docs.microsoft.com/ja-jp/connectors/sql/?WT.mc_id=AZ-MVP-5003113#using-formalparameters)を使用して宣言されたパラメーター「id」です。キーはパラメーター名であり、値のデータ型はテーブル定義と一致している必要があります。
そして、この「id」パラメーターの値として異議申し立てフォームから受け取った異議内容の値を設定することができます。
これで、SQL インジェクション対策はバッチリです。:ok_woman:

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230264/bb2f45ae-2dc3-169f-0e3e-fbecd8f32f9c.png)

最後に、[Slackにメッセージを投稿](https://docs.microsoft.com/ja-jp/connectors/slack/?WT.mc_id=AZ-MVP-5003113#post-message)します。
下図のように、投稿先の「チャネル」を選択してメッセージを編集します。メッセージはテキストに異議申し立てフォームから受け取った異議内容の値をペタペタ貼っていくかんじで編集できます。カンタンですね。
あとは、Slackにメッセージを投稿する際に表示させる名前 (ボット名) とアイコンを指定します。カンタンですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230264/ec961e0d-218d-5ad0-bf9c-3a67d9e98b13.png)


# まとめ

例年の試走会、競技会をオンライン化してみて、どんなことになったかというのを筆者になりに以下のようにまとめてみました。

- **昼夜問わず、ほぼ無人で稼働する環境** :sunny: :sparkles:
    - 例年は
        -  場所を借り、事前に会場を設営し、当日は各自の役割を果たす (多くの実行委員が稼働)
        -  チームは、事前に予約した時間枠に参加する、試走できる時間 (数時間) は限られている
    - 今年は
        - 今までより圧倒的な少人数で試行錯誤して準備を進める (構築する)
        - 昼夜問わず、ほぼ無人で稼働する環境を手に入れることができた
        - チームは好きな時に試走でき、試走期間中 (1週間程度) は今まで以上に有益な活動ができただろう
- **すべての活動がデータ化、そして見える化** :floppy_disk: :bar_chart:
    - 今までは、どのチームがいつ参加したかくらいは分かっていた (ほぼ人力ですが) が、今年はさらにどのチームがいつ、どれくらい試走したかが把握できる
    - 蓄えたデータを見える化、そして公開がとてもカンタンに
- **参加者のみなさんと協力して、より良いシステムづくり** :couple_ww:
    - 事例 (1) 走行中もキャンセルできれば、もっと多くのチームが試走できるのに...
        - チーム自ら”走行終了を宣言”できる機能を追加！
    - 事例 (2) ぜんぜん順番 (試走) が回ってこないよー
        - 走行順を決めるロジックを改善！ (過剰だった"優しさ"を緩和)
    - **多謝！** :heart_eyes:

最後まで読んでいただきありがとうございました。
この記事で紹介した内容がみなさんの業務や知識の向上に少しでもお役に立てればと思います。


[^1]: NV Promo NV シリーズを採用。キャンペーン価格で 40% 割引だった。このキャンペーンは 2020/10/31 で終了。
[^2]: [Single Page Application とは](https://digitalidentity.co.jp/blog/creative/about-single-page-application.html)
[^3]: [オープニング](https://youtu.be/yvVGV2RgvV0)と[空前絶後のオンラインチャンピオンシップ大会](https://youtu.be/M4eNyIlBuzU)と[裏チャンネル(おすすめ)](https://youtu.be/PNQp3yUsWbY)