Code Game Challengeは、学生の間で大きな関心を呼んでいる刺激的な競技形式です。 11月にボルゴグラードで開催されたロボティクス、組み込みシステム、コンピュータービジョンに関するIV全ロシアユーススクール(
http://roboschool.org )の一環として、私たちは参加者に新しい何かを提示したいと考えました。 そこで、ロボットとCGCを組み合わせるというRoboCGCのアイデアが生まれました。 カットの下の詳細。

エントリー
ですから、初心者にとっては、古典的なCGCが何であるかを気にかけますが、十分な情報はありません。
こちらと
こちらを読むことができ
ます 。
RoboCGCとは何ですか? これは、参加者の戦略がシミュレーターだけでなく、実際のロボットでも開始される古典的なコードゲームチャレンジです。 それ以外の場合、違いはありません。参加者は同じ方法でロボットを制御するプログラムを実装し、シミュレータで起動して作業の質を評価します。 シミュレーターでは、競技の主催者が提供する基本的な戦略や、他の参加者の戦略にアクセスできます。
今回、ゲームの世界では、参加者はレーザーを搭載したロボットを制御するタスクに直面していました。 レーザーはロボットに固定され、調整されます。 レーザーのボレー(発射体)の速度は無限です。 銃自体には3つの状態があります。
- 再装填-射撃の瞬間から銃を再装填できる瞬間まで、再装填時間が経過しなければなりません。
- シンプル-銃がリロードされたが、電荷を蓄積し始めていない場合、それはアイドル状態です。
- 電荷蓄積-ユーザーのコマンドで、機械はアイドルモードから電荷蓄積モードに切り替わります。
銃のチャージが最大値に達するとすぐに、ショットが自動的に行われます。 さらに、ユーザーは充電開始から自動ショットまでいつでも強制的にショットを発射できます。 ヒットで与えられるダメージは、蓄積された電荷に直線的に依存します。
マップには2つのロボット(チームごとに1つ)といくつかの障害物があります。 障害物は可動性です-ロボットはそれらを押すことができます。
浸漬
次に、システム自体に進みましょう。
システムはいくつかのコンポーネントで構成されています。

各モジュールを個別に検討します。
カスタム戦略
ユーザークラスインターフェイスは非常にシンプルで、ゲームワールドのすべてのステップで呼び出される1つの関数のみで構成されています。 ユニットの位置とその状態に関する情報、障害物の位置に関する情報、ゲーム世界に関する情報(プレイ時間、フィールドサイズなど)を含むゲーム世界に関する情報が機能に送信されます。
#pragma once #include "Common/IWorld.h" using namespace GameWorld::Strategy; namespace Client { namespace Strategy { class Player { public: void Move(IWorld* world); }; } }
ユーザーは単一のファイル内で作業できます。 1つのファイルがサーバーに送信されてコンパイルされます。 サーバーでは、このファイルは、シミュレーターとの対話を提供するラッパーを使用してコンパイルされます。
以前は、DLLモデルを使用していました。ユーザー戦略は別々のDLLにコンパイルされ、シミュレーターに読み込まれ、シミュレーターはこのDLLのメソッドを呼び出しました。 今回は個々のプロセスのモデルに切り替えました-この場合、いくつかの利点があります:実行時間とメモリ消費のより自由な制御(制限に違反した場合、シミュレータで多くのヒープが悪化したり、リリースされないままになる恐れなく、単に戦略でプロセスを終了します)リソース)。 クライアントコードとゲームワールドモジュール間の相互作用は、ソケットを介して実行されます。
ユーザーコードシーケンスは次のとおりです。

メッセージを送信するために、アライメントされた構造を使用しました-追加のシリアライゼーション/デシリアライゼーションなしで最も簡単な方法です。
ゲームの世界に関する情報を含むパッケージのタイトルは次のようになります。
struct StateHeader { int TotalUnits; // int TotalObstacles; // int Tick; // double Width; // double Height; // int CurrentTeam; // int TotalTeams; // int IsFinished; // };
1つのユニットに関する情報は、構造によって設定されます。
struct UnitDTO { double X; // double Y; // Y double Angle; // double Radius; // int Charge; // int HP; // int TeamId; // int Id; // };
障害物情報:
struct ObstacleDTO { double X; // double Y; // Y double Angle; // double Radius; // int Id; // };
プレイヤーの進捗状況に関する情報を含むパッケージのタイトル:
struct ControlHeader { int TotalUnits; // , int IsCrashed; // «» char Name[31]; // };
ユニットのアクションに関する情報:
struct UnitControlDTO { double LeftControl; // double RightControl; // bool IsStartCharging;// bool Fire; // int UnitId; // };
スターターモジュール
このモジュールは、構成の読み取り、適切な環境(シミュレーターまたはハードウェアプラットフォーム)の作成、ユーザー戦略の開始、ゲームサイクルの実装を担当します。
ゲームワールドの説明は、ロボットの物理特性(半径、ホイールベース、ホイール直径など)、シミュレーションパラメーター(フィールドサイズ、シミュレーション期間、プレイヤー数、各プレイヤーのユニット数、障害物の数を設定できる構成ファイルによって設定されます。 、銃の特性など)、開始パラメータ(ロボットと障害物の初期位置)、ハードウェアプラットフォーム構成(ロボットのIPアドレス、ロボットと障害物のマーカー)。
構成を読み取った後、シミュレーターまたはハードウェアプラットフォームのいずれかの環境が作成されます。 両方の環境のインターフェイスは同じであるため、それらの操作は同じです。
class IEnvironment { public: virtual void Initialize(boost::shared_ptr<GameWorld::Internal::World> world) = 0; virtual void Step() = 0; virtual bool CloseRequested() = 0; virtual bool Paused() = 0; virtual bool Idle() = 0; };
次に、ユーザー戦略のプロセスが開始され、環境の準備が整うまで待機します(必要なものについては、以下で説明します)。 環境の準備が完了するとすぐに、開始メッセージが戦略に送信され、シミュレーションサイクルが開始されます。その中で、戦略メッセージがゲームワールドの状態とともに各戦略に送信され、ユーザーの反応で応答が期待されます。 この段階では、ユーザーコードの実行時間が制御されます。答えが設定時間に到達しなかった場合、ユーザー戦略は終了します。 すべての戦略から回答を受け取った後、それらは処理されます-データは処理される環境に転送され、ゲームワールドの状態が更新されます。 その後、次の反復への移行があります。
シミュレーションモジュール
シミュレーションモジュールは、参加者がコンテストの対面部分で戦略をテストするために使用されます(つまり、戦略の作成)。 シミュレーターは単純なグラフィックを持ち、物理学(衝突、ヒット)などをシミュレートします。

ハードウェア相互作用モジュール
最も複雑で興味深いモジュール。 このモジュールは、ロボットにコマンドを送信し、現在の座標も受信します。
システムが実行されているコンピューターですべてのロジックが実行され、結果のコマンドのみがロボットに送信されます(エンジン制御のレベルで、LEDのステータスを設定します)。 ロボットと通信するには、コンピューターサーバーと両方のロボットが接続されているWiFi接続が使用されます。
現在の座標を取得するには、カメラを競技場の上に置き、移動するすべてのオブジェクトにマーカーを接着します。 シミュレーション中に、マーカーが認識され、その位置が決定されます。
カメラとして、第1世代のIntel RealSenseを使用しました。 長いUSBケーブルで作業しているときに第2世代のカメラに問題があったため、最初のバージョンに切り替えました。
シミュレータとは異なり、ロボットの準備が整うまで待機する必要があるため(ロボットが接続されていることを確認してください)、環境状態の中間段階を導入しました-ロボットが接続されるとすぐに、環境は準備メッセージを送信します。
モジュールは、マーカーの検索と位置の決定に加えて、拡張現実オブジェクトもレンダリングします。 競技中、カメラからの写真はプロジェクターに放送されました。 カメラ画像に加えて、ロボットの状態が表示され、ショットが描かれました。

ロボット
ロボットはIntel Galileoに基づいています。 さらに、エンジン管理用のMotorShiledとWiFiモジュールがインストールされました。 また、LEDを制御するためにシフトレジスタボードが作成されました(ArduinoにMotorShieldをインストールした後、空きピンはほとんどありません)。 3.3-9 Vの範囲で動作する2つのDCモーターがアクチュエーターとして使用され、これはすべて7.4 V x 1500 mAのli-poバッテリーで駆動されていました。

トーナメントソフトウェア
さらに、トーナメントソフトウェア(クライアントとサーバー)を準備しました。これらは、競技のフルタイムの部分で使用されました。 サーバーは、コンパイル用のカスタム戦略の送信とコンパイル済み戦略の受信、および他の参加者のコンパイル済み戦略の受信とシミュレーションを許可しました。

どうでしたか
インストールアセンブリ:

問題と解決策
コンテストの開発および実施中に、多くの問題に遭遇しました。いくつかは決定しましたが、バグに取り組むために残ったものもありました。
カメラ
最初は、フィールドの片側に立つカメラを使用することを計画しました

ただし、テストプロセス中に、フィールドの遠端にあるオブジェクトの認識が非常に悪いことがわかりました。 そのため、角度を変えるためにカメラを強く上げるか、カメラをフィールドの上に吊るす必要がありました。 その結果、後者のオプションを決定しました。

照明
大きな問題は照明のちらつきでした。 放電ランプのちらつきを補正するために、追加の画像処理をしたくありませんでした。 その結果、問題は松葉杖で「バックアップ」されました-25フレーム(つまり、フリッカー周波数の倍数の周波数)に切り替わり、しきい値コントラストの小さな調整が追加されました。
Wifi
最初は、アンテナのない2つのWiFiモジュールがありました。 一般に、これは開発には十分でしたが、最初の段階では、このオプションはそれ以上の作業では機能しないことが明らかになりました。 その結果、ロボットにはアンテナが装備されました。
ポジショニング
システムの組み立てと分解が繰り返し行われ、部品の配置(カメラに対するフィールド)が絶えず変化するため、キャリブレーション手順を追加しました-インストール後にマーカーを所定の位置に配置し、キャリブレーションを行って、次の起動のために構成ファイルに保存しました。
物理学
最大の問題。 シミュレーターの物理学は、最終的に実際のロボットの物理学とは異なりました。 この違いは、いくつかのコンポーネントで構成されていました。
- タイムラグ-シミュレータでは、参加者はすぐに実際の位置を受け取りました。ハードウェアプラットフォームの場合、ロボットの位置を少し遅れて取得しましたが、それは「オーバーシュート」につながり、多くのロボットが左右に曲がることができました。
- •物理学自体の違い-シミュレーターと実際の障害物の動きの物理学は対応していませんでした(質量に少し欠けていたため、実際の障害物はより困難に動きました)。
さらなる開発
すべての困難にもかかわらず、学生は私たちのイベントに興味があり、既存の問題を排除し、すべてのアイデアを実現するためにプラットフォームを開発する予定です。
ゲームの仕組みに関する重大な制限は、シェルを視覚化できないことでした。 これは、フィールド上にプロジェクターを配置することで解決できます。これにより、競技場に追加のオブジェクトが投影されます。 これにより、さまざまなメカニズムが可能になります。ボーナス、有限速度のシェル、健康状態の表示、その他の条件を追加できます。 さらに、これは興味深いタスクです。
競技場のサイズを増やしたいのですが、ここでは1台のカメラに制限されていました。 そのため、複数のカメラを使用する計画があります。