DEV Community

Nhlanhla Lucky Nkosi
Nhlanhla Lucky Nkosi

Posted on

Banana Controller: Building an affordable Custom Controller with the Arduino Uno

Let’s build a cheap custom controller using bananas and an Arduino Uno.

banana-controller
Image source: John Baichtal on Make: Community

Aim

In this article, I’ll show you how to build your own custom controller using one of the cheapest, beginner-friendly, and versatile micro-controller boards on the market: the Arduino Uno.

Background & Context

I am fascinated by how we, as humans, interact with computers. I believe that by experimenting with different ways of doing this, we can build very interesting things. The common problem with “new” technologies is that they are often expensive to play around with. We have to find means of making the technology easily and affordably accessible.

I learn best through practical examples. Since this is supposed to be a serious article - with no banana business, we’ll be building something very useful: a banana controller. Yes, we’ll build a custom controller using bananas.

I first came across the idea while attending the A Maze festival in Johannesburg a few years ago. I walked up to a stand and I was told that I could play Space Invaders with bananas. The experience blew my mind. They had used the Makey Makey to achieve this with ease. The Makey Makey classic board retails for around US$50 which is just over R800 (ZAR). The board is incredible and relatively well priced (i.m.o) for its capabilities. However, the price-tag limits access.

The Arduino Uno, on the other hand, can be bought for as little as R99 which is less than $10. At a fraction of the price, we can achieve (almost) the same goal: building a custom controller to play a game with bananas.


Tools

We’ll need a couple of tools to get this job done.

Tools

Here’s what you’ll need

  1. An Arduino Uno Board
  2. Arduino IDE
  3. Unity 3D
  4. Bananas

Solution Overview

The user/player will touch the banana. Using the Arduino, we’ll detect this touch and then notify Unity that the player has touched the banana. Unity will then use this information to make the game react.

Circuit

Electronics — How it works

The Arduino Uno comes with 6 Analog pins. Each pin has a 10-bit Analog to Digital Converter (ADC). With 10 bits, we can represent 1024 distinct values. The Arduino is powered with 5 Volts. Therefore, using the ADC, we can represent the 5V in 10 bits. With this understanding, we can use digital values in our software to represent voltage reading on the input pins. Consider the following:

Equation

This means that each digit difference picked up by our software represents a 4.9mV difference.


Arduino Software

We need software that will detect and interpret the touching of the banana. The following is all the code we need to run on our Arduino.

    const int threshold = 875;
    void setup()
    {
        Serial.begin(9600);
        Keyboard.begin();
    }
    void loop()
    {
        if (analogRead(A0) < threshold)
        {
            Serial.write(1);
            Serial.flush();
            delay(80);
        }

        if (analogRead(A5) < threshold)
        {
            Serial.write(2);
            Serial.flush();
            delay(80);
        }
    }

Use one of the Arduino IDEs to program your Uno. This code makes use of the analogRead() function to get the reading from the Arduino Analogue pins. When the reading drops below our threshold — determined through logging out the behavior during testing, we can assume that the fruit connected to the analog input has been touched. We then have to send a message to Unity.
The Uno is not the best board for activating keyboard events. Therefore, we use the serial port to communicate with the Unity program. Using Serial.write(), we pass on a simple message to be understood by whichever application will read the serial port. In this instance, we send the integer 1 when the first fruit is touched and integer 2 when the second one is touched.


Unity3D Software

With the Arduino sending either a 1 or a 2 when one of the fruits is touched, we now need to write some code to read the serial port and make use of the information being sent. Reading the serial in unity is not much of a hassle. First, you need access to ports and related functionality. Using System.IO.Ports gives us this functionality.

Next, you need to declare your stream. This configuration must match the serial port configuration used in your Arduino IDE. Set the port (COM6) and the baud rate (9600, is standard on most devices) on the variable declaration section of our like this:

    SerialPort stream = new SerialPort(COM6, 9600);`

On Start(), open the stream to start receiving data as soon as your program starts and set the reading timeout to 1 second.

    void Start () {
        stream.Open();
        stream.ReadTimeout = 1;
    }

On Update(), read the information being streamed.

    void Update(){
        int readValue = (int)stream.ReadByte();
    }

The line above will throw an exception when it does not receive data. I’d recommend wrapping it in a try-catch block and interrogating the exceptions it throws. We put this line in the Update function to ensure that we check it every frame — this ensures that we can detect the banana touch as soon as possible.
The stream has to be flushed to ensure that we read the latest and most up-to-date data possible. Adding stream.BaseStream.Flush(); after checking for data can achieve this.

I’d recommend setting the stream’s timeout to 1 second in the start function. The full Unity C# script called SerialPortComs will look like this:

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

    public class SerialPortComs : MonoBehaviour
    {
        SerialPort stream = new SerialPort("COM6", 9600);
        // Start is called before the first frame update
        void Start()
        {
            stream.Open();
            stream.ReadTimeout = 1;
        }
        // Update is called once per frame
        void Update()
        {
            if (stream.IsOpen)
            {
                try
                {
                    int readValue = (int)stream.ReadByte();
                    UseBananaInput(readValue);
                }
                catch (System.Exception)
                {
                    //handle errors
                }
                stream.BaseStream.Flush(); //Ensure data refresh
            }
        }
        void UseBananaInput(int value_sent_by_arduino)
        {
            //this is where you put code that makes use of the input
        }
    }

In the UserBananaInput function, you can now move an object or perform any other game action that relies on user interactions.


Resources

I gave a talk on this topic at BBD Software Development’s Es@cape conference in 2018. The talk touches on my motivation for this type of work and includes a live demo in which I do all of the above steps. You can work through both this article and the video. The talk is titled “Play with your food… and everything else.” You can watch it here.

You can find all the code used in this project on my GitHub page.

Conclusion

I hope you enjoyed reading this and learned something interesting. Let me know if you have any questions and I will gladly answer them. Please feel free to also show me what you build with custom controllers; I’d love to see what everyone else is working on. Check out my other projects which include educational games and teaching conversational IsiZulu on my site.

From me, Lucky: Sharp👍 Sharp👍

Godd bye brain

Top comments (0)