20210726のUnityに関する記事は6件です。

WEB版ETロボコンシミュレータについて(解説編)

こちらの続きです。 WEB版ETロボコンシミュレータの位置づけ ETロボコンシミュレータで検索すると色々な情報が引っ掛かりますので混乱する方もいらっしゃると思います。位置づけを簡単に整理すると下記の図のようになります。 WEB版ETロボコンシミュレータの画面説明 画面の説明は下図の通りです。API説明をクリックすると、本シミュレータで利用可能なAPIの説明とサンプルコードを見ることができます。本稿でも改めて説明します。 MiniScriptの仕様はMiniScriptから見ることができます。英語ですがとても簡単なので頑張って読んでみましょう。 シミュレータ操作はシミュレータ上にフォーカスが当たっているときに使える機能一覧です。ALTキーを押すとフォーカスを奪われる不具合が報告されていますので、予告なしに別のキーに変更される可能性があります。 AceエディタはMiniScriptの文法を理解し適切な色付けをしてくれます。実行結果はシミュレータ画面のDebug logをチェックするか、ブラウザのF12キーを押すことで確認できます。 スクリプト実行は Run Scriptボタンで行えます。この下にあるPauseボタンを押すとスクリプト実行を一時的に止めることができます。UninyのTimeScaleを0にすることで物理エンジンも止めています。もう一度Pauseボタンを押すと再開します。 スクリプト実行の横にあるLoad FileはローカルPCにあるファイルをAceエディタに読み込むことができます。Aceエディタのスクリプトを保存するには、Downloadボタンを押してください。ブラウザのダウンロード機能が働きます。Downloadボタンの左側にテキストを入力することで、ダウンロードファイル名を変更することができます。空の場合はランダムなファイル名になります。 HackEV走行体のモータ制御について HackEVは下図のような寸法となっており、右車輪、左車輪、アーム、しっぽをモータで動かすことができます。それぞれ、ev3_motor_set_power_left、ev3_motor_set_power_right、ev3_motor_set_power_arm、ev3_motor_set_power_tailという関数を用意しており、-100~100までの数値を取ることができます。また、ev3_motor_get_counts_left、ev3_motor_get_counts_right、ev3_motor_get_counts_arm、ev3_motor_get_counts_tailでモータの回転角度を取得できるため、HackEVの寸法と合わせて推測航法(デッドレコニング)を用いることで、走行体の走行距離や現在位置を算出することができます。 Hello, world ETロボコンAPIを用いて簡単にロボット動かしてみたい人は、下記スクリプトを試してみてください。走行体がスタート地点から10秒間まっすぐ進みます。wait は MiniScriptの内蔵関数で、指定秒数スクリプトの実行を待ちます。このスクリプトを組み合わせることで、ロボットを好きな場所に簡単に移動させることができます。 ev3_motor_set_power_left 50 ev3_motor_set_power_right 50 wait 10 MiniScriptの制御構文 MiniScriptはif、for、whileなど、基本的な制御構文を備えています。例えば下記のように記載することで、直進2秒、左旋回0.3秒の動作を11回繰り返します。end forという表記が見慣れないですが、これによって{}やインデントに頼った文法になっていないのは良いことだと思います。 for i in range(0,10) ev3_motor_set_power_left 50 ev3_motor_set_power_right 50 wait 2 ev3_motor_set_power_left -50 ev3_motor_set_power_right 50 wait 0.3 end for WEB版ETロボコンシミュレータ用API 現在サポートしている関数は下記です。取り得る値の範囲はEV3 APIを参考にしてください。 EV3制御 関数名 引数 機能 ev3_motor_set_power_left パワー 左モータのパワーを設定する ev3_motor_set_power_right パワー 右モータのパワーを設定する ev3_motor_set_power_arm パワー アームモータのパワーを設定する ev3_motor_set_power_tail パワー しっぽモータのパワーを設定する ev3_motor_stop_left モード 左モータの停止モードを設定する ev3_motor_stop_right モード 右モータの停止モードを設定する ev3_motor_stop_arm モード アームモータの停止モードを設定する ev3_motor_stop_tail モード しっぽモータの停止モードを設定する ev3_led_set_color カラー LEDカラーを設定する ev3_motor_get_counts_left 左モータの回転角(度)を取得する ev3_motor_get_counts_right 右モータの回転角(度)を取得する ev3_motor_get_counts_arm アームモータの回転角(度)を取得する ev3_motor_get_counts_tail しっぽモータの回転角(度)を取得する ev3_color_sensor_get_color カラーセンサが認識した色を取得する ev3_color_sensor_get_reflect カラーセンサの反射光強度を取得する ev3_color_sensor_get_r カラーセンサのR成分(赤)を取得する ev3_color_sensor_get_g カラーセンサのG成分(緑)を取得する ev3_color_sensor_get_b カラーセンサのB成分(青)を取得する ev3_ultrasonic_sensor_get_distance 超音波センサの測定距離を取得する ev3_ultrasonic_sensor_listen 超音波センサのListen状態を取得する ev3_gyro_sensor_get_angle ジャイロセンサの角度を取得する ev3_gyro_sensor_get_rate ジャイロセンサの角速度を取得する Unity制御用API デフォルトでは60FPS、TimeScale1.0で動作します。FPSを大きくとカラーセンサの更新周期を上げることができるため、ライントレースが安定する方向になります。FPSを小さくすると表示は間に合うようになるものの、ライントレースに失敗しやすくなります。TimeScaleを低くすることで遅いPCでも走行体の制御を間に合わすことができるかもしれません。ゲーミングマシンをお使いの方は、TimeScaleを大きくすることでシミュレーション時間を短縮できるかもしれません。 関数名 引数 機能 FPS Int 目標FPSを設定する TimeScale Float TimeScaleを設定する 最後に 本稿ではWEB版ETロボコンシミュレータがサポートしている機能を説明しました。インストールレスで気軽にETロボコン気分を味わえる本シミュレータをぜひお試しください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity】楽にオブジェクトプールを実装できる PoolableMonoBehaviour の紹介

✒背景 楽にオブジェクトプールを実装できる PoolableMonoBehaviour を作ったので紹介します。 楽なポイント プールは全て ObjectPool 、プールにセットするものは全て PoolableMonoBehaviour なので、宣言が楽 オブジェクト単体でプールに戻れるので、管理が楽 ?コード PoolableMonoBehaviour.cs は抽象クラスです。継承したクラスを繰り返し使うオブジェクトに追加して使用します。 PoolableMonoBehaviour.cs using UnityEngine; public abstract class PoolableMonoBehaviour : MonoBehaviour { public ObjectPool Pool { get; set; } public abstract void Init(); public abstract void Sleep(); } ObjectPool.cs は PoolableMonoBehaviour.cs を生成したりプールしたりできるクラスです。SetOriginal, Create, Release だけでも動きます。 ObjectPool.cs using UnityEngine; using System.Collections.Generic; using System.Threading.Tasks; public class ObjectPool : MonoBehaviour { private PoolableMonoBehaviour original; private Stack<PoolableMonoBehaviour> pool = new Stack<PoolableMonoBehaviour>(); /// <summary> /// オブジェクトプールするものをセット /// </summary> /// <param name="original">オブジェクトプールするもの</param> public void SetOriginal(PoolableMonoBehaviour original) { this.original = original; } /// <summary> /// プールから一つ取り出す /// </summary> /// <returns></returns> public Component Create() { PoolableMonoBehaviour obj; if (pool.Count > 0) { obj = pool.Pop(); } else { obj = Instantiate(original).GetComponent<PoolableMonoBehaviour>(); obj.Pool = this; } obj.Init(); return obj; } /// <summary> /// プールに戻す /// </summary> /// <param name="obj">オブジェクト</param> public void Release(PoolableMonoBehaviour obj) { obj.Sleep(); pool.Push(obj); } /// <summary> /// プールの要素数を取得 /// </summary> /// <returns>要素数</returns> public int GetPoolCount() { return pool.Count; } /// <summary> /// プールの要素を破壊 /// </summary> /// <param name="count">破壊数</param> public void Destroy(int count) { for (int i = Mathf.Min(pool.Count, count) - 1; i >= 0; i--) { Destroy(pool.Pop().gameObject); } } /// <summary> /// 全てのプールの要素を破壊 /// </summary> public void DestroyAll() { foreach (PoolableMonoBehaviour item in pool) { if (item == null) continue; Destroy(item.gameObject); } pool.Clear(); } /// <summary> /// あらかじめ生成 /// </summary> /// <param name="count">生成数</param> /// <param name="duration">生成時間</param> public async void Preload(int count, float duration) { if (!Mathf.Approximately(duration, 0f)) { int interval = (int)(duration / count * 1000); PreloadOnce(); for (int i = count - 2; i >= 0; i--) { await Task.Delay(interval); PreloadOnce(); } } else { for (int i = count - 1; i >= 0; i--) PreloadOnce(); } void PreloadOnce() { PoolableMonoBehaviour obj = Instantiate(original).GetComponent<PoolableMonoBehaviour>(); obj.Pool = this; Release(obj); } } } ?関数の説明 関数名 説明 void SetOriginal(PoolableMonoBehaviour original) オブジェクトプールするものをセットします。original : オブジェクトプールするもの Component Create() プールから一つ取り出します。戻り値 : PoolableMonoBehaviourを継承したクラス void Release(PoolableMonoBehaviour obj) プールに戻します。obj : 戻すオブジェクト int GetPoolCount() プールの要素数を取得します。戻り値 : 要素数 void Destroy(int count) プールの要素を破棄します。count : 破棄数 void DestroyAll() 全てのプールの要素を破棄します。 void Preload(int count, float duration) プールするオブジェクトをあらかじめ生成します。count : 要素数duration : 生成時間 ?使い方の例 弾を発射する例を作りました。 1. Shooterコンポーネントをシーン上のオブジェクトに追加します 2. 弾にしたいオブジェクトをプレハブにして、Bulletコンポーネントを追加します 3. シーンを再生してスペースキーを押すと弾が発射されます Shooter.cs using UnityEngine; public class Shooter : MonoBehaviour { [SerializeField] PoolableMonoBehaviour original; ObjectPool pool = new ObjectPool(); void Start() { pool.SetOriginal(original); } void Update() { if (Input.GetKeyDown(KeyCode.Space)) { var bullet = pool.Create() as Bullet; bullet.transform.position = transform.position; bullet.transform.rotation = transform.rotation; } } } Bullet.cs using UnityEngine; public class Bullet : PoolableMonoBehaviour { float aliveCount; public override void Init() { aliveCount = 1f; gameObject.SetActive(true); } public override void Sleep() { gameObject.SetActive(false); } void Update() { transform.position += transform.forward * 10f * Time.deltaTime; aliveCount -= Time.deltaTime; if (aliveCount < 0f) Pool.Release(this); } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unityにアタッチのボタンが表示されない

1.Visual Studio Tools for Unityのインストール 2.[Assets]-[Open C# project]
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ESP32からUnityへWiFiでデータ送信したい

理解のためのメモ やること ESP32からUnityへ、WiFiのアクセスポイント経由でデータを送信します。 UDPパケットを使います。 今回はESP32が送信、Unityが受信に一方向のみの通信です。 送信するデータ形式は符号あり2バイトのShort型が配列で10個並んだものです。 これを1バイトずつ送り、Unity側で受信後に2バイト数値に戻します。 Unity側ではインスペクターに受信データを表示します。 ポイント ESP32側では2バイトを1バイトに変換するために共用体を利用 Unity側では近い処理をBitConverterで実施 Unity側の受信処理はスレッドを立てて実行 参考 今回の記事はほぼこちらのトレースであります。ありがたく勉強させていただきます。 ESP32用スクリプト Arduino #include <WiFi.h> #include <WiFiUdp.h> const char* ssid = "SSID";//WiFiアクセスポイントのSSID const char* password = "password";//WiFiアクセスポイントのパスワード const char* client_address = "PCのIPを調べて入力";//送信相手のPCのIP const int client_port = 22222; //送り先のポート番号 const int server_port = 22224; //ESP32のポート番号 WiFiUDP udp; //送るデータのサイズ。データはショート型の符号付き2バイト、送信時は1バイトに変換。 static const int MSG_SIZE = 10;//送信データの数 static const int MSG_BUFF = MSG_SIZE * 2;//送信データのバイト数 //共用体の設定。共用体はたとえばデータをショートで格納し、バイト型として取り出せる typedef union { short sval[MSG_SIZE];//ショート型 uint8_t bval[MSG_BUFF];//符号なしバイト型 } UDPData; UDPData s_upd_message_buf; //共用体のインスタンスを宣言 int count = 0;//送信変数用のカウント void setup() { Serial.begin(115200); delay(500);//シリアル準備待ち用ディレイ //WiFi 初期化 WiFi.disconnect(true, true);//WiFi接続をリセット Serial.println("Connecting to WiFi to : " + String(ssid));//接続先を表示 delay(100); WiFi.begin(ssid, password);//Wifiに接続 while ( WiFi.status() != WL_CONNECTED) {//https://www.arduino.cc/en/Reference/WiFiStatus 返り値一覧 delay(100);//接続が完了するまでループで待つ } Serial.println("WiFi connected.");//WiFi接続完了通知 Serial.print("WiFi connected. ESP32's IP address is : "); Serial.println(WiFi.localIP());//デバイスのIPアドレスの表示 //UDP 開始 udp.begin(server_port); delay(500); } //送信用の関数 void sendUDP() { String test = "";//表示用の変数 udp.beginPacket(client_address, client_port);//UDPパケットの開始 for (int i = 0; i < MSG_BUFF; i++) { udp.write(s_upd_message_buf.bval[i]);//1バイトずつ送信 if (i % 2 == 0) {//表示用に送信データを共用体から2バイトずつ取得 test += String(s_upd_message_buf.sval[i / 2]) + ", "; } } Serial.println("[SEND] " + test );//送信データ(short型)を表示 udp.endPacket();//UDPパケットの終了 } void loop() { //送信するデータを作成 for (int i = 0; i < MSG_SIZE; i++) { s_upd_message_buf.sval[i] = (short)( i + count); } sendUDP();//UDPで送信 count += 10;//データ作成用のカウントを追加 if (count > 10000) { count = 0; } delay(500); } まずこちらのスケッチをESP32に書き込みます。 実行直後(リセット直後)に、シリアルモニタにESP32のIPアドレスを表示し、 その後は送信データを表示し続けます。 Unity用スクリプト udp_receive_test.cs using UnityEngine; using System.Net; using System.Net.Sockets; using System.Threading; using System; public class udp_receive_test : MonoBehaviour { int LOCAL_PORT = 22222;//受信に使うポートの番号 static UdpClient udp;//UDPを使う準備 Thread thread;//スレッドを使う準備 const int datanum = 10;//受信するshort型データの個数 static char[] c_buf = new char[datanum * 2];//データ受信用のchar型変数(1バイト) static short[] s_buf = new short[datanum];//データ格納用のshort型変数(2バイト) public int[] showdata = new int[10];//インスペクタ表示用 void Start() { udp = new UdpClient(LOCAL_PORT); udp.Client.ReceiveTimeout = 1000;//UDP通信のタイムアウト設定 thread = new Thread(new ThreadStart(ThreadMethod));//受信用スレッドを準備 thread.Start();//受信用スレッドを開始 } void Update() { //受信データをインスペクターに反映 for (int i = 0; i < datanum; i++) { showdata[i] = s_buf[i];//受信データをpublic配列に転記 } } void OnApplicationQuit()//アプリ終了時の処理 { thread.Abort(); } private static void ThreadMethod()//受信スレッド用の関数 { while (true) { IPEndPoint remoteEP = null; byte[] data = udp.Receive(ref remoteEP); //パケットサイズをチェックし、受信データをUnityに反映 if (data.Length == datanum * 2) // { for (int i = 0; i < datanum; i++) { s_buf[i] = BitConverter.ToInt16(data, i * 2); } } } } } 使い方と実行 ・Unityの新規プロジェクトを立ち上げます。 ・アセットに新規スクリプトを作成してファイル名を「udp_receive_test」とし、上記のスクリプトをコピペします。 ・ヒエラルキーウィンドウに空のオブジェクトを作成し、スクリプトをアタッチします。 ・空のオブジェクトを選択し、インスペクターを表示します。 ・スケッチが書き込まれたESP32を起動します。 ・インスペクターにカウントアップする数値が表示されます。 おわりに まだ変なところや無駄なところがあるかもしれません。 次は逆方向の送受信を試してみます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

WEB版ETロボコンシミュレータについて(導入編)

https://webglsim.etrobo.jp はじめに 私はETロボコン実行委員の一員として、2020年にUnityによるETロボコンシミュレータを開発しました。どんなものかはETロボコン 2021 プロモーションビデオを見ていただけると雰囲気がわかると思います。Youtubeには私の技術的な解説動画も公開されています。 ETロボコンシミュレータの課題 ETロボコン環境は参加者の間口を広げるために、WindowsだけでなくMacやLinuxにも対応しています。これは棚橋先生の凄まじい努力によるものですが、一方で、環境構築のための時間がかかる問題や、不具合発生時の問題切り分けが非常に難しい問題を抱えることになりました。(売っぱらう予定だったiMac2014がデバッグ用に大活躍しています...) また、TOPPERS/箱庭WGが開発した組込みCPUシミュレータAthrillとの連携も良い面と悪い面がありました。良い面は、実機向けのビルド環境と共通化できることです。シミュレータである程度確認したソフトウェアをロボットで動かそうと思えば動かせる、と言うところが素晴らしいです。悪い面は、Athrillの性能不足及び、UnityとAthrill間のUDP通信の遅さです。ゲーミングマシンであれば60fps以上で快適に動くものの、廉価PCでの動作はかなり厳しいものがあります。 その他にも、参加料を払っていただいている参加者の方々以外にはETロボコンシミュレータを提供することができず、教育用途で使ってみたいという方々からのご要望に応えることができませんでした。 WebGLによるETロボコンシミュレータのビルド 気まぐれでUnityのWebGLビルドをやってみたところ、ETロボコンシミュレータが意外に動きそうな感触を得ました。そこで、プロモーションや2022年大会での利用をめざして、WEB版ETロボコンシミュレータを開発することにしました。 UnityのWebGLでの開発は通常の開発よりも大変で、C#のソースコードを変更するとビルドに数分かかるような状況です。しかも、Unityエディタ上で動いたとしても、ちょっとしたことでブラウザ上で動かなくなるので、githubに少しづつコミットしながら動作確認をする必要がありました。 ロボット制御用スクリプト MiniScript Unity部分の目処が立ち、次の課題はロボット制御のスクリプトをどうするかでした。個人的にはPythonでやりたかったのですがいいソリューションが見つからず。Unityの中で軽量に動くスクリプト言語を探したところ、MiniScriptが良さそうだと思いました。Unityとのマイグレーション方法が明確であり、言語仕様がシンプルなので、初心者でも簡単にロボットを制御できそうです。 WEBエディタAce MiniScriptをどこで記述するかが問題になりました。最初はUnityのInputFieldを用いてエディタを実装したのですが、マウスをクリックするとテキストが全選択される問題や、WebGLのInputFieldがコピペに対応していない問題が発覚し、この解決にとても時間がかかった挙句、出来上がった機能(Script Panel)のあまりの使いづらさに、自分用のデバッグ機能として将来は闇に葬ることにしました。 MiniScript関係の情報を漁っていると、Aceを用いてUnityを制御する例を発見しました。と言うことで、これを参考にして作りました。 WEB版ETロボコンシミュレータの公開 最初は自分のアカウントのAzureStaticAppsに置いていたのですが、勤め先の環境ではプロキシさんが邪魔をして動かないことが判明しました。そこで、ETロボコンのサブドメインを設定していただき、無事公開となりました。ETロボコンのホームページのAboutの一番下からも行けますし、下記URLからでも行けます。 スマートフォンでは動作せず、PCの最近のWEBブラウザで動きます。 遊び方 WEB版ETロボコンシミュレータのAPIのページを見ると、サンプルコードやAPIが見れます。とりあえず走らせてみたい場合は下記コードをRun Scriptボタンで実行してください。Debug logをオンにすると実行ログが見れます。ブラウザのデバッグ機能(F12)でもみれます。GPU非搭載のPCの場合は、HackEVをHackEV(Simple)に変えると良いでしょう。 // P制御で走る。 v=50 // まっすぐの時の速度指令値 for i in range(0,10000) // 10000周期分動かす。 ref=ev3_color_sensor_get_reflect // カラーセンサから反射光の強さを取得する。 p=(ref-18)*2 // 目標値18からの差分に係数2をかける。 ev3_motor_set_power_left (v-p) // 右エッジの場合、目標値より暗い場合は右に曲がるように制御する。 ev3_motor_set_power_right (v+p) // 右エッジの場合、目標値より暗い場合は右に曲がるように制御する。 yield // 次の制御周期まで待つ end for 最後に 本稿ではWEB版ETロボコンシミュレータの開発経緯について説明しました。次回以降は、二輪倒立ロボット(EV3way)による倒立振子制御など、このシミュレータでできることを説明したいと思います。 おまけ 投稿しようと思ったら、タグは0より大きい値にしてください、と言うエラーが出て焦りました。初投稿あるあるなんでしょうか。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unityを使った映像配信方法

Unityを使って映像配信をしてみたかったので、方法を調べてみました。 1.OBS Studioに出力 Unity内の映像をOBSに出力し、HTTPサーバから映像を取得する方法 UnityCapture UnityCamを基に作られたUnity内のカメラをノートPCの内側カメラとして扱えるようになるUnityプラグイン 4kも対応可能 2.NDI(ネットワークデバイスインターフェイス) LANを介してビデオを共有することができる NDIホストを自動検出可能 ロイヤリティフリー KlakNDI NDIを使用してコンピューター間でビデオフレームを送受信できるようにするUnityプラグイン 3.SPOUT 同一PC内のアプリ間高で速映像共有ができる KlakSpoutUnity SPOUTを使用してコンピューター間でビデオフレームを送受信できるようにするUnityプラグイン 4.WebRTC(Web Real-Time Communication) ウェブブラウザやモバイルアプリケーション間でのリアルタイム通信で、Web会議システム等で利用されている。 WebRTC for Unity WebRTCを使用するためのUnityプラグイン Unity Render Streamingで同時に 複数の端末のブラウザに対して映像のストリーミング配信することができる。 Unity間での配信の参考記事 Sora Unity SDK 1:1,1:多で映像配信できるプラグイン 5.HLS(HTTP Live Streaming) ライブ配信、VOD(Video On Demand)配信に対応している通信規格 Abema TV等で使用されている Unityの配信用プラグインは配布されていない? 受信は以下のアセットで可能
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む