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 ".") |                     INCLUDE_DIRS ".") | ||||||
|  | |||||||
| @ -1,6 +1,8 @@ | |||||||
| #include "config.hpp" | #include "config.hpp" | ||||||
| 
 | 
 | ||||||
| 
 | //-----------------------------------
 | ||||||
|  | //------- motor configuration -------
 | ||||||
|  | //-----------------------------------
 | ||||||
| //configure motor driver
 | //configure motor driver
 | ||||||
| single100a_config_t configDriverLeft = { | single100a_config_t configDriverLeft = { | ||||||
|     .gpio_pwm = GPIO_NUM_14, |     .gpio_pwm = GPIO_NUM_14, | ||||||
| @ -13,10 +15,40 @@ single100a_config_t configDriverLeft = { | |||||||
|     .pwmFreq = 10000 |     .pwmFreq = 10000 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | //configure motor contol
 | ||||||
| motorctl_config_t configControlLeft = { | motorctl_config_t configControlLeft = { | ||||||
|     .msFade = 5000, |     .msFade = 3000, | ||||||
|     .currentMax = 10 |     .currentMax = 10 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| //create controlled motor
 | //create controlled motor
 | ||||||
| controlledMotor motorLeft(configDriverLeft, configControlLeft); | 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 "motordrivers.hpp" | ||||||
| #include "motorctl.hpp" | #include "motorctl.hpp" | ||||||
|  | #include "joystick.hpp" | ||||||
| 
 | 
 | ||||||
| //create global controlledMotor instances for both motors
 | //create global controlledMotor instances for both motors
 | ||||||
| extern controlledMotor motorLeft; | 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:
 |     //set loglevel for individual tags:
 | ||||||
|     //esp_log_level_set("motordriver", ESP_LOG_DEBUG);
 |     //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){ |     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 ---
 |         //--- testing the motor driver ---
 | ||||||
|         //fade up duty - forward
 |         //fade up duty - forward
 | ||||||
|         //   for (int duty=0; duty<=100; duty+=5) {
 |         //   for (int duty=0; duty<=100; duty+=5) {
 | ||||||
|         //       motorLeft.setTarget(motorstate_t::FWD, duty);
 |         //       motorLeft.setTarget(motorstate_t::FWD, duty);
 | ||||||
|         //       vTaskDelay(100 / portTICK_PERIOD_MS);
 |         //       vTaskDelay(100 / portTICK_PERIOD_MS);
 | ||||||
|         //   }
 |         //   }
 | ||||||
|         //
 |          | ||||||
|         //--- testing controlledMotor --- (ramp)
 |          | ||||||
|         //brake for 1 s
 |        //--- testing controlledMotor --- (ramp)
 | ||||||
|         motorLeft.setTarget(motorstate_t::BRAKE); |        // //brake for 1 s
 | ||||||
|         vTaskDelay(1000 / portTICK_PERIOD_MS); |        // motorLeft.setTarget(motorstate_t::BRAKE);
 | ||||||
|         //command 90% - reverse
 |        // vTaskDelay(1000 / portTICK_PERIOD_MS);
 | ||||||
|         motorLeft.setTarget(motorstate_t::REV, 90); |        // //command 90% - reverse
 | ||||||
|         vTaskDelay(5000 / portTICK_PERIOD_MS); |        // motorLeft.setTarget(motorstate_t::REV, 90);
 | ||||||
|         //command 100% - forward
 |        // vTaskDelay(5000 / portTICK_PERIOD_MS);
 | ||||||
|         motorLeft.setTarget(motorstate_t::FWD, 100); |        // //command 100% - forward
 | ||||||
|         vTaskDelay(1000 / portTICK_PERIOD_MS); |        // motorLeft.setTarget(motorstate_t::FWD, 100);
 | ||||||
|  |        // vTaskDelay(1000 / portTICK_PERIOD_MS);
 | ||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user