9
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

制御工学Advent Calendar 2023

Day 23

制御のゲーム

Last updated at Posted at 2023-12-22

はじめに

倒立振子で相撲をしよう。
というゲーム『Stable Master』(親方の意)を作ったのでプレアルファですが公開します。
こちらから触ってみてください。

image.png

基本ルール

力士のモデル

力士は下図のような車輪型倒立振子として表されています。プレイヤーは車輪の並進速度と振子の角度(+ユーザ入力)から車輪のトルクを決定する制御器を実装することで力士を操作します。

デフォルトでは左右キーまたはA/Dキーでそれぞれの方向のトルクが印加されます。

image.png

ゲームルール

トップページのSTARTボタンからゲームを開始できます。
image.png

  • 相撲と同じく、土俵内で振子部分が接地するか、土俵外に出た場合負けとなります。
  • 力士はそれぞれ「スタミナ」が定められており、スタミナ量は画面上部のバーで表示されます。
  • スタミナは印加トルクの2乗に比例して消費され、時間経過で回復します。
  • スタミナが0になった場合、一定時間トルクが印加できなくなります。

image.png

制御器設計

ユーザは力士を制御するためのコントローラを設計することができます。
トップページのDESIGNボタンで設計画面を開きます。

image.png

設計画面右側のテキストボックスにMiniscriptを使って制御用スクリプトを記述することで、力士の挙動を変更できます。

image.png

Miniscriptの文法はこちらをご参考ください。

このスクリプトでは、ゲーム側が事前に設定した以下の変数をグローバルに使用できます。

  • initialize: 初期化フラグ。このスクリプトはゲーム開始前の初期化時に一度、ゲームが始まってからは毎サンプルごとに呼び出されます。初期化時にはこの変数がinitialize = 1に、ゲーム開始後は0に設定されます。
  • wheel_velocity: 車輪部の右向き並進速度です。
  • pole_rotation: 振子部の右回り角度です。
  • horizontal_input: ユーザからの左右キーボード入力(矢印キーまたはA/Dキー)です。左入力の場合-1、右入力の場合1が設定されます。
  • space_input: ユーザからのスペースキー入力です。押下時1、解放時0が設定されます。

デフォルトでは以下のスクリプトが設定されており、PID制御を実装しています。

// Predefined Variables
//  - initialize:
//      Initialization flag. 1(True), 0(False)
//  - wheel_velocity: 
//      Horizontal velocity of wheel. (right is positive)
//  - pole_rotation:
//      Angle of pole. (deg, clockwise is positive)
//  - horizontai_input:
//      Horizontal axis input from keyboard. ([-1.0, 1.0])
//  - space_input:
//      Space bar input flag. (1(pressed), 0(released))

// Write initialization code here
if initialize == 1 then
    // Define PID controller class
    PID = {
        "gain_p": 0,
        "gain_i": 0,
        "gain_d": 0,
        "error_sum": 0,
        "error_previous": 0 }

    // Step method
    PID.Step = function(error)
        self.error_sum = self.error_sum + error
        control = self.gain_p * error +
            self.gain_i * self.error_sum +
            self.gain_d * (error - self.error_previous)
        self.error_previous = error

        return control
    end function

    // Instantiate controller
    pid = new PID
    pid.gain_p = 5.0
    pid.gain_i = 0.0
    pid.gain_d = 5.0

    // Define function calculates angular difference
    AngleDiff = function(a1, a2)
        diff = a1 - a2
        if abs(diff) < 180 then
            return diff
        else
            return diff - sign(diff) * 360
        end if
    end function

// Write code for control here
else
    // Feedback control
    error = AngleDiff(pole_rotation, 0)
    torque = pid.Step(error) + 10 * horizontal_input
end if

スクリプトの長さやメモリ使用量にゲーム側で制限は掛けていませんが、10 ms以内に実行が完了しない場合にはエラーが表示されます。

9
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?