Showing posts with label running. Show all posts
Showing posts with label running. Show all posts

Saturday, 10 June 2023

Treadmill Videogame Controller part 2

Since building the treadmill project late last year, I did actually manage to complete a full run through of the original Sonic the Hedgehog.

Along the way I found a few snags and issues with the treadmill:

Direction switch/lever

I soon found that the reed switch control from the cross trainer levers was problematic because there was a lack of tactile feedback to know when the lever was in the correct position for changing direction.

Therefore, I replaced it with a regular switch where normally open connected the ‘right’ key and the normally closed connected to the left key. Using a metal angle bracket I was able to mount it to the frame so that the switch is closed when the lever is fully forward, and open in any other position.

This means that when moving right I just need to keep the lever fully forward, and to change direction I just have to move it from that position.

Although I kept them in place for the duration of the Sonic play-through, I’ve since removed the cross trainer levers, as they do not provide any real benefit over a regular button.

Jump button

The large plastic button that I was using as a jump key broke (it was from a cheap “noise-maker” type toy, and the PCB literally snapped), so that was also replaced with a basic switch. I plan to change this up for something better in the future, but at the time I just wanted to go for a run.

Quick save and quick load 

I found, particularly on the more platform/puzzle sections of the game, it became necessary to make use of the quick save and quick load features of the emulator, so I added an external quick load button to the treadmills handlebar.

A better button system

All of the above can be distilled to a single point - that the button inputs were not good enough.

Although I started the project with the intention of minimising the number of regular button presses, it seems inevitable that there will always be some required.

Configuring the controls

In order to play other games I would need to make some additional adjustments for different control schemes. This would mean altering the firmware and re-uploading every single time I changed the game, which seemed needlessly convoluted.

There were two main reasons for using the Makey Makey. The first was to take advantage of its noise filtering features, and the second was its ability to act as a keyboard.

The noise filtering is the real selling point of using it, but there are other ways to obtain its input and then turn into keyboard input. So I adapted the firmware so that instead of sending keyboard input it would appear to the connected computer as a serial port. On each cycle it would send one byte, with each bit representing the button state (i.e. pressed or released) of each of the buttons.

This would allow a data transfer rate fast enough to handle pretty much any input I can throw at it.

The source code for this can be found at Github.

The software

The software will be an ongoing development project so I’m not going to be sharing it at the moment.

On the computer side, an application will continuously read the serial import, and then translate it into appropriate keyboard events via udev, thereby sending whatever that keyboard input is to ever application is active and in focus on the computer – in the case of this project that will be a game.

For this iteration of the treadmill I’m going to be using the acclaimed indie game Super Meat Boy – as it has a small range of inputs (left, right, sprint and jump) but adds a couple of extra bits of complexity for me to expand on with the treadmill.

Once the serial connection is established, a thread runs constantly, reading the latest byte from the Makey Makey.

It compares the byte to the previously read byte. If a bit that wasn’t previously set is now set, then a corresponding function is called in a secondary thread, which is the input thread.

The input thread maintains a count of “presses” from the treadmill rotations, which increases with each press as well as decreasing with the passing of the specified time interval (the “decay”).

If the count is positive then the first key (the direction) is pressed.

If the count is positive and greater than the defined sprint threshold then the sprint (shift) key is also pressed.

For the jump key, the serial thread will always report the state of the relevant bit to the input thread.

This compares a pair of booleans (jumping and lastJump) – which determines whether the jump (space) key should be pressed or released. It is done this way because Super Meat Boy differentiates between small and large jumps based upon the duration of the key press.

Saturday, 15 October 2022

Treadmill Videogame Controller

Like a lot of people, I spend a lot of time trying to balance the need for exercise and fitness with the desire to sit on the couch and play video games.

So I figured why not combine the two.

To start with I picked up a treadmill – this one is a manual treadmill as I want its movement to be dictated by my running, not by some electric motor.

There is a small control panel on the treadmill which provides some statistics. It is completely optional and not required to use the treadmill. It gets it’s power from a separate battery supply.

Although this is not particularly useful to me, it does indicate there is some type of encoder in the treadmill assembly to measure these values. Before even taking the treadmill part I can surmise that this is most likely either a magnet and reed switch assembly, a hall effect sensor, or a rotary encoder.

Once I got the treadmill, I could see a simple 2-wire lead from the base of the unit through to the control panel, connected with a 3.5mm jack.

I breadboarded a small breakout so that I could connect the oscilloscope and see what kind of signal was being passed.


This revealed that there’s 2.5v being sent down the line (tip of jack is positive), and that the signal would transition between high and low as the treadmill was used, and the frequency would increase as the speed increases.

In it’s most basic form, if we can translate those state transitions to key presses, that should work.

There was however a whole lot of noise in the signal which seemed to be caused by resonance in the treadmill frame, as there would be severe jumps simply by my touching it.

Initial Implementation

An initial attempt to use an Arduino and have the signal trigger interrupts wasn’t successful due to the noise, and filtering attempts became quickly time consuming.

The requirement for the filtering and the requirement for it to be an input device led me to a MakeyMakey development board.

This board is advertised as an educational toy, that allows users to turn anything into a key. In order to do this it provides a significant amount of signal processing and filtering. So in other words, exactly what I’m looking for.

This means that very little is required on the software side, as the Makey Makey presents inputs to the computer the same as a keyboard would, and applications generally will not notice any difference.

By simply connecting a crocodile clip from the tip of the 3.5mm jack to an ‘key’ on the Makey Makey, and connecting the body of the jack to the ground of it, that is already enough to get some response. Every pulse sent by the treadmill gets interpreted as a key press and release by the Makey Makey.

Problems

The only problem with that is with the treadmill in normal operation, the pulses (and therefore keypresses) are so quick that they do not translate real world movement into equivalent in-game movement.

With the treadmill running, the red marks show the time that the key is pressed. The two ‘bursts’ of movement on the treadmill appear as a total of 14 short keypresses.

 

Instead, either the rapid tap causes the character to barely move, or if the treadmill stops when the signal is high, the character runs at full speed without needing any further movement on the treadmill.

 

The treadmill stopped when the signal is high – making it look like the key is held down indefinitely, even though the user is not running

 

What I want to do is to bring the game input more “in step” (ha) with the movement of the treadmill, so that the same two bursts of treadmill movement would look more like the following:

 

The two bursts of activity are represented as two longer keypresses, as if the key were held down for the time the treadmill is moving

To do this, I forked the source repository of the Makey Makey project, and made some edits.

The changes are mostly in the updateInputStates function, and focus on the ‘right’ key on the Makey Makey, as I will be using a side-scroller game to test.

Demo

To demonstrate what this change does, below are two screenshots which represent a few seconds of continuous running on the treadmill.
The first is with the treadmill connected to the “Up” key, which is unaffected by the code changes. The input is shown as repeated press and release events.
The second is with the treadmill connected to the “Right” key, which is the one that I have changed.
The impact is shown any as press events, up until the point that the treadmill stops. This is the same as if the key were held down.

The test code is based on KeyEventDemo – the only change is that I removed the KeyTyped event as it is not relevant to this exercise.

Implementation 

Unfortunately there is no way of determining the treadmills direction of travel as it was obviously not designed for that, but in a game I may want to change direction.

What I have done is a workaround for now is I have made the same change for the left key as I did for the right and have wired the treadmill to the Makey Makey like so:

This means by simply flicking the switch I can change direction. In a subsequent moment of inspiration I swapped the switch for a pair of reed switches and a magnet attached to one of the cross-fit handlebars that are on the treadmill - allowing for the direction to be controlled with the left lever.

I have also wired a simple momentary switch to the space key to allow my character to jump.

For now this whole contraption is held together by screw terminals and crocodile clips as it is only a prototype and is a platform I want to expand on in future.

The Game

For this initial experiment I wanted to use a game where input is limited, as a proof of concept.

To keep with the theme of running and speed Sonic the Hedgehog seemed like a suitable choice.

I will be running this on a PC with a Sega Genesis/Mega Drive emulator.

Please note the various copyright and legal complexities around the use of emulators and ROMs - the short version is that you should not use ROMs of games you don't own.

I actually own two copies of the game - an original Mega Drive cartridge, and a PC version as part of the "Sega Mega Collection Plus". It's just that the Mega Drive emulated ROM is easier to interface with.

The end result: