【Unity】UnityとMATLAB/Simulinkの連携【Simulink】

本記事の概要

UnityとMATLAB/SimulinkをTCP/IP通信で接続します。MATLAB/Simulink側で設定した「角加速度」、「重心高さ」、「質量」をUnity側に送信し、Unity内の物理エンジンで独楽を回します。

主な項目

1.使用環境
2.Unityの紹介
3.Unityのセットアップ
4.Unity新規プロジェクト作成
5.Unityの画面構成
6.Unityシーンビューの操作
7.Unityシーンのセットアップ
8.MATLAB/Simulinkの紹介
9.MATLAB/Simulinkのセットアップ
10.MATLABの画面構成
11.MATLABスクリプトの作成
12.Simulinkの画面構成
13.Simulinkモデルの作成
14.システム実行

1.使用環境

・Unity:LTS推奨バージョン 2021.3.12f1

・MATLAB:R2022 b

・OS:Windows10 22H2

2.Unityの紹介

Unityとは、Unity Technologiesが開発・販売しているゲームエンジンです。PC、モバイル機器、家庭用ゲーム機、VR・AR・MR機器など幅広いプラットフォームに対応している上、個人であれば無料でほとんどの機能にアクセスできるため、導入ハードルが低いです。主な用途はゲーム開発ですが、動画制作や、産業分野などのシミュレーション、アプリケーション開発など、様々な活用事例があります。主なプログラミング言語はC#です。

※Unityの名称、ロゴなどは、米国およびその他の国における Unity Technologies またはその関係会社の商標または登録商標です。

https://unity.com/ja

3.Unityのセットアップ

・UnityHubのインストール

まずは、Unityのプロジェクトやバージョン管理をしてくれるソフト、UnityHubをインストールします。下記のサイトからインストーラーをダウンロードしましょう。
https://unity.com/ja/download

exeファイルがダウンロードされるので、画面の指示に従い、任意の場所にインストールしましょう。インストールが完了したら、UnityHubを起動しましょう。

・UnityEditorのインストール

UnityHubが起動できたら、次はUnityEditor(実際のゲーム開発ソフト)をインストールします。UnityHub左側の「インストール」をクリック、右上の「エディターをインストール」をクリックします。

「Unityエディターをインストール」の画面が表示されるので、「正式リリース」の中にある「2021.3.12f1 LTS」というバージョンの右に表示されている「インストール」をクリックしましょう。

※画像では更に最新版の2021.3.16f1が表示されていますが、こちらでも構いません。
LTSとは長期サポートが保証されているバージョンのことで、バグ修正などの頻度や安定性が高いです。特別な理由がない場合は、LTSの中で最も数字の大きいバージョンを選ぶと良いでしょう

「モジュールを加える」画面が表示されます。デフォルトで「Microsoft Visual Studio Community」(IDE、プログラミングソフト)にチェックが入っています。既にお使いのPCにインストールされている場合は不要なのでチェックを外しておきましょう。

同画面をスクロールし、「言語パック」の中から「日本語」あるいは、得意な言語を選んでチェックして「次へ」をクリックしましょう。
(「Microsoft Visual Studio Community」にチェックを入れていない場合は、「次へ」が「インストール」に変わっているので、クリックしてUnityEditorのインストールを開始しましょう。)

「Microsoft Visual Studio Community」にチェックを入れた場合は下図のような画面が表示されます。利用規約を読み、「上記の利用規約を理解し、同意します」にチェックを入れてインストールしましょう。インストール完了まで少し時間がかかるので、しばらく待機しましょう。

4.Unity新規プロジェクト作成

UnityHub左側の「プロジェクト」をクリック、右上に表示される「新しいプロジェクト」をクリックしましょう。

エディターバージョンが最新のLTSであることを確認して、「3D(コア)」テンプレートを選びます。任意のプロジェクト名(「Simulink_SpinningTest」など)にし、管理しやすい保存場所を選んだら「プロジェクトを作成」をクリックしましょう。プロジェクトが作成されるまでしばらく待ちます。

5.Unityの画面構成

表示するウィンドウの数、種類、位置、大きさなどをカスタマイズすることができます。慣れてきたら色々な配置を試してみましょう。今回は、デフォルトのまま進めます。

① ツールバー
Editorの再生や一時停止などが行なえます。

② ヒエラルキーウィンドウ
現在のシーン内にあるゲームオブジェクトのリストが表示されます。
(Unityでは、ゲームオブジェクトという入れ物に、コンポーネントという機能群を取り付けることで様々な機能を表現します)

③ シーンビュー/ゲームビュー
ゲームオブジェクト選択や操作などが行なえます。タブをゲームビューに切り替えると、実際のゲーム画面(カメラが映す画面)が確認できます。

④ インスペクターウィンドウ
選択中のゲームオブジェクトに関する情報が表示されます。

⑤ プロジェクト/コンソールウィンドウ
プロジェクトに関するアセット類(グラフィック、音源、スクリプト、その他)を管理することができます。タブをコンソールウィンドウに切り替えると、エラーなどのメッセージを確認できます。

6.Unityシーンビューの操作

マウスやキーボードを使用し、シーンビューのカメラ表示を操作できます。

右クリックドラッグ上下左右の回転
ホイールボタンドラッグ上下左右の移動
ホイール回転拡大・縮小
左クリックゲームオブジェクトの選択

右上のシーンギズモをクリックすることでも、カメラを回転させることができます。(例えば、Zの青い円錐をクリックすると、XY平面に正対できます。)

7.Unityシーンのセットアップ

・シーンの保存

ツールバーの「ファイル」→「別名で保存」から、シーンを保存します。「プロジェクト名→Assets→Scenes」内に任意の名前で保存しましょう。今回は「MainScene」とします。

・床の作成

ヒエラルキーの「+」プルダウンメニューから、「3Dオブジェクト」→「クアッド」を選択すると、ヒエラルキーに「Quad」というゲームオブジェクトが生成されます。

Quadを選択した状態で、管理しやすいように名前を変更しましょう。今回は「Floor」にします。次に、インスペクター内の「Transform」の「位置」を全て「0」に書き換えます。「回転」のXのみを「90」に書き換えます。「スケール」の右にあるマークをクリックするとXYZ全ての値を一気に変えることができます。X、Y、Zどれでもいいので「2」に書き換えましょう。
※インスペクターに、「Transform」「Quad(Mesh Filter)」「Mesh Renderer」「Mesh Collider」といったものが表示されていますが、これらを「コンポーネント」と呼びます。
※「位置」を書き換えるのが面倒に感じた場合、ツールバーの「編集」→「環境設定」内の「シーンビュー」という項目の「原点でオブジェクトを作成」にチェックを入れておくと良いでしょう。

・独楽の作成

ヒエラルキーの「+」から「空のオブジェクトを作成」をクリックすると、Transformコンポーネントのみを持つゲームオブジェクトが作成されるので、「位置」を(X, Y, Z)=(0, 0.2, 0)に変更します。名前を「Spinning」に変更します。
その後、インスペクターの「コンポーネントを追加」をクリックします。

表示されるメニューから「Physics」→「Rigidbody」と選択すると、Rigidbodyコンポーネントが作成されます。「重力を使用」のチェックを外しておきましょう。
※Rigidbodyは、ゲームオブジェクトに接触判定を持たせたり、物理演算を適用させたいときに使用するコンポーネントです。

同様に、「3Dオブジェクト」→「スフィア」を作成します。ヒエラルキーで、このスフィアを先程の「Spinning」にドラッグ・アンド・ドロップします。すると、スフィアが「Spinning」の1つ下の階層に配置されます(スフィアを「Spinning」の子オブジェクトにする、という操作です)。この状態でスフィアの「位置」を全て「0」にします。「スケール」を全て「0.006」に変更します。スフィアを選択して、コピーアンドペーストで合計12個にします。

プロジェクトウィンドウの「Assets」フォルダ内で、右クリック→「作成」→「C#スクリプト」を選択します。C#スクリプトの雛形が作成されるので、名前を「CircleDeployer」に変更して、ダブルクリックしましょう。そうすると、自動で「Microsoft Visual Studio」が起動します。
※他のソフトが起動した場合は、ツールバーの「編集」→「環境設定」内の「外部ツール」タブを選択して、「外部のスクリプトエディター」を「Microsoft Visual Studio 2019」に変更して、環境設定ウィンドウを閉じます。

「Microsoft Visual Studio」が起動したら、以下のスクリプトに書き換えます。
(「kanのメモ帳」様からお借りしたものを、一部書き換えています。
http://kan-kikuchi.hatenablog.com/entry/CircleDeployer

//  CircleDeployer.cs
//  http://kan-kikuchi.hatenablog.com/entry/CircleDeployer
//
//  Created by kan.kikuchi on 2016.01.12.

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

/// <summary>
/// 子にあるオブジェクトを円状に配置するクラス
/// </summary>
public class CircleDeployer : MonoBehaviour
{
    //半径
    [SerializeField]
    private float _radius;

    //=================================================================================
    //初期化
    //=================================================================================

    private void Awake()
    {
        Deploy();
    }

    //Inspectorの内容(半径)が変更された時に実行
    private void OnValidate()
    {
        Deploy();
    }

    //子を円状に配置する(ContextMenuで鍵マークの所にメニュー追加)
    [ContextMenu("Deploy")]
    private void Deploy()
    {

        //子を取得
        List<GameObject> childList = new List<GameObject>();
        foreach (Transform child in transform)
        {
            //名前に「Sphere」を含むオブジェクトだけを対象とするように変更
            if (child.gameObject.name.Contains("Sphere"))
            {
                childList.Add(child.gameObject);
            }
            
        }

        //数値、アルファベット順にソート
        childList.Sort(
          (a, b) => {
              return string.Compare(a.name, b.name);
          }
        );

        //オブジェクト間の角度差
        float angleDiff = 360f / (float)childList.Count;

        //各オブジェクトを円状に配置
        for (int i = 0; i < childList.Count; i++)
        {
            Vector3 childPostion = transform.position;

            float angle = (90 - angleDiff * i) * Mathf.Deg2Rad;
            childPostion.x += _radius * Mathf.Cos(angle);
            childPostion.z += _radius * Mathf.Sin(angle);//y→zに変更

            childList[i].transform.position = childPostion;
        }
    }
}
※本記事内のスクリプトの使用、または不具合等により生じた、いかなる損害に関して一切責任を負いませんので、ご了承下さい。また、スクリプトや本記事に関して、kanのメモ帳様へのお問い合わせなどはお控えください。

書き換えられたら保存して、UnityEditorに戻ります(コンパイルが始まるので少し待ちます)。「CircleDeployer」を「Spinning」にドラッグ・アンド・ドロップします(この操作を「アタッチする」といいます)。ヒエラルキーに、コンポーネントとして「CircleDeployer」が追加されていることを確認します。「半径」の数値を「0.0125」にしましょう。シーンビュー上で、スフィアが円形に並んだことを確認します。

同様に、「3Dオブジェクト」→「カプセル」を作成します。このカプセルも「Spinning」の子にします。その後に「位置」を(X, Y, Z)=(0, 0.006, 0)にします。「スケール」を(X, Y, Z)=(0.005, 0.012, 0.005)に変更します。

今度は「SpinningController」というC#スクリプトを作成し、以下のように入力してください。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Text;

public class SpinningController : MonoBehaviour
{
    [SerializeField] [Tooltip("IP アドレス")]
    string Host = "localhost";
    [SerializeField] [Tooltip ("ポート番号")]
    int Port = 55000;

    /// <summary>
    /// TCPネットワーク クライアントからの接続をリッスン。
    /// </summary>
    TcpListener listener;
    /// <summary>
    ///通信した結果をテキストで読み込むためのクラス
    /// </summary>
    StreamReader reader;
    /// <summary>
    /// 通信したテキストを保存する用の string
    /// </summary>
    private string msg;
    /// <summary>
    /// msgを分割したデータを保存する用
    /// </summary>
    private string[] _str_arr = new string [4];
    /// <summary>
    /// 通信結果から数値へ変換したものを保存するリスト
    /// </summary>
    public List <float> receivingValue = new List <float>();

    /// <summary>
    /// Rigidbodyを格納する
    /// </summary>
    Rigidbody rb = null;

    /// <summary>
    /// 回転中かどうかの判定用bool
    /// </summary>
    bool isSpin = false;

    void Start()
    {
        Application.targetFrameRate = 60;//目標フレームレートを60に設定

        IPAddress localAddr = IPAddress.Parse(Host);

        listener = new TcpListener(localAddr, Port);
        listener.Start();
        Debug.Log("TCPの接続を待ち受け開始");

        rb = this.GetComponent<Rigidbody>();//Rigidbodyコンポーネントを取得
        rb.maxAngularVelocity = 10000;//最大角速度を変更
    }

    void Connection_Start_And_Data_Acquisition()
    {
        _str_arr = new string[4];
        receivingValue = new List<float>();

        //接続を開始、データをテキスト形式で取得
        TcpClient client = listener.AcceptTcpClient();
        NetworkStream ns = client.GetStream();
        reader = new StreamReader(ns,Encoding.UTF8);
        msg = reader.ReadToEnd();

        //受信したテキストから使用可能な形に修正
        string s = msg.Replace("[","");
        s = s.Replace("]","");
        _str_arr = s.Split(';');
        for(int i = 0; i < _str_arr.Length; i++)
        {
            float _converting_value = 0;
            if(float.TryParse(_str_arr[i],out _converting_value))
            {
                receivingValue.Add(_converting_value);
            }
        }

        //receivingValue[0] : 初期角加速度[rad/^2]
        //receivingValue[1] : 重心位置[m]
        //receivingValue[2] : 質量[kg]
    }

    private void FixedUpdate()
    {

        if (!listener.Pending())
        {
            return;
        }
        else
        {
            Connection_Start_And_Data_Acquisition();

            //使用可能なデータが作成できたら、独楽の回転を開始
            if(_str_arr.Length == receivingValue.Count)
            {
                SpinningRotate();               
            }
        }
    }

    /// <summary>
    /// 独楽を回す
    /// </summary>
    void SpinningRotate()
    {
        rb.centerOfMass = transform.up * receivingValue[1];//重心位置を受け取る
        rb.mass = receivingValue[2];//質量を受け取る

        //回転開始時にだけ実行
        if (!isSpin)
        {
            rb.AddRelativeTorque(transform.up * receivingValue[0], ForceMode.Impulse);//初期角加速度を受け取る
            rb.useGravity = true;//重力を使用
            isSpin = true;//回転中の判定にする
        } 
    }

    /// <summary>
    /// アプリを終了したら通信を切断
    /// </summary>
    private void OnApplicationQuit()
    {
        if (listener.Pending())
        {
            reader.Close();
        }       
    }
}

スクリプトが作成できたら、「Spinning」にアタッチしてください。アタッチしたスクリプトの「Host」の項目をご自身のIPアドレスに書き換えてください。

※IPアドレスがわからない場合(Windows10の場合)
デスクトップのスタートボタンの隣の検索ウインドウに「コマンドプロンプト」と入力すると、同名のソフトが表示されるので、クリックして起動します。

コマンドプロンプトに「ipconfig」と入力してEnterキーを押すと、IPアドレスが表示されます。

・メインカメラの設定

ヒエラルキーから、「MainCamera」を選択します。インスペクターから、「Transform」の「位置」を(X, Y, Z)=(0, 0.18, -0.35)にします。「Camera」の「クリップ面」の「ニア」を「0.01」にします(カメラとの距離が0.01以下のものは描画しない、という設定です)。
次に、「SceneViewCamera」という名前のC#スクリプトを作成し、開きます。そして以下のコードに書き換えてください。

using UnityEngine;

/// <summary>
/// ゲームビューでもシーンビューのようにカメラ操作できるようにする
/// </summary>
[RequireComponent(typeof(Camera))]
public class SceneViewCamera : MonoBehaviour
{
    /// <summary>
    /// 拡縮速度
    /// </summary>
    [SerializeField, Range(0.01f, 1f)]
    private float wheelSpeed = 0.2f;

    /// <summary>
    /// 移動速度
    /// </summary>
    [SerializeField, Range(0.01f, 1f)]
    private float moveSpeed = 0.2f;

    /// <summary>
    /// 回転速度
    /// </summary>
    [SerializeField, Range(0.01f, 1f)]
    private float rotateSpeed = 0.2f;

    /// <summary>
    /// 移動前のマウス座標
    /// </summary>
    private Vector3 preMousePos;

    private void Update()
    {
        MouseUpdate();
        return;
    }

    private void MouseUpdate()
    {
        float scrollWheel = Input.GetAxis("Mouse ScrollWheel");
        if (scrollWheel != 0.0f)
        {
            MouseWheel(scrollWheel);
        }
            
        if (Input.GetMouseButtonDown(0) ||
           Input.GetMouseButtonDown(1) ||
           Input.GetMouseButtonDown(2))
        {
            preMousePos = Input.mousePosition;
        }
            
        MouseDrag(Input.mousePosition);
    }

    /// <summary>
    /// カメラの拡縮
    /// </summary>
    /// <param name="delta"></param>
    private void MouseWheel(float delta)
    {
        transform.position += transform.forward * delta * wheelSpeed;
        return;
    }

    /// <summary>
    /// カメラの操作
    /// </summary>
    /// <param name="mousePos"></param>
    private void MouseDrag(Vector3 mousePos)
    {
        Vector3 diff = mousePos - preMousePos;

        if (diff.magnitude < Vector3.kEpsilon)
            return;

        if (Input.GetMouseButton(2))
        {
            transform.Translate(-diff * Time.deltaTime * moveSpeed);
        }           
        else if (Input.GetMouseButton(1))
        {
            CameraRotate(new Vector2(-diff.y, diff.x) * rotateSpeed);
        }

        preMousePos = mousePos;
    }

    /// <summary>
    /// カメラの回転
    /// </summary>
    /// <param name="angle"></param>
    public void CameraRotate(Vector2 angle)
    {
        transform.RotateAround(transform.position, transform.right, angle.x);
        transform.RotateAround(transform.position, Vector3.up, angle.y);
    }
}

書き換えられたら保存して、「MainCamera」にアタッチしましょう。ここで一度シーンを再生してみましょう。ツールバー中央の再生ボタンを押すとゲームビューに切り替わります。

カメラの操作ができることを確認できたら、もう一度再生ボタンを押してシーンビューに戻りましょう。感度が高すぎると感じたら、「MainCamera」のインスペクターから、「SceneViewCamera」のスライダーで調節できます。

8.MATLAB/Simulinkの紹介

・MATLAB

MATLABは、MathWorks社が開発している数値解析ソフト及び、プログラミング言語名です。数値の計算やグラフ化などのビジュアライズを通して、データ解析やアルゴリズム開発などを行うことができ、世界中のエンジニアや科学者に利用されています。使うにはある程度のプログラミング知識が必要ですが、比較的簡易な記述で解析などを行うことができます。

※MATLABの名称、ロゴなどは、The MathWorks, Inc. の商標または登録商標です。

https://jp.mathworks.com/products/matlab.html

・Simulink

物理モデリング、シミュレーションソフトです。運動方程式などを元にブロック線図を作成し、デジタル上で制御システムなどの設計、シミュレーションを行うことができます。ノンコーディングでも扱うことができるのが特徴で、視覚的にわかりやすいシステム設計などを行うことができます。使用する際は、MATLABの導入が前提となります。

※Simulinkの名称、ロゴなどは、The MathWorks, Inc. の商標または登録商標です。

https://jp.mathworks.com/products/simulink.html

9.MATLAB/Simulinkのセットアップ

下記URLから、MathWorks社のサイトにアクセスします。

https://jp.mathworks.com/products/matlab.html

「MATLABを入手する」から、サイトの指示に従ってアカウントを作成してください。MATLABは有償のソフトウェアですが、30日間だけ無料の評価版を利用することもできます。アカウントを作成できたらログインして、製品の管理ページ内にMATLABとSimulinkが一覧にあることを確認します。「ダウンロード」ボタンから、お使いのOSに合ったバージョンを選択してダウンロードしてください。

ダウンロードしたインストーラーを実行し、指示に沿ってインストールします。「製品の選択」でMATLABとSimulinkにチェックが入っていることを確認しましょう。

インストールが完了したら、MATLABを起動しましょう。

10.MATLABの画面構成

① ツールストリップ
MATLABの主な作業メニューが表示されます。ここから各種コマンドを実行します。

② 現在のフォルダーブラウザー
Windowsエクスプローラーに相当し、ファイルへのアクセスが行なえます。

③ コマンドウィンドウ
プロンプト(>>)が指示するコマンドラインにコマンドを入力し、実行します。

④ ワークスペースブラウザー
スクリプトやコマンドの実行によって作成された変数を保存、表示します。

11.MATLABスクリプトの作成

・作業フォルダの作成

現在のフォルダーブラウザーから、任意の場所へ移動し、右クリック→「新規」→「フォルダ」でフォルダを作成、任意の名前(今回は「Unity_Spinning」)にします。

・スクリプトの作成

作成したフォルダを開き、右クリック→「新規」→「スクリプト」でスクリプトを作成、任意の名前(今回は「tcp_send_unity」)にします。「tcp_send_unity.m」をダブルクリックすると、コマンドウィンドウの位置にスクリプトエディターが表示されるので、以下のスクリプトを入力しましょう。

function tcp_send_unity(IP,port,value)
%コマンドウインドウのクリア
clc
%Simulinkで設定した IP と Port 番号を使用して、TCP アクセス開始
tcpipServer = tcpclient(IP,port);
%single配列から string へ変換
data = mat2str(value);
%データの送信
write(tcpipServer,data);
end

同じ要領でもうひとつスクリプトを作り(名前は「spinning_parameter」とします)、下記のように入力しましょう。

%独楽のパラメータ
angularAcceleration = 0.05; %[rad/s^2] 初期角加速度
centroid = 0.009; %[m] 9mm 重心高さ位置
mass = 0.04; %[kg] 40g 質量M

入力できたら、ツールストリップの「エディター」タブから保存しましょう。

スクリプトエディターで「spinning_parameter.m」を開いたまま、ツールストリップの「エディター」タブから、「実行」をクリックしましょう。

スクリプトが実行され、「ワークスペース」に変数が保存されていることを確認しましょう。

12.Simulinkの画面構成

・Simulinkプロジェクトの作成

MATLABツールバーの「ホーム」タブ内の「Simulink」ボタンをクリックします。

Simulinkスタートページが表示されるので、「空のモデル」にマウスカーソルを合わせると表示される「モデルを作成」をクリックします。

・画面構成

13.Simulinkモデルの作成

・モデルの保存

「シミュレーション」タブから任意の名前(今回は「spinning_control」)で保存しておきましょう。

・「MATLAB Function」ブロックの作成

エディター上でダブルクリックすると、「ブロックの検索」メニューが表示されます。

検索欄に「MATLAB」と入力し、一番上に表示される「MATLAB Function」をクリックします。

作成された「MATLAB Function」ブロックをダブルクリックすると、関数編集画面が表示されます。

そうしたら、以下のスクリプトを入力しましょう。

function tcp_send_unity_Function(IP,port,Input_value)
%MATLAB側で作成した「 tcp_send_unity.m 」へ IP と Port 番号などを受け渡す
coder.extrinsic("tcp_send_unity");
tcp_send_unity(IP,port,Input_value);
end

入力できたら、エクスプローラーバーから「spinning_control」をクリックすることでエディタに戻ることができます。

入力が追加されて「MATLAB Function」ブロックが見づらくなっているので、ブロックの角をドラッグして大きくしておくと良いでしょう。

「MATLAB Function」ブロック下部のブロック名をクリックすると名前の変更ができるようになるので、「Send_MATLAB_Function」に変更しましょう。

・「String Constant」ブロックの作成

エディター上でダブルクリック、「String」と検索し、「String Constant」ブロックを作成します。

作成したブロックをダブルクリックすると、ブロックパラメーターウィンドウが表示されるので、「文字列」のダブルクオーテーション「“”」の間に自身のIPアドレスを入力し、「OK」をクリックします。

その後、「String Constant」ブロックの端子→「Send_MATLAB_Function」ブロックのIP端子の順にクリックすると、ブロック同士が接続されます。

・「Constant」ブロックの作成

エディター上でダブルクリック、「Constant」と検索し、一番上に表示される「Constant」ブロックを作成します。ブロックをダブルクリックすると表示されるメニューの「定数値」を「55000」に書き換えます。その後、「Send_MATLAB_Function」ブロックのport端子に接続します。

同じ要領で「Constant」ブロックを3つ作成し、定数値をそれぞれ「angularAcceleration」、「centroid」、「mass」とします。

・「Vector Concatenate」ブロックの追加

エディター上でダブルクリック、「Vector」と検索し、一番上に表示される「Vector Concatenate」ブロックを作成します。作成したブロックをダブルクリックし、表示されたウィンドウの「入力数」を「3」にします。角をドラッグして大きくしておきます。

そうしたら、下図を参考に各ブロックを接続してください。

・「Slider」ブロックの作成

エディター上でダブルクリック、「Slider」と検索し、一番上に表示される「Slider」ブロックを作成します。「Slider」ブロックにマウスカーソルを合わせると、上部に「接続」アイコンが表示されるのでクリックします。

マウスカーソルが変化するので、その状態で「angularAcceleration」のConstantブロックをクリックします。接続ウィンドウが表示されるので、ラジオボタンをクリックして接続状態にします。その後、エディター右上のバツボタンをクリックします。

※ラジオボタンが表示されない場合は、接続ウィンドウの「クリックしてブロック線図を更新」というテキストをクリックしてみてください。それでも改善しない場合は、MATLAB側で「spinning_parameter.m」スクリプトの実行をし忘れていないか(ワークスペースに変数が保存されているか)確認してください。

「Slider」ブロックをダブルクリックして表示されるウィンドウで、「最小値」を「0.001」、「最大値」を「1」にしてください。その後、「Slider」ブロックをもう2つ作成し、「centroid」、「mass」のConstantブロックにそれぞれ接続してください。そうしたら下表を参考に、各スライダーの値を変更してください。

変数名最小値最大値
angularAcceleration0.0011
centroid00.05
mass0.0011

その後、下図のように接続できたら、保存しておきましょう。

14.システム実行

Unityエディターを再生します。ゲームビューに切り替わったら、Simulinkの「シミュレーション」タブから、「実行」をクリックします。

独楽が回り始め、そのうち停止します。上手く回らないときや挙動がおかしいときは、「angularAcceleration」、「centroid」、「mass」の値をスライダーで調節してみてください。「CircleDeployer」の半径を変えてみるのも面白いかもしれません。

本記事は以上です。お疲れ様でした。