まゆたまガジェット開発逆引き辞典

電子工作やプログラミングのHowtoを逆引き形式で掲載しています。作りたいモノを決めて学んでいくスタイル。プログラマではないので、コードの汚さはお許しを。参照していないものに関しては、コピペ改変まったく問いません

Unityで一定時間ごとに色(色相)を変える

OSCアプリやMIDIのフェーダでオブジェクトの色を変えようとしてた過程でできたので、忘れずにメモ。
Unityの公式リファレンスで「一定時間ごとにライトが明るくなったり暗くなったりする」というサンプルがありますが、それを改良した形です。
RGBで計算するとややこしいことになるので、色相(色味)のみを変えることにしました。
RGBからHSVへの正確な計算式もあるようですが、かなりややこしいのと使うのは照明程度なので今回はパスしました。
f:id:prince9:20181016055356g:plain

オブジェクトを設置する

1.「GameObject」メニュー→「3D Object」→「Cube」で適当にキューブを作る

スクリプトを書く

1.「Assets」を右クリックし、「Create」→「C# Script」を選択する
2.「HSVTestScript」等、名前をつける
3.Hierarchyにある「Cube」に「HSVTestScript」をドラッグ&ドロップする
4.Hierarchyにある「Cube」をクリックし、Inspectorの「HSVTestScript(script)」の中にある「Cube 1」を探す
5.「Cube 1」に、Hierarchyにある「Cube」ドラッグする
6.「HSVTestScript」をダブルクリックして、下記のスクリプトを入力する

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

public class ColorHSVrScript : MonoBehaviour {
//色が変わるタイミング(時間)を「Cube」のInspector(Duration)で指定、初期値は1.0F
public float duration = 1.0F;
//Hierarchyにある「Cube」を「Cube 1」にドラッグする(「Cube」のInspectorにあり)
	public GameObject cube1;

	// Use this for initialization
	void Start () {

	}
	
	// Update is called once per frame
	void Update () {
		//durationの時間ごとに色が変わる
		float phi = Time.time / duration * 2 * Mathf.PI;
		float amplitude = Mathf.Cos(phi) * 0.5F + 0.5F;
		//色をRGBではなくHSVで指定
		cube1.GetComponent<Renderer>().material.color = Color.HSVToRGB(amplitude, 1,1);
		
	}
}

UnityでMIDI機器を使ってオブジェクトと照明の色をコントロールする

VR上でのライブ演出の作業が必要となり、PCキーボードやマウス制御では事故ると思ってMIDI機器を引っぱり出しました。
いろいろ大変だったので、Keijiro Takahashiさんが作成された「MidiJack」をお借りして制御します。
今回はKORGの「nanoPAD1(初代)」を使いました。「nanoPAD2」や10月下旬に販売される新しいnanoPAD2でもいけると思います。

f:id:prince9:20181015231629g:plain

プロジェクトファイルはこちらです。
www.dropbox.com

※照明のところで、MIDIナンバーのコメントが一部違っています。このサイトに掲載しているスクリプトは修正済みです。スクリプトの実行に影響はないですが、すみません

※2 三項演算子と「Input.GetKeyDown」「Input.GetKeyUp」の相性が極めて悪いようです。
これらを使う場合は、素直に公式の下記を使います。
docs.unity3d.com


下記はMIDI機器のドライバがすでにインストール済みとして進めます。

MidiJackを読み込む

1.下記のURLにアクセスする
github.com

2.緑色のボタンの「Clone or Download」をクリックし、「Download ZIP」をクリックしてダウンロードする
3.ダウンロードしたものを解凍する
4.プロジェクトを作成し、「MidiJack-master」フォルダ→「MidiJack.unitypackage」をUnityの「Assets」フォルダにドラッグ&ドロップする
5.「Import」ボタンを押して読み込む

オブジェクトと照明を作成する

1.適当にオブジェクトと照明をを配置して、名前をつける
f:id:prince9:20181015211143p:plain

2.「GameObject」メニュー→「Create Empty」で空のオブジェクトを作成する
3.2.に名前をつける(ここでは「Cubes」にしました)
4.オブジェクトと照明を3.にドラッグ&ドロップして、下記のような構成にする
f:id:prince9:20181015211554p:plain

スクリプトを書く

5.「Assets」を右クリックし、「Create」→「C# Script」を選択する
6.5.に「MIDITestScript」等名前をつける
7.Hierarchyにある「Cubes」に「MIDITestScript」をドラッグ&ドロップする
8.「MIDITestScript」をダブルクリックして、下記のスクリプトを入力する

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

//https://github.com/keijiro/MidiJack

//注意: 下記の「MIDITestScript」がファイル名と同じかチェックする。違う場合はファイル名に書き直す
public class MIDITestScript : MonoBehaviour {
	

//「Cubes」をクリックしてInspectorを開き、mycubeオブジェクト3つとSpot Lightオブジェクト3つをドラッグする
public GameObject cube1,cube2,cube3,slight1,slight2,slight3;

/* 
色を配列に登録
        UnityではRGB値で指定できないので、RGB値の後に「f/255f」をつける
        例: RGB値 165,42,42(茶色)
           public Color Brown = new Color(165f/255f,42f/255f,42f/255f);
        */

//キュープ用の色の配列
Color[] collors = new Color[] { Color.white,Color.red, Color.green, new Color(0f/255f,206f/255f,209f/255f)};

//照明用の色の配列、照明を消すには「Color.clear」を使っているのでちょっと無理やり感
Color[] lcollors = new Color[] {Color.clear,Color.green, Color.yellow, new Color(188f/255f,6f/255f,12f/255f)};

	void NoteOn(MidiChannel channel, int note, float velocity)
    {
        //Debug.Log("NoteOn: " + channel + "," + note + "," + velocity);

         Color c1 = cube1.GetComponent<Renderer>().material.color;
          Color c2 = cube2.GetComponent<Renderer>().material.color;
           Color c3 = cube3.GetComponent<Renderer>().material.color;

            Color lightC1 = slight1.GetComponent<Light>().color;
            Color lightC2 = slight2.GetComponent<Light>().color;
            Color lightC3 = slight3.GetComponent<Light>().color;



//下記、三項演算子を使った条件分岐(キューブの色)          
c1 = (note == 39) ? collors[1] //nanoPadの1
: (note == 36) ? collors[0] //nanoPadの7
: cube1.GetComponent<Renderer>().material.color = c1; //その他のキーが押されたとき、状態を保持

c2 = (note == 48) ? collors[2] //nanoPadの2
: (note == 38) ? collors[0] //nanoPadの8
: cube2.GetComponent<Renderer>().material.color = c2; //その他のキーが押されたとき、状態を保持

c3 = (note == 45) ? collors[3] //nanoPadの3
: (note == 40) ? collors[0] //nanoPadの9
: cube3.GetComponent<Renderer>().material.color = c3; //その他のキーが押されたとき、状態を保持

cube1.GetComponent<Renderer>().material.color = c1;
cube2.GetComponent<Renderer>().material.color = c2;
cube3.GetComponent<Renderer>().material.color = c3;

/* 
上記を条件分岐の「if」で書き直すとこちら
if(note == 39)
    {
     cube1.GetComponent<Renderer>().material.color = collors[1];
    }
    else if(note == 36)
    {
    cube1.GetComponent<Renderer>().material.color = collors[0];
    }

    〜略
*/

/* 
上記を条件分岐の「switch〜case」で書き直すとこちら
switch (note) {

    case 39: 
        cube1.GetComponent<Renderer>().material.color = collors[1];
        break;

    case 36:   
        cube1.GetComponent<Renderer>().material.color = collors[0];
        break;

    〜略

    default:    
        Debug.Log("エラー");
        break;
}
*/

//下記、三項演算子を使った条件分岐(照明の色)         
lightC1 = (note == 43) ? lcollors[1] //nanoPadの4
: (note == 42) ? lcollors[0] //nanoPadの10
: slight1.GetComponent<Light>().color = lightC1; //その他のキーが押されたとき、状態を保持

lightC2 = (note == 51) ? lcollors[2] //nanoPadの5
: (note == 44) ? lcollors[0] //nanoPadの11
: slight2.GetComponent<Light>().color = lightC2; //その他のキーが押されたとき、状態を保持

lightC3 = (note == 49) ? lcollors[3] //nanoPadの6
: (note == 46) ? lcollors[0] //nanoPadの12
: slight3.GetComponent<Light>().color = lightC3; //その他のキーが押されたとき、状態を保持

slight1.GetComponent<Light>().color = lightC1;
slight2.GetComponent<Light>().color = lightC2;
slight3.GetComponent<Light>().color = lightC3;

/* 
長くなるが、こちらのほうが無理がなくていいかも
if(note == 43)
    {
     slight1.SetActive(true);
    }
    else if(note == 42)
    {
    slight1.SetActive(flase);
    }
*/

  
    }

    void NoteOff(MidiChannel channel, int note)
    {
       
		Debug.Log("NoteOff: " + note);
    }

 

	void OnEnable()
    {
        MidiMaster.noteOnDelegate += NoteOn;
        MidiMaster.noteOffDelegate += NoteOff;
        
    }

    void OnDisable()
    {
        MidiMaster.noteOnDelegate -= NoteOn;
        MidiMaster.noteOffDelegate -= NoteOff;
        
    }


	// Use this for initialization
	void Start () {
  	
		
	}
	
	// Update is called once per frame
	void Update () {
		
	}
}

スクリプト解説 三項演算子

nanoPadのボタンに割り振られている番号(MIDIナンバー)がバラバラだったため、やむなく条件分岐で処理を書くことにしました。
switch〜caseやif〜elseなどを使えば楽なのですが、スクリプトが長くなりがちです。
今回はこれら条件分岐を短めに書く「三項演算子」を使いました。
注意点としては、演算子なのでif〜elseの「else」に該当する部分が省略できないことです。

以下、例1-3すべて同じ動きをします。

例1: if文

string s;
        if (note == 39)
        {
            s = "No.1 0n";
        }
        else if (note == 48)
        {
            s = "No.1 0ff";
        }
        else {
            s = "Other 0ff";
        }

例2: switch文

string s;
switch (note) {
	case 39:
		 s = "No.1 0n";
		break;
	case 48:
		s = "No.1 0ff";
		break;

	default:
		s = "Other 0ff";
		break;
}

例3: 三項演算子

string s;
s = (note == 39) ? "No.1 0n"
: (note == 48) ? "No.1 0ff"
: "Other 0ff";

swtich文と比較すると分かりやすいかと思われます。

= (演算子の式1) ?  式1の条件が真のときの処理
:  (演算子の式2) ? 式2の条件が真のときの処理
: すべてが当てはまらないときの処理;


となっています。

スクリプト解説 照明の色について

ifやswitchを書かないようにしていたので、「Color.clear」で無理やり照明を消しています。これに関してはifかswitchを使って、「slight1.SetActive(trueまたはfalse);」にしたほうがよかったかもしれません。

MESHの動きタグでUnityちゃんを走らせる(アセットなし)

ソニーMESHの動きタグをめっちゃ振ると、Unityちゃんが走ります。
疲れるので、人によってはスクリプトの微調整が必要かもです。
とりあえずできたのでポストです。

GPIOを使い、M5Stack(Arduino)経由でUnityにデータを送ります。
f:id:prince9:20180927053705p:plain

基本的には下記と同じです。
prince9.hatenablog.com



Arduinoでシリアルモニタを立ち上げた状態でUnityを動かすと、シリアルが認識しません。注意!

■準備
ソニーMESHの「動きタグ」
ソニーMESHの「GPIO」
・M5Stack(Arduino)
・ワイヤー

●MESH
これを下記のように接続します。
f:id:prince9:20180925205928p:plain

●Unity側(アセットなし)
1.Unityのプロジェクトを作り、「GameOBject」メニュー→「3DObject」→「Cube」などを選び、適当にオブジェクトを作る
2.「File」メニュー→「Build Settings」を選択し、「Player Settings」をクリックする
3.Inspectorの「Other Settings」→「Api Compatibility Level」を「.NET 2.0」にする
4.「Build Settings」を閉じる

5.アセットストアからUnityちゃんのデータをダウンロードする
6.アセットストアの「ダウンロードボタン」を押した後に「インポートボタン」を押す
7.「Import」をクリックし、「Heirarchy」にUnityちゃんをドラッグ&ドロップする
(「UnityChan」→「Models」→「unitychan」)

8.「Assets」を右クリックし、「Create」→「C# Script」を選択する
9.「MESHReceive」など適当にファイル名をつけて、後からスクリプトを書く
10.スクリプトを書いたら保存し、「Hierarchy」にあるUnityちゃんにドラッグ&ドロップして適用する

11.「Create」→「Animator Controller」を選択し「UnitychanMoveController」などに変更
12.「Assets」の中にある「UnitychanMoveController」をダブルクリックし、画面左上の「Animator」タブが選択されていることを確認
f:id:prince9:20180927050844p:plain
13.灰色の何もないところで右クリックし、「Create State」→「Empty」を選択
14.「New State」をクリックし、名前を「Idle」にする
15.もう一度灰色の何もないところで右クリックし、「Create State」→「Empty」を選択
16.名前を「Run」にする
17.「Idle」をクリックし、「Inspector」の「Motion」の横の◯アイコンをクリック
f:id:prince9:20180927050948p:plain
15.「WAIT00」をクリックして、モーションを設定する
16.「Run」をクリックし、「Inspector」の「Motion」の横の◯アイコンをクリック
17.「RUN00_F」をクリックして、モーションを設定する
18.「Idle」を右クリックし、「Make Transition」を選択する
19.白い矢印がのびるので、「Run」をクリックする。これはアニメーションが待機状態(Idle)から走る(run)に移行する設定を示している
f:id:prince9:20180927051833p:plain
20.白い矢印をクリックし、「Inspector」→「Has Exit Time」のチェックを外す。このチェックはアニメーションが終了するまで次のアニメーションが開始されないという設定で、もっさりとした動きになることがある
21.下記の「+」ボタンをクリックし、「Bool」を選ぶ
f:id:prince9:20180927051915p:plain
22.「New Bool」を「Running」と名前を変える
23.「Conditions」の「+」ボタンをクリックし、「Running」を「true」にする
f:id:prince9:20180927052034p:plain
24.「Run」を右クリックし、「Make Transition」を選択する
25.白い矢印がのびるので、「Idle」をクリックして下記のようにする
f:id:prince9:20180927052136p:plain
26.できた矢印をクリックし、「Inspector」→「Has Exit Time」のチェックを外す
27.「Conditions」の「+」ボタンをクリックし、「true」となっているところをクリックして「false」にする
f:id:prince9:20180927052212p:plain
28.「Hierarchy」のunitychanを選択し、「inspector」→「Animator」 →「Controller」の「None」と書かれているところに、「Assets」の中にある「UnitychanMoveController」をドラッグ&ドロップする
29.「Inspector」→「Animator」の「Apply Root Motion」のチェックを外す。プログラミングによってキャラクターを動かすときはこのチェックを外す


■コード
まずMESHは以下になります。
動きタグで振動を認識したら、デジタル出力をHight(ON)にします。その1秒後にデジタル出力をLow(OFF)にすることで、Hight(ON)の状態をリセットしています。
リセットしないと、振った後にHightのままになってしまいます。
動くタグの動作確認のために音も鳴らしています。
f:id:prince9:20180927030917p:plain

Arduino(M5Stack)コード
動きタグが振られたときが1、振られていないときは0をUnityに送っています。
シリアルモニタ代わりにM5Stackを使用しています。

#include <M5Stack.h>

#define MESH_pin 36  // GPIOをGPIO36につなぐ

int mdata = 0; //MESHのデータ用変数
 int sdata = 0; //0or1に変換する変数

void setup(){
    M5.begin();


Serial.begin(9600);
    pinMode(MESH_pin, INPUT);
}

void loop() {
  // 画面クリア
    M5.Lcd.clear();
    M5.Lcd.setCursor(0, 0);

    mdata = analogRead(MESH_pin); //動きタグデータ読み込み
    sdata = mdata / 3000; //データが振られていないときは0、振ったときは3700〜3800前後で出てくるので、0か1かに変換
    
    Serial.println(sdata); // シリアルに出力
    
//Unityにデータを送るとシリアルモニタが使えないので、M5Stackをシリアルモニタ代わりに
 M5.Lcd.setTextColor(WHITE);
      M5.Lcd.setTextSize(5);
    M5.Lcd.print(sdata);
    
    delay(100); //0.1秒ごとにデータを出力。疲れないためにこの値を要調整
      M5.update();
}

「めっちゃ振ったらそのぶんだけ動く」=「めっちゃ振ったら大きく動く」ことで、Unityちゃんを走らせています。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO.Ports;

public class UnitychanMoveScript : MonoBehaviour {

//Animator Contollerを処理するときのおまじない
private Animator animator;


	//new SerialPort("")にArduinoアプリで調べてメモしたシリアルポート名を指定する
SerialPort sp = new SerialPort("/dev/cu.SLAB_USBtoUART", 9600);

	// Use this for initialization
	void Start () {

//Animator Contollerを処理するときのおまじない
		animator = GetComponent<Animator>();

//シリアルポートが開いているか否か
		if (!sp.IsOpen) {
			sp.Open();
			sp.ReadTimeout = 1000;
		} else {
			sp.Close();

		}
	
	}
	
	
	// Update is called once per frame
	void Update () {
		

		//文字列を数値に変換、meshMoveがArduinoアプリから送られてきた値
		int meshMove = int.Parse(sp.ReadLine());
		Debug.Log(meshMove);


//動きタグを振ったとき(meshMoveが1のとき)
		if(meshMove > 0) {
			
//Unityちゃんが走る
		 transform.position += transform.forward * 0.1f;
            animator.SetBool("Running", true);
		}
		else {

//振っていないときは止まる
            animator.SetBool("Running", false);
        }

//キーボードの左右キーで向きを変える
		if (Input.GetKey("right")) {
            transform.Rotate(0, 10, 0);
        }
        if (Input.GetKey ("left")) {
            transform.Rotate(0, -10, 0);
        }
		
		
	}
}

M5StackをArduinoのように使ってUnityに送る(MESHの動きタグ・アセットなし)

アナログ出力はちょっと工夫が必要っぽいので、まずはデジタル出力から。
Arduino使えば早いというツッコミはナシの方向で・・・(汗

ソニーMESHの動きタグを振ると、Unityのオブジェクトが移動します。
追記でたくさん振ると大きく動くようにすることで、アナログ出力っぽい挙動を出してみました。

テストなので簡単なものを。
上手くやれば、動きタグを振ってる間、キャラクターが走るということも可能です。
(キーボードで移動させるスクリプトに手を加えるだけ)

f:id:prince9:20180927032837j:plain

M5Stack(Arduino)とUnityとの接続は前回と同じです。アセットは使いません。
prince9.hatenablog.com

Arduinoでシリアルモニタを立ち上げた状態でUnityを動かすと、シリアルが認識しません。注意!

■準備
ソニーMESHの「動きタグ」
ソニーMESHの「GPIO」
・M5Stack(Arduino)
・ワイヤー

●MESH
これを下記のように接続します。
f:id:prince9:20180925205928p:plain

●Unity側(アセットなし)
1.Unityのプロジェクトを作り、「GameOBject」メニュー→「3DObject」→「Cube」などを選び、適当にオブジェクトを作る
2.「File」メニュー→「Build Settings」を選択し、「Player Settings」をクリックする
3.Inspectorの「Other Settings」→「Api Compatibility Level」を「.NET 2.0」にする
4.「Build Settings」を閉じる
5.「Assets」を右クリックし、「Create」→「C# Script」を選択する
6.「MESHReceive」など適当にファイル名をつけて、後からスクリプトを書く
7.スクリプトを書いたら保存し、「Hierarchy」にある1.で作ったオブジェクト名にドラッグ&ドロップして適用する

■コード
まずMESHは以下になります。
動きタグで振動を認識したら、デジタル出力をHight(ON)にします。その1秒後にデジタル出力をLow(OFF)にすることで、Hight(ON)の状態をリセットしています。
リセットしないと、振った後にHightのままになってしまいます。
動くタグの動作確認のために音も鳴らしています。
f:id:prince9:20180927030917p:plain

Arduino(M5Stack)コード
これも前のこちらのコードを改良したものです。
prince9.hatenablog.com
動きタグが振られたときが1、振られていないときは0をUnityに送っています。

M5Stackを使う利点として、簡単にシリアルモニタ代わりにできるという点があります。
UnityやProcessingなど、他の開発環境にデータを送る場合、Arduinoアプリのシリアルモニタが動いているとエラーが出るので・・・

#include <M5Stack.h>

#define MESH_pin 36  // GPIOをGPIO36につなぐ

int mdata = 0; //MESHのデータ用変数
 int sdata = 0; //0or1に変換する変数

void setup(){
    M5.begin();


Serial.begin(9600);
    pinMode(MESH_pin, INPUT);
}

void loop() {
  // 画面クリア
    M5.Lcd.clear();
    M5.Lcd.setCursor(0, 0);

    mdata = analogRead(MESH_pin); //動きタグデータ読み込み
    sdata = mdata / 3000; //データが振られていないときは0、振ったときは3700〜3800前後で出てくるので、0か1かに変換
    
    Serial.println(sdata); // シリアルに出力
    
//Unityにデータを送るとシリアルモニタが使えないので、M5Stackをシリアルモニタ代わりに
 M5.Lcd.setTextColor(WHITE);
      M5.Lcd.setTextSize(5);
    M5.Lcd.print(sdata);
    
    delay(500);
      M5.update();
}


●Unity
動きタグが繊細なせいか、一度振っても、下記のように複数値が返ってくることがあります。

0 ←振ってない
1 ←実際に振った
1 ←自分的には誤認識
1 ←自分的には誤認識
0 ←振ってない

なので、実際に振ったときのみ処理を行うよう、1の値を出した回数をカウントする変数「count」を作っています。
まずは単純に「振ったら動く」です。振るごとに動きます。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO.Ports;

public class meshUnityScript : MonoBehaviour {

	 private int mMove = 0;
	 private int count = 0;

	//new SerialPort("")にArduinoアプリで調べてメモしたシリアルポート名を指定する
SerialPort sp = new SerialPort("/dev/cu.SLAB_USBtoUART", 9600);

	// Use this for initialization
	void Start () {
		if (!sp.IsOpen) {
			sp.Open();
			sp.ReadTimeout = 1000;
		} else {
			sp.Close();

		}
		
	}
	
	// Update is called once per frame
	void Update () {
		//文字列を数値に変換、meshMoveがArduinoアプリから送られてきた値
		int meshMove = int.Parse(sp.ReadLine());
		Debug.Log(meshMove);

//動きタグを振ったとき(meshMoveが1のとき)
		if(meshMove > 0) {
			count += 1;
		}
		else {
			count = 0;

		}
//動きタグを「実際に振ったとき」オブジェクトを動かす
		if(count == 1) {
			mMove += 1;
			transform.Translate(Vector3.left * mMove,Space.World);
		}
		
	}
}

誤認識をあまり厳密に捉えず、「めっちゃ振ったらそのぶんだけ動く」=「めっちゃ振ったら大きく動く」場合のコードはこちらです。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO.Ports;

public class meshUnityScript : MonoBehaviour {

	 private int mMove = 0;
	 private int count = 0;

	//new SerialPort("")にArduinoアプリで調べてメモしたシリアルポート名を指定する
SerialPort sp = new SerialPort("/dev/cu.SLAB_USBtoUART", 9600);

	// Use this for initialization
	void Start () {
		if (!sp.IsOpen) {
			sp.Open();
			sp.ReadTimeout = 1000;
		} else {
			sp.Close();

		}
		
	}
	
	// Update is called once per frame
	void Update () {
		//文字列を数値に変換、meshMoveがArduinoアプリから送られてきた値
		int meshMove = int.Parse(sp.ReadLine());
		Debug.Log(meshMove);

//動きタグを振ったとき(meshMoveが1のとき)
		if(meshMove > 0) {
			count += 1;
mMove += 1;
			transform.Translate(Vector3.left * mMove,Space.World);
		}
		else {
			count = 0;

		}

		
	}
}

M5StackをArduinoのように使ってUnityに送る(光センサー・アセットなし)

本来は加速度センサーを使ったほうが分かりやすいですが、手持ちがなかったので光センサーで代用です。
光センサーに光を当てると、Unity側のオブジェクトが回転します。
いろいろ書いて最初は上手くいかなかったのですが、どうも「int rot = int.Parse(sp.ReadLine());」がキモなようです。

f:id:prince9:20180926055721p:plain
f:id:prince9:20180926055732p:plain
写真は手持ちがなくて10kオームの抵抗を使ったせいで、値が1kオームのときとは異なってますが、お気になさらず。

■準備(Arduinoと同じ)
・1kオームの抵抗
・光センサ
・M5Stack
・ワイヤー

Arduino
1.下記のように接続する
図と抵抗の値が違っていますが、抵抗の色は無視してください。1kオームを使用します。
f:id:prince9:20180925195123p:plain
2.Arduinoアプリの「ツール」メニュー→「シリアルポート」の「シリアルポート"なんとか" ▶︎」の「"なんとか"」の部分をメモする。下記の例の場合は「"/dev/cu.SLAB_USBtoUART"」をメモする
f:id:prince9:20180926032905p:plain

●Unity側(アセットなし)
1.Unityのプロジェクトを作り、「GameOBject」メニュー→「3DObject」→「Cube」などを選び、適当にオブジェクトを作る
2.「File」メニュー→「Build Settings」を選択し、「Player Settings」をクリックする
3.Inspectorの「Other Settings」→「Api Compatibility Level」を「.NET 2.0」にする
4.「Build Settings」を閉じる
5.「Assets」を右クリックし、「Create」→「C# Script」を選択する
6.「ArduinoReceive」など適当にファイル名をつけて、後からスクリプトを書く
7.スクリプトを書いたら保存し、「Hierarchy」にある1.で作ったオブジェクト名にドラッグ&ドロップして適用する


スクリプト
Unity側はYouTube動画もろもろに助けられました。

Arduino

#include <M5Stack.h>

#define LDR_pin 36  // センサーをGPIO36につなぐ
int val=0;
int sdata=0;

void setup(){
    M5.begin();

Serial.begin(9600);
    pinMode(LDR_pin, INPUT);
}

void loop() {
  // 画面クリア
    M5.Lcd.clear();
    M5.Lcd.setCursor(0, 0);
    
val = analogRead(LDR_pin);
sdata = val/4; //値が大きすぎる場合は0-255になるよう、「/4」の「4」の値を変更する
 Serial.println(sdata); // センサーを読み、シリアルに出力
 
//M5の液晶に値を表示
    M5.Lcd.setTextColor(WHITE);
      M5.Lcd.setTextSize(5);
    M5.Lcd.print(sdata);
    
    delay(500);
      M5.update();
}

●Unity側

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO.Ports;

public class ArduinoToUnityScript : MonoBehaviour {
int sdata = 0;

//new SerialPort("")にArduinoアプリで調べてメモしたシリアルポート名を指定する
SerialPort sp = new SerialPort("/dev/cu.SLAB_USBtoUART", 9600);

	// Use this for initialization
	void Start () {
		//シリアルポートが開いてないときはポートを開ける
		if (!sp.IsOpen) {
			sp.Open();
			sp.ReadTimeout = 1000;
		} else {
			sp.Close();

		}
		

		
	}
	
	// Update is called once per frame
	void Update () {
		//文字列を数値に変更
		int rot = int.Parse(sp.ReadLine());
		//オブジェクトの角度を変える
		transform.eulerAngles = new Vector3(0,rot,0);
		//コンソールにセンサーの値を出力
		Debug.Log(rot);

		
	}


}

M5StackをArduinoのように使う(MESHの動きタグ)

MESHの動きタグのデータをM5Stackに送り、M5Stackの色を変えるテストです。
動きタグを振ると、M5Stackの画面の色が変わります。

f:id:prince9:20180925210728p:plain
↑すみません、静止画です(汗

MESHのタグのデータをUnityなどに送ろうとしていたのですが、SDKが直のデータを出してくれずプロセスが大変になるので、GPIO経由で送ることにしました。
こっちのほうが楽ですね。お金かかるけど・・・時間をお金で買ったと思えば・・・

■準備
ソニーMESHの「動きタグ」
ソニーMESHの「GPIOタグ」
・M5Stack
・ワイヤー

これを下記のように接続します。
まずはGPIOのデジタル出力で試してみました。
f:id:prince9:20180925205928p:plain


■コード
まずMESHは以下になります。
動きタグを振ると、GPIOのデジタル出力が切り替わり、結果M5Stackの画面が切り替わります。
動きタグは設定をちゃんとしないと認識が微妙なときがあるため、データを検知したか知らせるために音を鳴らしています。

MESHのコード作成にあたり、下記を参考にさせて頂きました。
www.buildinsider.net

・MESHコード
f:id:prince9:20180925210141p:plain

Arduino(M5Stack)コード

#include <M5Stack.h>

#define MESH_pin 36  // GPIOをGPIO36につなぐ

void setup(){
    M5.begin();

Serial.begin(9600);
    pinMode(MESH_pin, INPUT);
}

void loop() {
  // 画面クリア
    M5.Lcd.clear();
    M5.Lcd.setCursor(0, 0);

   int sdata = digitalRead(MESH_pin);
    
    Serial.println(sdata); // GPIOの値を読み、シリアルに出力
    
if (sdata >= 1)
{
  M5.Lcd.fillScreen(GREEN);
}

else
{
  M5.Lcd.fillScreen(RED);
}
    delay(500);
      M5.update();
}

M5StackをArduinoのように使う(光センサー)

IoTとして使用されるケースが多いためか、ド基本が書かれているところが意外とないのでまとめ代わりに。
M5StackをArduino+LCD代わりにして、光センサの値をM5Stackの画面に表示します。
M5Stackはすでに使えるようになっているものとします。
この後、ソニーのMESHをつなげるので、動作チェック代わりにやってみました。

結果はこんな感じ(容量が大きくてGIFがアップロードできなかったので、静止画で)。
f:id:prince9:20180925195718p:plain
f:id:prince9:20180925195738p:plain
写真は手持ちがなくて10kオームの抵抗を使ったせいで、値が1kオームのときとは異なってますが、お気になさらず。

■準備(Arduinoと同じ)
・1kオームの抵抗
・光センサ
・M5Stack
・ワイヤー

これを下記のように接続します。
図と抵抗の値が違っていますが、抵抗の色は無視してください。1kオームを使用します。
f:id:prince9:20180925195123p:plain

■コード
下記のようなコードを書いてアップロードします。

#include <M5Stack.h>

#define LDR_pin 36  // センサーをGPIO36につなぐ
int val=0;

void setup(){
    M5.begin();

Serial.begin(9600);
    pinMode(LDR_pin, INPUT);
}

void loop() {
  // 画面クリア
    M5.Lcd.clear();
    M5.Lcd.setCursor(0, 0);
    
val = analogRead(LDR_pin);
sdata = val/4; //値が大きすぎる場合は0-255になるよう、「/4」の「4」の値を変更する
 Serial.println(sdata); // センサーを読み、シリアルに出力
 
    M5.Lcd.setTextColor(WHITE);
      M5.Lcd.setTextSize(5);
    M5.Lcd.print(sdata);
    
    delay(500);
      M5.update();
}