20190819のUnityに関する記事は5件です。

UnityでBGMの容量を大きく削減できるかもしれない知識

Unityでシーケンス音源を使ってみよう

オーディオデータというものはそれなりに容量を食います。
pcや据え置きゲーム機などストレージ容量や回線速度に余裕がある場合は気にする必要はありませんが、スマホや携帯端末ではアプリやダウンロードデータの容量は少ないほうが喜ばれます。
しかし、oggやmp3などの圧縮を利用しても尺の長い曲などはかなりの容量を使ってしまいます。
曲のジャンルなどにもよりますが、シーケンス音源を使うと大きく容量削減ができるかもしれません。

トラッカーモジュールの使い方

Unity公式マニュアル トラッカーモジュール
https://docs.unity3d.com/ja/2018.1/Manual/TrackerModules.html
Unityではトラッカーモジュールと呼ばれる形式をサポートしています。
トラッカーモジュールはmidiに似ていますが、音源をファイル内に内蔵でき、どのような環境でもほぼ同じ音で再生することができます。
Unityでは .it .s3m .xm .mod の四つの形式をサポートしていますが基本的には.it形式を使えば大丈夫です。

トラッカーモジュールの作成方法

作成するソフトには様々なものがありますが、Openmptがおすすめです。
Openmpt公式
https://openmpt.org/
Windows専用ですが、Wineを公式にサポートしておりMacやLinuxでもがんばれば動きます。
詳しい使い方に関しては長くなってしまうのでここには書きませんが、別の記事で書くかもしれません。

欠点

トラッカーモジュールはオーディオデータと違い、音の波形をそのまま記録するのではなく、楽譜のデータを内蔵された音源を利用して再生します。
そのため音質は内蔵された音源データに依存します。高品質のサンプリング音源を使ったオーケストラ曲などはオーディオデータより容量が増えてしまうかもしれません。
逆に、波形データが少なくて済むチップチューンなどには非常に向いています。
あと、波形データを記録しているわけではないのでエフェクトはUnity側でかける必要があります。

どのぐらい容量が減るのか

矩形波の波形で2分間適当に演奏したデータで比べてみます。
tes.itがトラッカー、tes.opusがogg形式(44100hz)でオーディオ化したものです。
ーーー結果ーーー
tes.it 7kb
tes.opus 2.57mb

大幅に容量が減りました。

おわり

うまく使えば容量削減できるのでぜひ使ってみてください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unityゆるふわアドカレ2019】UniEnumExtensionで500倍速の列挙型を扱おう【Mono.Cecil】

今日は私の誕生日なので24歳学生としては初投稿です。

この記事はUnityゆるふわサマーアドベントカレンダー 2019の19日目の記事です。
前々日17日の記事は @nanaki_pg さんの「Oculusの加速度センサを使ったVR空間での移動」でした!
前日18日の記事は @mao_ さんの「」でした!
翌日20日の記事は @kingyo222 さんの「Unity:UI Elements でいくつかサンプル書いたよ!」です!
翌々日21日の記事は @yKimisaki さんの「UIElementsでもUniRxを使いたい」です!

はじめに

UniEnumExtensionBoothGitHub上で公開されているエディタ拡張のアセットです。

「UniEnumExtension」を導入することで列挙型のToStringを元々のソースコードを一切書き換えずに概ね500倍から100倍以上高速化出来ます。

バージョン情報など

  • UniEnumExtension version 0.1.1
  • Unity2018.4, 2019.2で動作確認

導入方法

Gitを既にインストールしている場合

image.png

まず初めに新規プロジェクトを作成します。

image.png

Packagesフォルダには初期時点でAnalystic LibraryやPackage Manager UIなどが含まれていますね。

次にコマンドプロンプトやターミナルなどを起動してください。
対象プロジェクト以下のPackagesフォルダに移動してください。

git clone https://github.com/pCYSl5EDgo/UniEnumExtension
とコマンドを入力してください。

以下のような表示になるはずです。

image.png

Unityエディタに戻って見てみましょう。新たにUniEnumExtensionとMono.Cecilが増えたはずです。

image.png

以上でインストールは終了です。 簡単ですね!

Boothから購入した場合

ダウンロードしたzipファイルをその場に解凍します。
UniEnumExtension.unitypackageファイルが出てきますので、それをプロジェクトにドラッグ&ドロップなどでインポートしてください。
LICENSE-jpはつまり開発者は全員エディタ拡張として1PCにつき1つ購入して使用することと譲渡や再頒布の禁止などを定めているものです。

image.png

image.png

Assets/Plugins/UniEnumExtensionInstallerはGitHubからUniEnumExtensionをインストールするためだけのインストーラーです。
Packages/UniEnumExtensionを確認できたならば削除して構いません。

使い方

特に何もせずとも列挙型の性能が良くなります。

……というのでは解説が寂しいのでもうちょっと具体的に。 メニューのWindow/UniEnumExtensionをクリックすると以下のようなウィンドウが開きます。
image.png

"ProcessRewriteToString All Assemblies"にチェックが入っていますが、このチェックがあることで全Playerビルドに含まれるasmdefが処理対象となります。
チェックを外してみましょう。

image.png

UniEnumExtensionは処理対象の数に比例してコンパイル時間を長くします。列挙型が含まれないアセンブリを対象外に指定すれば処理時間は短くなります。
手元で計測した所1アセンブリあたり0.05~0.2秒ほど処理時間が掛かっていました。

なぜこのアセットが必要なのか?

Enums.NETに詳しいです。

  • ToStringなどでもリフレクションが走り、キャッシュが効いたり効かなかったりメソッドに依ってまちまち
  • System.Enumのメソッドは殆どが非ジェネリックであり、無駄なtypeof()が必要
    • 第2引数がobject型を要求したりするのでボクシング・アンボクシングが常に生じる
    • 戻り値の型がT[]ではなくArrayなのでキャスティング必須

さて、Enums.NETはEnumsNET名前空間とEnums静的クラスを定義することこれら問題を打破しました。
その結果、列挙型のToStringにおいて標準に比較して45倍の高速化を達成しました。
これは素晴らしいことです。

UniEnumExtensionは標準に対して300~500倍の高速化を達成しています。
これはMono.Cecilによる静的IL解析によりポストコンパイル時にボクシングの生じるメソッド呼び出しや仮想メソッド呼びなどを定数に置換したり、高速でアロケーションの少ない非仮想メソッド呼び出しに置換することで実現されています。

また、全然違う機能ですが、Burst Job内でforeachが使えます!

いかなる場合に高速化が行われているのか

  • 処理対象のアセンブリに含まれる列挙型に対するToString呼び出し全て1^
  • Enum.IsDefined(typeof(具体的な型名), 定数 | 文字列型の変数) は定数埋め込みあるいは高速な関数呼び出しに置換されます2^
    • 特に第2引数が定数である時、真偽値の定数埋め込みに置換されます
  • Enum.GetValues(typeof(具体的な型名))は高速な配列新規生成と初期化に置換されます
  • HasFlag(Enum)で生じる2回のボクシングと仮想メソッド呼び出しは0回のボクシングと具象メソッド呼び出しまたは定数埋め込みに置換されます
  • 処理対象アセンブリに含まれる列挙型にIEquatable<列挙型>を実装させることでSystem.Collections.DictionaryのTKeyに指定した時の動作が高速になる場合があります

高度なトピック

Packages/UniEnumExtension/BuildPlayer/EnumExtensionPostBuildPlayerScriptDll.csとPackages/UniEnumExtension/UI/Program.csを御覧ください。

EnumExtensionPostBuildPlayerScriptDll.cs は MonoビルドやIL2CPPビルド時にポストプロセスIL編集を行います。
UnityEditor.Build.IPostBuildPlayerScriptDLLsを実装したクラスはビルド時にいつの間にかインスタンス化され、コールバックが呼ばれます。コールバックのタイミングはビルドに使われる全C#ファイルがコンパイルされてDLLが出揃った時です。
public void OnPostBuildPlayerScriptDLLs(BuildReport report)
{
    step[0] = BeginBuildStep.Invoke(report, uniEnumExtension);
    try
    {
        Implement(report);
    }
    finally
    {
        EndBuildStep.Invoke(report, step);
    }
}

コールバック内では特に必要は無いですが、UnityEditor.Build.Reporting.BuildReportのinternalなAPIであるBegin/EndBuildStepを使っています。
公式リファレンス内に説明がないので具体的な働きは不明ですが、おそらくビルド時間やエラーハンドリングする際の情報量が増えるのでしょう。

private void Implement(BuildReport report)
{
    string[] guidArray = AssetDatabase.FindAssets("t:" + nameof(ProgramStatus));
    ProgramStatus programStatus = AssetDatabase.LoadAssetAtPath<ProgramStatus>(AssetDatabase.GUIDToAssetPath(guidArray[0]));
    programStatus.Initialize();
    IEnumerable<string> targetNames = programStatus.Enables.Zip(programStatus.OutputPaths, (enable, outputPath) => (enable, Path.GetFileName(outputPath))).ToArray();
    IEnumerable<string> assemblyPaths = report.files.Where(buildFile =>
    {
        if (buildFile.role != "ManagedLibrary")
        {
            return false;
        }
        if (string.IsNullOrWhiteSpace(buildFile.path)) return false;
        string buildName = Path.GetFileName(buildFile.path);
        return targetNames.All(pair => pair.Item2 != buildName) || targetNames.First(pair => pair.Item2 == buildName).Item1;
    }).Select(buildFile => buildFile.path);
    string directoryName = Path.GetDirectoryName(report.files[0].path);
    Debug.Log(directoryName);
    using (var extender = new EnumExtender(searchDirectory: new string[1] { directoryName }))
    {
        extender.Extend(assemblyPaths);
    }
}

シングルトンな設定ファイルなScriptableObjectを読み込みます。
その後BuildReportのfilesプロパティでDLLやPDBファイル一覧を得られます。
その内、roleがManagedLibraryなもので設定上処理対象なDLLのみをIEnumerable<string> assemblyPathsに取り出します。
これをEnumExtenderのインスタンスのExtendメソッドに渡せばIL書き換えがそのアセンブリ群に対して行われます。
EnumExtenderのコンストラクタにはアセンブリの参照を解決するためのディレクトリ名を与えます。
アセンブリの参照解決って?という方はMono.Cecil入門を御覧ください。

高レベルAPI

using(EnumExtender extender = new EnumExtender(string[] searchDirectory))
extender.Extend(IEnumerable<string> assemblyPaths);

が高レベルAPIとして露出されています。
assemblyPathsでパスを指定するとよしなに色々処理します。

低レベルAPI

EnumExtenderにはもう1つコンストラクタがあります。

public EnumExtender(IModuleProcessor[] moduleProcessorCollection, ITypeProcessor[] typeProcessorCollection, IMethodProcessor[] methodProcessorCollection, string[] searchDirectories)

UniEnumExtension.IModuleProcessor, UniEnumExtension.ITypeProcessor, UniEnumExtension.IMethodProcessorはモジュール(アセンブリ)、型、メソッドに対して処理を行うインターフェースです。
コンストラクタからIL処理を登録するのですね。

上述3インターフェースは公開されていますので独自にポストコンパイル時にフックしてEnumExtenderを実行すると良いでしょう。
注意点としては、EnumExtenderは必ずDisposeしてください。DisposeすることでILの書き込みが完了します。

EnumExtenderはUniEnumExtension.IExtenderを実装していますのでその段階からすげ替えるのも良いかもしれませんね。

public interface IExtender : IDisposable
{
    void Extend(IEnumerable<string> assemblyPaths);
}
public interface IModuleProcessor : IProcessor
{
    void Process(ModuleDefinition moduleDefinition);
}
public interface ITypeProcessor : IProcessor
{
    void Process(ModuleDefinition systemModuleDefinition, TypeDefinition typeDefinition);
}
public interface IMethodProcessor : IProcessor
{
    bool ShouldProcess(TypeDefinition typeDefinition);
    void Process(ModuleDefinition systemModuleDefinition, MethodDefinition methodDefinition);
}

感想

Mono.Cecilでポストコンパイル時constexprをする可能性を感じられました。
readonlyフィールドが実現してILレベルでもなんらかの形で表現出来たならば本当にconstexprが出来ると思います。

機能追加の要望などがありましたら、私のTwitterにDMまたはGitHubでIssueを立ててください

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Animator Controllerを上手く使ってハンドサイン、リップシンク、まばたき、表情遷移をする

こんにちは。八ツ橋まろんです。

この記事では、UnityのAnimator Controllerについて解説します。

本記事で解説するのは、pixivFANBOXで公開しているキャプチャシステム(というか配布unitypackage)「VR Motion Live」で行なっているコントロールの方法です。

リンクはこちら
https://www.pixiv.net/fanbox/creator/16717003/post/516193

3DのバーチャルYouTuberを動かすシステムはいくつかありますが、HTC Viveのような家庭用VR機器は機器が比較的安価かつトラッキングの性能がそこそこ良いため、企業系のVtuberによく採用されています。

HTC Viveのコントローラやトラッカーとアバターとの連動は有料アセットのFinal IKを使う例が大半で、多くの場合、身体のトラッキングはFinal IKだけで済んでしまいます。アバターを動かすだけならこれで十分ですが、更に表現の幅を広げたい場合は、以下のような機能の追加が考えられます。

・指のコントロール
・表情のコントロール
・リップシンク
・まばたき

これらは、フェイストラッキング用のカメラやハンドトラッキング用のグローブなどを併用することで実現できますが、システム全体が高価かつ複雑になってしまうため、HTC Viveの両手のコントローラによる制御で代用する方法があります。

環境

Unity2017.4.28f1
Windows 10
HTC Vive

Animator Controllerの基本

Animator Controller (以下Animator) を使うと、Animationの遷移ができます。
下の画像はAnimatorの例です。

このAnimatorの基本動作を書きます。
・Sceneが再生されると、緑色のEntry状態からスタートして、矢印に従いオレンジ色のFace 0 (default)状態に遷移します。
・水色のAnyStateは「どの状態からでも」という意味です。どのアニメーション状態にいても、条件を満たせばいつでもAnyStateから伸びる矢印に遷移します。
・現在、ParemeterのFaceは2なので、AnyStateからFace=2で遷移するFace 2状態に遷移します。
・よって、現在はFace 2状態のアニメーション「にっこり」が再生されて、アバターがにっこり笑っています。

Qiita_1.png

Animator Controllerの応用

Animatorにはレイヤー機能(Layer)があります。Layerによって、複雑なアニメーションの遷移を簡単にすることができます。
例えば、下の図はLayerのマスク機能(Mask)を使った例で、Hand Sign (L)というLayerでアバターの左手を制御しています。
この例では、Base LayerというLayer(一番上のレイヤー)でAスタンス(手を下した立ち姿で両手はパーにする)のアニメーションが指定されているのですが、Hand Sign (L)より上側にあるLayer(いま言ったBase Layerや、Face Expressionなど)のレイヤーでポーズが指定されていても、左手だけはHand Sign (L)によってアニメーションが上書きされるため、図では左手がチョキをしています。

実はこのチョキのアニメーションは、本来両手をチョキにするアニメーションなのですが、Maskで左手以外の部位をマスクしているため、右手には影響を与えません。

Qiita_2.png

また、以下の図のように、LayerのWeightを使い、スクリプトでWeightを上げ下げして口を開けたり閉じたりすることで、口パクなどが再現できます。
下の図では、Lyp SyncというLayerで口を開けた状態のアニメーションを指定し、そのWeightを変えることで口を開けたり閉じたりしています。
このとき、Maskによって他の部位に影響がないように、全ての部分をマスクしています。
Qiita_3.png

Custom Override Controllerの基本

Animatorの関連にCustom Override Controllerというものがあります。
これは、作成済みのAnimatorの構造をそのまま真似して、中身のアニメーションだけ差し替えるという使い方をするための物です。格闘ゲームなんかで言うと、Aボタンで攻撃、Bボタンでジャンプという遷移構造は全キャラクター共通なのでAnimatorで構造を作り、しかし攻撃モーションやジャンプモーションはキャラ毎に違うため、キャラクターごとにCustom Override Controllerを作成し、Animatorの構造だけ真似して、中身のアニメーションを差し替える、といった使い方です。

Custom Override Controllerで模倣するAnimatorを指定すると、このような画面が出てきます(下図右側)。既存のアニメーションに差し替えたいアニメーションを入れるだけなので、使い方がシンプルでわかりやすいです。
下の図では、左側の赤枠のHand (L)0~6のアニメーションの中身は、右側の赤枠のHand (L)0~6でアニメーションを指定しています。
下図右側でアニメーションがNoneになっている箇所は、元のAnimatorで指定されたアニメーションが適用されます。
Qiita_4.png

ハンドサイン、リップシンク、まばたき、表情遷移の実装

完成図を先に示します。こちらがAnimator
Qiita_5.png

こちらがMask
Qiita_6.png

こちらがViveコントローラの割り当て表
(割り当てるやり方についてはSteamVR Pluginの導入などが必要になるので別記事にします)
左手のコントローラの操作によって下図右のAnimatorのパラメータのHand (L)が0~6に変化します。
右手のコントローラの操作によって下図右のAnimatorのパラメータのHand (R)と、Faceが0~6に変化します。
(これはスクリプトによって制御しているので、その中身についてはこの記事では割愛。こういう風に割り当てたということだけ理解してもらえればよい。)
Qiita_7.png

?ハンドサインについて
左コントローラでHand (L)が変更され左手のハンドサインが変更されます。
右コントローラでHand (R)が変更され右手のハンドサインが変更されます。

?表情について
右コントローラでFaceが変更され、表情を変更します。
つまり右手のハンドサインも一緒に変更されます。

?リップシンクについて
右コントローラでLypSyncが変更され、リップシンクの ON / OFFを変更します。
つまり右手のハンドサインも一緒に変更されます。

?自動まばたきについて
右コントローラでAutoBlinkが変更され、自動まばたきのON / OFFを変更します。
つまり右手のハンドサインも一緒に変更されます。

そして、このAnimatorを指定したCustom Override Controllerを作ってやります。このCustom Override Controllerの中に表情やハンドサインなどのアニメーションを入れます。
Qiita_8.png

実際の動作

?左手の動作
左コントローラは左手のハンドサインの変更のみ行うので、動作は簡単ですので割愛します。

?右手の動作
右コントローラのハンドサインの部分の動作は簡単ですので割愛します。

?表情、まばたき、リップシンクの動作
右コントローラの状態が5のとき(=コントローラのトリガーを引いているとき)、スクリプトによってAnimatorのパラメータがFace = 5になるため、AnyStateからの遷移でFace 5、Auto Blink 5、Lip Sync 5のモーションが適用されます。上のCustom Override Controllerで言うとFace 5(目閉じ) / Blink 5(None) / LipSync 5(LypSync)のアニメーションが適用されます。

このとき、ベースとなる表情はFace 5(目閉じ)です。

別途のスクリプト(別記事にします)によってLipSync LayerのWeightとマイク音量を連動させると口パクします。
Animatorによって表情ごとにリップシンクの口の形を指定するので、「怒った表情では口を大きく開けたリップシンクをしたい」場合にも対応できます。
逆に、口パクを設定したくない表情では、アニメーションを設定しない(=None)にすることでリップシンクをOFFにできます。

同じように、別途のスクリプト(別記事にします)によってAutoBlink LayerのWeightを制御すると自動でまばたきをします。
これも、まばたきを設定したくない表情では、アニメーションを設定しない(=None)にすることでまばたきをOFFにできます。

おわりに

バーチャルキャラクターの実在感を出すにはハンドサインやリップシンク、まばたき、表情遷移がとても効果的です。これら全てをカメラやセンサーでトラッキングできなくとも、コントローラで操作し慣れることでトラッキングと同等以上に自然な動きができるようになります。特に表情に関して言えば、現実で笑ってなくても笑い顔を作れるのでトラッキングよりも便利かも(笑)

Unityを駆使して実在感のあるワンランク上の表現力を身につけていきましょ~!

以上、Animatorの遷移やLayer, Weight, Maskを上手く使ってハンドサイン、リップシンク、まばたき、表情遷移をする解説記事でした!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

UnityでInputの分岐器を作った話

概要

Unityあるある、「複数の操作可能なオブジェクトが同時に操作できてしまう」を抹殺するため、常に1か所にのみインプットを流す仕組みを作ったお話。
example.gif

作成したもの

https://github.com/domasyake/InputTurnout

経緯

 Unity、カスタマイズ前提で敢えて最低限の機能しか用意してないんだろうなーっていうもの幾つかあると個人的には思います、インプットなんかはそのうちの1つ。ゲームはプレイヤーキャラやUIなど、「入力によって操作できるもの」が多数必要になりますが、各自がバラバラにインプット情報を取得するとなると、操作対象の切り替えもBoolで判定したりとかGameObjectそのもののActiveで止めたりとかするしかなく、バグの温床になること請け合い。
 そこでインプット情報を常に1か所にのみ流すようにする分岐器(線路の切り替えするアレ)みたいなものを経由すれば、制御対象=インプット出力先となり各自で判定せずに済むだろうと考え作成しました。 
 ついでにインプットの依存先をInterfaceに強制できるのでインプット出力元の可変(アセット使ったりモック使ったり)にも対応できるようになります。

仕組み

インプットの出力元をサプライヤー、インプットを利用する側をレシーバーとします。
サプライヤーとして、実際に出力を行うEntityと常に非入力値を返すEmptyの2つを用意します。レシーバーは分岐器を介してサプライヤーにアクセスしますが、1つのレシーバーにのみEntityを、それ以外にEmptyを常に返すことでレシーバーは自身が今操作対象なのかどうかを意識せずに実装することができます。

使い方

GitHubのReleaseにあるUnityPackageをインポートしてください。サンプルも含まれているのでそちらも参考に。

レシーバー

private void Start(){
   InputTt.ChangeReceiver(this);//本来はレシーバーが直接ChangeReceiverするのではなく別途Managerなどの制御クラスで行うべき
}

private void Update(){  
   if (InputTt.Input(this).XXXX()){
   //移動処理とか
   }
}

サプライヤー

Interface

標準ではUnityEngine.Inputの主要メソッドのラッパーとして定義しています

IInputSupplier.cs
public interface IInputSupplier{
   bool anyKey{ get; }
   //中略
}

Entity

WrapUnityStandardInputEntity.cs
public class WrapUnityStandardInputEntity:IInputSupplier{
   public bool anyKey => Input.anyKey;
   //中略
}

Empty

WrapUnityStandardInputEmpty.cs
public class WrapUnityStandardInputEmpty:IInputSupplier{
   public bool anyKey => false; 
   //中略
}

Tips

  • あくまで本ライブラリはインプットを中継し分岐させるだけなので、サプライヤーはカスタマイズ前提です。 
  • EntityにMonobehaviour継承クラスを使用したい場合は、下記のようにInputTtクラスの初期化をコメントアウト等で無効にした上でセットを行ってください。
InputTt.cs
private static void SupplierInitialize(){
   //SetSupplier(new WrapUnityStandardInputEntity(),new WrapUnityStandardInputEmpty());
}

public static void SetSupplier(IInputSupplier entity,IInputSupplier empty){
   LogWrite("------see Input Supplier------");
   inputSupplier = entity;
   emptySupplier = empty;
}
  • あくまでInputTt.Input(object key)に渡されたインスタンスで判定を行っているだけなので複数のレシーバーで共通のインスタンスを持ってそれをキーとしてアクセスすれば複数クラスでインプットを受け取ることも可能です。
  • InputTt.IsActiveプロパティでインプットを停止できます。
  • インスタンスをキーにあらゆる変更を停止するFreeze()と解除用のUnFreeze()メソッドが用意されています。暗転時等、是が非でも操作させたくない時にIsActiveと合わせて使用したりなど。

余談

 冗長なコードが死ぬほど嫌いなので今まで3個くらいインプット制御のアプローチ作ってきたのですが、これが一番使い勝手よくてカスタマイズも楽だったので公開してみました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VIVEで操作するロボット Part0 -概要-

概要

大学4年間で触ったことのある技術や面白そうな技術を使って何か作りたい。
・サークルでロボット作ってた(回路班)
・プリント基板作りたい
・研究でRaspberryPi
・研究でDeepLearning
・Unity楽しそう
・BeatSaber楽しい

VIVEで操作できるロボットを作ろう!

目次

VIVEで操作するロボット Part0 -概要-(この記事)
VIVEで操作するロボット Part1 -Unityを使ってVIVEに動画出力-
VIVEで操作するロボット Part2 -RaspberriPiからUnityへ動画送信-
VIVEで操作するロボット Part3 -VIVEコントローラの情報をRaspberryPiへ送信-
VIVEで操作するロボット Part4 -サーボとモーターのテスト-
VIVEで操作するロボット Part5 -機体作成-
VIVEで操作するロボット Part6 -物体検出の実装-

仕様

ロボットの仕様
1. VIVEにカメラ映像を写す
2. 頭の動きによってカメラを動かす
3. VIVEコントローラのトラックパッドで移動
4. カメラ映像内の人や物を検出(DeepLearning使いたいだけ)

ただそれだけのロボット作ります。

ロボ概略図.png システム概略図.png

実現法

1. VIVEにカメラ映像を写す

Unity使うの初めて&RaspberryPiからPCに映像送信したことない
詳しい人に聞いてみたらUDPを使えばいいと言われたのでとりあえずこれ

UnityにSteamVRというプラグインがあるそうなのでそれを使用します。
Unityのメインカメラの前にカメラ映像を置く。
メインカメラに追従して常にメインカメラの前に映像が動くようにします。

Unity触りたいし調べてもVIVEをただのディスプレイにする方法が見つからないのでこの方法で作成します。

2. 頭の動きによってカメラを動かす

VIVEの角度(x軸、y軸)をUnityで取得します。
RaspberryPiへ角度送信。
(1.と同じUDPの予定、制御系は信頼性の高いTCPのほうがいいらしいが余裕ができるまでUDP)
二つのサーボモーターでカメラの角度を変えます。

3. VIVEコントローラのトラックパッドで移動

2.と同様
タイヤ構成は検討中です。
駆動輪2つでボールキャスター1つ使う3輪
駆動輪2つの4輪

4. カメラ映像内の人や物を検出

RaspberryPiで物体検出出来たらやりたい。
しかし、人や物体など検出するクラスが多いとDNNの規模が大きくなるため難しい…
クラスを限定する、もしくはカメラ映像を受け取ったPCで物体検出を行うなど検討中です。
DeepLearningのライブラリを使う場合はChainerを使います。

次の記事

VIVEで操作するロボット Part1 -Unityを使ってVIVEに動画出力-

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む