Justin Rahardjo

Controlling an Arduino with the Xbox One Controller (using JavaScript)

By Justin Rahardjo on May 19, 2018
white xbox one game controller

Recently we used an Xbox One Controller to send commands to an Arduino. Since a few people asked how this was done, I thought I’d write it up.

The code that was used on that particular project can be found here, for those that just wanted to jump straight into the source code.

It was a pretty simple setup. At a high level, the controller talks to a laptop (or any other computer) via Bluetooth and the laptop interprets this into commands to send over Serial to the Arduino.

High level diagram of the setup

Connect controller

So firstly we need to connect the controller to the computer. This is pretty straight forward on a Windows or OSX so I won’t go too much into it, basically just connect it via Bluetooth like you would for a mouse or a keyboard.

For those on Ubuntu or other Linux Distros, firstly connect it via Bluetooth and you may notice that the light on your controller is still blinking and if you keep an eye out on your Bluetooth settings, the controller keeps connecting and disconnecting. To fix this issue, firstly install sysfsutils if you don’t already have it.

  • Install sysfsutils
  • Add this line /module/bluetooth/parameters/disable_ertm=1 to /etc/sysfs.conf (remember to do this as an admin, e.g. use sudo)
  • Restart your computer

Now when you re-connect the controller, it should give you a solid light.

Arduino Serial

We would need to setup Serial on the Arduino. There are plenty of tutorials on how this works so please refer to those. For the purposes of this exercise we will use the code below. This code will receive a value for each colour and will write that value to the LEDs.

/*
  Turns on the led using serial
 */

// Initialize the LEDs
int blue = 9;
int green = 10;
int red = 11;

// Initialize the integers to keep the values of the leds
int blue_value;
int red_value;
int green_value;

// the setup routine runs once when you press reset:
void setup() {
  // initialize the pin as an output.
  pinMode(blue, OUTPUT);
  pinMode(red, OUTPUT);
  pinMode(green, OUTPUT);
  //   Start serial
  Serial.begin(9600);
}

void loop() {
  // Wait until we receive the 0xFF Character
  if (Serial.read() == 0xFF) {
    // Wait until we have 3 bytes available
    while (!(Serial.available() > 3)) Serial.println("wait");

    blue_value = Serial.read();
    red_value = Serial.read();
    green_value = Serial.read();

    // Echo back what we just received for debugging
    char sendBuffer[3];
    sprintf(sendBuffer, "%d%d%d", blue_value, red_value, green_value);
    Serial.println(sendBuffer);

    // Write the LED Values to show the colours
    analogWrite(blue, blue_value);
    analogWrite(green, green_value);
    analogWrite(red, red_value);
  }
}

As you can see, on line 27, we are waiting on an 0xFF character before we even think about the rest of the items that is being sent via serial. And we then read the next 3 bytes after that value and set it as the LED values. So when we setup our Serial code on the laptop, we need to make sure that we are sending the same items.

Reading Controller Input

Once the controller is connected, we would need to read those inputs so we can use it for our applications. To do so, we will use the awesome gamepad library. You can follow the documentation to receive inputs, this library makes it very straightforward to deal with the controller inputs.

Sending Serial Output

To send the Serial output, we will need two packages serialport and struct.

Using struct we define the data structure that we will be sending. As mentioned above, we will be sending an initial byte of 0xFF and then our data, which in this case are all signed integers. So we define it as follows:

const data = Struct()
    .word8Sle('start')
    .word8Sle('blue')
    .word8Sle('red')
    .word8Sle('green');
data.allocate();
const proxy = data.fields;
// Define default values
proxy.start = 0xFF;
proxy.blue = 0;
proxy.red = 0;
proxy.green = 0;

Once we define the data structure, we can open the serial port and send the data we want to send.

const port = new SerialPort(
    '/dev/ttyACM0',
    { baudRate: 9600 }
);
const buffer = data.buffer();
port.write(buffer, function (err) {
    if (err) return console.log('Error on write: ', err.message);
    console.log('Data sent successfully');
});
  • /dev/ttyACM0 would need to be replaced with the serial path you are using
  • Set the baud rate to be the same baud rate that was set in the Arduino Code

And that’s it, combining the two, you can use the values you receive from the controller and pass that along through to the Arduino using Serial.

Notes

One thing to note, it is a good practice to only send the Serial data on a certain interval. This allows the application to be more predictable and also, depending on what your Arduino is doing, you may need to insure that there is enough time in each loop to perform the necessary tasks before receiving the next lot of Serial data. Here is an example of what you can do.

function callbackFromJoystick(button, value) {
    if (button === 'blue') {
        proxy.blue = value;
    } else if (button === 'red') {
        proxy.red = value;
    } else if (button === 'green') {
        proxy.green = value;
    }
}
setInterval(function() {
    const buffer = data.buffer();
    port.write(buffer, ... );
}, 50);