Help us understand the problem. What is going on with this article?

UnityでWi-Fi受信可能な加速度コントローラーを作る

はじめに

Wiiリモコンのような、振ったり傾けたりしたデータをUnityで利用できると、
VR、エクササイズなど色々なジャンルのコンテンツを作ることができるようになります。
2016-12-04_131816.jpg

今回、がじぇっとるねさすに出品した加速度コントローラーを使ったアプリで使用した、Wi-Fiでデータ送信可能な加速度コントローラーの作り方を共有・公開させていただきました。
DSC02224.png

揃えるもの

パーツ

Wi-Fiモジュール ESP-WROOM-02 DIP化キット
GR-COTTON
3軸加速度センサモジュール KXSC7-2050

工作道具

ワイヤーストリッパー(またはニッパー、ナイフ等)
・配線
・ハンダ
・ハンダこて

電源

USBケーブル
スマホ用バッテリー

ソフトウェア

・KurumiWriter(後述)

ハードウェア接続

まずは3つのパーツを下記のように配線・半田付けします。
DSC02264.jpg
Wi-FiモジュールとGR-COTTONの接続に関しての説明はこちら
3軸加速度センサーのデータシートはこちらにあります。
半田付けしたら完成です。

ソフトウェア作成

GR-COTTON用加速度送信プログラム

こちらの記事を参考に、WebコンパイラーでGR-COTTON用のプログラムを作成します。

スクリーンショット 2016-12-12 14.50.24.png

準備ができたら、標準プロジェクトテンプレートにあるgr_sketch.cppの内容を下記のように変更します。

gr_sketch.cpp
/**
 * @example UDPClientMultiple.ino
 * @brief The UDPClientMultiple demo of library WeeESP8266. 
 * @author Wu Pengfei<pengfei.wu@itead.cc> 
 * @date 2015.02
 * 
 * @par Copyright:
 * Copyright (c) 2015 ITEAD Intelligent Systems Co., Ltd. \n\n
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version. \n\n
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "ESP8266.h"

#define HOST_PORT   (7001)
#define RECV_PORT   (7001)
#define ESP_Serial  Serial1
#define PIN_R  (22)
#define PIN_G  (23)
#define PIN_B  (24)

// A3,A4,A5 are analog xyz
#define pin_x (A3)
#define pin_y (A4)
#define pin_z (A5)
int valSq,valSqOld;
int x,y,z,ax,ay,az,ox,oy,oz;

const char *softSsid = "skipshoes4";
const char *softPwd = "123456789";
static uint8_t mux_id = 0;
int intCnt = 0;
bool isLEDDisp;

ESP8266 wifi;

void updateAccInfo(){
    ox = x;
    oy = y;
    oz = z;
    x = analogRead(pin_x);
    y = analogRead(pin_y);
    z = analogRead(pin_z);
    z = 1023-z; // 基盤の取付向きが逆

    ax = x-ox;
    ay = y-oy;
    az = z-oz;
}

int setAccStringArr(String strarr[],String ipList){
    int cnt = 0;
    if(ipList.length()>2){
        char charBuff[ipList.length()+2];
        ipList.toCharArray(charBuff,ipList.length());
        strarr[cnt]="";
        bool isTrim = false;
        for(int i=0; i<ipList.length();++i){
            int ascii = (int)(charBuff[i]);
            if(ascii>13){
                if(isTrim==false){
                    if(charBuff[i]==','){
                        isTrim = true;
                    }else{
                        strarr[cnt]+=String(charBuff[i]);
                    }
                }
            }else if((ascii==10)||(ascii==0)){
                cnt++;
                isTrim = false;
                strarr[cnt]="";
            }
        }
    }
    return cnt;
}

void setupWifi(){
    wifi.begin(ESP_Serial);

    Serial.print("FW Version:");
    Serial.println(wifi.getVersion().c_str());

    if (wifi.setOprToSoftAP()) {
        Serial.print("to softAp ok\r\n");
    } else {
        Serial.print("to softAp err\r\n");
    }
    delay(100);

    if(wifi.setSoftAPParam(softSsid, softPwd, 7, 4)){
        Serial.print("setSoftAPParam4 ok\r\n");
    }else{
        Serial.print("setSoftAPParam4 err\r\n");
    }
    delay(100);

    if (wifi.enableMUX()) {
        Serial.print("multi ok\r\n");
    } else {
        Serial.print("multi err\r\n");
    }
}

bool sendSub(String hostName){
    int ret = false;
    uint8_t buffer[128] = {0};
    mux_id++;
    if (mux_id >= 5) {
        mux_id = 0;
    }
    if (wifi.registerUDP(mux_id, hostName, HOST_PORT)) {
        Serial.println("reg udp ok");
    } else {
        Serial.println("reg udp err");
    }

    String sendStr = "x:" + String(x)+",y:" + String(y)+",z:" + String(z);

    wifi.send(mux_id,(const uint8_t*)(sendStr.c_str()), strlen(sendStr.c_str()));

    if (wifi.unregisterUDP(mux_id)) {
        ret = true;
        Serial.println("unreg udp ok");
    } else {
        Serial.println("unreg udp err");
    }
    return ret;
}

bool sendSubAll(){
    String ipList = wifi.getJoinedDeviceIP();
    String StrArr[10];
    int cnt = setAccStringArr(StrArr,ipList);
    if(cnt<=0){
        Serial.println("List=null");
        return false;
    }
    Serial.println("List=");
    for(int i=0; i<cnt;++i){
        Serial.println(StrArr[i]);
        sendSub(StrArr[i]);
    }
    return true;
}

void setLED(bool r, bool g, bool b){
    digitalWrite(PIN_R, r ? LOW : HIGH);
    digitalWrite(PIN_G, g ? LOW : HIGH);
    digitalWrite(PIN_B, b ? LOW : HIGH);
}

void setup(void)
{
    pinMode(PIN_R, OUTPUT);
    pinMode(PIN_G, OUTPUT);
    pinMode(PIN_B, OUTPUT);
    pinMode(pin_x, INPUT);
    pinMode(pin_y, INPUT);
    pinMode(pin_z, INPUT);
    x=0,y=0,z=0,ax=0,ay=0,az=0,ox=0,oy=0,oz=0;
    isLEDDisp = false;

    Serial.begin(9600);
    setupWifi();
    updateAccInfo();
    Serial.print("setup end\r\n");
}

void loop(void)
{
    uint8_t buffer[256] = {0};
    uint32_t len;
    updateAccInfo();
    sendSubAll();

    isLEDDisp = !isLEDDisp;
    if(!isLEDDisp){
        setLED(false,false,false);
    }else{
        setLED(true,false,false);
    }
}

コンパイルが成功し、さらに書き込みが終了するとGR-COTTONのLEDが赤く光ります。

Unity用加速度受信スクリプト

続いてUnity側で受信スクリプトを作成します。

空のGameObjectを作り、下記スクリプトをアタッチします。
スクリーンショット 2016-12-12 13.59.05.png

UDPReceiveTest.cs
using UnityEngine;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

public class UDPReceiveTest : MonoBehaviour
{
    static readonly int RingSize = 16;
    public int port = 7001;
    public GUISkin skin;
    public bool isTest = true;
    private string portStr;
    private UdpClient udp;
    private Thread thread;
    private string[] recvTextArr;
    private int buffPtr;
    private bool isReceiving;

    public string[] RecvTextArr{ get { return recvTextArr; } }
    public int BuffPtr{ get { return buffPtr; } }

    private void buffClear(){
        recvTextArr = new string[RingSize];
        buffPtr = 0;
        for(int i = 0; i < recvTextArr.Length; ++i){
            recvTextArr[i] = "";
        }
    }

    void Start()
    {
        isReceiving = true;
        portStr = port.ToString ();
        buffClear ();
        udp = null;
        thread = null;
        udpStart();
    }

    void Update()
    {
        if (isReceiving) {
            udpStart ();
        } else {
            udpStop ();
        }
    }

    void OnApplicationQuit()
    {
        udpStop();
    }

    void OnGUI()
    {
        if (!isTest) {
            return;
        }
        GUI.skin = skin;
        GUILayout.BeginArea(new Rect(350, 40, 550, 550));
        GUILayout.BeginHorizontal();
        portStr = GUILayout.TextArea (portStr);
        if (GUILayout.Button(isReceiving ? "Stop" : "Start"))
        {
            isReceiving = !isReceiving;
            if (isReceiving) {
                int resPort = 0;
                if (int.TryParse (portStr, out resPort)) {
                    port = resPort;
                    udpStart();
                } else {
                    portStr = port.ToString ();
                }
            }
        }
        if (GUILayout.Button("Clear"))
        {
            buffClear ();
        }
        GUILayout.EndHorizontal();
        int ptr = buffPtr;
        string outStr = "";
        for(int i = 0; i < recvTextArr.Length; ++i){
            outStr += ((i>0)?"\n":"")+recvTextArr [ptr];
            ptr--;
            if (ptr < 0) {
                ptr += RingSize;
            }
        }
        GUILayout.TextArea(outStr);
        GUILayout.EndArea();
    }

    private void udpStart()
    {
        if (udp == null)
        {
            udp = new UdpClient(port);
            udp.Client.ReceiveTimeout = 1000;
        }
        if (thread == null)
        {
            thread = new Thread(new ThreadStart(ThreadMethod));
            thread.Start();
        }
    }
    private void udpStop()
    {
        if (thread != null)
        {
            thread.Abort();
            thread = null;
        }
        if (udp != null)
        {
            udp.Close();
            udp = null;
        }
    }

    private void ThreadMethod()
    {
        Debug.Log("RecvStt");
        while (true)
        {
            if (isReceiving)
            {
                try
                {
                    IPEndPoint remoteEP = null;
                    byte[] data = udp.Receive(ref remoteEP);
                    buffPtr = (buffPtr+1) % RingSize;
                    recvTextArr[buffPtr] = Encoding.ASCII.GetString(data);
//                  Debug.Log("Recv:"+recvTextArr[buffPtr]);
                }
                catch (SocketException e)
                {
//                    Debug.Log(e.ToString());
                }
            }
            else
            {
            }
        }
    }
}

受信

ハードウェア(GR-COTTON)の電源が入った状態で、PCのWi-Fiを
上記GR-COTTON用プログラム中で設定した

const char *softSsid = "skipshoes4";
const char *softPwd = "01234567";

に接続します。

スクリーンショット-2016-12-12-13.53.17.jpg

接続できたらUnityを再生すると加速度データ(文字列)が流れてきます。
スクリーンショット 2016-12-12 15.15.58.png

あとはデータを利用して、好きなアプリを作ることができます。

モバイルの場合、端末でUnityの起動を確認してからWiFiを接続しないとUnityが起動しないようです。

WIO-NODEというボードを使用して同様のコントローラーを作るにはこちら

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした