Skip to content
ahujasid edited this page Sep 3, 2019 · 2 revisions

LED Waterfall

This was a project created in the first week of Immersive Experiences at CIID IDP '19 by Siddharth Ahuja and Mitsu Shah.

Introduction

Collect your LED crystals and keep them a secret! We used the LEDs and gyroscope in the Sense HAT to ‘pour’ light crystals into a container. The magic- you will only be able to see how many LED crystals you have poured into the container in the augmented world. This tutorial guides you through the process of sending a LED output on Sense HAT to Spacebrew, and visualising the outcome in Unity.

What we need

Hardware

  • 1 x Raspberry Pi 3 (Model B)
  • Sense HAT
  • A small, transparent container
  • USB external camera

Software

  • Unity
  • Spacebrew
  • Mixed Reality Hardware Kit Library
  • Spacebrew Library for Python
  • Sense HAT Library for Python

Step by step instructions

Connecting Raspberry Pi (“Pi”) to Spacebrew

1. Attach the Sense HAT on to our Pi

Attaching SenseHat to the Raspberry Pi

2. Now set up our Pi to enable access through Wi-Fi instead of USB cable

3. Install Mixed Reality Hardware Kit Library (“MRHKL”) onto our Pi

4. Log in to our Pi using the terminal via: ssh pi@[address our Pi received from wifi router]

5. We want the Spacebrew python script in the MRHKLib (Python folder)

a. We can create a new Python script and edit in our terminal
or
b. We can upload the script written in the text editor on our computer

Python Script for Sense HAT LEDs

In the script “Python Script for Pouring LED Crystals” we want to

  1. Program the LEDs to react to the x-axis tilt of the Sense HAT
  2. Publish a value on Spacebrew whenever the Sense HAT is tilted along its x-axis
import sys
import time
from pySpacebrew.spacebrew import Spacebrew
from sense_hat import SenseHat
from time import sleep
​
brew = Spacebrew("SenseHat_Sid_Mits", description="Joystick and LED letters",  server="192.168.1.191", port=9000)
brew.addPublisher("x", "range")
brew.addPublisher("y", "range")
brew.addPublisher("z", "range")
​
blue = (0, 0, 255)
nothing = (0,0,0)
​
​
pixels = [blue for i in range(64)]
​
sense = SenseHat()
sense.set_rotation(90)
​
sense.clear()
​
​
try:
    
    print("Press Ctrl-C to quit.")
    brew.start()
​
    while True:
        acceleration = sense.get_accelerometer_raw()
        x = acceleration['x']
        y = acceleration['y']
        z = acceleration['z']
​
        x_normalised = x*72
        y_normalised = y*72
        z_normalised = z*64
        x_normalised = -x_normalised
​
        print("x={0}, y={1}, z={2}".format(x, y, z))
​
        # publish the joystick press to Spacebrew
        brew.publish('x', acceleration['x'])
        brew.publish('y', acceleration['y'])
        brew.publish('z', acceleration['z'])
​
​
        pixels = [nothing if i < x_normalised else blue for i in range(64)]
        sense.set_pixels(pixels)
​
​
finally:
    brew.stop()

Unity

  1. Create a bounding object mesh to collect the LED crystals (when being ‘poured’ from the Sense HAT)
  2. Set up Particle System to prepare the augmented version of the falling LED crystals
  3. Set up Spacebrew subscribers (Select SpacebrewObject and edit elements of Spacebrew Client script from Unity)
  4. Set Spacebrew IP address
  5. Add number of subscribers we require and name them (In this case we require 1 subscriber with name ‘x’)
  6. Edit Spacebrew event script (to show what happens when and how fast the Sense HAT is tilted along its x-axis)
  7. SAVE THE CODE
using UnityEngine;
using System.Collections;
​
public class SpacebrewEvents : MonoBehaviour {
​
	SpacebrewClient sbClient;
//	bool lightState = false;
	public ParticleSystem particles;
	public GameObject tree1;
	public GameObject tree2;
	public GameObject tree3;
	int count;
​
​
​
	// Use this for initialization
	void Start () {
		GameObject go = GameObject.Find ("SpacebrewObject"); // the name of your client object
		sbClient = go.GetComponent <SpacebrewClient> ();
​
		// register an event with the client and a callback function here.
		// COMMON GOTCHA: THIS MUST MATCH THE NAME VALUE YOU TYPED IN THE EDITOR!!
		sbClient.addEventListener (this.gameObject, "x");
		count = 0;
	}
​
	void Update () {
		
	}
​
	public void OnSpacebrewEvent(SpacebrewClient.SpacebrewMessage _msg) {
​
​
		print ("Received Spacebrew Message");
//		print (_msg);
​
		// Look for incoming Satellite messages
		if (_msg.name == "x") {
			Debug.Log ("------Message received------");
			if (float.Parse(_msg.value,System.Globalization.CultureInfo.InvariantCulture) < -0.2f &&
				float.Parse(_msg.value,System.Globalization.CultureInfo.InvariantCulture) > -0.4f) {
				Debug.Log("----Negative----");
				ParticleSystem.EmissionModule em = particles.emission;
				em.enabled = true;
				em.rateOverTime = 2;
			}
​
			else if (float.Parse(_msg.value,System.Globalization.CultureInfo.InvariantCulture) < -0.4f &&
				float.Parse(_msg.value,System.Globalization.CultureInfo.InvariantCulture) > -0.6f) {
				Debug.Log("----Negative----");
				ParticleSystem.EmissionModule em = particles.emission;
				em.enabled = true;
				em.rateOverTime = 4;
				count++;
			}
​
			else if (float.Parse(_msg.value,System.Globalization.CultureInfo.InvariantCulture) < -0.6f &&
				float.Parse(_msg.value,System.Globalization.CultureInfo.InvariantCulture) > -0.8f) {
				Debug.Log("----Negative----");
				ParticleSystem.EmissionModule em = particles.emission;
				em.enabled = true;
				em.rateOverTime = 7;
				count++;
			}
​
			else if (float.Parse(_msg.value,System.Globalization.CultureInfo.InvariantCulture) < -0.8f &&
				float.Parse(_msg.value,System.Globalization.CultureInfo.InvariantCulture) > -1.0f) {
				Debug.Log("----Negative----");
				ParticleSystem.EmissionModule em = particles.emission;
				em.enabled = true;
				em.rateOverTime = 12;
				count++;
			}
​
​
			else 
			{
				Debug.Log("----Positive----");
				ParticleSystem.EmissionModule em = particles.emission;
				em.enabled = false;
				em.rateOverTime = 0;
			}
​
​
​
			Debug.Log (count);
​
			if (count < 50) {
			
				tree1.GetComponent<Renderer>().enabled = false;
				tree2.GetComponent<Renderer>().enabled = false;
				tree3.GetComponent<Renderer>().enabled = false;
			}
			if (count > 250) {
				tree1.GetComponent<Renderer>().enabled = true;
​
			}
			if (count > 350) {
				tree2.GetComponent<Renderer>().enabled = true;
			}
			if (count > 600) {
				tree3.GetComponent<Renderer>().enabled = true;
			}
		}
​

	}
​
	int GetAliveParticles()
	{
		ParticleSystem.Particle[] particles_arr = new ParticleSystem.Particle[particles.particleCount];
		return particles.GetParticles(particles_arr);
	}
​
}

Making the clients talk

Now that we have Sense HAT (publisher) and Unity (subscriber) connected to Spacebrew, let’s make them talk.

  1. Click on the node of the Publisher, and then click the Subscriber’s node You will see a line connecting the two nodes. That’s it!

Preparing the final set-up

  1. Go back to Unity to set-up the virtual environment.
  2. Set fiducial sheet on top of a flat surface
  3. Place the small container on it
  4. Set-up USB camera to have the best view of the container
  5. HIT PLAY

You are now ready to pour some (secret) LED Crystals into your container.

  1. Hold the Sense HAT in your hand above the container
  2. Tilt it along its x-axis
  3. On the computer screen, you will be able to see how many LED crystals have you collected
  4. Also, how fast or slow have you emptied them into your container

System Diagram

System Diagram

Behind the scenes

The final product
Emptying the LED Matrix
Connecting the Pi to Unity

Clone this wiki locally