Introduction: Stand-Alone Sim Racing Multi-HID Interface

About: I like tinkering sooo much people! :)

Recently I took my old PC racing wheel out of the box after a long storage time to give some new game a try. I must admit that I was impressed by the quality level improvement racing simulations have made these years.

This is true not only on the software side, but hardware too. On this latter, I couldn't stop myself joining the direct drive revolution and throw some money and time in the simracing world (and, you can bet it, had a lot of fun in the process).

Once my main rig was ready and my favourite simulator identified, what could be next? A button box, obviously! The time had come to start working on a brand new project and say goodbye to my keyboard and mouse!

The project main here is the interface I layed down. Even if the button box layout you have in mind is completely different from mine (see dedicated Step for details), this PCB will be likely good for it.

Features:

  • multi HID emulation: keyboard, joystick and mouse in the same device
  • up to 24 digital inputs, plus three auxiliary buttons
  • up to 2 analog joysticks (4 analog axis)
  • up to 24 LEDs (user definable voltage)
  • up to 3 rotary encoders
  • built-in LEDs driver circuits
  • stand-alone: no additional software needed (keeps the CPU happy!)
  • multi platform (works on any OS)
  • open-firmware

An example of very distinctive device this interface can help you realize? What about a joystick button box (ok, nothing special...) with incorporated chatbox?!

In this instructables I will show you how I realized a stand-alone, feature loaded, SimRacing button box/chat box interface. I will argument my design choices and describe the circuits adopted. I will share with you all the files needed to have it manufactured. I will share a complete firmware to put all features in your hands.

Last but not least, I will show you how I realized my button box.

Let's start!

Supplies

The PCB objects of this article is made of SMD components, so it's unlikely you are to manufacture it yourself, but commission the assembly to a specialized Company. A link to all necessary files is in latest Step.

For the realization of the box itself, instead, you are in the need for an adeguate-to-your-preferences number of push buttons, rotary encoders, analog joysticks. Buttons can be of the momentary or latching type.

The button box pictured in this Instructable is made of:

1x ABS black box (26 cm x 18 cm x 9 cm)

5x momentary push buttons with yellow LEDs (diameter: 22 mm, working tension: 5V)

4x momentary push buttons with yellow LEDs (diameter: 19 mm, working tension: 5V)

2x rotary encoders (those super cheap encoders often used i DIY projects are ok)

1x analog joystick (the full codename of the one I adopted is JH-D202X-R2/R4 5K, but any would work)

1x auto car tuning latching lever with red LED (working tension: 12V)

1x engine start button with red LED (working tension: 12V)

1x USB type C to USB-B panel mount adapter

1x arduino promicro

2x female pinheaders, 15 pins each


You are also in the need for a soldering iron, soldering tin, some cables, some drill bits (I used step drill bits for the first time here and was happy with the result), a mini drill, a scissor blade, patience, patience and, last but not least, patience.

WARNING! Remember to wear gloves, eye protective glasses and a mask when working on your box: keep all operations safe and have fun.

Step 1: Button Box: Challenges

A racing simulator button box calls for different elements to be present in order to be (nice and) effective. Buttons (switches) are the most obvious, but also rotary encoders and toggling/latching levers have to be taken into account. All these different user-interface elements have to be handled differently, so call for interface flexibility.

Keyboard emulation is a must have for a button box. Not only because some function cannot be mapped to other HID devices (i.e. "ESC" key to exit menus is often not re-assignable), but also because with the help of an open firmware one could code some phrase and have them typed at the press of a button. The chat box I mentioned earlier.

Another very important feature is the possibility to emulate joystick inputs. Joystick inputs does not interfere with other programs and most often have to be preferred over keyboard key presses.

To gain access to menu navigation with ease (and increase immersivness) an analog joystick is a good choice to replace mouse. Most racing simulators have options to assign mouse movements to the wheel or D-pad, but you have no control over parameters such as buttons assignations and speed. As far as I know, there are no commercial button boxes emulating a mouse for menu navigation and such.

A mouse, keyboard and joystick in the same device makes it a so called Multi-HID device.

Appropriate buttons illumination is something appealing both from a practical and aestetical point of view. Turning a LED on or off at the press of a button is trivial, but having full control over LEDs behaviour could be useful in some situations.

All these inputs and outputs call for a good amount of GPIOs on the microcontroller of choice, especially if hardware maximum flexibility is in the need (and it is here!).

Powering a lot of LEDs in addition to the whole PCB integrated circuits through USB could be a problem, but calls for additional wires and PSU. Depending on the number of elements the user plans to populate the button box with, an adegutate power handling is in the need.

Step 2: Button Box: My Solutions

Multi-HID device

The power of a complex multi-HID device is nowadays made easy adopting microcontroller boards such as Arduino boards based on 32u4 microcontroller or a Raspberry Pi Pico, just to cite my favourites. There are plenty of libraries that enormously simplify the task of emulating all the devices we listed in the previous Step, and most often are cross compatible.

In this project I used an Arduino Pro-Micro because it's ease of use and compatibility.

Number of GPIOs

The issue when dealing with microcontroller boards and control panels is in the number of inputs/outputsrequired, often larger than the microcontroller capability. There are various solutions to this, the most common being the button matrix (which is, in the end, the same approach adopted in common keyboards). Wiring buttons in a matrix configuration makes it possible to reduce the number of GPIOs from NxM to N+M, but at a cost: you cannot press more than one button at a time. Even if in this particular application it's not that serious issue, it makes toggle switches (used i.e. for the classic "ignition" switch) not usable. The need for blocking diodes in the circuit (or we should add "ghosting" to the list of matrix configuration issues) vanify the potential spare space advantage of such a solution with respect to the use of integrated circuits.

This is why I preferred to use input and output shift registers ICs to increase the number of inputs/outputs and keep buttons independend.

With shift registers we could add up to 32 inputs using only 4 GPIO's and 32 outs with a single additional GPIO.

Driver Circuit for LEDs

Common buttons integrated LEDs are rated @5V. The switch circuit and LED circuit are often independent, which makes possible to toy with light effects more complex than a "button pressed - light on" routine. The microcontroller board can directly handle a very limited amount of current (approx 20mA @5V per GPIO), so a well designed driver board is in the need. Having the option to select a power source more robust than the USB port could be necessary if we plan to support a high number of power-hungry LEDs in addition to all the circuits this board is loaded with (see next Step for more details).

Step 3: PCB Layout and Circuits

Pin Assignment

I want my button box to host at least one analog joystick for mouse emulation and at least two rotary encoders. All the other elements are momentary or latching switches/buttons/levers.

To increase the interface flexibility, two analog joysticks are actually supported which means four analog axis in total. Arduino's analog GPIOs used are A0, A1 and A2, A3.

Rotary encoders call for two digital GPIOs each. In my experience rotary encoders work best with interrupt routines, so arduino pro-micro's pins 0, 1, 2, 3 and 7 are the candidates. Three rotaries are here supported, with interrupt routines assigned to pins 2, 3 and 7.

To receive-data-from and send-data-to shift registers I have candidated the use of Serial Peripheral Interface (SPI) protocol. This reserves pins 16 (MOSI), 14 (MISO) and 15 (SCLK), PLUS two latch pins, one for inputs, the other for outputs.

Integrated Circuits

This PCB is intended to be feature-loaded but "generic", meaning "also usable in button box configurations different from mine". This is why I extended the number of inputs to 24 even if I used only a few in my box. The standard detection limit of joystick buttons in most softwares is 32, so 8 inputs are left for rotary encoders (one for every direction, so two each) and auxiliary switches. Rotaries (buffered, see next) and auxiliaries are directly handled by the microcontroller through dedicated GPIOs, which spares a shift register to the total count.

Rotative encoders signals are buffered via a 74HC14N Hex Inverting Schmitt trigger. This cleans the signal and makes it easier for the microcontroller to detect state changes. In my experience (mostly in the arcade world) this solution makes a big difference.

The maximum number of outputs is 24. Even if LEDs absorb a limited current, shift registers are not intended to drive them directly. This means that a driver circuit is in the need. Three ULN2803 high-voltage, high-current Darlington arrays each containing eight open collector Darlington pairs with common emitters are here used to drive LEDs.

As said, if the number of LEDs is limited, one could juice them with USB power, but what if the number of LEDs increse? Again, what if some of those LEDs are actually +12V LEDs and not +5V?I was open to no compromises here (as much as possible), then I ended laying out a tunable driver circuit for LEDs. In other words, the user can select to power any of the Darlinghton arrays from USB or an external source (+12V MAX!), independently. The power source of any Darlinghton array is independend from the other two, leaving the user the choice. In other words, one could power two Darlington's with USB and one with +12V from an external source, or all with external +5V, as a function of the nature and number of buttons in use.

A dedicated LED shows the presence of external power.

Layout

This PCB is intended to be placed somewhere on box "bottom" and wired to elements through cables. I preferred this approach to the "elements on the PCB" one because:

(a) leaves more elements choice (you are not forced to use those very specific elements matching the PCB footprint)

(b) limits PCB dimensions

Inputs and outputs have dedicated pads for direct soldering in exclusive PCB's areas with due labelling for easier identification:

  • B01-B24 are generic inputs. Buttons are obvious here, but any switch-based device would work such as a shifter, pedal, hand brake and so on. These are handled through the input shift registers
  • J1X, J1Y and J2X, J2Y are analog inputs. Any of these correspond to a single analog axis, then two joysticks in total. These are directly handled by the microcontroller board.
  • R1A, R1B, R2A, R2B and R3A, R3B are the three couples of inputs for incremental rotary encoders. These are buffered first, then enter dedicated microcontroller GPIO's. R1A, R2A and R3A are connected to interrupt GPIOs.
  • AUX1, 2 and 3 are inputs directly connected to microcontroller GPIOs. These are intended for special function such as shift, page selection etc etc.
  • L01-L24 are LEDs outputs. As said, LEDs are driven by three independent ULN2803, each powered by a user definable source. This source could be 5V coming from USB, or an external power source, the selection being dependend on the total current your LEDs will sink and working tension. The external power source can be, in example, 12V, but also 5V if you are worried that the current needed could exceed the 500 mA a common USB port can source.

Please, notice that LED pads goes to LEDs negative leg (sinking configuration). The positive leg must be connected to the relative power source (LA+, LB+ or LC+).

Step 4: What About Those Nice Car Tuning Elements?

Car tuning gives us a choice of very appealing elements for our button box. These are nice looking and add a lot to the immersion. The pictured "engine start" button and those switches with safety cup used for ignition are good examples of these elements.

Unfortunately, they come with some limitations:

1) they are rated @12V and 5V versions are not available.

2) their internal wiring

Point #1 has a simple solution, which is powering them +5V instead of +12V. Light will be a little dimmer, but not that much in my experience. This is the actual solution I adopted.

Another solution to point #1 is the use of a voltage divider to lowen the input voltage from 12V to 5V. It's a simple 2 resistor circuit one can actually realize between element terminals.

Adopting one solution or the other is mandatory or the interface will be damaged since shift registers and the microcontroller board are not +12V tolerant.

About point #2, these elements have not two independent circuits for switch and LED (four terminals, two for the switch, two for the LED), but a total of three terminals. They are intended to work "button pressed - light on, button released - light off" toggling the signal from "floating" to +12V (+5V adopting one of the two solutions to point #1) when pressed.

The internal wiring makes impossible to gain control over the LED routine, so we are forced to accept the factory "button pressed - light on" routine.

Step 5: Firmware

I wrote a generic firmware in order to give you maximum flexibility in layout design. The firmware is written to perform simple tasks (nothing too fancy) in order to be a good starting point for any project.

Arduino makes things easy because of it's open libraries. Here I have used Mattew Heironimus joystick library and some offical library (Mouse, Keyboard and SPI). Official arduino libraries are installed by default on the IDE; Mattew's lib must be installed instead (see link for detailed instructions).

Switches functions are triggered at state change only. This keeps the MPU cool, but also makes the use of momentary switches and latching switches interchangeable, without the need to treat them differently at coding level or adopting special hardware configurations. Box buttons can be freely assignedto joystick buttons (up to #24), keyboard keys (ASCII format) or mouse buttons. I assigned keyboard keys "ESC" and "ENTER" to two buttons. I also assigned left mouse click to another. All the other are joystick buttons.

In normal operation mode all LEDs are on.

When the mode toggling button is pressed, chat box mode is activated. In this mode the press of some button sends whole phrases to the chat. In chat box mode LEDs blink in order to give user a visual feedback. Phrases can be freely defined by the user and assigned to any button. To confirm and send to the outher world a phrase press "ENTER", to delete it press "ESC" (this at least if how it works in ACC).

The firmware emulates a mouse controlled by the analog joystick. The farther from the center the joystick lever, the faster the mouse movement.

Rotary (optical) encoders are read through a 1X counting routine. To avoid rotation losses even at high speeds, one of the two encoder optics is attached to MPU's interrupts pins, then hardware filtered (see previous step).

Please notice that even if rotary encoders are supported, I made a stupid mistake in my prototipe of the board such that I could not test the code (not with the PCB, at least). The shared PCB has been corrected, but I have not a copy of it to test the code and the fixed circuit.

Don't like the overall behaviour or have in mind some groundbreaking features? Perfect! This project is open-firmware which means that you can modify it's core at your will, even with limited coding skills (it's arduino magic people!).

Step 6: My Button Box!

To realize my button box I followed these operations:

0) covered the surface with masking tape, for protection

1) made some elements positioning test, in order to identify the "best" layout

2) set the correct positions for all elements

3) drilled a very small hole in the elements position centers

4) enlarged the small hole to 5-6 mm

5) realized the joystick hole

6) with a "steps" drill bit I enlarged the holes to adeguate dimensions to host the push buttons

7) placed the elements in their final positions

8) daisy-chained ground and USB lines directly on the elements

9) realized the square hole for the USB connector (USB-B to USB type C)

10) soldered the remaining pins to the button box PCB.

The small hole at point #3 acts as a "guide" for the following drilling operations.

Point #4 is because that's the diameter of the smallest elements in my panel (the rotary encoders).

Point #5 is for sure the most complicated and time consuming. This is why I made it first (figure it: your panel is almost complete and an error in the joystick hole kills the panel ...).

Point #8 has some details I want to share. In order to use the car tuning elements I bought (engine start button and ingnition switch) and set a common wiring for all inputs, I had to adopt an input pulldown circuitry. This means that buttons have to be connected to V+ in order to have the shift registers record a button press. So, buttons share the V+ line, not the GND line. This is true for LEDs too. LEDs are driven by Darlinghton pairs, which work in current sink configuration. This means that they share the V+ line. In my very specific configuration, I used the USB line to power everithing, so my buttons and LEDs are daisy chained to the USB line.

Please notice that I used naked wire for USB line, red wire for ground. This is NOT the best way to realise such wiring (the opposite would be) but naked wire speeds the operation a lot and I preferred to go that way.

I used two buttons dimensions: 19 mm and 22 mm. I think that 19 mm is actually the optimal diameter for this application.

Adopting steps drill bits to drill plastic was very efficient. I had to go easy anyway, in order to avoid enlargin the holes too much. A mini drill is heavily recommended to complete the work.

To realize the USB power jack squared hole (point #9) I used a mini drill to gross the area and finished with a scissor blade. This is another phase calling for patience.

Step 7: SMD Tips and Tricks

This project uses surface mount devices (SMD) and I opted for JLCPCB SMT assembly service because I had succesfully used their service in two previous projects and was very happy with the results.

Dealing with SMDs is more articulated than with through hole parts, but with the help of THESE instructions and JLCPCB online submission form everything went smooth and well.

I took some notes about the "criticalities" I found during my (limited in number) experiences with SMD assembly. I also noted solutions, for future use:

  • Triple check your design before submission, by running your software design rule check (DRC) and electrical rule check (ERC). It will be difficult to fix those after the realization (SMD, people...).
  • Check any single component authomatically chosen by JLCPCB site to be sure it fits the design. It happened to me, in example, that a resistor network was misinterpreted as a regular resitor. You will spot it immediately by looking at rendered PCB's components.
  • By carefully looking at rendered PCB, you also will spot with ease IC's with wrong orientation (see attached pictures), or even completely misplaced. You can change components orientation by left click on it and then right click to select the rotation angle. About misplacements, JLCPCB engineers will take care of it, no problem ;)
  • The board rendering screen is a good place to check for missing components. Carefully go though all the board to be sure that all components are there and go back if something is missing.
  • Components selection is the most important (and funniest, in my opinion) phase. If the automatic selected part is not available or in inventory shortage, do not desperate! Use a more generic term in the part research field. In example: use 74HC14 instead of CD74HC14M and more options will be in your hands.
  • When you are done with components selection, save your components list in the shopping chart. This is because it could be the case you want to make some modification to your design after that, and uploading a newly generated BOM will force you to check/select components once again. The shopping chart components list is saved in BOM format, so it will be a matter of uploading it to have all previously selected components directly listed.

Throughout the entire assembly planning process of your device, you never have the feeling of being left alone... proceed with caution and trust and all will be fine :)

Step 8: Acknowledgments

Many thanks to those nice girls and guys at JLCPCB for sponsoring the manufacturing of this project's FR-4 PCB and SMD assembly

JLCPCB is a high-tech manufacturer specialized in the production of high-reliable and cost-effective PCBs. They offer a flexible PCB assembly service with a huge library of more than 350.000 components in stock.

3D printing is part of their portfolio of services so one could create a full finished product, all in one place!

By registering at JLCPCB site via THIS LINK (affiliated link) you will receive a series of coupons for your orders. Registering costs nothing, so it could be the right opportunity to give their service a due try ;)

All Gerber files, sketches and utilities I realized for this project are stored >>HERE<< (Github). I always upload the most recent file's versions, so it could be the case that some PCB looks a little different from those pictured in my instructables.

My projects are free and for everybody. You are anyway welcome if you want to donate some change to help me cover components costs and push the development of new projects.

>>HERE<< is my paypal donation page, just in case ;)