This video is how I gutted my already modified old Thrustmaster F-16 FLCS joystick of my ViperPit and made it work again with the help of an Arduino Pro Micro. This flight stick (and also the other peripherals) do belong in a museum but where’s the fun in that? I modified it and now it’s a generic USB joystick that works on any recent system. I focus mostly on the 5×5 button matrix since this is the hardest part to understand. In the end are a few minutes of playing X4 Foundations with it to give it a good test run. Now it just needs some oil for the creaking 😅
Tried #wokwi – an online Arduino simulator – and ditched it again after fiddling with it for 5 minutes.
Looks good on first glance, admitted.
Raised my first eyebrow after not finding a diode. Ah well, used a 0-resistor instead as placeholder. I don’t see how I can demo a button matrix like that though.
Checked the download as ZIP function. Hm, there is no upload function, guess I have to register for saving online. Guess I can also just import the project text files via copy and paste again. Not comfortable but I can live with that. Found open tickets for both btw.
Made a little power distribution strip on a mini breadboard. Annoying, I have to adjust the colour of each connecting wire. Nice: The text editor allows mass selection just like vscode, so I can easily update a bunch of colours after making all connections. That’s something at least.
Added and wired up two Neopixels. That was annoying, they default to a perfect rectangle wich results in overlapping connection wires on the auto grid. Always. Tried to add a rotate property of 45 deg on a hunch – that worked! Why is there no option for this like with the resistors?
Eventually I tried to upload the Adafruit NeoPixel lib to get some blinken lights going… please subscribe to upload a library with a monthly fee of (╯°□°)╯︵ ┻━┻
I get it, we all want to earn money. I added whopping _5_ objects and run into the first brick wall. Not like this!
This is a project I kept postponing for years but when I eventually got my hands on all the required parts I had no longer an excuse and eventually built the first. It’s a portable music player for children that does not require internet access. It features selections of pre-installed music or audio books via RFID cards, that may come in all shapes and may even be integrated in toys. There are also 3 to 5 playback controls in the form of huge arcade buttons. Ideal especially for our middle one, who has to endure stationary stay for most of the week in a hospital.
And while this box is still missing proper decorations and button decals it’s full functional and portable. Also hey, kids ain’t stupid – they find the proper button without decal too. Even the baby found out where to put the RFID cards for the music to change 😉
The leg work for this was done by @xfjx@chaos.social and the project is described in great detail at https://www.voss.earth/tonuino/ – I did however not order the offered PCB and just soldered everything to a generic maker board to keep the costs down. Just like the arcade buttons, that I had left over from another project, I also have a bunch of such boards. The speaker was salvaged from an old entertainment system that broke down long ago and the box… ah well I guess it speaks for itself. Can’t say I was happy with the drill but the box was just perfect for our purpose.
First we built a test setup after salvaging all the needed hardware. The Ardunio parts are off the shelf, nothing special here. I had to improvise a little on the wiring due to missing wires. I opted for the older branch that just needs Arduino Studio, to install the software itself. There is a more modern version using platformIO but something with that does not like my vscode and I never managed to successfully compile it.
I eventually got the idea how the RFID cards worked and could be trained to the system and also did some tests like it’s maximum power usage. It has a passive speaker and cranked up to max it would consume 0.09A max – and on regular volume it was sitting at comfortable ~0.06A. Which is pretty fine. This would run for days with a decent power bank that could be dropped right into the box later if no external PSU is used.
Next was preparing the box. Luckily I had just the right drill for the buttons but making the holes was a pain in the neck. This had to be done very slow because the hard plastic would easily rip and splinter. I opted for a very massive USB connector in the end because the microUSB one used first broke on the 3rd use already. That was probably a little bit too cheap. The replacement is way more sturdy, which is kinda what I want for the children anyway. Everything the box needs to operate, like an old phone charger, a very long USB cable, and the RFID cards do fit inside the box for transport.
So one of the questions left was what to put on it’s internal SD card. Some of their favourite music, of course. What else though? Easy. We have a public audio centre at https://www.ardaudiothek.de/ offering a lot of stories and podcasts even for children. Downloading them one by one manually was cumbersome though. Luckily @1337core@chaos.social was just releasing his first version of Audiothek Downloader at https://github.com/Leetcore/audiothek-downloader so I had more gigabytes than the SD card could manage in minutes. The only issue was that the SD card needs the audio files enumerated so I did some quick scripting to rename the downloaded files. I had also no use for the downloaded cover images. It’s not beautiful but it got the job done:
#!/bin/bash
folder=$1
oldpwd=`pwd`
if [[ -z $folder ]]; then
echo "Missig paramater id"
exit
fi
folder="output/${folder}"
if [[ ! -d ${folder} ]]; then
echo "Missig folder ${folder}"
exit
fi
cd $folder
shopt -s extglob
for filename in +([0-9])_*.*; do
[ -e "${filename}" ] || continue
oldfile=${filename}
# remove including the first underscore to get the index
index=${filename%%_*}
index=${index##+(0)}
# pad the number with zeros
newfile=`printf %03d ${index}`
# combine new index with old filename, remove up and including first underscore
newfile=${newfile}_${filename#*_}
if [[ ! -f ${newfile} ]]; then
mv -v "${oldfile}" "${newfile}"
fi
done
declare -i n=1
declare -i i=1
for filename in *.mp3; do
[ -e "$filename" ] || continue
target_dir=`printf %02d ${i}`
if [[ ! -d ${target_dir} ]]; then
mkdir ${target_dir}
fi
target_file=`printf %03d ${n}`
if [[ ! -f "${target_dir}/${target_file}" ]]; then
mv -v "${filename}" "${target_dir}/${target_file}.mp3"
fi
n+=1
if (( n > 255 )); then
n=1
i+=1
fi
done
cd $oldpwd
exit 0
This goes into e.g. to-tonUINO.sh into the root folder of the Audiothek Downloader where it can be executed after downloading a category. Like this for example:
The resulting folder|s can be renamed, depending on what is already on the SD card, and moved to the SD card. It also makes sense to set the RFID card to audiobook mode so the TonUINO saves the position for the listener and does not start at the beginning again.
Now it’s up to the children to do some decorations. Our oldest wants her version built into a box that looks like a book. Hope we can get that one done soon too.
A lot happened since my last update on the simpit – under it’s hood. Function wise it changed not so much so the older demonstration video is still better for a quick demo. I still assembled a new video from clips of the first evening with the new hardware:
Quick trip from Armstrong Orbital over to the huge crater on HIP 117029-4 and back
So what changed? I got rid of the CY-822A USB joystick controller that, while good, was also limiting. Especially in inputs and how they would react. The Raspberry Pi, that I used to drive the status indicators, is also gone. This is all replaced by one single Arduino Mega that is connected via serial over USB.
A custom joystick daemon written in Rust is listening for data from the #Arduino and feeds back the flags of Elite Dangerous to drive the blinken lights. I also extended the source to add me some rotary encoders (with push button function) and I’m very happy with the result of this. That makes a whopping amount of 48 buttons and 6 axis (where 2 axis make one hat). And it feels _so good_ to have e.g. self destruct or eject cargo save under a protective cover now 😀
An enemy vessel exploded, the bounty is mineThat rocket was too close for comfortLimping to a hangar after taking battle damageEvading a firestorm from behind by moving sidewaysVarious screenshots from a gaming session of StarCitizen
The panel also got an external PSU with enough ampere to drive as many LED as I may imagine so I no longer abuse a phone charger for that or risk frying of the PCB / USB.
With all that in place I streamlined my pre-flight check-list quite a lot because way less hardware is involved and most of this is automated by now. It wasn’t all fun n giggles tho and while the new hard- and software “just worked” in e.g. #StarCitizen it was #EliteDangerous that gave me a hard time to actually use most of the new buttons.
Getting all the precious buttons into Elite as well (okay, limited to 32 thanks to an old dinput library but who is counting at this point – will simply set the rest to keyboard macros instead)
Turns out it had no idea about the device and model identifiers reported by the joystick daemon and that the kernel assumed a gamepad based on declaring e.g. ButtonNorth via the more recent xinput system really didn’t help – because that limited the amount of read buttons via xinput severe! In the end I set it’s identifier to a “vJoy” device. That I found in the DeviceMappings.xml of Elite and since this could be basically anything I gave it a try (and removed all “offending” magic gamepad buttons from the code) and sure enough Elite started accepting the inputs as expected and from there it was smooth sailing – got even the hat working.
Oh and for everyone who is wondering what exactly they are seeing on the “MFD” when I’m playing Elite: That’s basically a Website using the #Arwes FUI framework. Find a quick demo video here. Without the cardboard covering up parts of the screen it looks basically like this:
What the game showsWhat the ARWES website shows as MFD
I also started doodles for a version 2 – now that I have an idea what I really want.
Plans for another #SimPit based on a #Macross Valkyrie Cockpit
My Primary Buffer Panel is almost completely revamped 😄 Just an #Arduino now, no more #RaspberryPi in the mix. The CY-822A is also gone. I did add an external PSU to drive as many LED as I can imagine too 😄
I also programmed support for 4 to 8 rotary encoders and there is an additional slide potentiometer sitting on my desk. I still have to find space for that – but I want that very badly since I know how mining in #StarCitizen works 🙂 That makes now 49 buttons and 4 axes so far 🙃
You probably heard about this before: An Arduino can be made into an excellent DIY joystick. Most examples use a Leonardo or Micro for this for a very good reason. They one comes basically with a chip that is recognized as HID (Human Interface Device) hardware on any modern operating system.
This is not the case with a Mega. This one has other perks but HID it is not. It sure shows up as USB device and a ttyUSB is raised where serial communications with the Arduino can be initiated. I’m also aware that some flash the built in programmer of the Mega so it starts operating like the others (which obviously removed the built in programmer). I’m on Linux PC though so I thought it’s basically a job of tricking the system into recognizing it as joystick and call it a day and OMG was I wrong!
How it’s not done
My train of thoughts was like this: Linux still supports plenty of old serial joysticks so how complicated can it be to send some bits an existing driver recognizes. Old hardware like this is usually glued to the driver with the tool inputattach of the Linux Console Project. This does basically initialise a joystick on some serial connection and sends it off to a fitting kernel driver. This way even non-USB, or let’s better say non-HID hardware, is mapped to a kernel driver who in return will set-up the joystick subsystem and manage the communication with the stick via a serial connection.
Turns out I’m not the first one with that idea and apparently someone made it work by connecting old Playstation Controller and a Wii Classic Controller to an Ardunio and fake a Stinger device without the use of HID so Kudos to Jarno Lehtinen here and his Linux-Arduino-Serial-Joystick repo – you sure did sent me down a rabbit hole of horror and amazement. I couldn’t even get inputattach to wait for that magic string to be sent with anything else than 9600 baud and aligned stars! I also had to throw socat into this horrible mix because the Arduino would insist on rebooting on init so a timeout was guaranteed! In case you wonder how I did this:
socat -r left.raw -R right.raw pipe:/dev/ttyUSB0 PTY,link=/dev/ttyUSB1,rawer
# and xdd to show me the debug juice
tail -f left.raw | xxd -c4
# and on yet another terminal
inputattach --baud 9600 --stinger /dev/ttyUSB1
This also meant that I had to tear everything down for reprogramming the Arduino. Anyway, in the end I could finally get through that init phase where the stinger related code in inputattach is waiting for the magic key after sending “ E5E5” to finally load the Stinger kernel driver – communication for both ways confirmed!
At this point I had a pipe to prevent the timeout due to the resetting Arduino, the _only_ working baud rate 9600 I could figure out with the Mega, a loaded driver that was recognized as joystick and was sitting put and did… absolutely nothing. Null. Nada. Not a single bit made it to the driver and I could not figure out why. My guess is it needs a change in the baud rate to the original 1200 (?) of the Stinger but I have no idea if this is true. I could also not find any way how the stream is controlled and since the driver would fill up 2 bytes all the time and interpret them there is a fair chance that it would simply be one byte off all the time. Speculations tho, I simply didn’t grasp the stinger.c source so this is all just a theory. I do not want to admit how much time I sunk into this and I was pretty frustrated at this point. Reading some stupid serial? Not like this! Too many hoops!
So I threw it all in the bin 🚮
How it’s probably done
Say hi to /dev/uinput where you can basically raise virtual devices, like a joystick, without [much?] pain. I’m not the first one, of course, and funny enough the reason behind is very similar to mine. Read more on Virtual joystick on Linux by Gwilym Kuiper where this is all explained in great detail. The referred code at https://github.com/gwilymk/arduino-joystick sure did help me to get started and even without having touched Rust ever before I was able to quickly adjust this for my needs, doubling the possible buttons and get it up and running in just a few hours for my Linux PC. Cheers mate (also Jarno Lehtinen – you teached me a lot that day :D) 🕹️
So here it is: A Mega acting as joystick without HID over a serial connection driven by a userspace daemon (means no kernel driver required) written in Rust providing a virtual uinput device for a joystick on the “modern” event system. Heck it’s even recognized in Wine!
What a journey to begin with. Now I need a back-channel for my blinky lights so I get my Raspberry Pi back from simpit duty 🙃