Making a wireless joystickApril 19, 2020 Maker
I always liked the design of the Wii’s Nunchuck controller. But normally you can only use them if they’re physically wired to another device called the Wii Remote. However, with some hardware and software tinkering and time, it’s possible to turn a Nunchuck into a completely stand-alone wireless (PC) joystick. In this post, I’ll briefly go over how I achieved this, as well as share the open-source software and hardware resources I developed along the way.
When opening up a $4 Nunchuck-compatible knockoff, it’s easy to spot its two analog potentiometers, the two digital buttons, a MEMS accelerometer chip, and the tiny microprocessor hidden under a black blob. The microprocessor samples all these inputs, and sends out a digital version of this information over the cable that also supplies the device with power.
In order to convert this joystick into a wireless device, I used a Dremel to remove basically everything that wasn’t essential, leaving only the casing, a copperless PCB, the buttons and the potentiometers. Now, I could have chosen to reuse and repurpose more of the original electronics. But I wanted to optimize for battery life and capacity, and didn’t mind losing the accelerometer functionality and redoing the rest.
To power my modified Nunchuck, I bought the biggest rechargable battery I could find that would fit into the bottom part of the Nunchuck, which turned out to be a 35x20x8mm 300mAh LiPO battery. I also added in a cheap TP4056 battery charger IC, a charging indicator LED and a micro USB port placed exactly where the cord used to come out, and filled up the rest of that hole with epoxy.
A healthy LiPo battery outputs between 3.0V and 4.2V. So to convert that to the 1.8V -- 3.6V range required by some of the components, I simply used a diode with a forward voltage drop of 0.6V -- 0.8V which also doubles as reverse polarity protection. And to protect the battery against overcurrent and short circuiting, I added in a 500 mA polyfuse/PTC.
A New Processor
With battery power in place, I designed the main circuit around the AVR ATtiny44A. This neat little 8-bit microprocessor controls up to 12 I/O pins at up to 8Mhz, and can be programmed via a simple and cheap AVR USB ISP board, which itself is typically just another ATtiny44A device.
Like on the original Nunchuck board, the microcontroller samples and processes the analog and digital inputs, and then sends them out on a regular basis. But in this case, they’ll be sent around via a Chinese Bluetooth BLE 4.2 module called JDY-16. This cheap module can serve either as a Bluetooth master or a slave. So I programmed the ATtiny to switch between modes when a ‘secret’ button combination is pressed.
In slave mode, any PC could pair with it and use it as game joystick. But in master mode, the Nunchuck will actively connect to any other DIY Bluetooth project that happens to broadcast a Bluetooth name that starts with some preprogrammed string. That way, I can control other projects without those projects having to know if I’m controlling them with my Nunchuck, my PC, or some other similar Bluetooth device.
Besides the Bluetooth logic, there’s also a recalibration mode programmed into the ATtiny, allowing the deadzones and extremes of the analog joystick to be (re)measured and stored into EEPROM. And its power management code will put the device into deep sleep on inactivity or low power, and will wake it up again on the press of a button.
To further conserve battery life, I programmed the microprocessor to run at only 1 Mhz, and have it cut power to the other components on demand. That way, the whole device consumes less than 6 mA when actively used and less than 0.2 µA when idle. And so, a single charge is enough for dozens of hours of active use, and many years of inactivity.
All the components were tied together as shown in the following schematics, and everything inside the grey area was put on a tiny PCB that I milled on my new CNC.
The Flow of Data
On power up, the code on the ATtiny sends the necessary connection parameters to the Bluetooth module over its UART interface. And once connected, it will regularly send data updates over that same interface. Each update consists of a group of 4 bytes: 7 bits for the X position, 7 bits for the Y position, 7 bits for the button states (of which only 2 are used), 7 bits for a CRC hash, and one bit per byte to indicate if this is the last byte in each 4-byte block.
Internally, the Bluetooth 4 module sets up a brand-specific custom BLE GATT service to wirelessly communicate to other Bluetooth devices. And when it connects to another module of the same kind, this will effectively create a transparent bidirectional serial bridge. But when trying to communicate with a PC, a bit more custom work is required.
So I wrote Windows 10 program in C# that starts by scanning for a paired Bluetooth device with a name that starts with a specific string (i.e. the joystick’s name). And once connected, it subscribes to the right brand-specific Bluetooth GATT Services and Characteristics, checks and unpacks the 4-byte updates, and forwards them to a vJoy device.
vJoy (http://vjoystick.sourceforge.net/) is an open-source Windows device driver that’s just like a regular joystick device, but gets its input state from any application willing to feed it information. And so, the joystick’s state ends up going from the ATtiny microprocessor to the Bluetooth module, to the C# application, to vJoy, and finally to any application that supports regular Windows joysticks.
The finished mod works really well, but there’s always room for improvement. Especially on the hardware side. Stacking capacitors and reusing holes for multiple fragile wires does work, but it makes soldering and assembly harder that it needs to be.
Also, the sampling of the battery voltage level could have been made easier. In the implemented design, the voltage is measured via the MISO pin, which is connected to a voltage divider consisting of the ATtiny’s internal pull-up resistor to VCC and the external pull-down resistor to GND. And so, the digitized readout not only depends on the exact (unspecified) internal pull-up resistor value, but also on VCC which itself depends on diode D1’s current-dependent voltage drop.
And so, it would’ve been better if the pin’s internal pull-up was replaced by an external 100 kilo-ohm resistor connected directly to BAT+. That way, the voltage put on the MISO pin would be less dependent on drawn current, and the divided voltage would still be low enough to prevent harm if polarity is accidentially reversed. But for this one-off, I kept it as it is and instead compensated for the issue by complicating and fine-tuning the voltage sampling code a bit more.
- ATTINY-NUNCHUCK [ZIP]. C source code for the ATtiny44A, also containing lots of in-line assembly code. Can be compiled and linked using the AVR8 GNU toolchain, which I did via the included project files for Visual Studio 2015 and VisualGDB. Also includes the binaries. Source code is free to use under the GPLv3 license.
- NunchuckVJoy [ZIP]. Source code and binaries for the Windows 10 application that scans for the joystick and forwards it to a running vJoy instance. Visual Studio 2015 project files are included. Source code is free to use under the MIT license.
- EAGLE files [ZIP]. The Autodesk Eagle 8.5.0 board and schematics files. Published in the Public Domain.