This project is currently more of a software, proof of concept kind of thing. It was sparked when I first got intoMX Simulator and was absolutely hopeless at it (6 years later and I still struggle to make consistently clean laps, the game is hard) I decided if I could simulate motorcycle control, it would be a lot easier. First ideas involved hooking accelerometers to a set of handlebars so that I could tilt them in free space to feel like riding. This resulted in a pretty nifty tilt controller made from a hacked rollerball mouse, which sadly I no longer have. Needless to say, that barely resembles riding a bike at all and would not make riding in a simulator any easier(could be good for a more arcadey motorcycle game maybe?) This resulted in me pondering many mechanisms that could emulate countersteer-based leaning. Nothing ever came of these thoughts, but then Josh (sole creator of MX Simulator) released an update which allowed access to a nice live data stream from the game. This gave me the idea that perhaps I could input steering, the game calculates the lean and outputs it back to my controller to make it feel like I'm initiating a lean using counter-steer like real riding. Firstly though, I had to learn how to access and use this data stream which required an express course in C++. By express course, I mean youtube tutorials and lots of copy & paste programming.
I thought since I was learning C++ from scratch, I'd better start with a slightly simpler project before I went buying hardware to make a controller with. I decided to use the data stream to implement a basic rumble on my XBOX 360 controller. I figured I'd just take the positional data from the stream and derive an absolute acceleration which controlled the strength of the rumble. With a lot of help from Josh, the final iteration seems to work quite nicely but still misses the odd impact for some reason. I feel like it gives at lot more imersion to the game and it converted me from a 3rd person player to a 1st person player. The project can be viewed onthe MX Simulator Forums here.
So the first thing was to find a piece of hardward to interface with the PC through USB. The simplest and cheapest seemed to be theTeensy 2.0. I was a little cautious as it only seems available from the US, but I just ordered from the official store and it came in a few days, the whole transaction was very smooth. Easiest thing I could think of to start with was just set up some hobby servos in a configuration that demonstrated roll and pitch of the bike. Along with absolute position, the game outputs the vectors of two of the camera's axes which makes deriving pitch and roll data quite simple. It was then just a case of utilising theRaw HID example to send the data to my servos. I've modified the usb_private.h so that the packets are only 2 bytes long to save bandwidth (all my code is down at the bottom of the page.) The results to this are pretty cool I think but you can see a slight delay between game and servos which I'll get into later.
Now that I saw the basic idea worked, I needed to beef it up a little if I wanted it to be a usable controller. I'd seen a lot of motion controller projects use windscreen wiper motors as they have worm drive gearboxes which provide buckets of torque. I found one on ebay from a Renault Clio for £8 delivered so I got it to play around with. It had a current draw of about 6 amps with a decent load so I knew how substantial my H-bridge had to be. I was going to design my own H-bridge but I found a very reasonably priced one from Hong-Kong which looked decent quality on the pictures. I figured I would risk it because it was so cheap, it was worth it to just salvage the MOSFETs off of. It did take ages to come but when I got it I was pleasantly surprised at the quality and it looked like genuine International Rectifier MOSFet's had been used which can handle a continous drain current of 80A at 100 degrees celcius. There was no heat sink fitted but the package on it's own can dissipate 200W so I have plenty of headroom.
I threw it in an old Optimate III trickle charger case which looked like it was made for it and added a fan and thermistor in case I wanted a thermal cut out. Testing the motor under load with the fan, I couldn't get them to go over 60 degrees celcius so I didn't bother connecting the thermistor to anyhthing. It takes a seperate PWM and direction input for each motor and works at 5v logic levels so it's ideal for use with my Teensy. I then welded up a basic frame and handlebar setup with a feedback potentiometer on the roll axis and a steering potentiometer on the steering axis. This was thrown together especially quickly because I knew it was unlikely to work too well on the first iteration. Power came from a PC power supply which supposedly can source 19A on its 12v rail but actually cuts out well before then even with a 15ohm power resistor across the output. For the first test I didn't use the controller input, and used the default PWM frequency which seemed to be about 80Hz. This resulted in very jerky operation as the motor didn't start to move until about 40% duty-cycle. I also think I should have been using more than 12v because I imagine there is a sizeable drop across those MOSFETs. I'd rate the test a moderate success, it worked but doesn't give anywhere near the responsiveness required.
There's a very good reason that the steering wasn't implemented in the first demo....I didn't know how to. The Teensy has different USB modes for compiling the code, with one being Raw HID and another being Joystick HID but I dind't know how to combine them to get the features of both. I asked around the Arduino forum (there was no dedicatedTeensy forum at the time) but no joy so I set to work myself. I found the code for the USB modes lies in the hardware/teensy/cores folder of the Arduino directory. I basically duplicated the Raw HID folder and renamed it Raw HID 2 then poured through the corresponding files from the Raw HID and Joystick HID, blindly copying across any lines I thought were necessary from the Joystick files to my new files and editing numbers where necessary. I then had to edit some of the USB based files in the hardware/teensy/cores/teensy folder to get it to recognise the new mode. Amazingly it actually worked. Now that I know what I'm doing a bit better, I should probably go throught it all again to clean it up but it works well enough that I can't be bothered. It was then just a case of hooking up the steering pot and reading that as a joystick axis. Since I'd hooked the pot up directly to the axis, it had very limited travel so the resolution wasn't great and it picked up some noise from the motor and amplified it to big kicks in the bars. I then tried to add various spring mechanisms to the handlebars to give them a nicer feel but none of them really felt right.
Now that I had steering working, I wanted to make it a little more responsive so I found out how to change the PWM frequency I was using. Turns out to be fairly simple. There are various registers that control the timing of the PWM on different sets of pins. You can then set two prescalers which divide up a 64MHz clock to give the desired frequency according to this table:
In order to get a 15.6KHz PWM frequency you can just set DTPS40 and DTPS41 both high and set the last 4 bits to 1010 which will give a total division of 8*512 = 4096. 64000000/4096 = 15625Hz. It'll make more sense if you read my code I think, it's all commented.
Anyway, I got it all working but it still didn't feel right at all, and it wasn't just because I was using a switch for a throttle. The lack of feedback from the steering was strange and the leaning felt very unnatural. This iteration is still sitting in my garage, unloved.
It's not surprise that a steering system based on the position of the bars would feel strange because what the game actually does is applies a torque to the bars, proportional to the controller input and then dynamically calculates the bar position from this. You've probably already worked out what i'm getting at. I want to have a set of bars that read the torque I'm applying to them and then read the game data to output both the lean angle and steering position. I've asked Josh if he could output the steering position and he says he could, but I'd rather have something demonstratable before he went through the effort. I have however, recently bought a copy ofGP-Bikes which is another awesome game. The creator of this game has developed a plug-in example which allows you to take any data you can possibly think of from iniside the game. You just have to compile the code as a dll and give it the extension .dlo and drop it into the plug-ins folder. I set it up to stream the lean angle and it was much more responsive than my program for MX Simulator so I'm going to try and get it all working nicely on GP Bikes before I do any more development on MX Simulator.
In order to get the steering feedback to work properly I need a gearbox which can be back-driven so the the windscreen wiper gearbox is out. What I'm working around at the moment is a drill motor and gearbox, which is a little underpowered but I'm hoping it will give just enough feedback like a force-feedback steering wheel. I was going to try using the current through the motor to measure the torque but after some experimenting I've decided this won't work very well. Instead, I'm going to try using the existing clutch on the drill's gearbox to measure it. If you're not familiar, most battery drills use a planetary gearbox where the outer gear is free to spin and has little ramps on it's face edge. They then have a spring mechanism which puts pressure on ball bearings on the front of the outer gear and when the ramps reach them, the springs have to compress to allow the gear to continue spinning. When you adjust the torque setting, you put more or less tension on these springs. If the torque on the drill's driveshaft is less than is required to compress the springs then the outer gear will stop and the driveshaft will spin. If the torque on the shaft is greater than the torque required to compress the springs then the outer gear will spin and the driveshaft will remain still. What I plan to do is allow the outer gear a little more travel by putting extension springs on it and then take a lever off it and have it drive a potentiometer. In theory, the position of the pot should then be proportional to the torque on the driveshaft and I can use as my steering input on the game.
This whole steering setup will then be connected to a leaning pivot. I'm thinking of making it more like the pendulum style thatdoubledragoncc uses on his controllersas apparently this feels most natural. I can then hook the windscreen wiper motor up to drive the leaning.
So I've actually made a start on modifying the drill gearbox. It's not ideal for anything precision based as the motor has a lot of inertia and the gearbox is sloppy but it works quite nicely as a servo if I put enough tolerance in the feedback to account for the slack in the gearbox. Ideally, to be used as a controller, it should be geared lower which would reduce the effect of the play in the gearbox. Obviously if I used chain as in the design, the play in the chain would probably be even worse than the drill's gearbox.
I originally did some rough calculations and a nice dynamic simulation in Solidworks to determine I needed around 0.1N/MM spring rate, but as usual I ignored it and just found a nice pair of shiny new springs I happened to have which have an unknown spring rate. Instead I decided to just make everything adjustable so I could do some degree of tweaking one it was all assembled. Eager to try it out, I made a simple little program to emulate a torsion spring whereby the shaft position is proportional to the torque on the shaft and as you can see below, it worked fairly nicely with barely any tweaking. Obviously you can't feel it like I could but it really did feel like a spring.
Next up was to try it in the game and at my first attempts were very strange as I was clearly fighting the simulator's stabiliser. I rushed on over to the GP-Bikes forums to suggest providing direct control of the torque on the handlebars but I should have known, PiBoSo had already thought of it and added it. The next video is just a really rough demo to show that it plays nicely with the simulator (really sorry about the lighting, I thought I set the metering on the controller and not the screen but clearly the camera had other ideas.) Again, you can't feel the forces I was but it did feel surprisingly smooth and natural, especially on the rare occasions I actually got some speed up. Just with this quick test though, I can tell the little motor hasn't got enough power to drive full length handlebars with it's current gearing but luckily handlebars don't have much lock so I have plenty of room to gear it down. Just got to decide how I go about it now, chain drive certainly isn't ideal.
The various code and programs I've used in development so far are all availablehere.