Joystick calibration in GNU/Linux

Note: joystick correction parameters can now be set in the GIMX configurations, so there’s no need anymore to do any calibration at the operating system level.

The reference tool to tweak joysticks from userland in GNU/Linux is jscal. It is a command line tool that can be used to calibrate or remap joystick controls. Its calibration mode (jscal -c /dev/input/jsX) sadly does not work for calibrating the pedals from my Logitech Momo Racing wheel. Surprisingly, the manual is very vague about how the correction works:

 -s, --set-correction <nb_axes,type,precision,coefficients,...>
Sets correction to specified values. For each axis, specify the
correction type (0 for none, 1 for "broken line"), the precision,
and if necessary the correction coefficients ("broken line" 
corrections take four coefficients).
-p, --print-correction
Prints the current correction settings. The format of the output
is a jscal command line.

What’s a “broken-line” correction? What are the coefficients used for? I only found the answer in the kernel source code:
static int joydev_correct(int value, struct js_corr *corr)
{
  switch (corr->type) {
  case JS_CORR_NONE:
    break;

  case JS_CORR_BROKEN:
    value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 : 
            ((corr->coef[3] * (value - corr->coef[1])) >> 14)) : 
            ((corr->coef[2] * (value - corr->coef[0])) >> 14);
    break;

  default:
    return 0;
  }

  return value < -32767 ? -32767 : (value > 32767 ? 32767 : value);
}

The value calculation can be expanded like this:
if (value > corr->coef[0])
{
  if (value < corr->coef[1])
  {
    value = 0;
  }
  else
  {
    value = corr->coef[3] * (value - corr->coef[1])) >> 14;
  }
}
else
{
  value = corr->coef[2] * (value - corr->coef[0])) >> 14;
}

This leads to the following deductions:

  • coef[0] and coef[1] are two axis values
  • coef[2] and coef[3] are the correction factors that apply respectively below and above these axis values
  • coef[0] < coef[1] means there is a dead zone between these two axis values
  • coef[1] = coef[0] means there is no dead zone
  • coef[0] > coef[1] means coef[1] is ignored: it behaves as if coef[1] = coef[0]
  • the resulting value is divided by 16384

Let’s see what are the default correction settings for a Logitech Momo Racing wheel:

matlo@matlo-desktop ~ $ jscal -p /dev/input/js1
jscal -s 3,1,0,511,511,1050628,1050628,1,0,127,127,4227330,4227330,1,0,127,127,4227330,4227330 /dev/input/js1

Both gas and brake pedals have the same correction: 1,0,127,127,4227330,4227330
This maps a value from the [0,255] range to the [-32767,32767] range. The rest value 255 is mapped to 32767 when I expect it to be mapped to 0, and the “fully pressed” value 0 is mapped to -32767 when I expect it to be mapped to 32767…
To fix this, it’s possible to set coef[0] to 255 (which means coef[1] and coef[3] are not used and can be set to 0), and to set coef[2] to 32767 x 16384 / -255 = -2105312. The resulting jscal command is:
matlo@matlo-desktop ~ $ jscal -s 3,1,0,511,511,1050628,1050628,1,0,255,0,-2105312,0,1,0,255,0,-2105312,0 /dev/input/js1

Finally, it’s possible to save the calibration values:
matlo@matlo-desktop ~ $ sudo jscal-store /dev/input/js1
matlo@matlo-desktop ~ $ cat /var/lib/joystick/joystick.state 
NAME="Logitech  Logitech MOMO Racing "
VENDOR="046d"
PRODUCT="ca03"
jscal -u 3,0,1,2,10,288,289,290,291,292,293,294,295,296,297
jscal -s 3,1,0,511,511,1050628,1050628,1,0,255,0,-2105312,0,1,0,255,0,-2105312,0

Support for Xbox 360 gamepad

Thanks to the sixaxis emulator, it’s possible to use a Xbox 360 gamepad with the PS3.

This requires a small patch for the d-pad, which is defined as a “joystick hat”.

The configuration file is available there.

The d-pad support will be included in next packages.

Joystick support

Last sunday I went to a bric-a-brac sale. I was looking for a steering wheel to adapt to my emulator. I bought a Wingman Formula Force GP for 5€:


This wheel is quite old – it was released in 2002 – but it still has a force feedback and a usb connector (older steering wheels have a gameport connector). It is probably outdated but I bet I can’t find better for that price.

I committed some code that enables the use of this controller with the sixaxis emulator. It uses the joystick API of the SDL library. The code is not well designed and has some limitations (only one joystick plugged to the PC, mappings are hardcoded…), but it is for now a proof of concept. It can be activated by modifying the Makefile: remove the # character from the line “#CFLAGS+=-DJOYSTICK”, and perform a make clean and a make.

Note that your joystick may be wrapped by default to a mouse and/or a keyboard by your linux distro. This is annoying because it generates extra mouse/keyboard events that interfere with real mouse and keyboard events in the emulator. This behavior can be configured/removed with the xinput command line utility. For more info on that command, type “xinput –help”.