Saturday, April 20, 2019

Using thotcon 0x8 (Arduino Leonardo) badge and Deskcycle to walk/run in video games!

I bought a DeskCycle (https://deskcycle.com/products/deskcycle-under-desk-bike) so I can mindlessly cycle at home while working on other tasks. (I’m not 100% sure of the health impact but it doesn’t really matter for now) Of course, it came with a display that let you track your speed, distance, and etc. it also came with a 3.5mm aux audio cable that you can use if you wanted to have the tracker display on your desk. I had the idea of using the Deskcycle to walk or run in games, like Just Cause 3 or any similar game has good visuals.

First thing I did is to Google to see if anyone had interfaced Arduino with DeskCycle and someone had. Neave Engineering blog (https://neave.engineering/?s=deskcycle) has three articles on interfacing DeskCycle with an Arduino. One of the articles (https://neave.engineering/2015/04/03/arduino-speedometer-for-the-deskcycle/) mentions that there is a switch that closes as cycle revolutions happen, which made my job easier. Basically, the input from 3.5mm jack can be treated like button input.

This is where the Thotcon (https://thotcon.org/) 0x8 badge comes in. Thotcon 0x8 badge is built on Arduino Leonardo, which can also work as a keyboard! (Teensy would work too but I had a thotcon badge sitting around) A hackaday.io project post had the instructions to reprogram the badge via ICSP header (https://hackaday.io/project/21797-thotcon-0x8-badge/log/59432-badge-hacking-update). It involves connecting AVR programmer then burning bootloader. After that, the badge can be reprogrammed via USB.

At this point, I hadn’t read the whole article from Neave Engineering. I spent hours trying to make the badge press and hold ‘w’ key (to walk forward in a game) in a bunch of different ways. For some reason, key presses would stop/weren’t continuous and I had other issues too. I went back and looked at the Neave Engineering post again and decided to reuse that code. Neave Engineering code can be found here: https://github.com/kneave/dcspeedo/blob/master/speedo/speedo.ino  The code comments are very useful!

I cut my 3.5mm cable, found the two wires that connect when a cycle/revolution happens and attached one to ground and one to pin 12 (var name is trigger in the code). As far as I can tell, the bottom row of pins in Thotcon 0x8 badge are all ground pins, although, I might be wrong. I didn’t closely test all of them.

Here’s my badge, with DeskCycle output pins attached to pin 12 and ground:


Here’s my modified code that does a keypress:
#include <Keyboard.h>

const float pi = 3.14159265;
const float inchesPerMile = 63360;
const int wheelSize = 26;
const float gearRatio = 2.75;
const float wheelCircumference = wheelSize * pi;
long lastTriggerTime = 0;
long currentTriggerTime = 0;
long triggerInterval = 0;
int lastTriggerValue = 0;
int triggerValue = 0;
int trigger = 12;
float cadence = 0;
float currentSpeed = 0;

void setup() {
 pinMode(trigger, INPUT);           // set pin to input
 digitalWrite(trigger, HIGH);       // turn on pullup resistors
 Keyboard.begin();
 cli();//stop interrupts
 TCCR1A = 0;// set entire TCCR2A register to 0
 TCCR1B = 0;// same for TCCR2B
 TCNT1  = 0;//initialize counter value to 0
 OCR1A = 124;// = (16*10^6) / (2000*64) - 1 (must be <256)
 TCCR1A |= (1 << WGM01);
 TCCR1B |= (1 << CS01) | (1 << CS00);
 TIMSK1 |= (1 << OCIE1A);
 sei();//allow interrupts
 lastTriggerTime = millis();  
}//end setup

ISR(TIMER1_COMPA_vect) {
 triggerValue = digitalRead(trigger);
 triggerValue = triggerValue == 0 ? 1 : 0;
 currentTriggerTime = millis();
 triggerInterval = currentTriggerTime - lastTriggerTime;
 if(triggerInterval >= 2000)
 {
   cadence = 0;
   currentSpeed = 0;
 }
 if(lastTriggerValue != triggerValue)
 {
   lastTriggerValue = triggerValue;
   if(triggerValue == 1)
   {
     lastTriggerTime = currentTriggerTime;
     cadence = 60000 / triggerInterval;
     float rph = cadence * 60;
     float wheelRph = rph * gearRatio;
     float inchesPerHour = wheelCircumference * wheelRph;
     currentSpeed = inchesPerHour / inchesPerMile;      
   }
 }
}

void loop() {
 //not checking to see if w is pressed already since this code is not causing any issue.
 if (currentSpeed > 0){
   Keyboard.press('w');
 }
 else {
   Keyboard.releaseAll();
 }
}

I removed serial output stuff since it wasn’t needed. I only care about the speed.
If speed is higher than 0, then keep pressing w, else release all the keys.
If there hasn’t been a cycle/revolution in more than 2 seconds, speed is set to 0.

What else you can do? You can do if or switch loop based on the speed and add Shift key press (some games allow you to sprint with it), or change LED colors, and so on. (For changing LEDs on thotcon 0x8 badge, this should help: https://gist.github.com/gigawatts/a7e4b440b29895fd15d8c6f00d41852e and https://github.com/FastLED/FastLED/wiki/Basic-usage ) I assume you can also do something with Google Street View as well.