Работа с китаёзным джойстиком
- Войдите на сайт для отправки комментариев
Сразу оговорюсь: ни на что не претендую, просто разместил объяву. Итак: возникла как-то необходимость управлять с джойстика - да чем угодно управлять, теми же сервами. Посмотрел, что к чему, пощупал свои экземпляры вот таких китаёз:

и понял - не алё они, требуют индивидуальной калибровки как по осям, так и между экземплярами. Плюс - либо я плохо искал, либо никому не нужно было, но - в "библиотеках" работы с джойстиком не увидел полярных координат, от слова "вообще" - а ведь это вещь полезная, когда надо, например, удобно соотнести наклон джойстика с поворотом платформы вокруг своей оси. Короче:
1. Заголовочник:
#pragma once
//--------------------------------------------------------------------------------------------------------------------------------------
#include <Arduino.h>
//--------------------------------------------------------------------------------------------------------------------------------------
class Joystick
{
public:
Joystick();
void begin(uint8_t xPin, uint8_t yPin, int16_t midPointX, int16_t midPointY, uint8_t histeresis = 20);
void update();
// возвращает сырые значения с потенциометров
int16_t getXRaw();
int16_t getYRaw();
// возвращает нормализованные значения с потенциометров, приведённые к диапазону [-1.0, 1.0]
float getX();
float getY();
// возвращает угол по каждой из осей. degreesFreedom - степень свободы по оси, градусов
float getXAngle(uint8_t degreesFreedom=180);
float getYAngle(uint8_t degreesFreedom=180);
// возвращает угол в полярных координатах
float getPolarAngle();
private:
uint8_t pinX, pinY;
int16_t curX, curY;
int16_t midX, midY;
uint8_t histeresis;
float reflect(int16_t current, int16_t midpoint, uint8_t histeresis);
float computeAngle(float val, uint8_t degreesFreedom);
};
//--------------------------------------------------------------------------------------------------------------------------------------
2. Сырец:
#include "CoreJoystick.h"
//--------------------------------------------------------------------------------------------------------------------------------------
Joystick::Joystick()
{
pinX = pinY = 0;
curX = curY = 0;
midX = midY = 512;
histeresis = 20;
}
//--------------------------------------------------------------------------------------------------------------------------------------
float Joystick::reflect(int16_t current, int16_t midpoint, uint8_t histeresis)
{
if(current >= (midpoint - histeresis) && current <= (midpoint + histeresis))
return 0.0;
float reflectedPos = current - midpoint;
float result = (reflectedPos/midpoint);
if(result < -1.0)
result = -1.0;
if(result > 1.0)
result = 1.0;
return result;
}
//--------------------------------------------------------------------------------------------------------------------------------------
void Joystick::begin(uint8_t xPin, uint8_t yPin, int16_t midPointX, int16_t midPointY, uint8_t _histeresis)
{
pinX = xPin;
pinY = yPin;
midX = midPointX;
midY = midPointY;
histeresis = _histeresis;
}
//--------------------------------------------------------------------------------------------------------------------------------------
void Joystick::update()
{
curX = analogRead(pinX);
curY = analogRead(pinY);
}
//--------------------------------------------------------------------------------------------------------------------------------------
int16_t Joystick::getXRaw()
{
return curX;
}
//--------------------------------------------------------------------------------------------------------------------------------------
int16_t Joystick::getYRaw()
{
return curY;
}
//--------------------------------------------------------------------------------------------------------------------------------------
float Joystick::getX()
{
return reflect(curX,midX,histeresis);
}
//--------------------------------------------------------------------------------------------------------------------------------------
float Joystick::getY()
{
return reflect(curY,midY,histeresis);
}
//--------------------------------------------------------------------------------------------------------------------------------------
float Joystick::getPolarAngle()
{
float x = getX();
float y = getY();
float atanResult = atan2(y, x);
float ang = degrees(atanResult);
if (ang < 0)
ang += 360;
if(ang > 0)
ang = 360 - ang;
return ang;
}
//--------------------------------------------------------------------------------------------------------------------------------------
float Joystick::computeAngle(float val, uint8_t degreesFreedom)
{
val += 1.0;
float stepSize = float(degreesFreedom)/2.0;
return val*stepSize;
}
//--------------------------------------------------------------------------------------------------------------------------------------
float Joystick::getXAngle(uint8_t degreesFreedom)
{
return computeAngle(getX(),degreesFreedom);
}
//--------------------------------------------------------------------------------------------------------------------------------------
float Joystick::getYAngle(uint8_t degreesFreedom)
{
return computeAngle(getY(),degreesFreedom);
}
//--------------------------------------------------------------------------------------------------------------------------------------
midPointX, midPointY - это как раз калибровка, значения с потенциометров, когда джойстик находится в состоянии покоя, т.е. - не тронут шаловливыми ручками. histeresis - надеюсь, понятно, для чего: чуть загрубляем, чтобы не было мелких дрожаний. degreesFreedom - степень свободы по оси, как показала практика - оси данного дешёвого поделия не двигаются на 180 градусов, тащемта.
Код, ессно, можно и упростить, убрав хранение переменных в классе, но мне - и так норм. От использования float - сам не в восторге, но, ещё раз - это просто пример.
По итогу - все имеющиеся в наличии джойстики удалось откалибровать и уверенно снимать с них показания, самым актуальным было - именно полярные координаты.
Такой вот мопед, квон должен оценить :)
+55555)