Joystick calibration - PalladinoMarco/AlignedJoystick GitHub Wiki

Calibration procedure involves the acquisition of the values of the axes at rest (joystick at the center) and the acquisition of the values of the axes at the extreme points (minimum and maximum). It can therefore be defined that calibration is divided into two phases; the methods are:

void middleCalibration(uint16_t timeOfCal);
bool axesCalibration(uint16_t timeOfCal);

It’s essential to respect the order of the two phases, never the other way around. Basically, to calibrate the extreme points of each axis it is first necessary to know the central position.

Splitting the calibration into two stages leaves the developer free to choose the mode and time you want between one calibration and the other.

What is meant by mode?

Modality means the way the calibration procedure is handled. If your application allows the user to re-calibrate the joystick you will need to offer a calibration wizard. Or the procedure will be performed only once by the developer. This wizard can be done in many different ways, through a display, through the serial, using hardware like buttons and more. The calibrated points can be saved in eeprom (re-calibration by user) or set by the developer (permanent calibration).

In-depth analysis of calibration methods

A very important detail! To speed up and simplify the calibration procedure it is not required to calibrate one point at a time of each axis but the values are read and updated to each cycle, the joystick must be calibrated by rotating at maximum deflection along its perimeter (circular type calibration).

How to set pins, install the joystick and read the axis values we have already seen in the Basic Usage. We now turn to the calibration procedure.

void middleCalibration(uint16_t timeOfCal);

It is of void type and has as parameter uint16_t timeOfCal the time in milliseconds of the duration of the calibration, that is how much time will have to pass from when the call to the procedure is carried out to when this will finish setting the value of the central point. During this period the joystick must remain at rest.

bool axesCalibration(uint16_t timeOfCal);

For the parameter uint16_t timeOfCal the above description applies. Time refers to the calibration of both axes because they are calibrated simultaneously and not individually. Always remember that time must be in milliseconds.

This method is bolean, if the calibration procedure is successful it will be true otherwise it will be false. This allows us to give feedback to the user.

The errors for which the calibration failed were not defined because the user side results in a single error; There was no deflection of the joystick or it was not enough. For completeness, calibration fails if:

  • The calibration of the central point was omitted (development error).
  • The excursion between the minimum and the maximum is less than the minimum travel.

Where is the minimum travel defined?

Excellent observation! The minimum travel is defined within the file "Alignedjoy. h" in the constant AXIS_TRAVEL. By default its value is set to 550 and is intended as a total excursion between minimum and maximum. If you want to change this value it will be enough to redefine this constant in your sketch and the value will be overwritten.

#define AXIS_TRAVEL 300

Now the minimum excursion is worth 300.

A diagram of our calibration program could be made as follows:

// INCLUDE LIBRARY
#include <AlignedJoy.h>

// Overwrite the default value of AXIS_TRAVEL constant
#define AXIS_TRAVEL 300

// PINs DEFINITION
// joystick 1
#define PIN_JOY1_X   0  //(up  down)
#define PIN_JOY1_Y   1  //(left  right)

// TIMERs DEFINITION
// Here we have defined the calibration times in ms. `TIME_CAL_1` for calibration of the central point, `TIME_CAL_2` for calibration of the extreme points.
#define TIME_CAL_1 2000
#define TIME_CAL_2 3000

// CLASS CONSTRUCTOR
// new joystick object
AlignedJoy joystick_1(PIN_JOY1_X, PIN_JOY1_Y);

void setup() {
// Here we add the code that warns the user that he is about to start calibration.
joystick_1.middleCalibration(TIME_CAL_1);

// Here we add an alert the user that the central point calibration has been completed and the extreme points calibration is about to begin.
// Apply a delay to allow the user to read the message and make the call to the calibration function.

if(joystick_1.axesCalibration(TIME_CAL_2))
 {
  // Calibration succesfully!!
  // do something
 }
 else
 {
  // Calibration failed!!
  // do something
 }

}

void loop() {
 // read calibrated joystick axes value
 joystick_1.read(X);
 joystick_1.read(Y);
}

Here a complete example with wizard through serial:

CalibrationAndReadAligned

Get and Set (a great classic!)

If you have looked at the complete example above you will surely have noticed the get method:

uint16_t getCalibratedPoint(axis_t axis, point_t point);

Good! This function is unsigned int (16 bit) and if called we will return the calibrated point required through the parameters. We have two, axis_t axis and point_t point which are enumerator type defined in the class.

For axis we can choose X or Y flags and for point we can choose the flags MIN, MID and MAX. For example, if we want to know the minimum of the X axis and the maximum of the Y axis we can write like this:

objectname.getCalibratedPoint(X, MIN);
objectname.getCalibratedPoint(Y, MAX);

It's so easy, isn't it?

Now to the set method:

void setCalibratedPoint(axis_t axis, point_t point, uint16_t value);

It is of void type, so nothing will come back, simply set the desired value. The description of the parameters is equivalent to that of the get method excluding the last parameter "value" which must contain the value of the point we want to calibrate.

objectname.setCalibratedPoint(X, MIN, 121);
objectname.setCalibratedPoint(X, MAX, 996);

This method in fact does nothing but write in the variables of the class the values of the calibrated points, which happens automatically when the calibration is performed. We will use this method to avoid calibrating the joystick whenever the microcontroller is reset or when it is switched off and on again. That would be very unpleasant, so we need to permanently save our calibration.

Let’s see some examples of how to use the get and set.

The joystick will be calibrated by the user:

If the calibration is left to the user they should be saved in eeprom or on an external memory.

The process could be done like this:

  • start the system;
  • read the values from the eprom;
  • set the values read (use setCalibratedPoint());
  • continue with the rest;
  • if the user wants to recalibrate the joystick;
  • start the calibration procedure of the joystick (use middleCalibration() and axesCalibration());
  • recover the calibrated values (use getCalibratedPoint());
  • save the calibration in the eeprom;
  • continue with the rest;

The joystick will be calibrated only during development:

We’ll need a first sketch with the sole purpose of calibrating the joystick and visualizing the values (see CalibrationAndReadAligned example). In the final project sketch we will use only the setCalibratedPoint() of all calibrated points. Imagine that we have executed the calibration sketch and made a copy of the values of the calibrated points, in the final project to define the calibrated points we can do as follows:

#include <AlignedJoy.h>

#define PIN_JOY1_X   0
#define PIN_JOY1_Y   1

AlignedJoy joystick_1(PIN_JOY1_X, PIN_JOY1_Y);

void setup() {

  // I set the calibration points with the values obtained by executing the calibration sketch.
  // It is no longer necessary to calibrate the joistick.

  joystick_1.setCalibratedPoint(X, MIN, 121);
  joystick_1.setCalibratedPoint(X, MAX, 886);

  joystick_1.setCalibratedPoint(Y, MIN, 234);
  joystick_1.setCalibratedPoint(Y, MAX, 998);
}

void loop() {

 // do something reading the joystick
 joystick_1.read(X);
 joystick_1.read(Y);
 
}

The above can be done for all joysticks installed.