Skip navigation

Raspberry Pi

September 27, 2017 Previous day Next day

 

This guide provides step-by-step instructions for connecting a unity client to your MATRIX Creator. This connection will be used to demonstrate how unity can read data from every sensor the MATRIX Creator has.

 

Required Hardware

Before you get started, let's review what you'll need.

  • Raspberry Pi 3 (Recommended) or Pi 2 Model B (Supported) - Buy on Element14 - Pi 3 or Pi 2.
  • MATRIX Creator - The Raspberry Pi does not have a built-in microphone, the MATRIX Creator has an 8 mic array perfect for Alexa - Buy MATRIX Creator on Element14.
  • Micro-USB power supply for Raspberry Pi - 2.5A 5V power supply recommended
  • Micro SD Card (Minimum 8 GB) - You need an operating system to get started. NOOBS (New Out of the Box Software) is an easy-to-use operating system install manager for Raspberry Pi. The simplest way to get NOOBS is to buy an SD card with NOOBS pre-installed - Raspberry Pi 16GB Preloaded (NOOBS) Micro SD Card. Alternatively, you can download and install it on your SD card.
  • A USB Keyboard & Mouse, and an external HDMI Monitor - we also recommend having a USB keyboard and mouse as well as an HDMI monitor handy if you're unable to remote(SSH)into your Pi.
  • Internet connection (Ethernet or WiFi)
  • (Optional) WiFi Wireless Adapter for Pi 2 (Buy on Element14). Note: Pi 3 has built-in WiFi.

For extra credit, enable remote(SSH) into your device, eliminating the need for a monitor, keyboard, and mouse - and learn how to tail logs for troubleshooting.

 

Let's get started

We will be using MATRIX OS (MOS), to easily program the Raspberry Pi and MATRIX Creator in Javascript, and the Unity Engine.

 

Step 1: Setting up MOS

Download and configure MOS and its CLI tool for your computer using the following installation guide in the MATRIX Docs: Installation Guide

 

Step 2: Create a Unity-Sensor-Utility app

To create your own Unity-Sensor-Utility app on your local computer, use the command "matrix create Unity-Sensor-Utility". Then you will be directed to enter a description and keywords for your app. A new folder will be created for the app with five new files. The one you will be editing is the app.js file. From here you can clone the Unity-Sensor-Utility GitHub repo with the code or follow the guide below for an overview of the code.

 

Step 3: Start Socket Server

In the app.js file, you will need to require socket.io and create a server for the unity client to connect to. 6001 is the port left by default, but it can be changed to whatever you want.

 

///Start Socket Server
var io = require('socket.io')(6001);
console.log('server started');

 

Step 4: Configure & Start MATRIX Sensors

To read data from the MATRIX’s sensors, each sensor has to be initialized and configured with a refresh and timeout option. The options object will be used as a default for all the sensors. To save the data from each sensor, an empty JSON object is created and overwritten each time there’s a new sensor value. Each sensor has its own object.

 

////////////////////////////////////
// Config & Start MATRIX Sensors
///////////////////////////////////
var options = {
     refresh: 100,
     timeout: 15000
}

//Gyroscope
var gyroscopeData = {};
     matrix.init('gyroscope', options).then(function(data){
     gyroscopeData = data;
});
//UV
var uvData = {};
     matrix.init('uv', options).then(function(data){
     uvData = data;
});
//Temperature
var temperatureData = {};
     matrix.init('temperature', options).then(function(data){
     temperatureData = data;
});
//Humidity
var humidityData = {};
     matrix.init('humidity', options).then(function(data){
     humidityData = data;
});
//Pressure
var pressureData = {};
     matrix.init('pressure', options).then(function(data){
     pressureData = data;
});
//Accelerometer
var accelerometerData = {};
     matrix.init('accelerometer', options).then(function(data){
     accelerometerData = data;
});
//Magnetometer
var magnetometerData = {};
     matrix.init('magnetometer', options).then(function(data){
     magnetometerData = data;
});

 

Step 5: Event Listeners

With the MATRIX Creator now reading and storing sensor data, it’s time to handle how to send that data when requested. Event Listeners are created here to listen to any events that call the sensor name. Once that event is received, The MATRIX will respond by emitting another event back, but this event will contain the corresponding JSON object of the sensor requested. Sensor data will only be sent when requested because it is unlikely every sensor will be used at once. However they can all be sent if you choose.

 

////////////////////////////
//Event Listeners
///////////////////////////
io.on('connection', function (socket) {
  console.log('Client Connected\n Sending Data...');

  //Send gyroscope data on request
  socket.on('gyroscope', function () {
    socket.emit('gyroscopeData', gyroscopeData);
  });

  //Send uv data on request
  socket.on('uv', function () {
    socket.emit('uvData', uvData);
  });

  //Send uv data on request
  socket.on('temperature', function () {
    socket.emit('temperatureData', temperatureData);
  });

  //Send humidity data on request
  socket.on('humidity', function () {
    socket.emit('humidityData', humidityData);
  });

  //Send humidity data on request
  socket.on('pressure', function () {
    socket.emit('pressureData', pressureData);
  });

  //Send accelerometer data on request
  socket.on('accelerometer', function () {
    socket.emit('accelerometerData', accelerometerData);
  });

  //Send magnetometer data on request
  socket.on('magnetometer', function () {
    socket.emit('magnetometerData', magnetometerData);
  });

  //Client has left or lost connection
  socket.on('disconnect', function () {
    console.log('Client Disconnected');
  });
});

 

Step 6: Unity Setup

If you haven’t already, download the latest version of unity here:

Unity will act as the client to the socket.io server running on the MATRIX Creator. Once you have unity up and running, you’ll need to install a socket.io plugin from the asset store

In the “SocketIO” folder, from the newly downloaded asset, navigate to the “Prefabs” folder and then drag&drop the prefab located inside onto the current scene.The SocketIO game object added will require you to input your Raspberry Pi’s IP address and the server port defined in the MOS app we made.

  • ws://YOUR_PI_IP:6001/socket.io/?EIO=4&transport=websocket

 

Step 7: Creating MATRIX.cs

Moving onto the last steps, you’ll need to create a new c# file called MATRIX.cs inside your Unity Assets. Under the libraries you’ll need are the public booleans that will be determining which sensors we want from the MATRIX Creator. Below that is where the SocketIO object will be defined.

 

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

public class MATRIX : MonoBehaviour {
   //Pick Desired Sensors
   public bool useGyroscope = false;
   public bool useUV = false;
   public bool useTemperature = false;
   public bool useHumidity = false;
   public bool usePressure = false;
   public bool useAccelerometer = false;
   public bool useMagnetometer = false;

   private SocketIOComponent socket;

 

Step 8: On Scene Start

Everything defined in this function will be executed once the moment the current scene runs. The first thing that needs to be done here is to locate the socket.io game object we created from the prefab at the end of step 6. After that, we can include an event listener, similar to what was done in the MOS app, for each sensor to handle its values. How we handle the data will be described in a later step. The last part is to begin a Coroutine that contains an infinite loop.

 

   //On Scene Start
   public void Start()
  {
       //locate socket.io prefab
       GameObject go = GameObject.Find("SocketIO");
       socket = go.GetComponent();
       //Set Event Listeners
       socket.On("open", Open);//connection made
       socket.On("error", Error);//socket.io error
       socket.On("close", Close);//connection lost
       //Set MATRIX Sensor Event Listeners
       socket.On("gyroscopeData", gyroscopeData);
       socket.On("uvData", uvData);
       socket.On("temperatureData", temperatureData);
       socket.On("humidityData", humidityData);
       socket.On("pressureData", pressureData);
       socket.On("accelerometerData", accelerometerData);
       socket.On("magnetometerData", magnetometerData);

       //start non-blocking loop
       StartCoroutine("eventLoop");
  }

 

Step 9: Requesting Sensor Data

This eventLoop() Coroutine is essential because it allows us to write non-blocking code while we are requesting sensor data. A while(true) loop, that will never end,  is defined here to request sensor data based on which booleans are set to true from step 7. If true, the loop will emit a sensor event to the MATRIX Creator that will then respond by sending us an event back with the sensor data.

 

    ////////////////////////////////////////////
    // Requesting Device Data
    ////////////////////////////////////////////
    private IEnumerator eventLoop()
    {
        //delay to properly initialize
        yield return new WaitForSecondsRealtime(0.1f);
        //loop forever
        while (true)
        {
            yield return new WaitForSecondsRealtime(0f);//no delay
            //Use sensors if requested\\
            if (useGyroscope)
                socket.Emit("gyroscope");
            if (useUV)
                socket.Emit("uv");
            if (useTemperature)
                socket.Emit("temperature");
            if (useHumidity)
                socket.Emit("humidity");
            if (usePressure)
                socket.Emit("pressure");
            if (useAccelerometer)
                socket.Emit("accelerometer");
            if (useMagnetometer)
                socket.Emit("magnetometer");
        }
    }

 

Step 10: Handling Sensor Data

Here is where we define the functions that the event listeners in step 8 call on. The first 3 are functions for logging connection, disconnection, and errors from the socket.io when connecting to the server running in MOS. The rest of the functions are for each sensor the MATRIX Creator has. Similar to our MOS app, each function reads any data put into it and stores it into a static class that can be read by other scripts.

 

    ////////////////////////////////////////////
    // Event Listener Functions
    ////////////////////////////////////////////

    //////////////////////////
    // On Connection
    public void Open(SocketIOEvent e)
    {
        Debug.Log("[SocketIO] Open received: " + e.name + " " + e.data);
    }
    //////////////////////////
    // Socket.io Error
    public void Error(SocketIOEvent e)
    {
        Debug.Log("[SocketIO] Error received: " + e.name + " " + e.data);
    }
    //////////////////////////
    // Lost Connection To Server
    public void Close(SocketIOEvent e)
    {
        Debug.Log("[SocketIO] Close received: " + e.name + " " + e.data);
    }
    //////////////////////////
    // Gyroscope
    public static class Gyroscope
    {
        public static float yaw = 0f;
        public static float pitch = 0f;
        public static float roll = 0f;
        public static float x = 0f;
        public static float y = 0f;
        public static float z = 0f;
    }
    public void gyroscopeData(SocketIOEvent e)
    {
        Gyroscope.yaw = float.Parse(e.data["yaw"].ToString());
        Gyroscope.pitch = float.Parse(e.data["pitch"].ToString());
        Gyroscope.roll = float.Parse(e.data["roll"].ToString());
        Gyroscope.x = float.Parse(e.data["x"].ToString());
        Gyroscope.y = float.Parse(e.data["y"].ToString());
        Gyroscope.z = float.Parse(e.data["z"].ToString());
        Debug.Log(e.data);
    }
    //////////////////////////
    // UV
    public static class UV
    {
        public static float value = 0f;
        public static string risk = "";
    }
    public void uvData(SocketIOEvent e)
    {
        UV.value = float.Parse(e.data["value"].ToString());
        UV.risk = e.data["risk"].ToString();
        Debug.Log(e.data);
    }
    //////////////////////////
    // Temperature 
    public static class Temperature
    {
        public static float value = 0f;
        public static string risk = "";
    }
    public void temperatureData(SocketIOEvent e)
    {
        Temperature.value = float.Parse(e.data["value"].ToString());
        Debug.Log(e.data);
    }
    //////////////////////////
    // Humidity 
    public static class Humidity
    {
        public static float value = 0f;
        public static string risk = "";
    }
    public void humidityData(SocketIOEvent e)
    {
        Humidity.value = float.Parse(e.data["value"].ToString());
        Debug.Log(e.data);
    }
    //////////////////////////
    // Pressure 
    public static class Pressure
    {
        public static float value = 0f;
        public static string risk = "";
    }
    public void pressureData(SocketIOEvent e)
    {
        Pressure.value = float.Parse(e.data["value"].ToString());
        Debug.Log(e.data);
    }
    //////////////////////////
    // Accelerometer 
    public static class Accelerometer
    {
        public static float x = 0f;
        public static float y = 0f;
        public static float z = 0f;
    }
    public void accelerometerData(SocketIOEvent e)
    {
        Accelerometer.x = float.Parse(e.data["x"].ToString());
        Accelerometer.y = float.Parse(e.data["y"].ToString());
        Accelerometer.z = float.Parse(e.data["z"].ToString());
        Debug.Log(e.data);
    }
    //////////////////////////
    // Magnetometer 
    public static class Magnetometer
    {
        public static float x = 0f;
        public static float y = 0f;
        public static float z = 0f;
    }
    public void magnetometerData(SocketIOEvent e)
    {
        Magnetometer.x = float.Parse(e.data["x"].ToString());
        Magnetometer.y = float.Parse(e.data["y"].ToString());
        Magnetometer.z = float.Parse(e.data["z"].ToString());
        Debug.Log(e.data);
    }
}

 

Step 11: Reading Data

With MATRIX.cs done all that’s left is to attach the script onto our SocketIO object in our scene. Once attached there will be boxes you can check that will let you pick which sensors you want to read. Each sensor chosen will log its value in the Unity console. If you see the values of the sensor you choose then you’re good to go! Usage for reading each sensor in Unity can be found here: https://github.com/matrix-io/MATRIX-Unity-Sensor-Utility-App/tree/master/Unity-Assets#usage

 

Github

Filter Blog

By date: By tag: