Arduinoで始めるIoT~外から家電の操作を行うまで~

こんちゃ!洋梨🍐です。

「スマホから家電の操作したいな~」なんて思ったこと皆さん無いでしょうか?

きっとあると思います(暴論)^^

そこで今回はスマホから家電を操作する為の手順を公開したいと思います~

今回使うもの

製作環境

・Unity + C#

スマートフォン(操作)側アプリの開発に使います。今回紹介するソースコードはC#で書かれているので.NET FrameworkやXamarinでも動きますよ。(確認済)

・Arduino + C

リモコン(実行)側にはArduinoを用います。なお言語はC言語ベースです。

材料

・Arduino 本体


HiLetgo® 2個セット NEWバーション UNO R3 ATmega328P USB CH340G Arduinoと互換性 + USB ケーブル [並行輸入品]

今回の主役です。C言語を使って電子部品を扱うことができます。

・赤外線LED

リモコンの操作信号を再現するために使います。波長は 950nmに近いものを使います。※850nmでは動きませんでした。

・赤外線 受光モジュール

リモコンの操作信号を再現するために使います。

・ボタン

操作用に使います。

・Wi-Fiモジュール

スマートフォンから操作したい場合、使用します。Arduinoをインターネットに接続できるようにすればいいのでイーサネットでもOK!

オプション

・IC2 OLED (128×64)

Arduinoから情報を出力(可視化)するために今回は使いました。

・コンデンサー

リモコンの光を遠くまで飛ばせるようにするとき使います。

・リレー

赤外線操作ではなくコンセント操作を使いたいときにどうぞ

仕組み

簡単なイメージ図

例えば、普通は左のようにテレビの操作にリモコンを使いリモコンがテレビに信号を送っています。

しかし、スマホで操作したくてもスマホではテレビに信号を送ることができません。

そこで今回は信号を送る部分をArduinoに肩代わりしてもらい、スマホからArduinoを操作することで間接的にテレビに信号を送るというわけです。

作成 (Arduino側)

すべて説明すると長くなってしまうため簡単な説明です。

Arduinoでは赤外線信号を保存・再生します。

受光モジュールを使いリモコンの信号を事前にキャプチャーし、スマホからの信号が届いたら赤外線LEDを用いてキャプチャーした信号を 再生すればいいというわけです。

リモコンをキャプチャーする様子

まずキャプチャー(保存)するためのソースコードです。

次に再生するためのソースコードです。

このプログラムをボタンを押したときに呼び出すようにすればボタンを押したときにキャプチャーした信号が再生されるようになります。

赤外線LEDはカメラで点灯していることを確認できる。
上のGIFは実際に再生したところ。リモコンの信号と同じ点滅をしていることがわかる。

スマホからの操作に使用する際はUDPポートを監視し、信号が流れてきたら事前に決めたパケット構造に基づき対応した信号を再生するようにした。

操作用アプリ製作 (操作側)

紹介用に部屋の電気をON・OFFにする機能だけをつけたものにしてあります。C#で書かれています。なおUnityで動作確認済みです。

メインプログラム (Unity用)

ここで使っている「UDPSystem」のスクリプトは長いため以前書いた

こちらの記事をご覧ください。UDPパケットの送信には上記事のスクリプトを汎用しています。

スマートフォンで実行したときのスクリーンショット

これでスマートフォンからUDPでのパケットの送信ができるようになったと思います。もちろんTCPを使ってもできます。(むしろそっちのほうが良いかも)

テスト

このアプリで本当に信号(パケット)が出せているのか、しっかり届いているのかは調べないとわかりません。今回は「Wireshark」というパケットキャプチャーを使い、パケットが届いているかどうか確認したいと思います。

なお、外出先など外部からパケットを送信・受信(操作)するには「ポート開放」などが必要です。プログラムではUPnPやホールパンチングなど技術を使う必要があります。UPnPは比較的簡単なのでこちらを参考にしてみてください。

今回は外部(外出先)から使う事を推定しているのでテストではスマートフォンの4G回線(Docomo)からリクエストを送信します。

テストのイメージ図

今回テストで送信するリクエストは「ID(01)の機器の電源をON(01)にする」にします。つまりUDPで送るデーターは「0101」です。

先ほどのプログラムの「case 1:」の部分です!

パケットキャプチャー

アプリでプログラムを実行すると、自宅にあるPCの「パケットキャプチャー」で見るとUDPでパケット「0101」が届いているのが確認できました。これで外部からつけることができるという事が確認できました。

まとめ

今回はIoTデバイス作りの第一歩として家電操作を行いました。

この記事は以前私がレポートとしてやったものを記事に起こしたものになりますので詳しく知りたい方は こちらからレポートをダウンロード してください~

書いている途中で面倒になってしまったのもあり、説明がいくつか抜けて分からない部分があるかもしれませんでしたがすいませんです!(> 3 <)

「よくわかんないからプロジェクトファイルくれ」「もっと詳しく記事書いて」などリクエストはメールにお願いします!


ここまで読んでくれてありがとうございました!!

ホームページでは他にも

・様々な記事や作った作品および過程
・ソースコード、素材ファイル
・あらゆる”モノ”の作り方

などなど随時、記事や作品を新規公開・更新していますので是非見ていってくださいね!見ていただけると本当に嬉しいです!

Thank You Watching💛

UnityでPS4のコントローラーを使う方法

こんにちは!洋梨🍐です。

Unityでゲーム開発(PC・スマートフォンどちらでも)をしていくうち、コントローラーを使いたくなることがきっとあると思います。そんな方に向けて今回はUnityでコントローラーを使う手順を書こうと思います。


Unityのキャラクターを動かしている様子

コントローラーをパソコン(Android上ではBluetoothで)に接続

今回はコントローラーにPS4用コントローラー「Dual Shock 4」を使います。


ワイヤレスコントローラー (DUALSHOCK 4) ジェット・ブラック

ここに特別な設定はいりません。PCには通常のUSBケーブルで。AndroidスマートフォンにはBluetoothで接続するだけです。

Input Managerに登録

次にUnityのInput Manager上でDS4のボタンを認識させるために設定を行います。

「Edit」→「Project Setting」→「Input」で設定画面を出すことができます。

次にSizeを変更します。追加したいボタンの分だけ増やした数値を入力します。※使用しない既存の項目を変更しても良い

次にボタンそれぞれを登録していきます。と言いたいところですがもう既に割り当ててあるある場合もあるのでその場合は登録しなくても大丈夫です。

次の例ではDS4の×ボタン動作を割り当てたものです

割り当ての一例。DS4の「×ボタン」入力を受け付ける用です。

スクリプトから読み取る

登録したボタンを使うには

これだけです。これをUpdate()内などに書き込み、処理を行います。

Input.GetButtonDown(string) は押されているときtrueを返し、押されていないときはfalseを返します。

また、スティック入力の場合は Input.GetAxis(string) を使用します。

DS4の右スティックの位置を取得するには次のように書きます。

この x , y は位置に応じて -1 ~ +1 ã®å€¤ã«ãªã‚Šã¾ã™ã€‚動かしていない(中央)ときは0になります。

ちなみにこの Horizontal 及び Vertical は元々 Input Manager に登録されていると思います。

しかし、左スティックは登録されてないと思うので左スティックも使いたい場合は Input Manager から登録する必要があります。既存の Horizontal を参考に2つ目を作って使うことになります。

どんな感じに使うのか(参考程度)

PS4の右スティックで移動、×ボタンで上に上がるサンプルになります。動かしたいオブジェクトにアタッチすることで使用することができるはずです。なお、使用前に Input Manager での登録が必要です。

以上です!


ここまで読んでくれてありがとうございました!!

ホームページでは他にも

・様々な記事や作った作品および過程
・ソースコード、素材ファイル
・あらゆる”モノ”の作り方

などなど随時、記事や作品を新規公開・更新していますので是非見ていってくださいね!見ていただけると本当に嬉しいです!

C#でUPnPを使った ポートマッピング

ゲームを始めオンラインでの通信機能が必要になる事は多いと思います。

そんな時立ちはだかる難関の1つ。それはNAT越えです。

NAT越えをする手段はいくつか考えられますが、今回は一番簡単(?)なUPnPを使ってルーターにポートフォアリングを設定して通信通路を確保したいと思います。 この記事はその時の記録です。

実行・テスト環境

テスト環境:Unity 2018 2.9f1

今回のプログラムはUnity+C#で作成。

パケット送信などの仕組み・ソースコードは 前に書いた記事「UnityでUDP通信を行うには」 などを参考にしてください。

ルーターにポートフォアリング(ポート転送)をリクエストする

ネットワーク内のルーターを探索する

探索の為に「M-Search」リクエストを送信先「 239.255.255.250 : 1900 」(ブロードキャスト)にUDPで送信します。

「M-SEARCH」送信の様子

その後ルーターなどUPnP対応機器からのリスポンス「NOTIFY」が同じアドレスで返ってくるので受信します。

UPnP対応機器からのリスポンス「NOTIFY」

ルーターの情報を取得

先ほどの情報を元にルーターに「HTTP / GET」で詳細情報をリクエストします。

リクエストは以下のようなプログラムで実装しました。


私の環境では「192.168.0.12」のPCから「192.168.0.1」のルーターにリクエストを送信している

なお、リクエストに成功すると「HTTP 200 OK」が返され、XML形式の情報を入手することができます。

そのXMLのうち今回は <controlURL> の情報を元にリクエスト先アドレスを入手します。

リクエストをルーターに送信

先ほどの情報を元に対象のアドレスに「HTTP / POST」でリクエスト内容(SOAPプロトコル)を送信します。

今回テストに送信したリクエストは以下の通りです。

このリクエストではポート「12345」のUDP通信を「192.168.0.12」に転送するリクエストをしています。

ExternalPortとInternalPortは転送元と転送先なので通常同じにします。

リスポンスを受信し成功確認

上のSOAPリクエストを送信するとルーターからリスポンスを受け取ります。

この時、「HTTP 200 OK」なら成功です。

HTTP/1.1 200 OK で成功だとわかる
ルーターの管理者ページでも確認できる

成功すると上図のように管理者ページにも追加されているのがわかる。

なお、失敗だと「 HTTP/1.1 500 Internal Server Error 」が返されます。失敗原因としては「既にポートが使用中」「UPnP設定の上限まで達している」などが挙げられます。

そもそも何も返ってこない場合、そもそもどこかが間違えているはずですので再確認してみてくださいね。

外部からの送信テスト

ポートフォアリングの設定などがしっかり出来ていることを確認するために外からUDPでパケットを送信してみます。

パケット送信アプリで送信テスト

スマートフォンからDocomo(4G)のキャリア回線で自宅のパソコンへとメッセージを送信。

パケット(メッセージ)が届いているのが分かる

受信できていれば完璧です。

オンラインゲーム作りの第一歩ですかね^^

今度は「UDPホールパンチング」という方法でも挑戦してみたいと思います。
またその時は記事を書きますね


ここまで読んでくれて本当にありがとうございました~^

ホームページでは他にも

・様々な記事や作った作品および過程
・ソースコード、素材ファイル
・あらゆる”モノ”の作り方

などなど随時、記事や作品を新規公開・更新していますので是非見ていってくださいね!見ていただけると本当に嬉しいです!

また、「このアプリの作り方を知りたい。この部分どうなってるの?」「身の回りのこんなもの作れるの?」などなどご意見何でも受け付けていますので是非連絡くださいね!

Unityでカメラ(PC/スマホ)を使う方法

Unity上で「カメラを使って~をしたい!」「写真を撮りたい!」という方、多いのではないでしょうか?そこで今回はUnityでカメラを使う方法について書きたいと思います。

カメラにアクセスするには?

「WebCamTexture」といったクラスを使います。

このクラスを使うと、カメラ(Webカメラ・スマートフォンのカメラ)で映し出された映像をテクスチャとして扱うことができまるようになります。

※なお、スマートフォンの場合フロント・リアカメラどちらにでもアクセスすることが可能です。

とりあえず映してみる

まずは「どうやってプログラムを書けばカメラの映像を出せるかだけが知りたいんだよ」という方も多いと思うのでとりあえずサクッとカメラの映像を表示させてみようと思います。


もし、PCにカメラがついていない環境で開発する人(デスクトップPCなど)は

このような安いものでも探してみるといいかもしれません~👼


1.まずプロジェクトを作成し、カメラの映像を表示させるための「RawImage」を設置します。

※「Create」→「UI」→「Raw Image」から作成可能です。

2.スクリプトを作成します。

ファイル名:WebCameraTest.cs

3.スクリプトをシーン上のオブジェクト(今回はEventSystemにしているが何でも良い)にアタッチし、その後スクリプト内RawImageにもアタッチする

4.実行してみる。PCの場合はカメラを接続してから実行してください。

しかし!環境によって次の問題が発生する場合があります。

・スマホで実行したとき、求めているカメラの方向ではない(リア・フロント)
・PCでやったがそもそも映らない
・移された画像の向きが反対

これらには理由がありますので次項で解説していきたいと思います。

WebCamTextureをいじってみる

使用するカメラを選択・変更する

アプリの実行環境によってはカメラがいくつか複数個、接続されている可能性があります。この場合、表示させるカメラを選ばなくてはいけません。

もし前項で実行したが表示されなかったという人は、表示できないカメラにアクセスしていたのかもしれないのでここで正しい表示させたいカメラを選ぶことが大切です。

カメラを選択する

先ほどのソースコードに追加し、ボタンをクリックするとカメラを変更できるようにしたいとおもいます。

スクリプトを上のように変更し、シーン上に変更用ボタンを生成します。その後、ボタンのOnClickにpublic void ChangeCamera()を割り当てれば完了です。

ボタンを押せばカメラが切り替わると思います。(複数個接続時)

※また、スマホのリア・フロントカメラは別々のカメラとして扱われます。

取得する画質・フレームレートを変更する

WebCamTextureのインスタンス生成時に引数として画質やフレームレートを指定すると変更することができます。

カメラによっては対応していない場合もあります。
(例:HDカメラでFull HDをリクエスト等)

カメラをミラー表示にする

この映像を、

こうする。

やり方はRawImageのスケール(Scale)のXを-1にするだけです。

上下反転したい場合はYを-1にすればOKです。

3Dオブジェクトに表示する

このように3Dのオブジェクトにカメラの映像を張り付けることもできます。

GameObjectのテクスチャをWebCamTextureに変える事で実装可能です。

まとめ

ここではUnityでカメラを使う方法について説明しました。カメラを使えば写真を撮る以外にも様々な使い方ができるようになるのではないでしょうか?

Unityでカメラを使った例:
Webカメラを使って顔認識 モーションキャプチャーへの道(Part 1)

これからもカメラを用いた様々な使い道を見つけていきたいですね!

読んでくれて本当にありがとうございました^^

もしよろしければ他の記事も観ていってくださるとうれしい限りです!

Unity上でUDP/IPを用いた通信機能(マルチプレイ)を実装する

こんちゃ!洋梨🍐です。

unityでマルチプレイをはじめとする通信機能を実装したい方、多いのではないでしょうか?

そこでUNET(廃止予定の様ですが…)、Socket.ioなどを使おうと考えた・考えている方も多いと思うのですが私は勉強の為やライセンスの問題、使いやすさの点から1から作ってみたのでそれまでの過程及びソースコードなどを記事にしました。

今回作るもの

今回はUnityの動く端末間で、オブジェクトの位置情報を共有できるようにしていきたいと思います。


PC・スマホ間でステージ内Cubeの位置情報を共有している図

応用次第ではクライアントサーバー形式・p2p形式でのマルチプレイ機能実装など様々なことに使えるのではないでしょうか?

仕様

今回はゲームオブジェクトの位置共有、つまりTransform.positionのVector3 情報を受信及び反映、送信したいとおもいます。

なお、今回行う通信はアクションゲームで使うことを推定し、高速化を図るためUDPで行います。

Tips 「TCPとUDPの違い」
TCP : 安定性は高いが低速。

>ゲームではチャットやマッチメイキングに使われる。
UDP : 不安定だが高速。

>FPSなど速さが大切なゲームの通信で使われている。
(※RUDP : 二つを組み合わせ安定性、高速を兼ねそろえたもの。実装はアプリ側。)

プロジェクト

今回作ったプロジェクト

今回はステージ内に配置したCubeの座標を共有します。椅子とかは距離感をつかみやすい様になんとなくおいた飾りです。Textには現在のCubeの座標を表示しようと思います。

(プロジェクトファイルのダウンロードは下にあります。)

スクリプト

main.cs メイン。主な動作はここに書く。
UdpSystem.cs UDP通信の動作をまとめてあるものです
MyNetwork.cs IPアドレス取得等、ネットワーク関連の基本動作を担当

(ソースファイルのダウンロードは下にあります。)

ポート番号

同じでもいいのですが今回はホスト端末Aには5001、クライアント端末Bには5002としてあります。なお、送信に使うポートは6001としました。

パケット構造

今回は位置情報の共有のみなのでVector3(x,y,z)の情報が入るパケットを作って送ります。パケット情報を管理するクラスは以下の通りです。

DATAクラスはインスタンス生成時の引数(Vector3もしくはbyte配列)に応じてfloat x,y,zの値に変換します。インスタンス生成後、ToVector3(),ToByte()で双方に変換できるようにしています。

Vector3のそれぞれの値(x,y,z)はfloat型なので4byteです。そのためパケットサイズは12Byteになります。パケットの構造は以下の通りです。

今回の送信パケットのデーター構造

※今回は受信側・送信側と1対1での通信で一つのオブジェクトの位置座標共有しかしていないためパケットに識別番号や送信元IPなど情報を含んでいません。なお、TCPなら送信元IP等がなくてもコネクションでわかりますがUDPはそうもいかないため含まないと判別できません。

ソースコード

※なお、今回紹介するソースコードは以前私が作ったマルチプレイ仕様ゲームの一部を切り取り、説明用に編集したものになります。

Main.cs

UdpSystem.cs

ライセンスなんて書いちゃってますけどこの Younaship.com をどっかに紹介してほしいなーって思ってるだけなんであまり気にしなくて大丈夫です。

ソースファイル説明

UdpSystem.cs の説明です。

Class : UDPSystem()

コントラクタ
UDPSystem(Callback)

インスタンス生成時、コールバック関数を引数としてとります。このコールバックは受信時発生するため送信用として生成するときはnullでも大丈夫です。

関数

Set(hostIP,hostPort,clientIP,clientPort)
自分及び相手のIP、ポートをセットします。
Receive()
受信を開始します。受信するとコールバックが呼ばれます。
Send(byte[])
byte[]を「clientIP:Port」へ送信します。
Send_NonAsync(byte[])
byte[]を同期送信します。※同期送信なので送信中はほかの動作は停止します。
Stop()
WebSocket を閉じます。

Class : ScanIPAddr()

自分のIPアドレス取得用のクラスです。
var myIpAddr = ScanIPAddr.IP[n] といった感じで使います。
nには識別番号を入れます。

~NOTE~
例えばスマートフォンの場合、Wi-fi接続時はキャリア回線(4G/3G)でのIPアドレス・Wi-fi上でのIPアドレスが存在してしまうため選ばなくてはいけません。また、PCの場合仮想PCのネットワークアダプタがあるとそのIPアドレスが存在してしまいます。どちらにおいても優先順位が高いほう(接続中)が0になっているはずなのでデフォルトでは0でいいと思います。状況に合わせて変えてください。

Class : ScanDevice()

特に現段階であまり意味ないです。気にしないでください。

ソースファイル・動作説明

・まず通信を開始するためにUdpClientクラスのインスタンスを生成します。

ホスト側 (ipAddr)
udpSystem = new UDPSystem(null);
udpSystem.Set(ipAddr, 5001, ipAddr2, 5002);

クライアント側(ipAddr2)
udpSystem = new UDPSystem((x) => Receive(x));
udpSystem.Set(ipAddr2, 5002, ipAddr, 5001);
udpSystem.Receive();

クライアント側には受信時の動作としてReceive(byte[])を指定しています。
これで指定ポートでの受信時にReceive(byte[])関数が呼ばれるようになります。(引数は受信したByte配列)

・Update()内で繰り返し行う部分を書き込みます

ホスト側
vector3 = gameObject.transform.position;
DATA sendData = new DATA(vector3);
udpSystem.Send(sendData.ToByte(),99);

ホスト側はゲームオブジェクトの座標を取得・送信を繰り返します。
SendData.ToByte()でVector3の座標情報をByte配列に変換し、その内容をudpSystem.Send()で送信しています。

またSend()で送信する際に引数99をとっているのは理由がありまして、私の作ったSend関数は送信に失敗した場合(送信処理中などで)に10回までコンテニューをするようになっているためにループで呼ぶ際は失敗するとどんどん送信待機中のデータが溜まってしまうので引数に10以上の数値を入れることで失敗しても1度しか送らないようにし、回避しています。この辺は各自でカスタマイズしてください。

クライアント側
gameObject.transform.position = vector3;

vector3に保存されている値をゲームオブジェクトに反映させています。

void Receive(byte[] bytes)
{
DATA getData = new DATA(bytes);
vector3 = getData.ToVector3();
}

クライアント側のみサーバーからデータを受信時この関数が呼び出されます。受信したByte配列のデータを使える形に変換及び読み取り用の変数vector3に代入しています。

共通部分
text.text = “(” + vector3.x + “,” + vector3.y + “,” + vector3.z + “)”;

現在のゲームオブジェクトの位置を数値として画面に表示しているだけです。


ダウンロード

「ソースコード見ただけじゃ分からんわ👼」
「いや、動かんやけど♡」

という方などに向けてプロジェクトやソースコードの配布を行います。
※なお、全ての環境における動作保証はしていません事をご理解ください。

当方が確認した動作環境

・「デスクトップPC」- (有線LAN) – (wi-fi) -「スマホ」
・「ノートPC」- (wi-fi) – 「スマホ」
・ 「デスクトップPC」- (有線LAN) -「ノートパソコン」

での通信ができることを確認しました。なお、スマホは「Android(Xperia-Z5及びX)、iphone 6」を用いて確認しました。

ソースファイル ( main.cs、UdpClient.cs )

(2019/01/18 追記) 一応これでも動きますが変な部分・書き直すべき部分があったので一部書き直しています。いつか新しいソースコードに変えておきます。

Unity プロジェクトファイルのダウンロード (zip形式)


ここまで読んでくれてありがとうございました!
沢山の人でゲーム業界・アプリ業界など盛り上げていけるといいですね!

ホームページでは他にも

・様々な記事や作った作品および過程
・ソースコード、3Dファイル
・あらゆる”モノ”の作り方

などなど随時記事を新規公開・更新していますので是非見ていってくださいね!見ていただけると本当に嬉しいです!

また、「このアプリの作り方を知りたい。この部分どうなってるの?」「身の回りのこんなもの作れるの?」などなどご意見何でも受け付けていますので是非連絡くださいね!

スマホ向けに始めるVR Part1

どうも!洋梨🍐です!

みなさん「VR」ご存知でしょうか?
今この「VR」や「AI」がホットな分野だと思います!(個人的意見)

そんなわけで今回は簡単なVRアプリの作り方について初心者にもわかりやすく書いていこうと思います!

作成時間の目安は

Unity、プログラミング未経験者:30分
Unity初心者:10分
Unity経験者:5分

ほどで出来ると思われるほどVRの参入は簡単です!
※個人的体感速度になります。

ぜひ、そもそもアプリを作ったことがない方もやってみてくださいね♪

用意するもの

・スマートフォン (今回はAndroid)

作成したアプリをインストールして使います。
今回私は Xperia Z5 を使用しました。

※事前に設定で開発者オプション→USBデバックをONにしておいてください

・ヘッドマウントディスプレイ(HMD)


↑( 私が買ったのはこちら)↑
アプリを実行するのに使います。

・Unity

まだPCに入ってない方はこちらから無料版をダウンロードしてください!

・GoogleVR SDK (For Unity)

Unityに取り込んで使います。ここからダウンロードできます。

プロジェクトの作成

まずUnityを起動し、プロジェクトを作成します。

お好きな名前、ファイルパスに設定し3Dで作成してください。

GoogleVR ForUnity のインポート

事前にダウンロードした「GoogleVRForUnity_[バージョン名].unitypackage」をUnityが起動した状態で開きます。すると、

この画面が出ると思うので最初は無心でImportをクリックしてください!

インポートが完了するとAssets/GoogleVRが作成されているのが分かると思います。

Prefubのアタッチ

Assets/GoogleVR/Prefubsの中から

・GvrEventSystem

・GvrControllerMain

・GvrEditorEmulator

を探して無心でとりあえずシーンに追加します。

PlayerSetting

Unity上部タブ「Edit」→「Project Setting」→「Player」を開きます。

ドロイド君タブ内のXR Settingを開き、Supportedにチェックをつけ、+ボタンから上画像のように無心で追加します。

オブジェクトの追加 (任意)

この上までの作業でもう既にVRアプリは完成しています!

しかし、ステージ上に何もないため実行しても何もない世界を見渡すだけになってしまいますので何かしら追加したいと思います。

過去に作った3Dモデルがあれば配置してもいいし、

無ければ右クリック・Createから3D Objectなどで作ってもいいと思います!

ビルド

ではこれでプロジェクトが完成したのでアプリを実際動かしていきたいと思います。Unity上部タブから「File」→「Build Settings」を開きます。

そしてAndroidを選びます。スマホがPCに接続されていることを確認したら、「Build And Run」で実行します。2台以上接続されている場合Run Deviceから実行する端末を選んでください。

※IphoneなどIOSでの実行はXcodeに出力、および実行の手順がありますが割愛させていただきます。

スマートフォンでVRアプリが実行できれば成功です。
思ってたよりとても簡単だったのではないでしょうか?

まだこれでは見渡すだけなので好評だったら動けるようにしたり、ゲームにしてみたりと続きを書いてみようかと思います~


エラーが起きる

この記事通りに実行しても環境によりエラーが出ることがあります。
アプリ開発・プログラミングにエラーはつきものです(;^ω^)
ここには一般的なエラーと解決方法を書いておきます。

UnityException: Minimum API Level Not Supported on Requested VR Device.Cardboard Requires a Minimum API Level of 19.

指定最低APIレベルが低すぎます。この場合ですと、Level 19 ( Android4.4 )以上にする必要があります。PlayerSettingを見直してみてください。

Build completed with a result of ‘Failed’

様々な原因がありますが主には

・スマホが接続されていない。(adbで接続できているか確認)
・JDK・SDKのパスが間違っている。(External Toolsで確認)
・パッケージ名が初期のまま(PlayerSetting→PackageNameを変更)


読んでいただきありがとうございました^^

これからもどんどん記事を書いていこうと思ってますのでどうぞよろしくお願いします!!

最新の記事を見る→

Unity上で顔認識 ~Webカメラでモーションキャプチャーへの道~ Part2

どうも!洋梨🍐です!

前回の記事

[ Unity上で顔認識 ~Webカメラでモーションキャプチャーへの道~ Part1 ]

の続きになります!

マスク画像から輪郭を抽出

基本動作

UnityでのTextureのデーターは左下を0,0として保存されています。

そのため、マスクデーターも同じく左下を0,0として2次元配列として保存しています。

今回マスクデーターの配列はByte型を使用しました。bool型でも良かったのですがスタート位置をマークしたかった為、Byte型にしました。


※( Byte[ width , height ] px の引数としている部分 )

さて、ピクセルデーターから輪郭を抽出するには

このように周りのピクセルをたどっていくのが一般的なようなのでこの方法で行きたいと思います。

しかしこの処理は1フレーム事に行うため、この部分が重い処理だとフレームレート低下に繋がってしまいます。そのためアルゴリズムの最適化などが必要になります。

処理の流れ

左下の0,0からX軸方向にピクセルデータを取得していき、ヒットした点を起点として今回は反時計回りに探索していきます。

次に探索する方向が分かるように、図のように方向ごとに数字を割り振ります。

この数字を引数とした関数を作り、前回の探索した方向から次探し始めるべき方向を決めます。今回は大きい数字から少ない数字へと探索します。

※たとえば4からの場合4321 9 … と探索します。

この関数では初めてピクセルにヒットし呼び出された時

4から探索を始めます。

なぜなら下から上へ・左から右へと探索してきたので、

5、6、7、8には存在しないためです。

このような法則を元に次の探索開始点を求める関数を別に用意します。

前の探索方向を元に次の開始方向を返す関数 GetNextWay( int )

※また、前の数字が偶数だった場合5回、奇数だった場合6回で探索できない場合おかしい(エラー)という事も踏まえてこの段階で例外処理も入れておきます。

このように探索していき探索後、引数としてとったピクセルデーター配列の変数(byte[ , ])を(探索したピクセルを)1から2にしていきます。

そして探索開始点に戻ってきたら処理を終了します。

探索開始時呼び出す関数 StartScan( int , int ,ref byte[ , ] )

探索するメイン関数(1) Scan(int , ref int ,ref int ,ref List<Pixel_XY>)

保存用クラス class Pixel_XY

このままだとノイズの輪郭も判定してしまっているため小さい輪郭(輪郭のピクセル数がしきい値以下)は除外するなどの処理をします。

※これらの結果は Dictionary<int, List<Pixel_XY>> result として保存されます。
また、result.Countで輪郭の総数、result[ int ].Countで [int]つ目の輪郭のピクセル数が分かるようになっています。

このデーターを元に画面に囲ったボックスを表示すると

↓ このようになります ↓

かなりそれっぽくなってきたのでは無いでしょうか?

これで大体の顔を特定できたという事で、次は体の部分を特定できるようにしていきたいと思います!!

読んでくれてありがとうございます!

他にも様々な記事を書いていますので是非見ていってくださいね^^

Unity上で顔認識 ~Webカメラでモーションキャプチャーへの道~ Part1

どうも!洋梨です!🍐

先日、Facerig + Live2D を用いてWebカメラで2Dモデルを動かしているのを見て、Webカメラで3Dモデルを動かすことはできないのか?と考えました。

※(Live2Dについてはこちら Facerigはこちら をご覧ください。)

ここで私は

1.顔を画像から探す
2.顔から下を人物と特定。
3.人物から体のポーズを取得。
4.ポーズデーターを3Dモデルに反映させる。

これが出来れば動かせるようになるのではないか?と自分は考えたのでこれから順々に作っていこうと思います。Unityはまだ使い始めて半年のためWebカメラは使用したことが無かったので、そこから順に書いていきたいと思います。

画像から顔を取得する

まずは画像から顔を取得できるようにしたいと思います。
これには定番「OpenCV」を使うことも考えたのですが、

・せっかくなら最初から作ってみたい
・Phython向き
・そもそも高度正確な抽出は必要なく、顔の位置がわかる程度でいい
・背景は部屋で撮るため単色
・余計な処理を除いて軽くしたい

という点から作ることにしました。

抽出方法についてなのですが手軽に軽く済ましたかったので今回は背景差分法、RGB(HSV)を用いて肌を検出、及び顔を抽出してみました。

UnityでWebカメラから画像を取得

この部分は他にかなり参考になるサイトがあると思うので簡単な説明です。

詳しい説明が欲しい方が多いようなのでWebカメラから画像を取得する方法はこちらをご覧ください~


ソースコード

WebCamTexture を使ってカメラから画像を取得します。
また、今回は画質はを求めていないため、320×240を指定しています。


※ちなみに今回私が買った・使っているWebカメラはこちら


LOGICOOL ウェブカム HD画質 120万画素 C270

費用を抑えたかったのでかなり安いやつを選びました。私はモーションキャプチャの研究用に買ったので大丈夫ですが、「配信したい」など画質を求めて買うのはやめましょう。

しかしデスクトップPCなどWebカメラがついてない方は今後の為にも購入をお勧めします。(値段もそこまでしないので)


WebCamTexture を RawImageのTextureにセットし、実行します。

Webカメラのデーターを取得できるとこのように表示することができます。

※IndexOutOfRangeExceptionなどエラーが発生する場合、カメラ番号に値するカメラが存在していない可能性があります。Windows 10に標準搭載されているカメラアプリなどで表示できるか確認してみてください。

画像から肌を検出

上のソースコードをUpdate()などに書きフレーム毎呼び出します。

Near_Color_Chack_RGB() は 入力された色と一定範囲内の色だった場合、Trueを返す自作関数です。

Near_Color_Chack_RGB(Color 32)

これで肌の色に近いピクセルを抽出することが出来ました。

また、ここにさらにHSVによる判定も加えて「PixelData[,]」からノイズを減らし、精度を多少上げます。


この段階で「pixelData[,]」をマスクとしてレイヤーを重ねて表示すれば肌の色だけ取得できているのが確認できると思います。

※なお、今回はUnityでよく使われる「Color」クラスでなく「Color32」を使っています。理由はこれにより速度を大幅に上昇させることができるからです。

これで今回は顔のマスクデーターを作成するところまで出来ました。
では次回はこのマスクデーターをさらに管理しやすくしていきたいと思います!

次へ「モーションキャプチャへの道 Part 2」


ここまで読んでくれてありがとうございます!

ホームページでは他にも

・様々な記事や作った作品および過程
・ソースコード、素材ファイル
・あらゆる”モノ”の作り方

などなど随時、記事や作品を新規公開・更新していますので是非見ていってくださいね!見ていただけると本当に嬉しいです!

また、「このアプリの作り方を知りたい。この部分どうなってるの?」「身の回りのこんなもの作れるの?」などなどご意見何でも受け付けていますので是非連絡くださいね!