Unityで、磁気浮上を模擬するプログラムを作成しました。
#1. 要求事項
[1] 磁気浮上アクチュエータを2個とする。
[2] 磁気浮上アクチュエータは浮上体の下面につける。
[3] ある位置に停止させる(定位置制御)
#2. 実施事項
[1] 磁気浮上アクチュエータを子オブジェクトとする。
[2] 浮上体は親オブジェクトとして、磁気浮上アクチュエータである子オブジェクトをFixed Jointで固定する。
#3. 具体的な実施事項
・親オブジェクトに追加するスクリプトから、子オブジェクトを読み出し、子オブジェクトに重力に反する力を発生させる。
・定位置制御として、位置P速度PI制御及び重力補償を加える。
動画が埋め込められないので、状況は分かりにくいですが、スクリプトのみを添付しますので、
参考になればと思います。
#4. スクリプト
###4.1 コード
using UnityEngine;
public class Carrier_Control : MonoBehaviour
{
public Rigidbody carrier;
private double f1;
private double f2;
private double posY_old1 = 0;
private double posY_old2 = 0;
private double posY_old = 0;
private double Kp = 20;
private double Kv = 20;
private double Ts = 1;
private double Ki = 0.02;
private double M = 10;
private double G = 9.8;
private double Mg;
private double velY_old = 0;
private double velY = 0;
private double refV = 0;
private double refV_old = 0;
// Start is called before the first frame update
void Start()
{
Mg = M/2 * G;
}
// Update is called once per frame
void FixedUpdate()
{
Transform myTransform = this.transform;
Vector3 pos = myTransform.position;
Transform mag1Transform = transform.GetChild(0).gameObject.GetComponent<Transform>();
Transform mag2Transform = transform.GetChild(1).gameObject.GetComponent<Transform>();
Vector3 magPos1 = mag1Transform.position;
Vector3 magPos2 = mag2Transform.position;
velY = (pos.y - posY_old)/Ts;
refV = (0.45 - pos.y) * Kp;
f1 = (refV-velY_old) * Kv + (refV + refV_old - velY_old) * Ki * Kv;
f2 = (refV-velY_old) * Kv + (refV + refV_old - velY_old) * Ki * Kv;
Vector3 force1 = new Vector3(0.0f, (float)(f1*M/2+Mg), 0.0f);
Vector3 force2 = new Vector3(0.0f, (float)(f2*M/2+Mg), 0.0f);
Rigidbody mag1 = transform.GetChild(0).gameObject.GetComponent<Rigidbody>();
Rigidbody mag2 = transform.GetChild(1).gameObject.GetComponent<Rigidbody>();
mag1.AddForce(force1);
mag2.AddForce(force2);
posY_old1 = magPos1.y;
posY_old2 = magPos2.y;
posY_old = pos.y;
velY_old = velY;
refV_old = refV - velY_old;
}
}
##4.2 コードのポイント
Qiitaの参考記事にもありますが、Unityの基本はgameObjectを利用することであり、Transformクラスをコンポーネントとして取得し、さらに、位置情報を取得する点。
Transform mag1Transform = transform.GetChild(0).gameObject.GetComponent<Transform>();
Transform mag2Transform = transform.GetChild(1).gameObject.GetComponent<Transform>();
Vector3 magPos1 = mag1Transform.position;
Vector3 magPos2 = mag2Transform.position;
Rigidbodyクラスをコンポーネントとして取得し、子オブジェクトに力を発生させる点。
Rigidbody mag1 = transform.GetChild(0).gameObject.GetComponent<Rigidbody>();
Rigidbody mag2 = transform.GetChild(1).gameObject.GetComponent<Rigidbody>();
mag1.AddForce(force1);
mag2.AddForce(force2);
#5. 感想
Unityをうまく使いこなすには、GameObjectの理解が重要ですね。参考記事1
ちなみに、データの逐次計算部分は、FixedUpdate()を利用してください。
Update()では浮上させることができませんでした。