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

UniTask 使用例を集める

protected virtual async UniTask<SthResponse> _getAllResponseAsync(CancellationToken cancellationToken) { if (_allResponse != null) { return _allResponse; } _allResponse = await GetAsync<SthResponse>("SthAPI/AllResponseApi", cancellationToken); _webApiRequester.SetMasterVersion(_allResponse.Version); return _allResponse; } public async UniTask<TResponse> GetAsync<TResponse>(string path, CancellationToken cancellationToken) where TResponse : class { return await Get<TResponse>(path).GetValue(cancellationToken); } 続く
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

WEB版ETロボコンシミュレータについて(倒立振子編)

こちらの続きです。 ETロボコンと言えば倒立振子だった ETロボコン2009年大会から採用されたNXT走行体により、ETロボコンは倒立振子全盛期を迎えました。Mathworks社のMatlab/Simulinkにより作成された倒立振子プログラムをNXTで動くようにした先人の努力は素晴らしいものがあり、EV3への変化を経て2019年大会まで採用されていました。 2020年はコロナ禍により、シミュレータ大会が開催されることが決定し、真っ先にあきらめたのが倒立振子の採用でした。倒立振子を実現するためには5ms周期での制御が必須と言われていたのですが、大会で採用されたETロボコンシミュレータとAthrillの組み合わせでは10ms周期以上になることは見えていたため技術的に諦めざるを得ませんでした。 WEB版ETロボコンシミュレータのMiniScriptは5ms周期で動く。 Unityの物理エンジンの制御周期(FixedUpdate)を5msに設定していたこともあって、試しに下記スクリプトでMiniScriptのyieldの性能を図ってみた結果、4.998秒という結果が返ってきましたので、私のPCでは普通に5ms周期で回っていることがわかりました。この感覚はなんかArduinoっぽいです。 t=time for i in range(1,1000) yield // 次の制御周期まで待つ end for print time-t ということで、倒立振子をサポートしようという気持ちが大きくなりました。 EV3way倒立振子モデルの用意 軽量な3Dモデルを利用したかったので、塚本さんが以前作成したものを流用させていただきました。 このモデルに対して、清水さんのパラメータ設定を参考にして、タイヤと本体にRigidBodyとコライダーを設置しました。タイヤの重さ0.05kg、直径約4cm、本体の重さ0.8kg、サイズ幅0.18m×奥行0.08m×高さ0.18mとなっており、本体の下端がタイヤの中心とHingeJoint(モータ)で繋がっています。 倒立振子の原理とジャイロセンサについて 詳しい原理はNXTway-GS(2輪型倒立振子ロボット) C APIなどを参考にしてください。ざっくりというと、一輪車のバランスを取るのと同じようなもので、本体の角度がまっすぐ(0度)になるように、車輪の角度と角速度と、本体の角速度を使ってバランスを取る制御です。 車輪の角度はev3_motor_get_counts_leftとev3_motor_get_counts_rightで取得できます。角速度は後述の倒立振子ライブラリ内で微分するので自分で計算する必要はありません。 本体の角速度はジャイロセンサで計測できます。本シミュレータでは ev3_gyro_sensor_get_rate で取得できます。実機のジャイロセンサはノイズがあり、ドリフトと呼ばれる現象が発生するため、オフセットを適切に設定しないとうまく倒立できません。本シミュレータは今のところノイズもドリフトも入れてないので、簡単に制御できるはずですね。 Unityでジャイロセンサを模擬するために、body.transform.eulerAngles.x を用いて角度を取得しています。bodyは計測対象のGameObjectと考えてください。これを周期で割ることで角速度に変換しています。 倒立振子ライブラリのMiniScriptへの移植 倒立振子ライブラリbalancer.c を脳死モードでMiniScriptに置きかえて、バッテリ補正項を外して、あとはとにかく立つパラメータを探した結果がこちらのスクリプト。なぜこのパラメータで倒立するのか説明できないのですが、立たない理論よりは立つ現実が大事なのです。 balancer={} // ローパスフィルタ係数(左右車輪の平均回転角度用) balancer.A_D = 0.8 // ローパスフィルタ係数(左右車輪の目標平均回転角度用) balancer.A_R = 0.996 // 状態フィードバック係数 // K_F[0]: 車輪回転角度係数 // K_F[1]: 車体傾斜角度係数 // K_F[2]: 車輪回転角速度係数 // K_F[3]: 車体傾斜角速度係数 balancer.K_F = [ -0.870303, -31.9978, -1.1566, -2.78873 ] // サーボ制御用積分フィードバック係数 balancer.K_I = -0.44721 // 車体目標旋回角速度係数 balancer.K_PHIDOT = 25.0 * 2.5 // モータ目標回転角速度係数 balancer.K_THETADOT = 7.5 // 制御周期[s] balancer.EXEC_PERIOD = 0.005 // コマンド最大値 balancer.CMD_MAX = 100.0 // 初期化 balancer.ud_err_theta = 0.0 balancer.ud_theta_ref = 0.0 balancer.ud_thetadot_cmd_lpf = 0.0 balancer.ud_psi = 0.0 balancer.ud_theta_lpf = 0.0 balancer.DEG2RAD=(pi * 2) / 360 balancer.ret_pwm_r=0 balancer.ret_pwm_l=0 balancer.control=function(args_cmd_forward, args_cmd_turn, args_gyro, args_gyro_offset, args_theta_m_l, args_theta_m_r) tmp_thetadot_cmd_lpf = (((args_cmd_forward / balancer.CMD_MAX) * balancer.K_THETADOT) * (1.0 - balancer.A_R)) + (balancer.A_R * balancer.ud_thetadot_cmd_lpf) tmp_theta = (((balancer.DEG2RAD * args_theta_m_l) + balancer.ud_psi) + ((balancer.DEG2RAD * args_theta_m_r) + balancer.ud_psi)) * 0.5 tmp_theta_lpf = ((1.0 - balancer.A_D) * tmp_theta) + (balancer.A_D * balancer.ud_theta_lpf) tmp_psidot = (args_gyro - args_gyro_offset) * balancer.DEG2RAD tmp = [ balancer.ud_theta_ref, 0.0, tmp_thetadot_cmd_lpf, 0.0 ] tmp_theta_0= [ tmp_theta, balancer.ud_psi, (tmp_theta_lpf - balancer.ud_theta_lpf) / balancer.EXEC_PERIOD, tmp_psidot ] tmp_pwm_r_limiter = 0.0 for tmp_0 in range(0,3) tmp_pwm_r_limiter = tmp_pwm_r_limiter + (tmp[tmp_0] - tmp_theta_0[tmp_0]) * balancer.K_F[tmp_0] end for tmp_pwm_r_limiter =(tmp_pwm_r_limiter*20 + (balancer.K_I * balancer.ud_err_theta)*2) tmp_pwm_turn = (args_cmd_turn / balancer.CMD_MAX) * balancer.K_PHIDOT tmp_pwm_l_limiter = tmp_pwm_r_limiter + tmp_pwm_turn balancer.ret_pwm_l = tmp_pwm_l_limiter tmp_pwm_r_limiter = tmp_pwm_r_limiter-tmp_pwm_turn balancer.ret_pwm_r = tmp_pwm_r_limiter balancer.ud_err_theta = ((balancer.ud_theta_ref - tmp_theta) * balancer.EXEC_PERIOD) +balancer.ud_err_theta balancer.ud_theta_ref = (balancer.EXEC_PERIOD * tmp_thetadot_cmd_lpf) + balancer.ud_theta_ref balancer.ud_thetadot_cmd_lpf = tmp_thetadot_cmd_lpf balancer.ud_psi = (balancer.EXEC_PERIOD * tmp_psidot) + balancer.ud_psi balancer.ud_theta_lpf = tmp_theta_lpf end function speed=40 //前進速度 str=0 //旋回速度 for i in range(0,10000) // 倒立振子制御 balancer.control(speed,str, ev3_gyro_sensor_get_rate,0,ev3_motor_get_counts_left,ev3_motor_get_counts_right) ev3_motor_set_power_left balancer.ret_pwm_l ev3_motor_set_power_right balancer.ret_pwm_r yield end for HackEVをEV3Wayに変更して Run Scriptを押すと倒立振子で前進します。 MiniScriptの倒立振子ライブラリ化 自分で最適なパラメータを見つけたい人は前述の方法で頑張ってもらうとして、エンジョイ勢はもっと簡単に倒立振子を体験したいと思うことでしょう。ということで、MiniScriptからさらにC#に移植して、MiniScriptから呼び出せる関数として、balance_init、balance_control、balance_pwm_l、balance_pwm_rを用意しました。使い方は下記の通り。これで誰でも簡単に倒立振子を楽しめますね。 speed=40 //前進速度 str=0 //旋回速度 balance_init // 倒立振子初期化 for i in range(0,3000) // 倒立振子制御 balance_control speed,str, ev3_gyro_sensor_get_rate,0,ev3_motor_get_counts_left,ev3_motor_get_counts_right ev3_motor_set_power_left balance_pwm_l ev3_motor_set_power_right balance_pwm_r yield end for 最後に 本稿では二輪ロボットEV3wayをシミュレータ上で倒立振子させる方法について説明しました。さらに、ライントレースと組みあわせることで古き良きETロボコン気分を体験することができます。ぜひお試しください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unity2019.1.7f1のiOSビルドで、大きいファイルがアップロード出来ない

Unity2019.1.7f1のiOSビルドから、UnityWebRequestを使用して動画を送信しようとしたところ、アップロードされた動画が壊れ再生出来ない状態でした。 今更ながら、2019バージョンですが、備忘録的に残しておきます。 1. 結論 こちらのフォーラムを参照しました。 You could think that the issue is on our side, but in fact if we update the "streamSize" value of the generated UnityWebRequest.mm then it works at 100%. 上記のように、iOSビルドで生成された UnityWebRequest.mm の [streamSize] を大きい値に変更すると、正常に動画を送信することが出来ました。 2019.2以降では正常に動作するみたいです。 2. UnityWebRequestでファイルを送信する 自分用にファイル送信のコード残しておきます。 SendCapture.cs string filePath = "端末のファイルパス"; string fileName = "test" string uploadURL = "https://test.com/xxx" public IEnumerator UploadFile() { byte[] movieByteArray = File.ReadAllBytes(filePath); // formにバイナリデータを追加 WWWForm form = new WWWForm(); form.AddBinaryData("file", movieByteArray, fileName, "video/mp4"); // HTTPリクエストを送る UnityWebRequest request = UnityWebRequest.Post(uploadURL, form);         yield return request.SendWebRequest(); if (request.isNetworkError || request.isHttpError) { // POSTに失敗した場合,エラーログを出力 Debug.Log("responseCode / error : " + request.error); } else { // POSTに成功した場合,レスポンスコードを出力 Debug.Log("responseCode / success : " + request.responseCode); } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Unity]HMDの右目にキャラクターが表示されない

やったこと Project Setting > XR Plug-in Managerで設定をチェック。 Stereo Rendering Mode をMulti Passに変更。 原因 キャラクターに使われているshaderがsingle instance viewに対応してない。 ex) VRMのMToon shaderなど。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

多種類対応のオブジェクトプールを作る。

Unityにおいてかなりよく使われると思われるObjectPool。 私もかなりこれのお世話になりました、というか現在進行形でなっています。 ある時、私は沢山の種類のObjectPoolを必要としました。 でも大量に宣言するの面倒くさいしコード見づらい... そこからかくかくしかじかあって多種類対応のObjectPoolを作りました。 私と同じ様なものを求めているかつての私みたいな人達のため、 それを残しておきたいと思います。 コード using System.Collections; using System.Collections.Generic; using UnityEngine; public class MultiType_ObjPool : MonoBehaviour { public List<GameObject> PrefabList = new List<GameObject>(); public Dictionary<string,Stack<GameObject>> ObjPoolDic = new Dictionary<string,Stack<GameObject>>(); public List<GameObject> EnableObjList = new List<GameObject>(); public int AddCount;//足りない時に追加で生成する数 public void Register(string name,int count){//登録 GameObject regist = PrefabList.Find(x => x.name == name); if(!ObjPoolDic.ContainsKey(regist.name)){ ObjPoolDic.Add(regist.name,new Stack<GameObject>()); } for(int a = 0;a<count;a++){ GameObject pObj = Instantiate(regist); pObj.SetActive(false); ObjPoolDic[regist.name].Push(pObj); } } public GameObject Create(string name){//生成 if(!ObjPoolDic.ContainsKey(name)){ Register(name,AddCount); } GameObject returnobj = ObjPoolDic[name].Pop(); returnobj.SetActive(true); EnableObjList.Add(returnobj); return returnobj; } public void Sleep(GameObject sobj){//使い終わった後の処理 sobj.SetActive(false); EnableObjList.Remove(sobj); ObjPoolDic[sobj.name].Push(sobj); } } 動作説明 Dictionaryを使って様々な種類のオブジェクトプールを取得する仕組みです。 Stackを使用することで軽量化を図っています。 アクティブなオブジェクトを別でListに入れているのでそこから様々な処理を出来ます。 補足 ・一応このスクリプトは勝手に使ってもらってOKです! ・初記事などで読みづらい部分があると思います、許してください。 ・質問とか(もしよければLGTMも)ジャンジャンください!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

WEB版ETロボコンシミュレータについて(ライントレース編)

こちらの続きです。 ライントレースに必須となるカラーセンサについて HackEV走行体には下図のように、アームにカラーセンサが備え付けられています。アームを固定することでカラーセンサの取得値を安定させることができます。カラーセンサには複数のAPIが用意されています。 ev3_color_sensor_get_reflectはセンサについているライトの反射光を受けて、輝度値を返す関数です。初心者がライントレースに用いるには一番簡単な関数です。黒色が9、白色が38くらいになるように設定されているので、ライントレースの目標値としてこの間の値を選択するとよいでしょう。 カラーセンサの本来の役割であるRGB値(赤、緑、青)を取得する関数として、ev3_color_sensor_get_r、ev3_color_sensor_get_g、ev3_color_sensor_get_bが用意されています。実際の走行体ではreflectとrgbは同時に取得できないのですが、本シミュレータでは簡単化のため、両方問題なく取得できてしまいます。 ライントレースには使えませんが、色を判別するための関数としてev3_color_sensor_get_colorが用意されています。EV3RT C APIのcolorid_tに書かれている順で0~7の値を返します。ただし、本シミュレータでは無色と茶の判定をさぼっており、黒(1)、青(2)、緑(3)、黄(4)、赤(5)、白(6)を返す実装となっています。内部的にはRGBをHSVに変換して距離の最も近い色を選んでいます。RGBのまま距離計算をすると黄と緑の判定精度が落ちることが知られています。 ライントレースの仕組み カラーセンサの値を見て、白ならライン方向へ、黒ならラインの外側へ走行体を向かせて前に進むことでラインに沿って走行することができます。簡単だけどガタガタな動きをするオンオフ制御、なめらかだけど急カーブに弱いP制御、急カーブにも耐えられるがノイズに弱いPD制御などがあります。ETロボコン名物のコースの魔物は、目に見えないノイズ(外光、影、カメラの赤外線など)が正体なのかもしれません。より技術的な説明は過去の記事を参考にするとよいでしょう。 MiniScriptでのオンオフ制御 下記のようなプログラムを実行してみましょう。ちょっと極端な例ですが、黒に近づくと左車輪を動かし、白に近づくと右車輪を動かします。これでも結構いいところまで進みますが、ゴールに到達することはできません。数値を調整して、ゴールまでたどり着けるようにしてみてください。 // オンオフ制御で走る。 for i in range(0,10000) ref=ev3_color_sensor_get_reflect if ref<18 then // 目標値18より小さい場合(黒) ev3_motor_set_power_left 50 ev3_motor_set_power_right 0 else // 目標値18以上の場合(白) ev3_motor_set_power_left 0 ev3_motor_set_power_right 50 end if yield end for MiniScriptでのP制御 オンオフ制御では走行体のガタガタがどうしても残ります。下記のようにP制御を採用することで、ラインのエッジに近いときほど旋回制御量を減らすことができ、より滑らかに走らせることができます。目標値やP制御の係数を調整することで、より速く、より安定した走りをめざすことができます。 // 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 MiniScriptでのPD制御 ETロボコンで最も使われる制御だと思います。上記P制御の例に対して、1周期前の反射光の値を覚えておいて、現在の反射光の値との差を出すことでD(微分値)を計算することができます。P制御と比べて何か変わりましたか? 目に見える変化はないはずです。右エッジ(簡単な方)の場合、P制御でも十分走り切れることが多いです。ただし、速度を上げたり、左エッジ(カーブが多い方)を走る場合は、急なカーブを曲がるためにPD制御が必要になります。ここからは自分で工夫してみてください。 // PD制御で走る。 v=50 // まっすぐの時の速度指令値 old_ref=18 for i in range(0,10000) // 10000周期分動かす。 ref=ev3_color_sensor_get_reflect // カラーセンサから反射光の強さを取得する。 diff=ref-old_ref p=(ref-18)*2 // 目標値18からの差分に係数2をかける。 d=diff*10 // 微分値に係数をかける。 print d ev3_motor_set_power_left (v-p-d) // 右エッジの場合、目標値より暗い場合は右に曲がるように制御する。 ev3_motor_set_power_right (v+p+d) // 右エッジの場合、目標値より暗い場合は右に曲がるように制御する。 old_ref=ref yield // 次の制御周期まで待つ end for 外乱について 本シミュレータは現時点(2021/7/27)では外乱がないためかなり安定した走行ができます。一方で、大会用のETロボコンシミュレータではスポットライトの強度や影の向きを変えられるため、より繊細な制御が求められます。そして、実機ではコースの歪みやたわみとの闘いも起こります。本シミュレータの今後の拡張として、外乱やセンサノイズの導入は必要になると考えています。 最後に 本稿ではMiniScriptによるライントレースの方法について説明しました。カラーセンサの特徴をよく知ることで、高速かつ滑らかなライントレースを実現することができます。ぜひ、本シミュレータでチューニングの楽しさを体験してみてください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む