Recent Posts

2017-06-26

Sim racing and game controllers - part 4 - Arduino leonardo project - TENSIOMETERS

Check the previous entries about the project: part1part2, part3 and the video and problems.

So I'm still using the Arduino racing pad since 2 years. I'm still racing in LFS, now in Assetto Corsa with it. I've complained about what's bad about it. And now I've solved another issue that I've had - the crappy joysticks. I've used FSR402 tensiometers for both accelerator and braking. This seems much more natural than using the lever sticks. And precise. Now I can drive powerful cars with no ABS and TC in Assetto Corsa :)

Why tensiometers?


When I've started thinking about that crappy joysticks, I've looked at what the game consoles are doing for the trigger buttons on the pads:

  • X360 pad uses a potentiometer with clever levers,
  • Playstation uses tensiometers,
  • X One uses Hall Effect sensors.
I wanted to buy the replacement parts for the X360 to check the levers, but the tensiometers are just cheaper. The Hall Effect sensors seem to be a very cool idea, but you really need to have an idea how to sort out the mechanics.

How does it look:

Bad. Ugly. But works.









I've placed the tensiometers along another edge of this beautiful lunch box. And now I can use both methods of controlling the speed of the car by just remapping controls. Frankly speaking - I haven't used the levers since I've got the tensiometers running.

Wiring FSR402 to Arduino:

Check this for examples of wiring and code: https://learn.adafruit.com/force-sensitive-resistor-fsr/using-an-fsr. After wiring the tensiometer properly you use it within the code like any other potentiometer.

Video:


Summary:

This just works. I'm using this for gaming weekly or biweekly (you know, 3 kids) for the last 3-4 months.

Using tensiometers for game controlers has another potential application. People making pedals for racing always look for methods to measure travel for acceleration and pressure for braking - to simulate real car hydraulics. All not ridiculously expensive steering wheels on the market use potentiometers for all pedals. And with a very simple mechanism (1 swing, some foam) you can get a pressure measuring tensiometer based pedal - you'll need a bigger tensiometer thou.

Code:

The requirements for having this running are described in the part3 of this "journey".

#include "HID-Project.h"

const int pinLed = LED_BUILTIN;
const int pinButton = 2;

// this is for printing to COM - set to 1 to get printouts
const int printuj = 0 ;

void setup() {
  pinMode(pinLed, OUTPUT);
  pinMode(pinButton, INPUT_PULLUP);
  Gamepad.begin();

  if ( printuj == 1 ) {
    Serial.begin(9600);
  }
}

void loop() {
  // limits for steering
  float steeringmin=0;
  float steeringmax=1023;
  // limits for joystick braking
  float brakemin=0;
  float brakemax=1023;
  // limits for joystick accelerating
  float accelmax=1023;
  // limits for tensometer acceleration and braking
  float brakemaxb=910;
  float accelmaxb=910;
  float accelmin=0;
  float min=-32767;
  float max=32767;
  float diff=max-min;
  float minB=-123;
  float maxB=+123;
  float diffB=maxB-minB;

  // steering
  float steer = (float)analogRead(0)/(steeringmax-steeringmin)*diff + min;

  // acceleration, braking for joysticks and for tensometers
  float accel = ((float)analogRead(2)/(accelmax-accelmin))*diff + min;
  float brake = ((float)analogRead(1)/(brakemax-brakemin))*diff + min;
  float accelb = ((float)analogRead(4)/(accelmaxb-accelmin))*diffB + minB;
  float brakeb = ((float)analogRead(3)/(brakemaxb-brakemin))*diffB + minB;

  // all 4 buttons readouts
  int gearup = digitalRead(2);
  int geardown = digitalRead(3);

  int gearupb = digitalRead(4);
  int geardownb = digitalRead(5);

  // idiotic deadzones for joystick
  if ((accel <= 3) and (accel >= -3)) {
    accel=0;
  }
  if ((brake <= 3) and (brake >= -3)) {
    brake=0;
  }

  // limits for tensometers
  if (accelb > maxB) {
    accelb=maxB;
  }
  if (brakeb > maxB) {
    brakeb=maxB;
  }

  // this is the COM printing
  if ( printuj == 1 ) {
        Serial.print ((int)steer);
        Serial.print (' ');
        Serial.print (analogRead(0));
        Serial.print (' ');
        Serial.print ((int)accel);
        Serial.print (' ');
        Serial.print (analogRead(2));
        Serial.print (' ');
        Serial.print ((int)brake);
        Serial.print (' ');
        Serial.print (analogRead(1));
        Serial.print (' ');
        Serial.print (gearup);
        Serial.print (' ');
        Serial.print (geardown);
        Serial.print (' ');
        Serial.print (gearupb);
        Serial.print (' ');
        Serial.print (geardownb);
                Serial.print (' ');
                Serial.print (analogRead(3));
                Serial.print (' ');
                Serial.print ((int)brakeb);
            Serial.print (' ');
                Serial.print (analogRead(4));
                Serial.print (' ');
                 Serial.print ((int)accelb);
        Serial.println (' ');
  }

 \\ button switching
 if (gearup == 0)
 {
   Gamepad.press(1);
 } else {
   Gamepad.release(1);
 }

 if (geardown == 0)
 {
   Gamepad.press(2);
 } else {
   Gamepad.release(2);
 }
 if (gearupb == 0)
 {
   Gamepad.press(3);
 } else {
   Gamepad.release(3);
 }

 if (geardownb == 0)
 {
   Gamepad.press(4);
 } else {
   Gamepad.release(4);
 }


 \\ output to axises. xA is 16bit, the rest I don't remember and it does not matter.
 Gamepad.xAxis((int)steer);
 Gamepad.yAxis((int)accel);
 Gamepad.rxAxis((int)brake);
 Gamepad.zAxis((int)accelb);
 Gamepad.rzAxis((int)brakeb);


 Gamepad.write();

}

Next step: getting some better chassis for the device.