From 4eb1c5d43abe1896dab5a880684321a4df625e15 Mon Sep 17 00:00:00 2001 From: jonny_ji7 Date: Wed, 8 Jun 2022 19:50:17 +0200 Subject: [PATCH] Create class 'evaluatedJoystick' - Create class 'evaluatedJoystick' - evaluates a joystick with 2 analog signals - scales the adc input to coordinates with detailed tolerances - calculates angle and radius - defines an enum with position information - Add joystick configuration and class instance to config.cpp - Add code for testing the new class to main.cpp - Add joystick.cpp to cmakelists now function `joystick.getData` can be used globally to obtain a struct with current position data of the joystick --- main/CMakeLists.txt | 2 +- main/config.cpp | 36 ++++++++- main/config.hpp | 4 + main/joystick.cpp | 188 ++++++++++++++++++++++++++++++++++++++++++++ main/joystick.hpp | 101 ++++++++++++++++++++++++ main/main.cpp | 33 +++++--- 6 files changed, 349 insertions(+), 15 deletions(-) create mode 100644 main/joystick.cpp create mode 100644 main/joystick.hpp diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 5f23fe3..d218cfa 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,2 +1,2 @@ -idf_component_register(SRCS "main.cpp" "motordrivers.cpp" "motorctl.cpp" "config.cpp" +idf_component_register(SRCS "main.cpp" "motordrivers.cpp" "motorctl.cpp" "config.cpp" "joystick.cpp" INCLUDE_DIRS ".") diff --git a/main/config.cpp b/main/config.cpp index 186617d..c9cc667 100644 --- a/main/config.cpp +++ b/main/config.cpp @@ -1,6 +1,8 @@ #include "config.hpp" - +//----------------------------------- +//------- motor configuration ------- +//----------------------------------- //configure motor driver single100a_config_t configDriverLeft = { .gpio_pwm = GPIO_NUM_14, @@ -13,10 +15,40 @@ single100a_config_t configDriverLeft = { .pwmFreq = 10000 }; +//configure motor contol motorctl_config_t configControlLeft = { - .msFade = 5000, + .msFade = 3000, .currentMax = 10 }; //create controlled motor controlledMotor motorLeft(configDriverLeft, configControlLeft); + + + + +//-------------------------------------- +//------- joystick configuration ------- +//-------------------------------------- +joystick_config_t configJoystick = { + .adc_x = ADC1_CHANNEL_3, //GPIO39 + .adc_y = ADC1_CHANNEL_0, //GPIO36 + //range around center-threshold of each axis the coordinates stays at 0 (adc value 0-4095) + .tolerance_zero = 100, + //threshold the coordinate snaps to -1 or 1 before configured "_max" or "_min" threshold (mechanical end) is reached (adc value 0-4095) + .tolerance_end = 80, + //threshold the radius jumps to 1 before the stick is at max radius (range 0-1) + .tolerance_radius = 0.05, + + //min and max adc values of each axis + .x_min = 975, + .x_max = 2520, + .y_min = 1005, + .y_max = 2550, + //invert adc measurement + .x_inverted = true, + .y_inverted = true +}; + +//create global joystic instance +evaluatedJoystick joystick(configJoystick); diff --git a/main/config.hpp b/main/config.hpp index fdfaf5c..e5bc45b 100644 --- a/main/config.hpp +++ b/main/config.hpp @@ -2,6 +2,10 @@ #include "motordrivers.hpp" #include "motorctl.hpp" +#include "joystick.hpp" //create global controlledMotor instances for both motors extern controlledMotor motorLeft; + +//create global joystic instance +extern evaluatedJoystick joystick; diff --git a/main/joystick.cpp b/main/joystick.cpp new file mode 100644 index 0000000..4a112fa --- /dev/null +++ b/main/joystick.cpp @@ -0,0 +1,188 @@ +#include "joystick.hpp" + + +//definition of string array to be able to convert state enum to readable string +const char* joystickPosStr[7] = {"CENTER", "Y_AXIS", "X_AXIS", "TOP_RIGHT", "TOP_LEFT", "BOTTOM_LEFT", "BOTTOM_RIGHT"}; + +//tag for logging +static const char * TAG = "evaluatedJoystick"; + + + + +//----------------------------- +//-------- constructor -------- +//----------------------------- +//copy provided struct with all configuration and run init function +evaluatedJoystick::evaluatedJoystick(joystick_config_t config_f){ + config = config_f; + init(); +} + + + + +//---------------------------- +//---------- init ------------ +//---------------------------- +void evaluatedJoystick::init(){ + ESP_LOGI(TAG, "initializing joystick"); + //initialize adc + adc1_config_width(ADC_WIDTH_BIT_12); //=> max resolution 4096 + + //FIXME: the following two commands each throw error + //"ADC: adc1_lock_release(419): adc1 lock release called before acquire" + //note: also happens for each get_raw for first call of readAdc function + //when run in main function that does not happen + 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 + + //define joystick center from current position + defineCenter(); //define joystick center from current position +} + + + + +//----------------------------- +//--------- readAdc ----------- +//----------------------------- +//function for multisampling an anlog input +int evaluatedJoystick::readAdc(adc1_channel_t adc_channel, bool inverted) { + //make multiple measurements + int adc_reading = 0; + for (int i = 0; i < 16; i++) { + adc_reading += adc1_get_raw(adc_channel); + } + adc_reading = adc_reading / 16; + + //return original or inverted result + if (inverted) { + return adc_reading; + } else { + return 4095 - adc_reading; + } +} + + + + +//---------------------------- +//------ getCoordinate ------- +//---------------------------- +//function to read voltage at a gpio pin and scale it to a value from -1 to 1 using the given thresholds and tolerances +float evaluatedJoystick::getCoordinate(adc1_channel_t adc_channel, bool inverted, int min, int max, int center, int tolerance_zero, int tolerance_end) { + + float coordinate = 0; + + //read voltage from adc + int input = readAdc(adc_channel, inverted); + + //define coordinate value considering the different tolerances + //--- center --- + if ((input < center+tolerance_zero) && (input > center-tolerance_zero) ) { //adc value is inside tolerance around center threshold + coordinate = 0; + } + //--- maximum --- + else if (input > max-tolerance_end) { + coordinate = 1; + } + //--- minimum --- + else if (input < min+tolerance_end) { + coordinate = -1; + } + //--- positive area --- + else if (input > center) { + float range = max - center - tolerance_zero - tolerance_end; + coordinate = (input - center - tolerance_end) / range; + } + //--- negative area --- + else if (input < center) { + float range = (center - min - tolerance_zero - tolerance_end); + coordinate = -(center-input - tolerance_end) / range; + } + + ESP_LOGD(TAG, "coordinate=%.3f, input=%d/4095, isInverted=%d", coordinate, input, inverted); + //return coordinate (-1 to 1) + return coordinate; + +} + + + + +//------------------------------- +//---------- getData ------------ +//------------------------------- +//function that reads the joystick, calculates values and returns a struct with current data +joystickData_t evaluatedJoystick::getData() { + //get coordinates + //TODO individual tolerances for each axis? Otherwise some parameters can be removed + ESP_LOGD(TAG, "getting X coodrinate..."); + float x = getCoordinate(config.adc_x, config.x_inverted, config.x_min, config.x_max, x_center, config.tolerance_zero, config.tolerance_end); + data.x = x; + ESP_LOGD(TAG, "getting Y coodrinate..."); + float y = getCoordinate(config.adc_y, config.y_inverted, config.y_min, config.y_max, y_center, config.tolerance_zero, config.tolerance_end); + data.y = y; + + //calculate radius + data.radius = sqrt(pow(data.x,2) + pow(data.y,2)); + if (data.radius > 1-config.tolerance_radius) { + data.radius = 1; + } + + //calculate angle + data.angle = (atan(data.y/data.x) * 180) / 3.141; + + + //define position + //--- center --- + if((fabs(x) == 0) && (fabs(y) == 0)){ + data.position = joystickPos_t::CENTER; + } + //--- x axis --- + else if(fabs(y) == 0){ + data.position = joystickPos_t::X_AXIS; + } + //--- y axis --- + else if(fabs(x) == 0){ + data.position = joystickPos_t::Y_AXIS; + } + //--- top right --- + else if(x > 0 && y > 0){ + data.position = joystickPos_t::TOP_RIGHT; + } + //--- top left --- + else if(x < 0 && y > 0){ + data.position = joystickPos_t::TOP_LEFT; + } + //--- bottom left --- + else if(x < 0 && y < 0){ + data.position = joystickPos_t::BOTTOM_LEFT; + } + //--- bottom right --- + else if(x > 0 && y < 0){ + data.position = joystickPos_t::BOTTOM_RIGHT; + } + + + return data; +} + + + + +//---------------------------- +//------ defineCenter -------- +//---------------------------- +//function that defines the current position of the joystick as center position +void evaluatedJoystick::defineCenter(){ + //read voltage from adc + x_center = readAdc(config.adc_x, config.x_inverted); + y_center = readAdc(config.adc_y, config.y_inverted); + + ESP_LOGW(TAG, "defined center to x=%d, y=%d", x_center, y_center); +} + + + diff --git a/main/joystick.hpp b/main/joystick.hpp new file mode 100644 index 0000000..26c65ef --- /dev/null +++ b/main/joystick.hpp @@ -0,0 +1,101 @@ +#pragma once + +extern "C" +{ +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/gpio.h" +#include "driver/adc.h" +#include "esp_log.h" +#include "esp_err.h" +} + +#include + + +//====================================== +//========= evaluated Joystick ========= +//====================================== +//class which evaluates a joystick with 2 analog signals +// - scales the adc input to coordinates with detailed tolerances +// - calculates angle and radius +// - defines an enum with position information + + +//-------------------------------------------- +//---- struct, enum, variable deklarations --- +//-------------------------------------------- +//struct with all required configuration parameters +typedef struct joystick_config_t { + //analog inputs the axis are connected + adc1_channel_t adc_x; + adc1_channel_t adc_y; + + //range around center-threshold of each axis the coordinates stays at 0 (adc value 0-4095) + int tolerance_zero; + //threshold the coordinate snaps to -1 or 1 before configured "_max" or "_min" threshold (mechanical end) is reached (adc value 0-4095) + int tolerance_end; + //threshold the radius jumps to 1 before the stick is at max radius (range 0-1) + float tolerance_radius; + + //min and max adc values of each axis + int x_min; + int x_max; + int y_min; + int y_max; + + //invert adc measurement (e.g. when moving joystick up results in a decreasing voltage) + bool x_inverted; + bool y_inverted; +} joystick_config_t; + + + +//enum for describing the position of the joystick +enum class joystickPos_t {CENTER, Y_AXIS, X_AXIS, TOP_RIGHT, TOP_LEFT, BOTTOM_LEFT, BOTTOM_RIGHT}; +extern const char* joystickPosStr[7]; + + + +//struct with current data of the joystick +typedef struct joystickData_t { + joystickPos_t position; + float x; + float y; + float radius; + float angle; +} joystickData_t; + + + +//------------------------------------ +//----- evaluatedJoystick class ----- +//------------------------------------ +class evaluatedJoystick { + public: + //--- constructor --- + evaluatedJoystick(joystick_config_t config_f); + + //--- functions --- + joystickData_t getData(); //read joystick, calculate values and return the data in a struct + void defineCenter(); //define joystick center from current position + + 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); + //read input voltage and scale to value from -1 to 1 using the given thresholds and tolerances + float getCoordinate(adc1_channel_t adc_channel, bool inverted, int min, int max, int center, int tolerance_zero, int tolerance_end); + + //--- variables --- + joystick_config_t config; + int x_center; + int y_center; + + joystickData_t data; + float x; + float y; +}; + diff --git a/main/main.cpp b/main/main.cpp index ec19c3f..430baa1 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -51,7 +51,8 @@ extern "C" void app_main(void) { //set loglevel for individual tags: //esp_log_level_set("motordriver", ESP_LOG_DEBUG); - esp_log_level_set("motor-control", ESP_LOG_DEBUG); + //esp_log_level_set("motor-control", ESP_LOG_DEBUG); + esp_log_level_set("evaluatedJoystick", ESP_LOG_DEBUG); @@ -63,23 +64,31 @@ extern "C" void app_main(void) { while(1){ + vTaskDelay(100 / portTICK_PERIOD_MS); + + //--- testing joystick class --- + joystickData_t data = joystick.getData(); + ESP_LOGI(TAG, "position=%s, x=%.1f%%, y=%.1f%%, radius=%.1f%%, angle=%.2f", + joystickPosStr[(int)data.position], data.x*100, data.y*100, data.radius*100, data.angle); + //--- testing the motor driver --- //fade up duty - forward // for (int duty=0; duty<=100; duty+=5) { // motorLeft.setTarget(motorstate_t::FWD, duty); // vTaskDelay(100 / portTICK_PERIOD_MS); // } - // - //--- testing controlledMotor --- (ramp) - //brake for 1 s - motorLeft.setTarget(motorstate_t::BRAKE); - vTaskDelay(1000 / portTICK_PERIOD_MS); - //command 90% - reverse - motorLeft.setTarget(motorstate_t::REV, 90); - vTaskDelay(5000 / portTICK_PERIOD_MS); - //command 100% - forward - motorLeft.setTarget(motorstate_t::FWD, 100); - vTaskDelay(1000 / portTICK_PERIOD_MS); + + + //--- testing controlledMotor --- (ramp) + // //brake for 1 s + // motorLeft.setTarget(motorstate_t::BRAKE); + // vTaskDelay(1000 / portTICK_PERIOD_MS); + // //command 90% - reverse + // motorLeft.setTarget(motorstate_t::REV, 90); + // vTaskDelay(5000 / portTICK_PERIOD_MS); + // //command 100% - forward + // motorLeft.setTarget(motorstate_t::FWD, 100); + // vTaskDelay(1000 / portTICK_PERIOD_MS); }