Photos:

Video:

This video shows me placing dolls on a board and pressing a button which spawns them into my Unity scene. This is only a prototype, which is far from perfect, and you can see me fiddle with the position of the blue doll (and later the red doll) after the Arduino failed to pick them up.

Description:

Place dolls on a board and push the ‘spawn’ button, the dolls on said board will then appear in a digital environment (created with Unity). Each doll can be differentiated by their color, both in their physical and digital representation. When the ‘spawn’  button is pushed, the digital environment will be emptied and then refilled with the dolls placed on the board (if any). In the digital environment, the dolls are given instructions to move to random positions inside given boundaries.

Each doll holds a different resistor that can be read by the Arduino, which is what allows the Arduino to determine the dolls color. The Arduino then sends that information to Unity, where it is interpreted and carried out.

Music: Brian Eno – New Space Music (Visualizer)

Progress Images:

These images include some of the 3d models I made as well as  parts of the fabrication process.

Reflection:

There are many events in our lives that we share with our family and friends. Under quarantine however, we are no longer able to share the same physical spaces with one another as we once could. It was my goal, for this project, to simulate these life events as they may have appeared before quarantine. Where representations of our family and friends would be able to share a virtual environment in lieu of a physical one.

I chose to create a funeral setting after attending a zoom call in memorial of my late uncle. I began to picture what my own funeral might look like, and who I hoped would attend.

So I made a board that would essentially act as the invite list, and a few dolls that would represent the people you might invite.

This project is only a prototype of the initial idea. The environment I made was very open to interpretation, and not necessarily personal. In a future iteration, I would make it so that, rather than color, each doll would represent a specific person in your life. I feel that this would drastically change how a person would interact with this project. Specifically, I believe that it would make placing the dolls on the board a much more personal experience. There are many other levels of customization I could hope to incorporate, but to create a literal connection between the dolls at your disposal and the people in your life is perhaps the most significant.

I was glad to be able to incorporate Unity in this project. Getting the Arduino to communicate with Unity was a good learning experience, and I believe will be useful in the future. I used SolidWorks to create the models in the scene as well.  It was very satisfying to be able to bring together these different skills I’ve developed over the semester into one project.

Code:

Arduino:

int pin_1 = A0;
int pin_2 = A1;
int pin_3 = A2;
int pin_4 = A3;

int sim_button = 5;

int array_size = 4;
int pin_list[] = {pin_1, pin_2, pin_3, pin_4};
float pin_readings[] = {0.0, 0.0, 0.0, 0.0};
int send_to_unity[] = {0, 0, 0, 0};

int pin; 
float pin_reading = 0.0;

int raw = 0;
int Vin = 5;
float Vout = 0;
float R_1K = 1000;
float R_unknown = 0;
float buffer = 0;


void setup() {
  Serial.begin(9600);
  
  pinMode(pin_1, INPUT);
  pinMode(pin_2, INPUT);
  pinMode(pin_3, INPUT);
  pinMode(pin_4, INPUT);
  pinMode(sim_button, INPUT);
}

void loop() {
  if (digitalRead(sim_button) == HIGH) {
    for (int i = 0; i < array_size; i++) {
      pin = pin_list[i];
      pin_reading = resistor_read(pin);
      pin_readings[i] = pin_reading;
      send_to_unity[i] = doll_num(pin_reading);
    }
    
    for (int i = 0; i < array_size; i++) {
      Serial.write(i);
      Serial.flush();
      Serial.write(send_to_unity[i]);
      Serial.flush();
    }    
    delay(1000);
  }
}

float resistor_read(int pin) {
  raw = analogRead(pin);
  if(raw){
    buffer = raw * Vin;
    Vout = (buffer)/1024.0;
    buffer = (Vin/Vout) - 1;
    R_unknown = R_1K * buffer;
    return(R_unknown);
  } else {
    return(0.0);
  }
}

int doll_num(float resistor_val) {
  if (0.0 <= resistor_val && resistor_val < 5.0) {
    //0 empty
    return 0;
  } else if (90.0 < resistor_val && resistor_val < 150.0) {
    //100 red
    return 1;
  } else if (300.0 < resistor_val && resistor_val < 500.0) {
    //330 yellow
    return 2;
  } else if (1900.0 < resistor_val && resistor_val < 2600.0) {
    //2k white
    return 3;
  } else if (4000.0 < resistor_val && resistor_val < 6000.0) {
    //5k1 blue
    return 4;
  } else {
    return 0;
  }
}

Unity:

spawn_dolls:

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

public class spawn_dolls : MonoBehaviour
{
    
    public SerialPort sp = new SerialPort("/dev/cu.usbmodem14101", 9600);
    public GameObject doll_prefab;

    private int pin_num = 0;
    private int pin_name = 0;

    private GameObject[] doll_list;

    public Material color;

    void Start()
    {
        sp.Open();
        sp.ReadTimeout = 1;

        doll_list = new GameObject[] {null, null, null, null};
    }

    // Update is called once per frame
    void Update()
    {
        if (sp.IsOpen) {
            try 
            { 
                // read the incoming byte:
                pin_num = sp.ReadByte();
                pin_name = sp.ReadByte();

                if (pin_num == 0) {
                    //first doll, delete last batch
                    for (int i = 0; i < 4; i++){
                        if (doll_list[i] != null) {
                            Destroy(doll_list[i]);
                            doll_list[i] = null;
                        }
                    }
                }

                if (pin_name != 0) {
                    spawn_doll(pin_num, pin_name);
                }

            }
            catch (System.Exception)
            {

            }
        }
    }


    void spawn_doll(int pin_num, int pin_name){

        Vector3 position = new Vector3(Random.Range(-300.0F, 300.0F), 100, Random.Range(-150.0F, 200.0F));//position
        GameObject doll_clone = (GameObject) Instantiate(doll_prefab, position, Quaternion.identity);

        GameObject body = doll_clone.transform.GetChild(0).gameObject;
        GameObject hands = doll_clone.transform.GetChild(1).gameObject;
        GameObject head = doll_clone.transform.GetChild(2).GetChild(0).gameObject;

        Renderer body_render = body.GetComponent<Renderer>();
        Renderer hands_render = hands.GetComponent<Renderer>();
        Renderer head_render = head.GetComponent<Renderer>();


        if (pin_name == 1) {
            body_render.material.color = Color.red;
            hands_render.material.color = Color.red;
            head_render.material.color = Color.red;
            doll_clone.transform.localScale = new Vector3(0.9F,0.9F,0.9F);

        } else if (pin_name == 2) {
            body_render.material.color = Color.yellow;
            hands_render.material.color = Color.yellow;
            head_render.material.color = Color.yellow;
            doll_clone.transform.localScale = new Vector3(0.92F,0.92F,0.92F);

        } else if (pin_name == 3) {
            body_render.material.color = Color.white;
            hands_render.material.color = Color.white;
            head_render.material.color = Color.white;
            doll_clone.transform.localScale = new Vector3(0.94F,0.94F,0.94F);

        } else if (pin_name == 4) {
            body_render.material.color = Color.blue;
            hands_render.material.color = Color.blue;
            head_render.material.color = Color.blue;
            doll_clone.transform.localScale = new Vector3(0.96F,0.96F,0.96F);

        } else {
            body_render.material.color = Color.black;
            hands_render.material.color = Color.black;
            head_render.material.color = Color.black;
            doll_clone.transform.localScale = new Vector3(1F,1F,1F);
        }

        doll_list[pin_num] = doll_clone;
    }
}

doll_movement:

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

public class doll_movement : MonoBehaviour
{   
    private GameObject head;
    private GameObject hands;
    private GameObject body;
    private GameObject head_axis;
    private GameObject neck_axis;

    public float xMax;
    public float zMax;
    public float xMin;
    public float zMin;

    public float moveSpeed = 2;
    public float turnSpeed = 45;
    
    private Vector3 position = Vector3.zero;

    private float timer;
    private float timer_limit;

    private int move_bool;

    void Start()
    {
        body  = transform.GetChild(0).gameObject;
        hands  = transform.GetChild(1).gameObject;
        head_axis  = transform.GetChild(2).gameObject;
        head  = transform.GetChild(2).GetChild(0).gameObject;
        neck_axis  = transform.GetChild(3).gameObject;

        timer_limit = Random.Range(1.0f, 10.0f);
        move_bool = Random.Range(0, 4);

        RandomizePosition();

    }

    void Update()
    {
        timer += Time.deltaTime;
        
        if (transform.localPosition.x > xMax) {
            RandomizePosition();
            timer = 0.0f;
            timer_limit = Random.Range(1.0f, 10.0f);
            move_bool = Random.Range(0, 4);
        }
        if (transform.localPosition.x < xMin) {
            RandomizePosition();
            timer = 0.0f;
            timer_limit = Random.Range(1.0f, 10.0f);
            move_bool = Random.Range(0, 4);
        }
        if (transform.localPosition.z > zMax) {
            RandomizePosition();
            timer = 0.0f;
            timer_limit = Random.Range(1.0f, 10.0f);
            move_bool = Random.Range(0, 4);
        }
        if (transform.localPosition.z < zMin) {
            RandomizePosition();
            timer = 0.0f;
            timer_limit = Random.Range(1.0f, 10.0f);
            move_bool = Random.Range(0, 4);
        }

        if (timer > timer_limit) {
            RandomizePosition();
            timer = 0.0f;
            timer_limit = Random.Range(1.0f, 10.0f);
            move_bool = Random.Range(0, 4);      
        }

        if (move_bool != 3) {
            MoveGameObject();
        }

    }

    private void RandomizePosition()
    {
        position = new Vector3(Random.Range(-200, 200),transform.position.y, Random.Range(-200, 200));
    }

    private void MoveGameObject ()
    {
        Vector3 angle = position - transform.position;
        if(angle.y != 0)angle.y = 0;
        if(position.y != transform.position.y)position.y = transform.position.y;
        if(transform.position != Vector3.MoveTowards(transform.position, position, moveSpeed * Time.deltaTime))
        {
            transform.position = Vector3.MoveTowards(transform.position, position, moveSpeed * Time.deltaTime);
            transform.rotation = Quaternion.RotateTowards(transform.rotation,Quaternion.LookRotation(angle),turnSpeed * Time.deltaTime);
        }
    }

}

Resources used:

  • https://www.circuitbasics.com/arduino-ohm-meter/
  • https://www.alanzucconi.com/2015/10/07/how-to-integrate-arduino-with-unity/
  • https://answers.unity.com/questions/336663/random-movement-staying-in-an-area.html
  • https://answers.unity.com/questions/1456945/how-to-make-a-gameobject-move-randomly-withing-a-b.html