Joystick APIs
Joystick
The Joystick class provides a wrapper around a 2-axis analog joystick, with an associated reader function for grabbing the raw values. When the joystick update() is called, the raw values are mapped into the range [-1,1] for each axis according to the configuration provided.
Code examples for the task API are provided in the joystick example folder.
API Reference
Header File
Classes
-
class Joystick : public espp::BaseComponent
2-axis Joystick with axis mapping / calibration.
Basic Circular and Rectangular Joystick Example
float min = 0; float max = 255; float center = 127; float deadband_percent = 0.1; float deadband = deadband_percent * (max - min); // circular joystick espp::Joystick js1({ .x_calibration = {.center = center, .minimum = min, .maximum = max}, .y_calibration = {.center = center, .minimum = min, .maximum = max}, .type = espp::Joystick::Type::CIRCULAR, .center_deadzone_radius = deadband_percent, .range_deadzone = deadband_percent, }); // square joystick (for comparison) espp::Joystick js2({ .x_calibration = {.center = center, .center_deadband = deadband, .minimum = min, .maximum = max, .range_deadband = deadband}, .y_calibration = {.center = center, .center_deadband = deadband, .minimum = min, .maximum = max, .range_deadband = deadband}, }); // now make a loop where we update the raw valuse and print out the joystick values fmt::print("raw x, raw y, js1 x, js1 y, js2 x, js2 y\n"); for (float x = min - 10.0f; x <= max + 10.0f; x += 10.0f) { for (float y = min - 10.0f; y <= max + 10.0f; y += 10.0f) { js1.update(x, y); js2.update(x, y); fmt::print("{}, {}, {}, {}, {}, {}\n", x, y, js1.x(), js1.y(), js2.x(), js2.y()); } }
ADC Joystick Example
static constexpr adc_unit_t ADC_UNIT = CONFIG_EXAMPLE_ADC_UNIT == 1 ? ADC_UNIT_1 : ADC_UNIT_2; static constexpr adc_channel_t ADC_CHANNEL_X = (adc_channel_t)CONFIG_EXAMPLE_ADC_CHANNEL_X; static constexpr adc_channel_t ADC_CHANNEL_Y = (adc_channel_t)CONFIG_EXAMPLE_ADC_CHANNEL_Y; std::vector<espp::AdcConfig> channels{ {.unit = ADC_UNIT, .channel = ADC_CHANNEL_X, .attenuation = ADC_ATTEN_DB_12}, {.unit = ADC_UNIT, .channel = ADC_CHANNEL_Y, .attenuation = ADC_ATTEN_DB_12}}; espp::OneshotAdc adc({ .unit = ADC_UNIT_2, .channels = channels, }); auto read_joystick = [&adc, &channels](float *x, float *y) -> bool { // this will be in mv auto maybe_x_mv = adc.read_mv(channels[0]); auto maybe_y_mv = adc.read_mv(channels[1]); if (maybe_x_mv.has_value() && maybe_y_mv.has_value()) { auto x_mv = maybe_x_mv.value(); auto y_mv = maybe_y_mv.value(); *x = (float)(x_mv); *y = (float)(y_mv); return true; } return false; }; espp::Joystick js1({ // convert [0, 3300]mV to approximately [-1.0f, 1.0f] .x_calibration = {.center = 1700.0f, .center_deadband = 100.0f, .minimum = 0.0f, .maximum = 3300.0f}, .y_calibration = {.center = 1700.0f, .center_deadband = 100.0f, .minimum = 0.0f, .maximum = 3300.0f}, .get_values = read_joystick, }); espp::Joystick js2({ // convert [0, 3300]mV to approximately [-1.0f, 1.0f] .x_calibration = {.center = 1700.0f, .center_deadband = 0.0f, .minimum = 0.0f, .maximum = 3300.0f}, .y_calibration = {.center = 1700.0f, .center_deadband = 0.0f, .minimum = 0.0f, .maximum = 3300.0f}, .type = espp::Joystick::Type::CIRCULAR, .center_deadzone_radius = 0.1f, .get_values = read_joystick, }); auto task_fn = [&js1, &js2](std::mutex &m, std::condition_variable &cv) { js1.update(); js2.update(); fmt::print("{}, {}\n", js1, js2); // NOTE: sleeping in this way allows the sleep to exit early when the // task is being stopped / destroyed { std::unique_lock<std::mutex> lk(m); cv.wait_for(lk, 500ms); } // don't want to stop the task return false; }; auto task = espp::Task({.callback = task_fn, .task_config = {.name = "Joystick"}, .log_level = espp::Logger::Verbosity::INFO}); fmt::print("js1 x, js1 y, js2 x, js2 y\n"); task.start();
Public Types
-
enum class Type
Type of the joystick.
Note
When using a Type::CIRCULAR joystick, it’s recommended to set the individual x/y calibration deadzones to be 0 and to only use the deadzone_radius field to set the deadzone around the center.
Values:
-
enumerator RECTANGULAR
The default type of joystick. Uses the rangemappers for each axis (to convert raw values from input range to be [-1,1]) independently which results in x/y deadzones and output that are rectangular.
-
enumerator CIRCULAR
The joystick is configured to have a circular output. This means that the x/y < deadzones are circular around the input and range and the output is clamped to be on or within the unit circle.
-
enumerator RECTANGULAR
-
typedef std::function<bool(float *x, float *y)> get_values_fn
function for gettin x/y values for the joystick.
- Param x
Pointer to the x value. Function should fill this variable with the latest reading.
- Param y
Pointer to the y value. Function should fill this variable with the latest reading.
- Return
True if the values were able to be retrieved, false otherwise.
Public Functions
-
explicit Joystick(const espp::Joystick::Config &config)
Initalize the joystick using the provided configuration.
- Parameters
config – Config structure with initialization information.
-
void set_type(espp::Joystick::Type type, float radius = 0, float range_deadzone = 0)
Set the type of the joystick.
See also
See also
See also
Note
If the Joystick is Type::CIRCULAR, the actual calibrations that are saved into the joystick will have 0 deadzone around the center value and range values, so that center and range deadzones are actually applied on the vector value instead of on the individual axes independently.
- Parameters
type – The Type of the joystick.
radius – Optional radius parameter used when
type
is Type::CIRCULAR. When the magnitude of the joystick’s mapped position vector is less than this value, the vector is set to (0,0).range_deadzone – Optional deadzone around the edge of the unit circle when
type
is Type::CIRCULAR. This scales the output so that the output appears to have magnitude 1 (meaning it appears to be on the edge of the unit circle) if the magnitude of the mapped position vector is greater than 1-range_deadzone. Example: if the range deadzone is 0.1, then the output will be scaled so that the magnitude of the output is 1 if the magnitude of the mapped position vector is greater than 0.9.
-
void set_center_deadzone_radius(float radius)
Sets the center deadzone radius.
Note
Radius is only applied when
deadzone
is Deadzone::CIRCULAR.- Parameters
radius – Optional radius parameter used when
deadzone
is Deadzone::CIRCULAR. When the magnitude of the joystick’s mapped position vector is less than this value, the vector is set to (0,0).
-
float center_deadzone_radius() const
Get the center deadzone radius.
- Returns
The center deadzone radius.
-
void set_range_deadzone(float range_deadzone)
Sets the range deadzone.
Note
Range deadzone is only applied when
deadzone
is Deadzone::CIRCULAR.- Parameters
range_deadzone – Optional deadzone around the edge of the unit circle when
deadzone
is Deadzone::CIRCULAR. This scales the output so that the output appears to have magnitude 1 (meaning it appears to be on the edge of the unit circle) if the magnitude of the mapped position vector is greater than 1-range_deadzone. Example: if the range deadzone is 0.1, then the output will be scaled so that the magnitude of the output is 1 if the magnitude of the mapped position vector is greater than 0.9.
-
float range_deadzone() const
Get the range deadzone.
- Returns
The range deadzone.
-
void set_calibration(const espp::FloatRangeMapper::Config &x_calibration, const espp::FloatRangeMapper::Config &y_calibration, float center_deadzone_radius = 0, float range_deadzone = 0)
Update the x and y axis mapping.
See also
See also
Note
If the Joystick is Type::CIRCULAR, the actual calibrations that are saved into the joystick will have 0 deadzone around the center and range values, so that center and range deadzones are actually applied on the vector value.
- Parameters
x_calibration – New x-axis range mapping configuration to use.
y_calibration – New y-axis range mapping configuration to use.
center_deadzone_radius – The radius of the unit circle’s deadzone [0, 1.0f] around the center, only used when the joystick is configured as Type::CIRCULAR.
range_deadzone – Optional deadzone around the edge of the unit circle when
type
is Type::CIRCULAR. This scales the output so that the output appears to have magnitude 1 (meaning it appears to be on the edge of the unit circle) if the magnitude of the mapped position vector is greater than 1-range_deadzone. Example: if the range deadzone is 0.1, then the output will be scaled so that the magnitude of the output is 1 if the magnitude of the mapped position vector is greater than 0.9.
-
void update()
Read the raw values and use the calibration data to update the position.
Note
Requires that the get_values_ function is set.
-
void update(float raw_x, float raw_y)
Update the joystick’s position using the provided raw x and y values.
Note
This function is useful when you have the raw values and don’t want to use the get_values_ function.
- Parameters
raw_x – The raw x-axis value.
raw_y – The raw y-axis value.
-
float x() const
Get the most recently updated x axis calibrated position.
- Returns
The most recent x-axis position (from when update() was last called).
-
float y() const
Get the most recently updated y axis calibrated position.
- Returns
The most recent y-axis position (from when update() was last called).
-
espp::Vector2f position() const
Get the most recently updated calibrated position.
- Returns
The most recent position (from when update() was last called).
-
espp::Vector2f raw() const
Get the most recently updated raw / uncalibrated readings. This function is useful for externally performing a calibration routine and creating updated calibration / mapper configuration structures.
- Returns
The most recent raw measurements (from when update() was last called).
-
inline const std::string &get_name() const
Get the name of the component
Note
This is the tag of the logger
- Returns
A const reference to the name of the component
-
inline void set_log_tag(const std::string_view &tag)
Set the tag for the logger
- Parameters
tag – The tag to use for the logger
-
inline espp::Logger::Verbosity get_log_level() const
Get the log level for the logger
See also
See also
- Returns
The verbosity level of the logger
-
inline void set_log_level(espp::Logger::Verbosity level)
Set the log level for the logger
See also
See also
- Parameters
level – The verbosity level to use for the logger
-
inline void set_log_verbosity(espp::Logger::Verbosity level)
Set the log verbosity for the logger
See also
See also
See also
Note
This is a convenience method that calls set_log_level
- Parameters
level – The verbosity level to use for the logger
-
inline espp::Logger::Verbosity get_log_verbosity() const
Get the log verbosity for the logger
See also
See also
See also
Note
This is a convenience method that calls get_log_level
- Returns
The verbosity level of the logger
-
inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
Set the rate limit for the logger
See also
Note
Only calls to the logger that have _rate_limit suffix will be rate limited
- Parameters
rate_limit – The rate limit to use for the logger
-
struct Config
Configuration structure for the joystick.
Public Members
-
espp::FloatRangeMapper::Config x_calibration
Configuration for the x axis.
-
espp::FloatRangeMapper::Config y_calibration
Configuration for the y axis.
-
espp::Joystick::Type type = {espp::Joystick::Type::RECTANGULAR}
The type of the joystick. See Type enum for more information.
-
float center_deadzone_radius{0}
The radius of the unit circle’s deadzone [0, 1.0f] around the center, only used when the joystick is configured as Type::CIRCULAR.
-
float range_deadzone = {0}
The deadzone around the edge of the unit circle, only used when the joystick is configured as Type::CIRCULAR. This scales the output so that the output appears to have magnitude 1 (meaning it appears to be on the edge of the unit circle) when the joystick value magnitude is within the range [1-range_deadzone, 1].
-
espp::Joystick::get_values_fn get_values = {nullptr}
Function to retrieve the latest unmapped joystick values. Required if you want to use update(), unused if you call update(float raw_x, float raw_y).
-
espp::FloatRangeMapper::Config x_calibration
-
enum class Type