Add joystick-calibration wizzard (store in nvs), Optimize Menu

- menu:
    - Add item joystick calibration wizzard
    - Add item RESET (clear nvs and restart)
    - Add configuration option to not show/change value. Instead only show confirm message
      apply this to all items only running action
    - Optimize formatting and comments

- main:
    - pass nvsHandle to display task and joystick class

- joystick:
    - Add methods to write and load calibration values (axis min/max adc value) from nvs
    - Add method to get raw adc value
This commit is contained in:
jonny_jr9
2024-02-21 11:30:36 +01:00
parent c9c371a742
commit cdfa64fbc0
5 changed files with 467 additions and 144 deletions

View File

@@ -19,8 +19,9 @@ static const char * TAG_CMD = "joystickCommands";
//-------- constructor --------
//-----------------------------
//copy provided struct with all configuration and run init function
evaluatedJoystick::evaluatedJoystick(joystick_config_t config_f){
evaluatedJoystick::evaluatedJoystick(joystick_config_t config_f, nvs_handle_t * nvsHandle_f){
config = config_f;
nvsHandle = nvsHandle_f;
init();
}
@@ -30,7 +31,7 @@ evaluatedJoystick::evaluatedJoystick(joystick_config_t config_f){
//---------- init ------------
//----------------------------
void evaluatedJoystick::init(){
ESP_LOGI(TAG, "initializing joystick");
ESP_LOGW(TAG, "initializing ADC's and loading calibration...");
//initialize adc
adc1_config_width(ADC_WIDTH_BIT_12); //=> max resolution 4096
@@ -41,6 +42,12 @@ void evaluatedJoystick::init(){
adc1_config_channel_atten(config.adc_x, ADC_ATTEN_DB_11); //max voltage
adc1_config_channel_atten(config.adc_y, ADC_ATTEN_DB_11); //max voltage
//load stored calibration values (if not found loads defaults from config)
loadCalibration(X_MIN);
loadCalibration(X_MAX);
loadCalibration(Y_MIN);
loadCalibration(Y_MAX);
//define joystick center from current position
defineCenter(); //define joystick center from current position
}
@@ -81,17 +88,17 @@ joystickData_t evaluatedJoystick::getData() {
ESP_LOGV(TAG, "getting X coodrdinate...");
uint32_t adcRead;
adcRead = readAdc(config.adc_x, config.x_inverted);
float x = scaleCoordinate(readAdc(config.adc_x, config.x_inverted), config.x_min, config.x_max, x_center, config.tolerance_zeroX_per, config.tolerance_end_per);
float x = scaleCoordinate(readAdc(config.adc_x, config.x_inverted), x_min, x_max, x_center, config.tolerance_zeroX_per, config.tolerance_end_per);
data.x = x;
ESP_LOGD(TAG, "X: adc-raw=%d \tadc-conv=%d \tmin=%d \t max=%d \tcenter=%d \tinverted=%d => x=%.3f",
adc1_get_raw(config.adc_x), adcRead, config.x_min, config.x_max, x_center, config.x_inverted, x);
adc1_get_raw(config.adc_x), adcRead, x_min, x_max, x_center, config.x_inverted, x);
ESP_LOGV(TAG, "getting Y coodrinate...");
adcRead = readAdc(config.adc_y, config.y_inverted);
float y = scaleCoordinate(adcRead, config.y_min, config.y_max, y_center, config.tolerance_zeroY_per, config.tolerance_end_per);
float y = scaleCoordinate(adcRead, y_min, y_max, y_center, config.tolerance_zeroY_per, config.tolerance_end_per);
data.y = y;
ESP_LOGD(TAG, "Y: adc-raw=%d \tadc-conv=%d \tmin=%d \t max=%d \tcenter=%d \tinverted=%d => y=%.3lf",
adc1_get_raw(config.adc_y), adcRead, config.y_min, config.y_max, y_center, config.y_inverted, y);
adc1_get_raw(config.adc_y), adcRead, y_min, y_max, y_center, config.y_inverted, y);
//calculate radius
data.radius = sqrt(pow(data.x,2) + pow(data.y,2));
@@ -569,4 +576,124 @@ motorCommands_t joystick_generateCommandsShaking(joystickData_t data){
ESP_LOGI(TAG_CMD, "motor right: state=%s, duty=%.3f", motorstateStr[(int)commands.right.state], commands.right.duty);
return commands;
}
// corresponding storage key strings to each joystickCalibratenMode variable
const char *calibrationStorageKeys[] = {"stick_x-min", "stick_x-max", "stick_y-min", "stick_y-max", "", ""};
//-------------------------------
//------- loadCalibration -------
//-------------------------------
// loads selected calibration value from nvs or default values from config if no data stored
void evaluatedJoystick::loadCalibration(joystickCalibrationMode_t mode)
{
// determine desired variables
int *configValue, *usedValue;
switch (mode)
{
case X_MIN:
configValue = &(config.x_min);
usedValue = &x_min;
break;
case X_MAX:
configValue = &(config.x_max);
usedValue = &x_max;
break;
case Y_MIN:
configValue = &(config.y_min);
usedValue = &y_min;
break;
case Y_MAX:
configValue = &(config.y_max);
usedValue = &y_max;
break;
case X_CENTER:
case Y_CENTER:
default:
// center position is not stored in nvs, it gets defined at startup or during calibration
ESP_LOGE(TAG, "loadCalibration: 'center_x' and 'center_y' are not stored in nvs -> not assigning anything");
// defineCenter();
return;
}
// read from nvs
int16_t valueRead;
esp_err_t err = nvs_get_i16(*nvsHandle, calibrationStorageKeys[(int)mode], &valueRead);
switch (err)
{
case ESP_OK:
ESP_LOGW(TAG, "Successfully read value '%s' from nvs. Overriding default value %d with %d", calibrationStorageKeys[(int)mode], *configValue, valueRead);
*usedValue = (int)valueRead;
break;
case ESP_ERR_NVS_NOT_FOUND:
ESP_LOGW(TAG, "nvs: the value '%s' is not initialized yet, loading default value %d", calibrationStorageKeys[(int)mode], *configValue);
*usedValue = *configValue;
break;
default:
ESP_LOGE(TAG, "Error (%s) reading nvs!", esp_err_to_name(err));
*usedValue = *configValue;
}
}
//-------------------------------
//------- loadCalibration -------
//-------------------------------
// loads selected calibration value from nvs or default values from config if no data stored
void evaluatedJoystick::writeCalibration(joystickCalibrationMode_t mode, int newValue)
{
// determine desired variables
int *configValue, *usedValue;
switch (mode)
{
case X_MIN:
configValue = &(config.x_min);
usedValue = &x_min;
break;
case X_MAX:
configValue = &(config.x_max);
usedValue = &x_max;
break;
case Y_MIN:
configValue = &(config.y_min);
usedValue = &y_min;
break;
case Y_MAX:
configValue = &(config.y_max);
usedValue = &y_max;
break;
case X_CENTER:
x_center = newValue;
ESP_LOGW(TAG, "writeCalibration: 'center_x' or 'center_y' are not stored in nvs -> loading only");
return;
case Y_CENTER:
y_center = newValue;
ESP_LOGW(TAG, "writeCalibration: 'center_x' or 'center_y' are not stored in nvs -> loading only");
default:
return;
}
// check if unchanged
if (*usedValue == newValue)
{
ESP_LOGW(TAG, "writeCalibration: value '%s' unchanged at %d, not writing to nvs", calibrationStorageKeys[(int)mode], newValue);
return;
}
// update nvs value
ESP_LOGW(TAG, "writeCalibration: updating nvs value '%s' from %d to %d", calibrationStorageKeys[(int)mode], *usedValue, newValue);
esp_err_t err = nvs_set_i16(*nvsHandle, calibrationStorageKeys[(int)mode], newValue);
if (err != ESP_OK)
ESP_LOGE(TAG, "nvs: failed writing");
err = nvs_commit(*nvsHandle);
if (err != ESP_OK)
ESP_LOGE(TAG, "nvs: failed committing updates");
else
ESP_LOGI(TAG, "nvs: successfully committed updates");
// update variable
*usedValue = newValue;
}

View File

@@ -8,6 +8,8 @@ extern "C"
#include "driver/adc.h"
#include "esp_log.h"
#include "esp_err.h"
#include "nvs_flash.h"
#include "nvs.h"
}
#include <cmath>
@@ -55,6 +57,7 @@ typedef struct joystick_config_t {
enum class joystickPos_t {CENTER, Y_AXIS, X_AXIS, TOP_RIGHT, TOP_LEFT, BOTTOM_LEFT, BOTTOM_RIGHT};
extern const char* joystickPosStr[7];
typedef enum joystickCalibrationMode_t { X_MIN = 0, X_MAX, Y_MIN, Y_MAX, X_CENTER, Y_CENTER } joystickCalibrationMode_t;
//struct with current data of the joystick
typedef struct joystickData_t {
@@ -70,31 +73,45 @@ typedef struct joystickData_t {
//------------------------------------
//----- evaluatedJoystick class -----
//------------------------------------
class evaluatedJoystick {
public:
//--- constructor ---
evaluatedJoystick(joystick_config_t config_f);
class evaluatedJoystick
{
public:
//--- constructor ---
evaluatedJoystick(joystick_config_t config_f, nvs_handle_t * nvsHandle);
//--- functions ---
joystickData_t getData(); //read joystick, calculate values and return the data in a struct
void defineCenter(); //define joystick center from current position
//--- functions ---
joystickData_t getData(); // read joystick, calculate values and return the data in a struct
// get raw adc value (inversion applied)
int getRawX() { return readAdc(config.adc_x, config.x_inverted); }
int getRawY() { return readAdc(config.adc_y, config.y_inverted); }
void defineCenter(); // define joystick center from current position
void writeCalibration(joystickCalibrationMode_t mode, int newValue); // load certain new calibration value and store it in nvs
private:
//--- functions ---
//initialize adc inputs, define center
void init();
//read adc while making multiple samples with option to invert the result
int readAdc(adc1_channel_t adc_channel, bool inverted = false);
private:
//--- functions ---
// initialize adc inputs, define center
void init();
// loads selected calibration value from nvs or default values from config if no data stored
void loadCalibration(joystickCalibrationMode_t mode);
// read adc while making multiple samples with option to invert the result
int readAdc(adc1_channel_t adc_channel, bool inverted = false);
//--- variables ---
// handle for using the nvs flash (persistent config variables)
nvs_handle_t *nvsHandle;
joystick_config_t config;
int x_min;
int x_max;
int y_min;
int y_max;
int x_center;
int y_center;
joystickData_t data;
float x;
float y;
};
};