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
This commit is contained in:
		
							parent
							
								
									84bfe211ac
								
							
						
					
					
						commit
						4eb1c5d43a
					
				| @ -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 ".") | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
							
								
								
									
										188
									
								
								main/joystick.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										188
									
								
								main/joystick.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -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); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										101
									
								
								main/joystick.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								main/joystick.hpp
									
									
									
									
									
										Normal file
									
								
							| @ -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 <cmath> | ||||
| 
 | ||||
| 
 | ||||
| //======================================
 | ||||
| //========= 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; | ||||
| }; | ||||
| 
 | ||||
| @ -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);
 | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user