Control rc car using raspberry pi (Part 4 : Build the controller)
Tags: beginners, unity3d, raspberrypi, csharp
Published: 2023-08-10 14:13:46

##The controller app UI
The UI for the app is very simple, just two buttons to run forward and backward, and a text to indicate the speed.
To turn the car, you need to turn the phone.

![Controller UI components](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l3lni2micdqnegvvf0vc.png)

You can find the project on github [here](https://github.com/medmor/CarController.git)

##The controller scripts

Learn to code using Unity is very simple, all you need is to crate a `monobehavior` script, attach it to a `gameobject` and you are good to go. Make things move!.

There are three important parts in our app.

###The UnityWebRequest
We can send web requests by using the `UnityWebRequest` class from the namespace `UnityEngine.Networking`.
To achieve this I created a singleton script that can be called from all other scripts that needs to send web requests. The script is like this:
```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;

public class RequestManager : MonoBehaviour
{
    [SerializeField] private string baseUrl;

    private static RequestManager instance;

    public static RequestManager Instance
    {
        get { return instance; }
        set
        {
            if (instance == null)
            {
                instance = value;
            }
        }
    }

    private void Awake()
    {
        instance = this;
    }

    public void SendRequest(string command)
    {
        StartCoroutine(Upload(command));
    }

    IEnumerator Upload(string command)
    {
        List<IMultipartFormSection> formData = new List<IMultipartFormSection>();

        UnityWebRequest request = UnityWebRequest.Post(baseUrl + command, formData);
        yield return request.SendWebRequest();

        if (request.result != UnityWebRequest.Result.Success)
        {
            Debug.Log(request.error);
        }
    }
}

```
###Sendig Requests to run the car forward and backward

The buttons are set to listen to the `PointerDown` and `PointerUp` events.
```
    public void OnPointerDown()
    {
        isPressed = true;
    }
    public void OnPointerUp()
    {
        isPressed = false;
    }
```
While the pointer is down the speed will increase, and after a threshold in the difference of speed we send a Request for the server.
```
 void Update()
    {
        if (isPressed)
        {
            if (speed < minSpeed)
            {
                speed = minSpeed;
            }
            speed += speedIncrement * Time.deltaTime;
            if (speed > 100)
            {
                speed = 100;
            }
            if (Mathf.Abs(speed - lastSpeed) > speedDiffrenceThreshold || speed == 100)
            {
                UpdateSpeedIndicator();
                lastSpeed = speed;
                RequestManager.Instance.SendRequest(direction + "/" + (int)speed);
            }

        }
        else if (speed > 0)
        {
            speed = 0;
            lastSpeed = 0;
            UpdateSpeedIndicator();
            RequestManager.Instance.SendRequest("stop"); UpdateSpeedIndicator();
        }

    }
```
The `RunController` script is like this:
```
using UnityEngine;
using UnityEngine.UI;

using TMPro;
public class RunController : MonoBehaviour
{
    enum Directions { forward, backward }
    [SerializeField] Directions direction;
    [SerializeField] private Image speedIndicator = default;
    [SerializeField] private float speedDiffrenceThreshold = 10;
    [SerializeField] private float speedIncrement = 5;
    [SerializeField] private float minSpeed = 50;
    [SerializeField] private TextMeshProUGUI speedText;

    private float speed = 0;
    private float lastSpeed = 0;
    private bool isPressed = false;

    void Update()
    {
        if (isPressed)
        {
            if (speed < minSpeed)
            {
                speed = minSpeed;
            }
            speed += speedIncrement * Time.deltaTime;
            if (speed > 100)
            {
                speed = 100;
            }
            if (Mathf.Abs(speed - lastSpeed) > speedDiffrenceThreshold || speed == 100)
            {
                UpdateSpeedIndicator();
                lastSpeed = speed;
                RequestManager.Instance.SendRequest(direction + "/" + (int)speed);
            }

        }
        else if (speed > 0)
        {
            speed = 0;
            lastSpeed = 0;
            UpdateSpeedIndicator();
            RequestManager.Instance.SendRequest("stop"); UpdateSpeedIndicator();
        }

    }
    public void OnPointerDown()
    {
        isPressed = true;
    }
    public void OnPointerUp()
    {
        isPressed = false;
    }
    private void UpdateSpeedIndicator()
    {
        speedText.text = ((int)speed).ToString();
    }
}
```

###Turning the car left and right
We use the smarthphne accelerometer to turn the car right and left. Unity makes this very simple, We just need to use the built in `Input.acceleration`.
The `DirectionController` script is like this:
```
using UnityEngine;


public class DirectionController : MonoBehaviour
{
    [SerializeField] private float directionChangeThreshold = 0.15f;
    enum Directions
    {
        center, left, right
    }
    Directions direction = Directions.center;
    Directions lastSentDirection = Directions.center;
    void FixedUpdate()
    {
        if(Input.acceleration.x > directionChangeThreshold)
        {
            direction = Directions.right;
        }
        else if(Input.acceleration.x < -directionChangeThreshold)
        {
            direction = Directions.left;
        }
        else
        {
            direction=Directions.center;
        }
        if(lastSentDirection != direction)
        {
            lastSentDirection = direction;
            RequestManager.Instance.SendRequest(direction.ToString());
        }
    }

}
```