formatting and bug fixes

This commit is contained in:
tyler miller 2025-01-13 13:52:57 -05:00
parent 5a8a1500eb
commit d5777031e4
6 changed files with 436 additions and 414 deletions

10
.clang-format Normal file
View file

@ -0,0 +1,10 @@
BasedOnStyle: Chromium
IndentWidth: 4
Language: Cpp
ColumnLimit: 100
UseTab: Never
BreakBeforeBraces: Custom
FixNamespaceComments: true
ShortNamespaceLines: 0
BraceWrapping:
BeforeElse: true

View file

@ -10,13 +10,13 @@
@details
AlignedJoy is a class written in C++ for Arduino to interface classic analog joysticks.
Reading the analog values of a joystick with Arduino is very simple, so what is the purpose of this class?
Through the methods of the class you can calibrate one or more joysticks, read and memorize the calibration points.
For dynamic applications, calibrated points can be stored in eeprom. Or once the calibration points are obtained,
they can be set in constant mode. See description of methods.
The strength of the class is that having the calibration parameters is able to align the values of the axes
of the respective joysticks. Its very useful when you want to manage something with a certain precision and
when you have a joystick with misaligned axis values.
Reading the analog values of a joystick with Arduino is very simple, so what is the purpose of
this class? Through the methods of the class you can calibrate one or more joysticks, read and
memorize the calibration points. For dynamic applications, calibrated points can be stored in
eeprom. Or once the calibration points are obtained, they can be set in constant mode. See
description of methods. The strength of the class is that having the calibration parameters is able
to align the values of the axes of the respective joysticks. Its very useful when you want to
manage something with a certain precision and when you have a joystick with misaligned axis values.
# LICENSE #
@ -45,8 +45,7 @@
#include "AlignedJoy.h"
AlignedJoy::AlignedJoy(uint8_t xPin, uint8_t yPin)
{
AlignedJoy::AlignedJoy(uint8_t xPin, uint8_t yPin) {
this->xPin = xPin;
this->yPin = yPin;
this->joystickCentered = false;
@ -56,22 +55,19 @@ AlignedJoy::AlignedJoy(uint8_t xPin, uint8_t yPin)
pinMode(this->yPin, INPUT);
};
void AlignedJoy::axesAlign(void)
{
void AlignedJoy::axesAlign(void) {
// Imposed the smallest value between the two calibrated minima.
this->alignMin = min(this->xAxisCalibMinimum, this->yAxisCalibMinimum);
// Imposed the largest value between the two calibrated maxima.
this->alignMax = max(this->xAxisCalibMaximum, this->yAxisCalibMaximum);
}
void AlignedJoy::middleCalibration(uint16_t timeOfCal)
{
void AlignedJoy::middleCalibration(uint16_t timeOfCal) {
// New istance of the timer
calibrationTimer TIME_CAL_1;
// Repeat for the required time
while(TIME_CAL_1 < timeOfCal)
{
while (TIME_CAL_1 < timeOfCal) {
// Assigns the value to each loop.
this->xAxisCalibCenter = analogRead(this->xPin);
this->yAxisCalibCenter = analogRead(this->yPin);
@ -80,10 +76,8 @@ void AlignedJoy::middleCalibration(uint16_t timeOfCal)
this->joystickCentered = true;
}
bool AlignedJoy::axesCalibration(uint16_t timeOfCal)
{
if(joystickCentered)
{
bool AlignedJoy::axesCalibration(uint16_t timeOfCal) {
if (joystickCentered) {
// New values for comparison
static uint16_t last_X_min = this->xAxisCalibCenter;
static uint16_t last_X_max = this->xAxisCalibCenter;
@ -94,35 +88,30 @@ bool AlignedJoy::axesCalibration(uint16_t timeOfCal)
calibrationTimer TIME_CAL_2;
// Repeat for the required time
while(TIME_CAL_2 < timeOfCal)
{
while (TIME_CAL_2 < timeOfCal) {
// Read analog value
uint16_t x = analogRead(this->xPin);
uint16_t y = analogRead(this->yPin);
// Logic acquisition. Assigns the lowest or highest values to each loop.
if(x < this->xAxisCalibCenter && x < last_X_min)
{
if (x < this->xAxisCalibCenter && x < last_X_min) {
last_X_min = this->xAxisCalibMinimum = x;
}
if(x > this->xAxisCalibCenter && x > last_X_max)
{
if (x > this->xAxisCalibCenter && x > last_X_max) {
last_X_max = this->xAxisCalibMaximum = x;
}
if(y < this->yAxisCalibCenter && y < last_Y_min)
{
if (y < this->yAxisCalibCenter && y < last_Y_min) {
last_Y_min = this->yAxisCalibMinimum = y;
}
if(y > this->yAxisCalibCenter && y > last_Y_max)
{
if (y > this->yAxisCalibCenter && y > last_Y_max) {
last_Y_max = this->yAxisCalibMaximum = y;
}
}
// verify that there is the minimum excursion between the minimum and the maximum of each axis.
// verify that there is the minimum excursion between the minimum and the maximum of each
// axis.
if ((this->xAxisCalibMaximum - this->xAxisCalibMinimum) >= AXIS_TRAVEL &&
(this->yAxisCalibMaximum - this->yAxisCalibMinimum) >= AXIS_TRAVEL)
{
(this->yAxisCalibMaximum - this->yAxisCalibMinimum) >= AXIS_TRAVEL) {
// set flag true
this->joystickFullCalibrated = true;
@ -131,24 +120,19 @@ bool AlignedJoy::axesCalibration(uint16_t timeOfCal)
return true;
}
else
{
else {
return false;
}
}
else
{
else {
return false;
}
}
void AlignedJoy::setCalibratedPoint(axis_t axis, point_t point, uint16_t pointValue)
{
switch(point)
{
void AlignedJoy::setCalibratedPoint(axis_t axis, point_t point, uint16_t pointValue) {
switch (point) {
case MIN:
switch(axis)
{
switch (axis) {
case X:
this->xAxisCalibMinimum = pointValue;
break;
@ -159,8 +143,7 @@ void AlignedJoy::setCalibratedPoint(axis_t axis, point_t point, uint16_t pointVa
break;
case MID:
switch(axis)
{
switch (axis) {
case X:
this->xAxisCalibCenter = pointValue;
break;
@ -171,8 +154,7 @@ void AlignedJoy::setCalibratedPoint(axis_t axis, point_t point, uint16_t pointVa
break;
case MAX:
switch(axis)
{
switch (axis) {
case X:
this->xAxisCalibMaximum = pointValue;
break;
@ -184,8 +166,7 @@ void AlignedJoy::setCalibratedPoint(axis_t axis, point_t point, uint16_t pointVa
}
// verify that there is the minimum excursion between the minimum and the maximum of each axis.
if ((this->xAxisCalibMaximum - this->xAxisCalibMinimum) >= AXIS_TRAVEL &&
(this->yAxisCalibMaximum - this->yAxisCalibMinimum) >= AXIS_TRAVEL)
{
(this->yAxisCalibMaximum - this->yAxisCalibMinimum) >= AXIS_TRAVEL) {
// set flag true
this->joystickFullCalibrated = true;
@ -194,15 +175,12 @@ void AlignedJoy::setCalibratedPoint(axis_t axis, point_t point, uint16_t pointVa
}
}
uint16_t AlignedJoy::getCalibratedPoint(axis_t axis, point_t point)
{
uint16_t AlignedJoy::getCalibratedPoint(axis_t axis, point_t point) {
uint16_t pointValue;
switch(point)
{
switch (point) {
case MIN:
switch(axis)
{
switch (axis) {
case X:
pointValue = this->xAxisCalibMinimum;
break;
@ -213,8 +191,7 @@ uint16_t AlignedJoy::getCalibratedPoint(axis_t axis, point_t point)
break;
case MID:
switch(axis)
{
switch (axis) {
case X:
pointValue = this->xAxisCalibCenter;
break;
@ -225,8 +202,7 @@ uint16_t AlignedJoy::getCalibratedPoint(axis_t axis, point_t point)
break;
case MAX:
switch(axis)
{
switch (axis) {
case X:
pointValue = this->xAxisCalibMaximum;
break;
@ -239,30 +215,26 @@ uint16_t AlignedJoy::getCalibratedPoint(axis_t axis, point_t point)
return pointValue;
}
uint16_t AlignedJoy::read(axis_t axis)
{
uint16_t AlignedJoy::read(axis_t axis) {
uint16_t axisValue;
switch(axis)
{
switch (axis) {
case X:
if(joystickFullCalibrated)
{
axisValue = map(analogRead(this->xPin), this->xAxisCalibMinimum, this->xAxisCalibMaximum, this->alignMin, this->alignMax);
if (joystickFullCalibrated) {
axisValue = map(analogRead(this->xPin), this->xAxisCalibMinimum,
this->xAxisCalibMaximum, this->alignMin, this->alignMax);
}
else
{
else {
axisValue = analogRead(this->xPin);
}
break;
case Y:
if(joystickFullCalibrated)
{
axisValue = map(analogRead(this->yPin), this->yAxisCalibMinimum, this->yAxisCalibMaximum, this->alignMin, this->alignMax);
if (joystickFullCalibrated) {
axisValue = map(analogRead(this->yPin), this->yAxisCalibMinimum,
this->yAxisCalibMaximum, this->alignMin, this->alignMax);
}
else
{
else {
axisValue = analogRead(this->yPin);
}
break;
@ -270,7 +242,6 @@ uint16_t AlignedJoy::read(axis_t axis)
return axisValue;
}
uint16_t AlignedJoy::read(axis_t axis, int32_t out_min, int32_t out_max)
{
uint16_t AlignedJoy::read(axis_t axis, int32_t out_min, int32_t out_max) {
return map(read(axis), this->alignMin, this->alignMax, out_min, out_max);
}

View file

@ -10,13 +10,13 @@
@details
AlignedJoy is a class written in C++ for Arduino to interface classic analog joysticks.
Reading the analog values of a joystick with Arduino is very simple, so what is the purpose of this class?
Through the methods of the class you can calibrate one or more joysticks, read and memorize the calibration points.
For dynamic applications, calibrated points can be stored in eeprom. Or once the calibration points are obtained,
they can be set in constant mode. See description of methods.
The strength of the class is that having the calibration parameters is able to align the values of the axes
of the respective joysticks. Its very useful when you want to manage something with a certain precision and
when you have a joystick with misaligned axis values.
Reading the analog values of a joystick with Arduino is very simple, so what is the purpose of
this class? Through the methods of the class you can calibrate one or more joysticks, read and
memorize the calibration points. For dynamic applications, calibrated points can be stored in
eeprom. Or once the calibration points are obtained, they can be set in constant mode. See
description of methods. The strength of the class is that having the calibration parameters is able
to align the values of the axes of the respective joysticks. Its very useful when you want to
manage something with a certain precision and when you have a joystick with misaligned axis values.
# LICENSE #
@ -73,12 +73,11 @@ typedef enum point:uint8_t{
MAX
} point_t;
class AlignedJoy
{
class AlignedJoy {
public:
/**
@brief Class onstructor. Create a new object of the joystick and set the axes (X/Y) pin to input mode
@brief Class onstructor. Create a new object of the joystick and set the axes (X/Y) pin to input
mode
@param xPin (x analog port pin of the device)
@param yPin (y analog port pin of the device)
*/
@ -115,7 +114,8 @@ class AlignedJoy
@warning
All calibration points (min and maximum) for each axis (x and y) must be defined to
obtain a scale reading of the two axes.
Only the extreme calibration points can be set, the center point is defined only for calibration purposes.
Only the extreme calibration points can be set, the center point is defined only for
calibration purposes.
@param axis X or Y axle enumerator flag.
@param point MIN, MID or MAX enumertor flag of the calibration point.
@param value point value to set. For example to set value (876) of the X MAX
@ -130,7 +130,8 @@ class AlignedJoy
@details
It can be used to compare the saved values with the new ones, to read the values saved in
the eeprom with the "setCalibratedPoint" function or for debug.
@see https://github.com/PalladinoMarco/AlignedJoystick/wiki wiki documentation for more details.
@see https://github.com/PalladinoMarco/AlignedJoystick/wiki wiki documentation for more
details.
@param axis X or Y axle enumerator flag.
@param point MIN, MID or MAX enumertor flag of the calibration point.
@return calibrated point of the axis request. For example to get the calibrated point of Y MIN
@ -141,23 +142,26 @@ class AlignedJoy
uint16_t getCalibratedPoint(axis_t axis, point_t point);
/**
@brief This method returns the required axis value. If calibrated, returns the aligned axis values.
@brief This method returns the required axis value. If calibrated, returns the aligned axis
values.
@param axis X or Y axle enumerator flag.
@return analog read of the axis request. For example to read Y axis @code objectname.read(Y); @endcode
@return analog read of the axis request. For example to read Y axis @code objectname.read(Y);
@endcode
*/
uint16_t read(axis_t axis);
/**
@brief This method returns the required joystick axis values in the set range (map functions)
@details
If you want to get a mapping by keeping the scale of calibrated values do not use the arduino map
unction (already included in the method) but use the optional parameters "out_min" and "out_max"
of the read method.
For arduino map @see https://www.arduino.cc/reference/en/language/functions/math/map/
If you want to get a mapping by keeping the scale of calibrated values do not use the arduino
map unction (already included in the method) but use the optional parameters "out_min" and
"out_max" of the read method. For arduino map @see
https://www.arduino.cc/reference/en/language/functions/math/map/
@param axis X or Y axle enumerator flag.
@param out_min minimum range output value.
@param out_max maximum range output value.
@return analog read of the relative axis in map mode, for example to control a servo motor, do this:
@return analog read of the relative axis in map mode, for example to control a servo motor, do
this:
@code
objectname.read(X, 1000, 2000);
objectname.read(Y, 1000, 2000);
@ -209,25 +213,69 @@ class AlignedJoy
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
class calibrationTimer
{
class calibrationTimer {
private:
unsigned long ms;
public:
calibrationTimer(void) { ms = millis(); }
calibrationTimer(unsigned long val) { ms = millis() - val; }
calibrationTimer(const calibrationTimer& orig) { ms = orig.ms; }
operator unsigned long() const { return millis() - ms; }
calibrationTimer & operator = (const calibrationTimer &rhs) { ms = rhs.ms; return *this; }
calibrationTimer & operator = (unsigned long val) { ms = millis() - val; return *this; }
calibrationTimer & operator -= (unsigned long val) { ms += val ; return *this; }
calibrationTimer & operator += (unsigned long val) { ms -= val ; return *this; }
calibrationTimer operator - (int val) const { calibrationTimer r(*this); r.ms += val; return r; }
calibrationTimer operator - (unsigned int val) const { calibrationTimer r(*this); r.ms += val; return r; }
calibrationTimer operator - (long val) const { calibrationTimer r(*this); r.ms += val; return r; }
calibrationTimer operator - (unsigned long val) const { calibrationTimer r(*this); r.ms += val; return r; }
calibrationTimer operator + (int val) const { calibrationTimer r(*this); r.ms -= val; return r; }
calibrationTimer operator + (unsigned int val) const { calibrationTimer r(*this); r.ms -= val; return r; }
calibrationTimer operator + (long val) const { calibrationTimer r(*this); r.ms -= val; return r; }
calibrationTimer operator + (unsigned long val) const { calibrationTimer r(*this); r.ms -= val; return r; }
calibrationTimer& operator=(const calibrationTimer& rhs) {
ms = rhs.ms;
return *this;
}
calibrationTimer& operator=(unsigned long val) {
ms = millis() - val;
return *this;
}
calibrationTimer& operator-=(unsigned long val) {
ms += val;
return *this;
}
calibrationTimer& operator+=(unsigned long val) {
ms -= val;
return *this;
}
calibrationTimer operator-(int val) const {
calibrationTimer r(*this);
r.ms += val;
return r;
}
calibrationTimer operator-(unsigned int val) const {
calibrationTimer r(*this);
r.ms += val;
return r;
}
calibrationTimer operator-(long val) const {
calibrationTimer r(*this);
r.ms += val;
return r;
}
calibrationTimer operator-(unsigned long val) const {
calibrationTimer r(*this);
r.ms += val;
return r;
}
calibrationTimer operator+(int val) const {
calibrationTimer r(*this);
r.ms -= val;
return r;
}
calibrationTimer operator+(unsigned int val) const {
calibrationTimer r(*this);
r.ms -= val;
return r;
}
calibrationTimer operator+(long val) const {
calibrationTimer r(*this);
r.ms -= val;
return r;
}
calibrationTimer operator+(unsigned long val) const {
calibrationTimer r(*this);
r.ms -= val;
return r;
}
};

View file

@ -10,25 +10,21 @@ bool JoystickAxisCalibration::valid() const {
return min < mid < max;
}
void writeNvm(const NonVolatileMemory &nvm)
{
for (size_t ii = 0; ii < sizeof(NonVolatileMemory); ii++)
{
void writeNvm(const NonVolatileMemory& nvm) {
for (size_t ii = 0; ii < sizeof(NonVolatileMemory); ii++) {
EEPROM.write(ii, nvm.rawBytes[ii]);
}
}
void writeCalibration(const JoystickCalibration& cal) {
NonVolatileMemory nvm = {};
nvm.joystickCal = cal;
nvm.calData.joystickCal = cal;
writeNvm(nvm);
}
void readNvm(NonVolatileMemory &nvm)
{
void readNvm(NonVolatileMemory& nvm) {
nvm.calData.validMarker = 0;
for (size_t ii = 0; ii < sizeof(NonVolatileMemory); ii++)
{
for (size_t ii = 0; ii < sizeof(NonVolatileMemory); ii++) {
nvm.rawBytes[ii] = EEPROM.read(ii);
}
}

View file

@ -9,8 +9,7 @@
#define __NVMEEPROM_H__
#include <cstdint>
struct JoystickAxisCalibration
{
struct JoystickAxisCalibration {
/// Minimum value axis could be
uint16_t min;
/// average center point of axis
@ -23,7 +22,6 @@ struct JoystickAxisCalibration
bool valid() const;
} __attribute__((packed));
/// calibration of min/max for single axis analog signals with no mid point
/// ie: a potentiometer
struct LinearAnalogCalibration {
@ -32,25 +30,23 @@ struct LinearAnalogCalibration {
inline bool valid() const { return min < max; }
} __attribute__((packed));
struct JoystickCalibration
{
struct JoystickCalibration {
JoystickAxisCalibration x;
JoystickAxisCalibration y;
} __attribute__((packed));
static constexpr uint32_t VALID_MARKER_DEFAULT = 0xcafecall;
union NonVolatileMemory
{
struct Calibration {
union NonVolatileMemory {
/// place hard-coded start marker at the beginning of the data
/// to indicate validity
uint32_t validMarker = VALID_MARKER_DEFAULT;
struct Calibration {
JoystickCalibration joystickCal;
LinearAnalogCalibration linearCal;
} __attribute__((packed)) calData;
uint8_t rawBytes[NonVolatileMemory::Calibration] = {};
uint8_t rawBytes[sizeof(NonVolatileMemory::Calibration)] = {};
inline bool valid() const { return calData.validMarker == VALID_MARKER_DEFAULT; }
};

View file

@ -1,7 +1,7 @@
#include <Arduino.h>
#include <AlignedJoy.h>
#include "NvmEeprom.hpp"
#include <Arduino.h>
#include "Arduino_LED_Matrix.h"
#include "NvmEeprom.hpp"
// joystick calibration
#define TIME_CAL_1 2000
@ -12,21 +12,24 @@ AlignedJoy joystick_1(0, 1); /// X on A0, Y on A1
ArduinoLEDMatrix ledMatrix;
/// Run calibration on the provided joystick. Save the results to the provided calibration
bool runJoystickCalibrationRoutine(AlignedJoy &joy, JoystickCalibration &cal)
{
bool runJoystickCalibrationRoutine(AlignedJoy& joy, JoystickCalibration& cal) {
/*
* Start the joystick calibration in the center position. Use this method only if the calibration of the axles is desired (axesCalibration).
* Start the joystick calibration in the center position. Use this method only if the
* calibration of the axles is desired (axesCalibration).
*/
// CALIBRATION 1
Serial.print("Center Joystick Calibration \n\nLeave the joystick in the centre position during the calibration\ntime which is set to ");
Serial.print(
"Center Joystick Calibration \n\nLeave the joystick in the centre position during the "
"calibration\ntime which is set to ");
Serial.print(TIME_CAL_1);
Serial.println(" milliseconds.");
delay(5000);
Serial.println("Calibration started!");
delay(500);
/*
* for calibrate the joystick center point use "centerCalibration" method; objectname.centerCalibration(uint16_t timeOfCal).
* "timeOfCal" is the calibration time in milliseconds
* for calibrate the joystick center point use "centerCalibration" method;
* objectname.centerCalibration(uint16_t timeOfCal). "timeOfCal" is the calibration time in
* milliseconds
*/
joy.middleCalibration(TIME_CAL_1);
Serial.println("Joystick Centered!");
@ -38,34 +41,36 @@ bool runJoystickCalibrationRoutine(AlignedJoy &joy, JoystickCalibration &cal)
* It is recommended to rotate the joystick in a circular way along its circumference throughout
* the calibration time.
*/
Serial.print("Start axes Calibration \n\nRotate the joystick in a circular way along its circumference\nthroughout the calibration time (");
Serial.print(
"Start axes Calibration \n\nRotate the joystick in a circular way along its "
"circumference\nthroughout the calibration time (");
Serial.print(TIME_CAL_2);
Serial.println(" milliseconds).");
delay(5000);
Serial.println("Calibration started!");
delay(500);
/*
* for calibrate the joystick axes points use "axesCalibration" method (bool type); objectname.axesCalibration(uint16_t timeOfCal).
* "timeOfCal" is the calibration time in milliseconds.
* for calibrate the joystick axes points use "axesCalibration" method (bool type);
* objectname.axesCalibration(uint16_t timeOfCal). "timeOfCal" is the calibration time in
* milliseconds.
*/
if (joy.axesCalibration(TIME_CAL_2))
{
Serial.println("Calibration succesfull!!");
if (joy.axesCalibration(TIME_CAL_2)) {
Serial.println("Calibration succesfull!");
}
else
{
Serial.println("Calibration failed!!");
else {
Serial.println("Calibration failed!");
return false;
}
// Print all points calibrated
/*
* You can use these values to save them to eeprom memory. In this way you will avoid requiring the joystick calibration at each boot time.
* To set the parameters read by eeprom you have to use the "setCalibratedPoint" method.
* If your project does not require the re-calibration of the joystick then you can make a sketch like this only to display the calibrated
* values to set them in the final project using the "setCalibratedPoint" method.
* To get the calibrated point values use getCalibratedPoint(axis_t axis, point_t point).
* The parameters: the labels of the "axis_t" shall be X and Y; the labels of "point_t" is MIN, MID and MAX.
* You can use these values to save them to eeprom memory. In this way you will avoid requiring
* the joystick calibration at each boot time. To set the parameters read by eeprom you have to
* use the "setCalibratedPoint" method. If your project does not require the re-calibration of
* the joystick then you can make a sketch like this only to display the calibrated values to
* set them in the final project using the "setCalibratedPoint" method. To get the calibrated
* point values use getCalibratedPoint(axis_t axis, point_t point). The parameters: the labels
* of the "axis_t" shall be X and Y; the labels of "point_t" is MIN, MID and MAX.
*/
Serial.print("X min -> ");
Serial.print(joy.getCalibratedPoint(X, MIN));
@ -90,15 +95,12 @@ bool runJoystickCalibrationRoutine(AlignedJoy &joy, JoystickCalibration &cal)
return true;
}
void setup()
{
void setup() {
// SERIAL INITIALIZE
Serial.begin(115200);
ledMatrix.loadSequence(LEDMATRIX_ANIMATION_STARTUP);
ledMatrix.begin();
while (!Serial)
{
while (!Serial) {
}
ledMatrix.play(true);
@ -109,9 +111,11 @@ void setup()
// run joystick calibration if needed
bool calibrationInvalid = nvm.valid();
do {
calibrationInvalid |= !nvm.joystickCal.x.valid() || !nvm.joystickCal.y.valid();
calibrationInvalid |=
!nvm.calData.joystickCal.x.valid() || !nvm.calData.joystickCal.y.valid();
if (calibrationInvalid) {
calibrationInvalid |= !runJoystickCalibrationRoutine(joystick_1, nvm.calData.joystickCal);
calibrationInvalid |=
!runJoystickCalibrationRoutine(joystick_1, nvm.calData.joystickCal);
}
} while (calibrationInvalid);
// ensure calibration has been applied
@ -125,14 +129,11 @@ void setup()
// run analog lever calibration if needed
// write NVM in the event any values were updated
writeNvm(nvm);
}
void loop()
{
void loop() {
// print joystick axes value
Serial.print("joystick_1 X -> ");
Serial.print(joystick_1.read(X));