Linux joystick seems mis-calibrated in an SDL game (Freespace 2 Open) [closed]

Posted on

Problem :

I have a USB joystick (Saitek Cyborg 3D) which shows up on my recently installed Ubuntu 9.04 box as /dev/input/js0, and jstest is showing values in the range +-32767 as I would expect. I just dug up a copy of FreeSpace Open, a game which uses SDL and worked with no problems on a previous Ubuntu install about a year ago, and the joystick seems very mis-calibrated. All axes (X, Y, twist, throttle) seem at least 20% off-center. The X and Y axes at least definitely aren’t reaching their end points.

A relevant message on the SDL mailing list in January 2009 received no concrete answers.

Here is joy-unix.cpp from the project source. I’m not quite running trunk, but as you can see from the revision log there, no actual code changes have happened to that file for over 3 years.

Solution :

I noticed the problem in d2x (a Descent port), which also uses SDL, so I went digging in SDL. testjoystick from the SDL source showed the problem as well. Looking at the SDL linux joystick driver, the problem is mentioned. Search for joydev_pattern in that file and you’ll see what they’re doing; search for calibrate and they do mention this problem. Basically they use /dev/input/event6 (or whichever) in preference to /dev/input/js0, unless compiled with --disable-input-events, even knowing the event device can’t be calibrated (i.e. the calibration set on js0 will be ignored).

Having found all that, Google searches involving that configure option reveal that hidden away in the comments to a Linux howto for fs2_open, someone has actually had this problem already.

I have reported this bug to Ubuntu. To work around, pick any one of:

  • Set SDL_JOYSTICK_DEVICE=/dev/input/js0 (you could put this in /etc/environment and reboot to apply it everywhere). Edit: SDL will still have the evdev device as a second joystick, so in games like d2x that respond to the second joystick as well by default, visit the options screen and remove those extra bindings.
  • Recompile libSDL with --disable-input-events.
  • rmmod evdev (quite likely to lose any unusual input devices you have).

Sounds like the game needs to be provided with the min/max/center axis values from the joystick. The default values might be 0/32768/65536 rather than -32676/0/32760 you’re seeing? That’s more obviously a lot more than 20% off, so maybe it’s trying to auto-calibrate at some point. It also looks like the joytest2 console command can show in-game values which might provide some added insight.

From joy_init():

// Fake a calibration
if (joy_num_sticks > 0) {
    for (i=0; i<JOY_NUM_AXES; i++) {
        joystick.axis_center[i] = 32768;
        joystick.axis_min[i] = 0;
        joystick.axis_max[i] = 65536;
    }
}

I see a calibration function (joy_cheap_cal() at joy.cpp:454) but it’s not immediately obvious where that’s called from, or if there are other methods within the game for re-calibrating the axis values. I love Freespace, so when I get home I’ll download the code and poke around a bit. You might also try running jscal just for good measure?

Leave a Reply

Your email address will not be published. Required fields are marked *