Unity PID

For a project at University, I needed to come up with a way to get objects to fall at similar rates to the player to provide an illusion close to that of Alice and Wonderland. The object for testing was an armchair.

I modelled in Blender a simple tube to provide the walls of the hole and applied a brick texture using the smart UV wrapping in Blender along with the texture assignment in Unity.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class topoftube : MonoBehaviour {

    public Transform SpawnPoint;
    public Rigidbody ChairSpawn;

    public int NumberOfClocks = 0;
    public int NumberofChairs = 2;

    private Vector3 getNewPos() { //  used to create a random spawn pos with range of 2.5 +-
        Vector3 SpawnPos = new Vector3(SpawnPoint.position.x + Random.Range(-2.5f, 2.5f), SpawnPoint.position.y + 20 +  Random.Range(-20.0f,20.0f),
            SpawnPoint.position.z + Random.Range(-2.5f, 2.5f));
        return SpawnPos;
    }


    private void OnTriggerEnter(Collider other)
    {

        // Player has entered the top of the tube
        // start to place falling objects

        Rigidbody[] RigidFabChair = new Rigidbody[NumberofChairs]; // create array of Rigidbody objects
        for (int i = 0; i < NumberofChairs; i++) // loop through to create the number of chairs required
        {
            RigidFabChair[i] = Instantiate(ChairSpawn, getNewPos(), SpawnPoint.rotation) as Rigidbody; // create a new instants of the ChairSpawn
            RigidFabChair[i].mass = Random.Range(0.5f, 2.0f); // Provide a random mass to the new object
            RigidFabChair[i].transform.rotation = Quaternion.Euler(Random.Range(-40, 40), Random.Range(-40, 40), Random.Range(-40, 40)); // adjust the rotation
        }
    }
}

This CSharp script is then applied to an object with a trigger attached so that once the player enters the tube the OnTriggerEnter function is called. The script utilises the Prefab object in unity and then along with some randomness, places the object over the tube ready to fall when the player starts to fall.

As part of some testing, a PID controller was applied to each object to adjust the velocity of the object as they fell. With applying a PID controller, it would then be possible to have more control over the characteristics of the objects falling.

This is the script that was applied to the falling object’s prefab.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;

public class SpeedLimiting : MonoBehaviour {
    private float error = 0.0f;
    private float error_prev = 0.0f;
    private float integral = 0.0f;
    private float derivative = 0.0f;
    private float output = 0.0f;
    private float Kp = 0.2f;
    private float Ki = 0.9f;
    private float Kd = 0.0f;
    private float bias = 0.0f;
    private int desired = 12;

    private float lastoutput = 0.0f;


    // Use this for initialization
    void Start () {
     
    }
   
    // Update is called once per frame
    void Update () {
        Rigidbody rb = GetComponent<Rigidbody>();

        error = desired - Mathf.Abs(rb.velocity.y);
        integral = integral + (error * Time.deltaTime);
        derivative = (error - error_prev) / Time.deltaTime;
        output = (Kp * error) + (Ki * integral) + (Kd * derivative) + bias;
        error_prev = error;
        lastoutput = output; //last min averaging


            rb.velocity = new Vector3(rb.velocity.x, -((lastoutput+output)/2), rb.velocity.z);
       

    /*
        string path = "Assets/modles/fallingobjects/speed.txt";
        StreamWriter writer = new StreamWriter(path, true);
        writer.WriteLine(-output);
        writer.Close();
        */


    }
}

With adjusting the Kp, Ki and Kd values, different characteristics can be observed.