2022-07-27

DIY Surface Dial

Microsoft's Surface line of hardware has some nice computers and accessories. Among the accessories there's the Surface Dial - a Bluetooth knob that can do things like volume control, scrolling, undo/redo and some other functions in certain applications, mostly artist-oriented. For some reason the physical form of the Surface Dial appeals to me, but since its price is not exactly in the impulse buy territory and I don't have a practical need for it, I never got one. But now I have made my own version of it. It's not as nice as the real one and it's missing some of the functionality, but it really does work as a Surface Dial in the software that supports it.

There are two aspects to this device, making the physical hardware and programming it so that Windows recognizes it as a Surface Dial.

From the hardware perspective, we need two things - a way of detecting the dial's rotation and a button. On the real Surface Dial the entire knob works as a button, but in my version, there's a separate button in the middle, made using a mechanical keyboard switch. As for the dial itself, instead of using an off-the-shelf rotary encoder, I made my own using small neodymium magnets and two Hall effect sensors. Its principle of operation is the same as with other incremental encoders, the sensors are oriented so that their signals have a phase difference. In theory we could get better resolution by using the full resolution of the sensors' output, instead of treating them as binary, but I haven't done that. The resolution I got is determined by the number of magnets (48).

I designed the case for the device in Fusion 360 and 3D printed it. The dial sits on a 6806 ZZ bearing and has a very satisfying feel. Here's what it looked like during assembly.

For the microcontroller I chose the Adafruit QT Py RP2040, it's small and uses the RP2040 chip from Raspberry Pi (it has a similar form factor to Seeed Studio's XIAO RP2040).

Since we're talking about Microsoft, I half-expected the Surface Dial's protocol to be some proprietary nonsense that would require reverse engineering to replicate. Imagine my surprise when I found out that it's actually standard HID and there's proper documentation for it. All you have to do is put the right stuff in the HID report descriptor and it works similarly to a regular USB mouse or keyboard.

I put all the code and 3D-printable files on GitHub, along with a list of components used and instructions how to put them together.

2022-07-09

Two mice, two cursors

I always thought that when you connect two mice to a computer, there should be two mouse cursors, one for each mouse. Unfortunately that's not really how it works on modern operating systems, at least not by default. Software add-ons exist that draw a second cursor for the second mouse (and also perform some tricks to make button clicks work as expected). I'm sure they work fine, but I came up with a pure hardware solution to the problem that requires no special software running on the host. Here's a video demonstrating this solution.

What you can see here is two mice, connected through a USB hub to an Arduino Leonardo with a USB Host Shield. The mice are wireless, but they use 2.4 GHz USB receivers so they're effectively USB devices. The Arduino is connected to the computer and acts as a USB mouse.

The Arduino reads inputs from the two mice, does its magic, and sends the resulting inputs to the computer. What's the trick that makes the computer display two cursors? If you look closely, you'll notice that the two cursors flicker a bit. That's because they're not really two cursors, instead it's just the one normal cursor oscillating quickly between two positions on the screen, appearing as two due to persistence of vision. The Arduino keeps track of the X/Y positions of both cursors and updates them based on the inputs received from each mouse. Then it alternates between the two causing the illusion of two cursors. To be able to do that it uses absolute cursor positioning, unlike a regular mouse, which only sends the X/Y deltas and doesn't know where on the screen the cursor is at any moment. (I have previously used absolute cursor positioning for both good and evil.)

One remaining problem is what to do when you click a button on one of the mice. The user will naturally expect for the click to happen at the screen position of the cursor corresponding to that mouse. So we can't keep alternating between the two cursors. For as long as the button is pressed, we only send the cursor position of the mouse that's doing the clicking. This means that the second cursor disappears for a brief moment, but the clicks work as expected.

If you want to play around with it, I posted the source code on GitHub. It uses the standard USB HID protocol and works with Windows, Linux and Mac, without any additional software needed on the computer.

2022-07-07

Razer Raion padhack

One of the problems when making a custom fightstick (arcade controller for fighting games) is modern console compatibility. While it was easy to make an Arduino or similar board work as a USB controller for the PS3, unfortunately it is no longer the case with the PS4 and PS5. Only licensed controllers work with them due to restrictions introduced by Sony. Every licensed controller has a private key embedded in it that allows it to perform some kind of authentication when connected to a console. One solution to this problem is a practice known as padhacking: taking the insides of an existing licensed controller and transplanting them into a different enclosure, for example a fightstick-shaped one, carefully soldering wires between buttons and the right places on the donor PCB.

In theory you can use any controller for this, like a DualShock 4 or a DualSense, but it makes sense to choose one that will be relatively cheap to obtain and also easy to solder to. One such controller is the Razer Raion. It was originally released for the PS4, but since it qualifies as a "specialty peripheral", it also works in PS5 games. I got one and made a mixbox-layout fightstick using its PCB.

First I had to figure out where the solder points that I need are on the PCB. Fortunately I found this helpful tweet and with this information it was a fairly straightforward job.

The rest of the fightstick was similar to what I've done previously, in fact I just modified one of the designs to accomodate the Raion PCB. Here's what it looks like inside. As you can see it uses common ground.

One thing to keep in mind when converting a controller like this is the matter of SOCD cleaning - what happens when you press opposing direction buttons at the same time? Most traditional controllers don't have to worry about this because it's physically impossible to simultanously trigger opposing directions on them. But when you make a stick that has separate buttons for up, down, left and right, that can be pressed independently, it's something you have to start thinking about. In case of the Razer Raion, it uses a scheme called first input priority, meaning that if you press and hold left, then press and hold right, it will keep sending left. When you release left, then it will start sending right. If I didn't like this, I'd have to add an external SOCD cleaner between the buttons and the Raion PCB.

I posted the 3D-printable models for this stick on Printables. It uses Kailh low profile (choc v1) mechanical keyboard switches for the buttons. Here's what the final result looks like.

2022-07-06

Flatbox

Having previously made some 3D printed fightsticks (arcade controllers for fighting games) that were just plastic boxes with holes for arcade buttons or mechanical keyboard switches, I started thinking, could I make one that's even thinner? On my previous designs I just soldered wires to the keyboard switches, but they're really intended to be soldered onto a printed circuit board. Using a PCB instead of the wire spaghetti inside the case seemed like a good way to shave a few millimeters off. And it turns out there are companies in China that will manufacture a custom PCB for you for very reasonable prices. And thus the Flatbox was born. I ended up making four revisions of it.

Up to this point I was using Arduino Pro Micros as the brains of my fightsticks, so it seemed natural to start with a PCB that I could solder a Pro Micro onto. The PCB would just serve as a connection between the Arduino's pins and the keyboard switches (I used Kailh choc v1 low profile switches). I designed my board in KiCAD, arranged the switch footprints in a hitbox-style layout, generated the Gerber files and sent them off to JLCPCB for manufacturing. After some days I was excited to receive a package with my boards inside.

I've never done anything like this before so I wasn't sure if the boards would even work at all. I'm used to prototyping on breadboards, if you make a wrong connection there it's usually not a big deal and it's a matter of seconds to correct it. Here if I made a mistake, not only would it cost money, but I'd also have to wait a week or two for another package from China. But fortunately everything worked great! I quickly designed and 3D printed an enclosure for it. I was very pleased with the result, just 10 millimeters thick!

I was encouraged by this initial success, but I thought having to solder an Arduino board onto my PCB wasn't very elegant. Surely an Arduino is just another PCB and I should be able to include the microcontroller and all the other necessary components on my PCB and eliminate the need for an additional board. That's what I did for revision 2. I designed the board to use SMD (surface mount) components for everything except the keyboard switches and option buttons. I would probably not be able to solder them manually, but fortunately JLCPCB will happily do the assembly for you, you just have to provide two more files in addition to the Gerbers (list of components and their placement on the board). This time I was even more afraid that it wouldn't work at all, because there was a lot more I could mess up, but surprisingly the whole thing worked on the first attempt. Because it uses the same chip as the Pro Micro (ATmega32U4), I was able to use the same firmware. I was very happy, because even though manufacturing the boards was a little more expensive, it was suddenly starting to look somewhat like a real product.

Speaking of firmware, while it's easy to make a USB HID device that works with a PC or a PS3, it is unfortunately not the case with more modern consoles. From the PS4 onwards, Sony started restricting their systems to only work with licensed controllers. Each licensed pad or stick has some special chip with a private key inside it that lets it authenticate to the console. And DIY-ers are out of luck. Except you can buy PCBs that somehow get around Sony's restrictions (I don't know how they do it). I wanted a version of the Flatbox that was compatible with the PS4 so for revision 3 I went back to the idea of soldering an add-on board onto the main PCB. I chose the Brook PS3/PS4 board because of its small size. The only SMD components on the main board are the USB port and the two resistors that it requires.

The fourth and final revision of the Flatbox again has all the components on the main PCB and doesn't require an add-on board. It is similar to revision 2, but instead of the ATmega32U4 chip it uses Raspberry Pi's RP2040. It is the revision I like best, even though it's not compatible with the PS4 or the PS5.

All the files needed to make your own Flatbox are on GitHub, including KiCAD projects for the PCBs, 3D-printable models for the case and source code for the firmware.

2022-07-04

Fightsticks

Fighting games like Virtua Fighter, Tekken or Street Fighter originated at the arcades and have traditionally been played on cabinets with heavy duty joysticks and buttons. Even though they're mostly played on consoles and PCs these days, many players use arcade sticks modeled after the arcade cabinets, either because they consider them superior to controllers or simply because they enjoy their old school look and feel.

Arcade stick parts like buttons and joysticks can be bought separately so it's fairly easy to make your own stick. All that's needed is some kind of a box and a microcontroller that will read the state of the buttons and send the appropriate inputs to the PC or console. Not suprisingly, there's a thriving DIY community of fightstick makers.

I designed a few arcade stick cases meant to be 3D printed. The ones shown below all use an Arduino Pro Micro as the brains, running this firmware, compatible with PC and PlayStation 3. If you like any of them and want to try making your own, I've posted all the 3D-printable models on Printables, along with more pictures and details on how to make them.

The first one uses the most classic layout, with a Sanwa JLF joystick, 30 mm action buttons and 24 mm option buttons at the back. I made versions with 6 and 8 actions buttons.

The traditional appeal of arcade sticks doesn't mean that things are standing still. Some new stick layouts have emerged over the years, the most popular of them probably being the hitbox layout, which ditches the actual joystick and instead uses four buttons for the direction inputs. The large button at the bottom is the jump button and it's meant to be operated by either your left or right thumb. This layout seems best suited for 2D games like Street Fighter. You can see my take on this control scheme below.

Another layout that uses buttons instead of the joystick is the mixbox layout. It uses keyboard keys in a more familiar WASD shape for the direction inputs. In my opinion it's better for 3D fighters like Virtua Fighter and Tekken than the hitbox layout. Here's my version.

In addition to new stick layouts, people have also started putting alternative parts in their sticks. One move that's obvious in retrospect is to try using mechanical keyboard switches instead of the traditional arcade buttons. There are many different keyboard switches to choose from and they also allow the fightstick case to be much slimmer. Here's my attempt at a hitbox-layout controller that uses Kailh low profile keyboard switches and is just 14 mm thick (I call it the Slimbox).

Similarly, here's a mixbox-layout version of the same idea (Slimbox M).