I’ve recently been reconnecting with my brother via the PC game Elite Dangerous. The pace of the game is up to the player and allows for conversation between action. It’s an in-depth spaceship simulator game and there are a ridiculous number of controls. Even my joystick with 16 buttons felt insufficient. So I decided to make my own thrust control, similar to the one in the game’s ships.
The hand grip has 16 buttons and a wheel with 60 deg of rotation. The entire hand grip slides back and forth on an aluminum rail for the primary throttle control. There are 5-way (up/down/left/right/press) directional switches under the thumb and index finger and six colored buttons on the left front side. It shows up as a generic joystick in Windows and the controls can be mapped to any function in any game.
The base is constructed of scrap metal pieces I had around. It’s nice and heavy and doesn’t slide too easily. For the rest of the fabrication, I used Fusion 360 to create a model and generate STL files. The parts were then printed on an Ender 3 v2. I got a small screw kit marketed for laptop repair off of Amazon, which was perfect for this application.
Inside, an STM32 Blue Pill board does everything. I programmed it from scratch using libopencm3. The documentation was sparse and examples scarce, but I eventually got it to do what I wanted. This is my first project using Visual Studio Code with platform.io and libopencm3. Although the learning curve was rather steep, this development environment was not bad to use.
The buttons are grouped into three banks. Each 5-way switch and the group of six buttons have an isolated ground to one of the Blue Pill’s GPIO pins. However, the other sides of the switches are wired parallel in groups of two or three. This allows 6 + 3 wires to provide the state of up to 18 buttons on the grip. This is common practice for grid-like arrangements of buttons, but is just as applicable here. Keeping the wire bundle small was important for smooth operation and there were fewer wires to pin. The image below from Arduino.cc illustrates the concept.
The buttons also had to be packed up so each button state occupied only one bit. So there was some stuff like this in there: btns |= (swbnk1[i] << i);
The source is on GitHub.
In addition to the 16 discrete signals, there are two analog inputs. A rotary potentiometer measures the wheel angle and a linear potentiometer measures the grip displacement. The wheel rotation is constrained to about 110 degrees and the STM32 ADC has 12-bit resolution. It was necessary to convert the raw input values to -127 to 127 to match the USB HID report descriptor.
Windows’ built-in game controller test app was extremely useful! I have used the controller a few times now and it works great. Having the additional controls at my fingertips makes the game easier and more enjoyable. Of course the keyboard has many more buttons, but the feel and positioning makes all the difference. Controlling the thrusters with the corresponding direction of the thumb switch is more intuitive than using R,F,Q and E on the keyboard. And pushing the entire grip forward to increase the throttle feels more engaging than rotating the puny slider on the back of the joystick.
It took several iterations to get the final result. The first two hand grips were comically large and uncomfortable. I had to add a fourth wheel to the roller assembly for it to roll smoothly. I had a cable chain for the wires coming out of the hand grip, but it sort of works better without it. I tried mounting the small buttons directly to the cover, but the pins kept breaking so at the last minute I soldered them to a piece of proto board. Of course that didn’t fit in the grip so I had to hack it up in Fusion 360 and the smooth contours I worked so hard on were partially lost. But overall I am very happy with the result. I already have some ideas for improvement. For example, plan to fully enclose the base and mount some toggle switches or other controls to it.