Visualization in Web Browser and Unity

For this week, Mimi and I worked together to visualize IMU orientation in both web browser and also in Unity. For the web serial vsiualizer, after experimenting with processing and trying to make it work, we decided to use the webserial API for Chrome browser. It was much easier to do (thanks to chrome. ) For this one, we learned to use Adafruit Unified Sensor and BNO055.

Arduino Wiring

Final Wiring
Wire Details

Final webserial visualizer

From computer
Computer + in-person

Arduino BNO055 code web visualizer

          

        #include 
          #include 
          #include 
          #include 
            
          Adafruit_BNO055 bno = Adafruit_BNO055(55);
          
          void setup(void) 
          {
            Serial.begin(9600);
            Serial.println("Orientation Sensor Test"); Serial.println("");
            
            /* Initialise the sensor */
            if(!bno.begin())
            {
              /* There was a problem detecting the BNO055 ... check your connections */
              Serial.print("Ooops, no BNO055 detected ... Check your wiring or I2C ADDR!");
              while(1);
            }
            
            delay(1000);
              
            bno.setExtCrystalUse(true);
          }
          
          void loop(void) 
          {
            /* Get a new sensor event */ 
            sensors_event_t event; 
            bno.getEvent(&event);
            
            /* Display the floating point data */
            Serial.print("X: ");
            Serial.print(event.orientation.x, 4);
            Serial.print("\tY: ");
            Serial.print(event.orientation.y, 4);
            Serial.print("\tZ: ");
            Serial.print(event.orientation.z, 4);
            Serial.println("");
            
            delay(100);
          }

        
        


Unity IMU

Then we tried to visualize the same thing in Unity. Unity took a while, as I don't know how to use C-sharp. The compiling took a while, syntax etc took a long time to make a very simple thing work. The connection between Arduino and Unity also was not easy. I need to upload the file first, and then the port will be occupied by Unity. If I want to change anything, I have to close the port and then reconnect after reuploading.
Final look
Unity Interface

IMU C sharp code

          


            using UnityEngine;
using Uduino;

public class ReceiveIMUValues : MonoBehaviour {

    Vector3 position;
    Vector3 rotation;
    public Vector3 rotationOffset ;
    public float speedFactor = 15.0f;
    public string imuName = "r"; // You should ignore this if there is one IMU.

    void Start () {
      //  UduinoManager.Instance.OnDataReceived += ReadIMU;
      //  Note that here, we don't use the delegate but the Events, assigned in the Inpsector Panel
    }

    void Update() { }

    public void ReadIMU (string data, UduinoDevice device) {
        //Debug.Log(data);
        string[] values = data.Split('/');
        if (values.Length == 5 && values[0] == imuName) // Rotation of the first one 
        {
            float w = float.Parse(values[1]);
            float x = float.Parse(values[2]);
            float y = float.Parse(values[3]);
            float z = float.Parse(values[4]);
            this.transform.localRotation = Quaternion.Lerp(this.transform.localRotation,  new Quaternion(w, y, x, z), Time.deltaTime * speedFactor);
        } else if (values.Length != 5)
        {
            Debug.LogWarning(data);
        }
        this.transform.parent.transform.eulerAngles = rotationOffset;
      //  Log.Debug("The new rotation is : " + transform.Find("IMU_Object").eulerAngles);
    }
}


            

            

IMU Arduino code

          

            #include "Uduino.h"  // Include Uduino library at the top of the sketch
Uduino uduino("IMU");

#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
#include "Wire.h"


MPU6050 mpu;

// MPU control/status vars
bool dmpReady = false;  // set true if DMP init was successful
uint8_t devStatus;      // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize;    // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount;     // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer

// orientation/motion vars
Quaternion q;           // [w, x, y, z]         quaternion container
VectorInt16 aa;         // [x, y, z]            accel sensor measurements
VectorInt16 aaReal;     // [x, y, z]            gravity-free accel sensor measurements
VectorInt16 aaWorld;    // [x, y, z]            world-frame accel sensor measurements
VectorFloat gravity;    // [x, y, z]            gravity vector
float euler[3];         // [psi, theta, phi]    Euler angle container
float ypr[3];           // [yaw, pitch, roll]   yaw/pitch/roll container and gravity vector


void setup() {
  Wire.begin();
  Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties

  Serial.begin(38400);

  while (!Serial); // wait for Leonardo enumeration, others continue immediately

  mpu.initialize();
  devStatus = mpu.dmpInitialize();
  mpu.setXGyroOffset(54); //++
  mpu.setYGyroOffset(-21); //--
  mpu.setZGyroOffset(5);

  if (devStatus == 0) {
    mpu.setDMPEnabled(true);
    // set our DMP Ready flag so the main loop() function knows it's okay to use it
    dmpReady = true;
    // get expected DMP packet size for later comparison
    packetSize = mpu.dmpGetFIFOPacketSize();
  } else {
    // Error
    Serial.println("Error!");
  }
}



void loop() {
  uduino.update();

  if (uduino.isInit()) {
    if (!dmpReady) {
      Serial.println("IMU not connected.");
      delay(10);
      return;
    }

    int  mpuIntStatus = mpu.getIntStatus();
    fifoCount = mpu.getFIFOCount();

    if ((mpuIntStatus & 0x10) || fifoCount == 1024) { // check if overflow
      mpu.resetFIFO();
    } else if (mpuIntStatus & 0x02) {
      while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();

      mpu.getFIFOBytes(fifoBuffer, packetSize);
      fifoCount -= packetSize;

      SendQuaternion();
      //SendEuler();
      //SendYawPitchRoll();
      //SendRealAccel();
      //SendWorldAccel();
    }
  }
}



void SendQuaternion() {
  mpu.dmpGetQuaternion(&q, fifoBuffer);
  Serial.print("r/");
  Serial.print(q.w, 4); Serial.print("/");
  Serial.print(q.x, 4); Serial.print("/");
  Serial.print(q.y, 4); Serial.print("/");
  Serial.println(q.z, 4);
}

void SendEuler() {
  // display Euler angles in degrees
  mpu.dmpGetQuaternion(&q, fifoBuffer);
  mpu.dmpGetEuler(euler, &q);
  Serial.print(euler[0] * 180 / M_PI); Serial.print("/");
  Serial.print(euler[1] * 180 / M_PI); Serial.print("/");
  Serial.println(euler[2] * 180 / M_PI);
}

void SendYawPitchRoll() {
  // display Euler angles in degrees
  mpu.dmpGetQuaternion(&q, fifoBuffer);
  mpu.dmpGetGravity(&gravity, &q);
  mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
  Serial.print(ypr[0] * 180 / M_PI); Serial.print("/");
  Serial.print(ypr[1] * 180 / M_PI); Serial.print("/");
  Serial.println(ypr[2] * 180 / M_PI);
}

void SendRealAccel() {
  // display real acceleration, adjusted to remove gravity
  mpu.dmpGetQuaternion(&q, fifoBuffer);
  mpu.dmpGetAccel(&aa, fifoBuffer);
  mpu.dmpGetGravity(&gravity, &q);
  mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
  Serial.print("a/");
  Serial.print(aaReal.x); Serial.print("/");
  Serial.print(aaReal.y); Serial.print("/");
  Serial.println(aaReal.z);
}

void SendWorldAccel() {
  // display initial world-frame acceleration, adjusted to remove gravity
  // and rotated based on known orientation from quaternion
  mpu.dmpGetQuaternion(&q, fifoBuffer);
  mpu.dmpGetAccel(&aa, fifoBuffer);
  mpu.dmpGetGravity(&gravity, &q);
  mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
  mpu.dmpGetLinearAccelInWorld(&aaWorld, &aaReal, &q);
  Serial.print("a/");
  Serial.print(aaWorld.x); Serial.print("/");
  Serial.print(aaWorld.y); Serial.print("/");
  Serial.println(aaWorld.z);
}

            
            

LED blink and fade in Unity

LED blink
Control LED high and low

LED strip Arduino code

          


#include 
  #include 
  #define NUM_LEDS 60
  #define DATA_PIN 3
  
  CRGB leds[NUM_LEDS];
  
  Uduino uduino("PixelBoard");
  
  
  
  void setup() {
    // put your setup code here, to run once:
    Serial.begin(9600);
  
    FastLED.addLeds(leds, 60);
    FastLED.setBrightness(20);
  
    uduino.addCommand("turnOn", turnOnPixel);
    uduino.addCommand("turnOff", turnOffPixel);
  
  }
  
  void turnOnPixel() {
  
    int led = atoi(uduino.getParameter(0));
  
    int r = atoi(uduino.getParameter(1));
  
    int g = atoi(uduino.getParameter(2));
  
    int b = atoi(uduino.getParameter(3));
  
    leds[led].setRGB(r,g,b);
    FastLED.show();
    
  }
  
  void turnOffPixel() {
  
    int led = atoi(uduino.getParameter(0));
  
    leds[led].setRGB(0,0,0);
    FastLED.show();
  }
  
  
  void loop() {
    // put your main code here, to run repeatedly:
    uduino.update();
    delay(10);
  
  }

            

            

Resources

  1. Additional coding info
  2. webserial visualizer
  3. MPU 6050 web server
  4. Piano Project
  5. Unity IMU
  6. Microphone control Unity Object
  7. Measure Sound level
  8. Unity Mic InputValues
  9. sound level measurement arduino
  10. LED arudino bluetooth
  11. MPU 6050 arduino tutorial
  12. Arduino Processing Visualization