Nintendo Switch Controller

Github: https://github.com/kevinbchen/switch-controller

This is a simple electronics project to wirelessly control a Nintendo Switch using an Xbox One controller. There are 2 main parts:

There are commercial 3rd-party controllers and wireless adapters that achieve the same thing much more cleanly and conveniently; this was mainly a fun side project to get back into electronics and 3d-printing. Of course, having control over the software does enable things like a turbo mode for specific buttons (to hit rocks and chop trees more easily in Animal Crossing!).

Although the software is currently written for an Xbox One Controller, other usb controllers should also work, assuming the usb host shield library support them. In addition, the transmitter can also be replaced by a PC, opening up potential for some basic automation.

Hardware

Transmitter components:

The transmitter is powered directly from the Xbox controller’s 2 AA batteries, stepped up to 5V. This gets regulated back down to 3.3V for all the components, but USB VBUS still needs 5V. Probably pretty inefficient, but needs no modification to the controller itself, besides exposing connections to the batteries. In total, the transmitter draws ~120 mA from the batteries (~100 mA from the controller itself).

Receiver components:

The receiver is powered by via USB (5V). The HC-06 has its own regulator for VCC, so we just need a voltage divider for the module’s RX pin.

The enclosures were designed in Fusion 360 and 3d printed. I also printed a controller battery cover with an opening to run connections to the batteries.

Software

Dependencies:

The transmitter uses the USB Host Library to read in the Xbox controller state. It encodes the state into 7 bytes and sends them over the bluetooth serial link, along with an initial 0xFF byte as a sentinel. A state “packet” is sent every 10ms, or immediately if the controller state changes (ignoring small changes in analog values). The 7 data bytes sent are:

    byte buttons1;  // 0:Y, 1:B, 2:A, 3:X, 4:L, 5:R, 6:ZL, 7:ZR
    byte buttons2;  // 0:-, 1:+, 2:Lstick, 3:Rstick, 4:Home, 5:Capture
    byte lx;
    byte ly;
    byte rx;
    byte ry;
    byte dir;

The button bytes are simple bitmasks. The lx/ly/rx/ry bytes are in [0, 254] and represent each axis of the left/right analog sticks, wiht 128 being center (255 avoided because of sentinel). The dir byte is in [0, 8] and represents the number of 45 degree clockwise increments from up for the directional pad, with 8 being no direction.

The receiver simply reads in these packets, and uses the SwitchJoystick Library to send these inputs to the Nintendo Switch. There’s some simple logic for skipping packets if the serial RX queue is being flooded.

Misc Notes

Latency

Latency was intially a concern, but I was able to reduce it somewhat with a combination of:

I don’t have qualitative numbers, but I think it’s fairly reasonable now.