Merge branch 'dev' - new wiring, currentlimit, deadtime, fixes
This commit is contained in:
		
						commit
						224ac47214
					
				| @ -22,8 +22,8 @@ extern "C" | ||||
| class gpio_evaluatedSwitch { | ||||
|     public: | ||||
|         //--- input ---
 | ||||
|         uint32_t minOnMs = 30; | ||||
|         uint32_t minOffMs = 30; | ||||
|         uint32_t minOnMs = 90; | ||||
|         uint32_t minOffMs = 60; | ||||
|         gpio_evaluatedSwitch( //constructor minimal (default parameters pullup=true, inverted=false)
 | ||||
|                 gpio_num_t gpio_num_declare | ||||
|                 ); | ||||
|  | ||||
										
											Binary file not shown.
										
									
								
							| @ -12,6 +12,7 @@ idf_component_register( | ||||
|         "wifi.c" | ||||
|         "http.cpp" | ||||
|         "auto.cpp" | ||||
| 		"currentsensor.cpp" | ||||
|     INCLUDE_DIRS  | ||||
|         "." | ||||
|     ) | ||||
|  | ||||
							
								
								
									
										121
									
								
								main/config.cpp
									
									
									
									
									
								
							
							
						
						
									
										121
									
								
								main/config.cpp
									
									
									
									
									
								
							| @ -1,48 +1,63 @@ | ||||
| #include "config.hpp" | ||||
| 
 | ||||
| //-----------------------------------
 | ||||
| //------- motor configuration -------
 | ||||
| //-----------------------------------
 | ||||
| //--- configure left motor ---
 | ||||
| //===================================
 | ||||
| //======= motor configuration =======
 | ||||
| //===================================
 | ||||
| //--- configure left motor (hardware) ---
 | ||||
| single100a_config_t configDriverLeft = { | ||||
|     .gpio_pwm = GPIO_NUM_26, | ||||
|     .gpio_a = GPIO_NUM_16, | ||||
|     .gpio_b = GPIO_NUM_4, | ||||
|     .ledc_timer = LEDC_TIMER_0, | ||||
|     .ledc_channel = LEDC_CHANNEL_0, | ||||
|     .abInverted = true, | ||||
| 	.aEnabledPinState = false, //-> pins inverted (mosfets)
 | ||||
| 	.bEnabledPinState = false, | ||||
|     .resolution = LEDC_TIMER_11_BIT, | ||||
|     .pwmFreq = 10000 | ||||
| }; | ||||
| 
 | ||||
| //--- configure right motor ---
 | ||||
| //--- configure right motor (hardware) ---
 | ||||
| single100a_config_t configDriverRight = { | ||||
|     .gpio_pwm = GPIO_NUM_27, | ||||
|     .gpio_a = GPIO_NUM_18, | ||||
|     .gpio_a = GPIO_NUM_2, | ||||
|     .gpio_b = GPIO_NUM_14, | ||||
|     .ledc_timer = LEDC_TIMER_1, | ||||
|     .ledc_channel = LEDC_CHANNEL_1, | ||||
|     .abInverted = false, | ||||
| 	.aEnabledPinState = false, //-> pin inverted (mosfet)
 | ||||
| 	.bEnabledPinState = true,  //-> not inverted (direct)
 | ||||
|     .resolution = LEDC_TIMER_11_BIT, | ||||
|     .pwmFreq = 10000 | ||||
| }; | ||||
| 
 | ||||
| //--- configure motor contol ---
 | ||||
| motorctl_config_t configMotorControl = { | ||||
|     .msFadeAccel = 1300, //acceleration of the motor (ms it takes from 0% to 100%)
 | ||||
|     .msFadeDecel = 700, //deceleration of the motor (ms it takes from 100% to 0%)
 | ||||
|     .currentMax = 10 | ||||
| 
 | ||||
| //TODO add motor name string -> then use as log tag?
 | ||||
| //--- configure left motor (contol) ---
 | ||||
| motorctl_config_t configMotorControlLeft = { | ||||
|     .msFadeAccel = 1900, //acceleration of the motor (ms it takes from 0% to 100%)
 | ||||
|     .msFadeDecel = 1000, //deceleration of the motor (ms it takes from 100% to 0%)
 | ||||
| 	.currentLimitEnabled = true, | ||||
| 	.currentSensor_adc =  ADC1_CHANNEL_6, //GPIO34
 | ||||
| 	.currentSensor_ratedCurrent = 50, | ||||
|     .currentMax = 30, | ||||
| 	.deadTimeMs = 900 //minimum time motor is off between direction change
 | ||||
| }; | ||||
| 
 | ||||
| //create controlled motor instances
 | ||||
| controlledMotor motorLeft(configDriverLeft, configMotorControl); | ||||
| controlledMotor motorRight(configDriverRight, configMotorControl); | ||||
| //--- configure right motor (contol) ---
 | ||||
| motorctl_config_t configMotorControlRight = { | ||||
|     .msFadeAccel = 1900, //acceleration of the motor (ms it takes from 0% to 100%)
 | ||||
|     .msFadeDecel = 1000, //deceleration of the motor (ms it takes from 100% to 0%)
 | ||||
| 	.currentLimitEnabled = true, | ||||
| 	.currentSensor_adc =  ADC1_CHANNEL_4, //GPIO32
 | ||||
| 	.currentSensor_ratedCurrent = 50, | ||||
|     .currentMax = 30, | ||||
| 	.deadTimeMs = 900 //minimum time motor is off between direction change
 | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| //------------------------------
 | ||||
| //------- control config -------
 | ||||
| //------------------------------
 | ||||
| //==============================
 | ||||
| //======= control config =======
 | ||||
| //==============================
 | ||||
| control_config_t configControl = { | ||||
|     .defaultMode = controlMode_t::JOYSTICK, //default mode after startup and toggling IDLE
 | ||||
|     //--- timeout ---    
 | ||||
| @ -54,9 +69,9 @@ control_config_t configControl = { | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| //-------------------------------
 | ||||
| //----- httpJoystick config -----
 | ||||
| //-------------------------------
 | ||||
| //===============================
 | ||||
| //===== httpJoystick config =====
 | ||||
| //===============================
 | ||||
| httpJoystick_config_t configHttpJoystickMain{ | ||||
|     .toleranceZeroX_Per = 1,  //percentage around joystick axis the coordinate snaps to 0
 | ||||
|     .toleranceZeroY_Per = 6, | ||||
| @ -66,25 +81,25 @@ httpJoystick_config_t configHttpJoystickMain{ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| //--------------------------------------
 | ||||
| //------- joystick configuration -------
 | ||||
| //--------------------------------------
 | ||||
| //======================================
 | ||||
| //======= joystick configuration =======
 | ||||
| //======================================
 | ||||
| joystick_config_t configJoystick = { | ||||
|     .adc_x = ADC1_CHANNEL_3, //GPIO39
 | ||||
|     .adc_y = ADC1_CHANNEL_0, //GPIO36
 | ||||
|     //percentage of joystick range the coordinate of the axis snaps to 0 (0-100)
 | ||||
|     .tolerance_zeroX_per = 3, | ||||
|     .tolerance_zeroY_per = 7, | ||||
|     .tolerance_zeroX_per = 7, //6
 | ||||
|     .tolerance_zeroY_per = 10, //7
 | ||||
|     //percentage of joystick range the coordinate snaps to -1 or 1 before configured "_max" or "_min" threshold (mechanical end) is reached (0-100)
 | ||||
|     .tolerance_end_per = 5,  | ||||
|     .tolerance_end_per = 4,  | ||||
|     //threshold the radius jumps to 1 before the stick is at max radius (range 0-1)
 | ||||
|     .tolerance_radius = 0.05, | ||||
|     .tolerance_radius = 0.09, | ||||
| 
 | ||||
|     //min and max adc values of each axis (after inversion is applied)
 | ||||
|     .x_min = 1230, //=> x=-1
 | ||||
|     .x_max = 2700, //=> x=1
 | ||||
|     .y_min = 1260, //=> y=-1
 | ||||
|     .y_max = 2700, //=> y=1
 | ||||
|     //min and max adc values of each axis, !!!AFTER INVERSION!!! is applied:
 | ||||
|     .x_min = 1392, //=> x=-1
 | ||||
|     .x_max = 2650, //=> x=1
 | ||||
|     .y_min = 1390, //=> y=-1
 | ||||
|     .y_max = 2640, //=> y=1
 | ||||
|     //invert adc measurement
 | ||||
|     .x_inverted = true, | ||||
|     .y_inverted = true | ||||
| @ -92,41 +107,45 @@ joystick_config_t configJoystick = { | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| //----------------------------
 | ||||
| //--- configure fan contol ---
 | ||||
| //----------------------------
 | ||||
| fan_config_t configFanLeft = { | ||||
|     .gpio_fan = GPIO_NUM_2, | ||||
|     .msRun = 5000, | ||||
|     .dutyThreshold = 35 | ||||
| }; | ||||
| fan_config_t configFanRight = { | ||||
|     .gpio_fan = GPIO_NUM_15, | ||||
|     .msRun = 5000, | ||||
|     .dutyThreshold = 35 | ||||
| //============================
 | ||||
| //=== configure fan contol ===
 | ||||
| //============================
 | ||||
| fan_config_t configCooling = { | ||||
|     .gpio_fan = GPIO_NUM_13, | ||||
|     .dutyThreshold = 40, | ||||
| 	.minOnMs = 1500, | ||||
| 	.minOffMs = 3000, | ||||
| 	.turnOffDelayMs = 5000, | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| //=================================
 | ||||
| //===== create global objects =====
 | ||||
| //=================================
 | ||||
| //create global joystic instance
 | ||||
| //TODO outsource global variables to e.g. global.cpp and only config options here?
 | ||||
| 
 | ||||
| //create controlled motor instances (motorctl.hpp)
 | ||||
| controlledMotor motorLeft(configDriverLeft, configMotorControlLeft); | ||||
| controlledMotor motorRight(configDriverRight, configMotorControlRight); | ||||
| 
 | ||||
| //create global joystic instance (joystick.hpp)
 | ||||
| evaluatedJoystick joystick(configJoystick); | ||||
| 
 | ||||
| //create global evaluated switch instance for button next to joystick
 | ||||
| gpio_evaluatedSwitch buttonJoystick(GPIO_NUM_33, true, false); //pullup true, not inverted (switch to GND use pullup of controller)
 | ||||
| gpio_evaluatedSwitch buttonJoystick(GPIO_NUM_25, true, false); //pullup true, not inverted (switch to GND use pullup of controller)
 | ||||
|                                                                 | ||||
| //create buzzer object on pin 12 with gap between queued events of 100ms 
 | ||||
| buzzer_t buzzer(GPIO_NUM_12, 100); | ||||
| 
 | ||||
| //create global httpJoystick object
 | ||||
| //create global httpJoystick object (http.hpp)
 | ||||
| httpJoystick httpJoystickMain(configHttpJoystickMain); | ||||
| 
 | ||||
| //create global control object
 | ||||
| //create global control object (control.hpp)
 | ||||
| controlledArmchair control(configControl, &buzzer, &motorLeft, &motorRight, &joystick, &httpJoystickMain); | ||||
| 
 | ||||
| //create global automatedArmchair object (for auto-mode)
 | ||||
| //create global automatedArmchair object (for auto-mode) (auto.hpp)
 | ||||
| automatedArmchair armchair; | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -17,6 +17,8 @@ | ||||
| //#define JOYSTICK_LOG_IN_IDLE
 | ||||
| 
 | ||||
| 
 | ||||
| //TODO outsource global variables to e.g. global.cpp and only config options here?
 | ||||
| 
 | ||||
| //create global controlledMotor instances for both motors
 | ||||
| extern controlledMotor motorLeft; | ||||
| extern controlledMotor motorRight; | ||||
| @ -39,7 +41,6 @@ extern automatedArmchair armchair; | ||||
| //create global httpJoystick object
 | ||||
| extern httpJoystick httpJoystickMain; | ||||
| 
 | ||||
| //configuration for fans
 | ||||
| extern fan_config_t configFanLeft; | ||||
| extern fan_config_t configFanRight; | ||||
| //configuration for fans / cooling
 | ||||
| extern fan_config_t configCooling; | ||||
| 
 | ||||
|  | ||||
| @ -5,7 +5,6 @@ extern "C" | ||||
| #include "esp_log.h" | ||||
| #include "freertos/queue.h" | ||||
| 
 | ||||
| 
 | ||||
| //custom C libraries
 | ||||
| #include "wifi.h" | ||||
| } | ||||
| @ -20,9 +19,9 @@ extern "C" | ||||
| 
 | ||||
| //tag for logging
 | ||||
| static const char * TAG = "control"; | ||||
| 
 | ||||
| const char* controlModeStr[7] = {"IDLE", "JOYSTICK", "MASSAGE", "HTTP", "MQTT", "BLUETOOTH", "AUTO"}; | ||||
| 
 | ||||
| 
 | ||||
| //-----------------------------
 | ||||
| //-------- constructor --------
 | ||||
| //-----------------------------
 | ||||
| @ -55,9 +54,9 @@ controlledArmchair::controlledArmchair ( | ||||
| //---------- Handle loop -----------
 | ||||
| //----------------------------------
 | ||||
| //function that repeatedly generates motor commands depending on the current mode
 | ||||
| //also handles fading and current-limit
 | ||||
| void controlledArmchair::startHandleLoop() { | ||||
|     while (1){ | ||||
| 
 | ||||
|         ESP_LOGV(TAG, "control task executing... mode=%s", controlModeStr[(int)mode]); | ||||
| 
 | ||||
|         switch(mode) { | ||||
| @ -65,7 +64,6 @@ void controlledArmchair::startHandleLoop() { | ||||
|                 mode = controlMode_t::IDLE; | ||||
|                 break; | ||||
| 
 | ||||
| 
 | ||||
|             case controlMode_t::IDLE: | ||||
|                 //copy preset commands for idling both motors
 | ||||
|                 commands = cmds_bothMotorsIdle; | ||||
| @ -77,7 +75,6 @@ void controlledArmchair::startHandleLoop() { | ||||
| 				//since loglevel is DEBUG, calculateion details is output
 | ||||
|                 joystick_l->getData(); //get joystick data here
 | ||||
| #endif | ||||
| 
 | ||||
|                 break; | ||||
| 
 | ||||
| 
 | ||||
| @ -109,7 +106,6 @@ void controlledArmchair::startHandleLoop() { | ||||
|                 //apply motor commands
 | ||||
|                 motorRight->setTarget(commands.right.state, commands.right.duty);  | ||||
|                 motorLeft->setTarget(commands.left.state, commands.left.duty);  | ||||
| 
 | ||||
|                 break; | ||||
| 
 | ||||
| 
 | ||||
| @ -173,11 +169,12 @@ void controlledArmchair::startHandleLoop() { | ||||
|                break; | ||||
| 
 | ||||
| 
 | ||||
|               //  //TODO: add other modes here
 | ||||
|               //TODO: add other modes here
 | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         //--- run actions based on received button button event ---
 | ||||
| 		//note: buttonCount received by sendButtonEvent method called from button.cpp
 | ||||
|         //TODO: what if variable gets set from other task during this code? -> mutex around this code
 | ||||
|         switch (buttonCount) { | ||||
|             case 1: //define joystick center or freeze input
 | ||||
| @ -385,7 +382,6 @@ void controlledArmchair::changeMode(controlMode_t modeNew) { | ||||
| #ifdef JOYSTICK_LOG_IN_IDLE | ||||
| 			esp_log_level_set("evaluatedJoystick", ESP_LOG_DEBUG); | ||||
| #endif | ||||
| 
 | ||||
| 			break; | ||||
| 
 | ||||
|         case controlMode_t::HTTP: | ||||
| @ -428,6 +424,7 @@ void controlledArmchair::changeMode(controlMode_t modeNew) { | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| //TODO simplify the following 3 functions? can be replaced by one?
 | ||||
| 
 | ||||
| //-----------------------------------
 | ||||
| //----------- toggleIdle ------------
 | ||||
| @ -445,7 +442,6 @@ void controlledArmchair::toggleIdle() { | ||||
| //------------------------------------
 | ||||
| //function to toggle between two modes, but prefer first argument if entirely different mode is currently active
 | ||||
| void controlledArmchair::toggleModes(controlMode_t modePrimary, controlMode_t modeSecondary) { | ||||
| 
 | ||||
|     //switch to secondary mode when primary is already active
 | ||||
|     if (mode == modePrimary){ | ||||
|         ESP_LOGW(TAG, "toggleModes: switching from primaryMode %s to secondarMode %s", controlModeStr[(int)mode], controlModeStr[(int)modeSecondary]); | ||||
|  | ||||
| @ -15,10 +15,11 @@ enum class controlMode_t {IDLE, JOYSTICK, MASSAGE, HTTP, MQTT, BLUETOOTH, AUTO}; | ||||
| //string array representing the mode enum (for printing the state as string)
 | ||||
| extern const char* controlModeStr[7]; | ||||
| 
 | ||||
| //--- control_config_t ---
 | ||||
| //struct with config parameters
 | ||||
| typedef struct control_config_t { | ||||
|     controlMode_t defaultMode;  //default mode after startup and toggling IDLE
 | ||||
|     //--- timeout ---
 | ||||
|     //timeout options
 | ||||
|     uint32_t timeoutMs;         //time of inactivity after which the mode gets switched to IDLE
 | ||||
|     float timeoutTolerancePer;  //percentage the duty can vary between timeout checks considered still inactive
 | ||||
| } control_config_t; | ||||
| @ -55,6 +56,7 @@ class controlledArmchair { | ||||
| 
 | ||||
|         //function that toggles between two modes, but prefers first argument if entirely different mode is currently active
 | ||||
|         void toggleModes(controlMode_t modePrimary, controlMode_t modeSecondary); | ||||
| 
 | ||||
|         //toggle between certain mode and previous mode
 | ||||
|         void toggleMode(controlMode_t modePrimary); | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										75
									
								
								main/currentsensor.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								main/currentsensor.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,75 @@ | ||||
| extern "C" { | ||||
| #include "hal/timer_types.h" | ||||
| #include "esp_log.h" | ||||
| } | ||||
| 
 | ||||
| #include "currentsensor.hpp" | ||||
| 
 | ||||
| //tag for logging
 | ||||
| static const char * TAG = "current-sensors"; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| //--------------------------
 | ||||
| //------- getVoltage -------
 | ||||
| //--------------------------
 | ||||
| //local function to get average voltage from adc
 | ||||
| float getVoltage(adc1_channel_t adc, uint32_t samples){ | ||||
| 	//measure voltage
 | ||||
| 	int measure = 0; | ||||
| 	for (int j=0; j<samples; j++){ | ||||
| 		measure += adc1_get_raw(adc); | ||||
| 		ets_delay_us(50); | ||||
| 	} | ||||
| 	return (float)measure / samples / 4096 * 3.3; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| //=============================
 | ||||
| //======== constructor ========
 | ||||
| //=============================
 | ||||
| currentSensor::currentSensor (adc1_channel_t adcChannel_f, float ratedCurrent_f){ | ||||
| 	//copy config
 | ||||
| 	adcChannel = adcChannel_f; | ||||
| 	ratedCurrent = ratedCurrent_f; | ||||
| 	//init adc
 | ||||
| 	adc1_config_width(ADC_WIDTH_BIT_12); //max resolution 4096
 | ||||
| 	adc1_config_channel_atten(adcChannel, ADC_ATTEN_DB_11); //max voltage
 | ||||
| 	//calibrate
 | ||||
| 	calibrateZeroAmpere(); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| //============================
 | ||||
| //=========== read ===========
 | ||||
| //============================
 | ||||
| float currentSensor::read(void){ | ||||
| 	//measure voltage
 | ||||
| 	voltage = getVoltage(adcChannel, 30); | ||||
| 
 | ||||
| 	//scale voltage to current
 | ||||
| 	if (voltage < centerVoltage){ | ||||
| 		current = (1 - voltage / centerVoltage) * -ratedCurrent; | ||||
| 	} else if (voltage > centerVoltage){ | ||||
| 		current = (voltage - centerVoltage) / (3.3 - centerVoltage) * ratedCurrent; | ||||
| 	}else { | ||||
| 		current = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	ESP_LOGI(TAG, "read sensor adc=%d: voltage=%.3fV, centerVoltage=%.3fV => current=%.3fA", (int)adcChannel, voltage, centerVoltage, current); | ||||
| 	return current; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| //===============================
 | ||||
| //===== calibrateZeroAmpere =====
 | ||||
| //===============================
 | ||||
| void currentSensor::calibrateZeroAmpere(void){ | ||||
| 	//measure voltage
 | ||||
| 	float prev = centerVoltage; | ||||
| 	centerVoltage = getVoltage(adcChannel, 100); | ||||
| 	ESP_LOGW(TAG, "defined centerVoltage (0A) to %.3f (previous %.3f)", centerVoltage, prev); | ||||
| } | ||||
							
								
								
									
										20
									
								
								main/currentsensor.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								main/currentsensor.hpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | ||||
| #include <driver/adc.h> | ||||
| 
 | ||||
| //supported current sensor working method:
 | ||||
|   //0V = -ratedCurrent  
 | ||||
|   //centerVoltage = 0A
 | ||||
|   //3.3V = ratedCurrent
 | ||||
| 
 | ||||
| class currentSensor{ | ||||
| 	public: | ||||
| 		currentSensor (adc1_channel_t adcChannel_f, float ratedCurrent); | ||||
| 		void calibrateZeroAmpere(void); //set current voltage to voltage representing 0A
 | ||||
| 		float read(void); //get current ampere
 | ||||
| 	private: | ||||
| 		adc1_channel_t adcChannel; | ||||
| 		float ratedCurrent; | ||||
| 		uint32_t measure; | ||||
| 		float voltage; | ||||
| 		float current; | ||||
| 		float centerVoltage = 3.3/2; | ||||
| }; | ||||
							
								
								
									
										65
									
								
								main/fan.cpp
									
									
									
									
									
								
							
							
						
						
									
										65
									
								
								main/fan.cpp
									
									
									
									
									
								
							| @ -15,12 +15,12 @@ static const char * TAG = "fan-control"; | ||||
| //-----------------------------
 | ||||
| //-------- constructor --------
 | ||||
| //-----------------------------
 | ||||
| controlledFan::controlledFan(fan_config_t config_f, controlledMotor* motor_f ){ | ||||
| controlledFan::controlledFan (fan_config_t config_f, controlledMotor* motor1_f, controlledMotor* motor2_f ){ | ||||
| 	//copy config
 | ||||
| 	config = config_f; | ||||
|     //copy pointer to motor object
 | ||||
|     motor = motor_f; | ||||
| 
 | ||||
| 	//copy pointer to motor objects
 | ||||
| 	motor1 = motor1_f; | ||||
| 	motor2 = motor2_f; | ||||
| 	//initialize gpio pin
 | ||||
| 	gpio_pad_select_gpio(config.gpio_fan); | ||||
| 	gpio_set_direction(config.gpio_fan, GPIO_MODE_OUTPUT); | ||||
| @ -32,25 +32,50 @@ controlledFan::controlledFan(fan_config_t config_f, controlledMotor* motor_f ){ | ||||
| //--------- handle ---------
 | ||||
| //--------------------------
 | ||||
| void controlledFan::handle(){ | ||||
|     //get current state of the motor
 | ||||
|     motorStatus = motor->getStatus(); | ||||
| 	//get current state of the motor (motorctl.cpp)
 | ||||
| 	motor1Status = motor1->getStatus(); | ||||
| 	motor2Status = motor2->getStatus(); | ||||
| 
 | ||||
| 	//--- handle duty threshold ---
 | ||||
| 	//update timestamp if any threshold exceeded
 | ||||
| 	if (motor1Status.duty > config.dutyThreshold | ||||
| 			|| motor2Status.duty > config.dutyThreshold){ //TODO add temperature threshold
 | ||||
| 		if (!needsCooling){ | ||||
| 			timestamp_needsCoolingSet = esp_log_timestamp(); | ||||
| 			needsCooling = true; | ||||
| 		} | ||||
| 		timestamp_lastThreshold = esp_log_timestamp(); | ||||
| 	} else { | ||||
| 		needsCooling = false; | ||||
| 	} | ||||
| 
 | ||||
| 	//--- turn off condition ---
 | ||||
| 	if (fanRunning | ||||
| 			&& !needsCooling //no more cooling required
 | ||||
| 			&& (motor1Status.duty == 0) && (motor2Status.duty == 0) //both motors are off 
 | ||||
| 			   //-> keeps fans running even when lower than threshold already, however turnOffDelay already started TODO: start turn off delay after motor stop only?
 | ||||
| 			&& (esp_log_timestamp() - timestamp_lastThreshold) > config.turnOffDelayMs){ //turn off delay passed
 | ||||
| 		fanRunning = false; | ||||
| 		gpio_set_level(config.gpio_fan, 0);         | ||||
| 		timestamp_turnedOff = esp_log_timestamp(); | ||||
| 		ESP_LOGI(TAG, "turned fan OFF gpio=%d, minOnMs=%d, WasOnMs=%d", (int)config.gpio_fan, config.minOnMs, esp_log_timestamp()-timestamp_turnedOn); | ||||
| 	} | ||||
| 
 | ||||
| 	//--- turn on condition ---
 | ||||
| 	if (!fanRunning | ||||
| 			&& needsCooling | ||||
| 			&& ((esp_log_timestamp() - timestamp_turnedOff) > config.minOffMs) //fans off long enough
 | ||||
| 			&& ((esp_log_timestamp() - timestamp_needsCoolingSet) > config.minOnMs)){ //motors on long enough
 | ||||
| 		fanRunning = true; | ||||
| 		gpio_set_level(config.gpio_fan, 1);         | ||||
| 		timestamp_turnedOn = esp_log_timestamp(); | ||||
| 		ESP_LOGI(TAG, "turned fan ON gpio=%d, minOffMs=%d,  WasOffMs=%d", (int)config.gpio_fan, config.minOffMs, esp_log_timestamp()-timestamp_turnedOff); | ||||
| 	} | ||||
| 
 | ||||
| 	//TODO Add statemachine for more specific control? Exponential average?
 | ||||
|     //update timestamp if threshold exceeded
 | ||||
|     if (motorStatus.duty > config.dutyThreshold){ | ||||
|         timestamp_lastThreshold = esp_log_timestamp(); | ||||
|     } | ||||
| 	//TODO idea: try other aproach? increment a variable with certain weights e.g. integrate over duty, then turn fans on and decrement the variable again
 | ||||
| 	 | ||||
|     //turn fan on if time since last exceeded threshold is less than msRun
 | ||||
|     if (esp_log_timestamp() - timestamp_lastThreshold < config.msRun) { | ||||
|         gpio_set_level(config.gpio_fan, 1);         | ||||
|         ESP_LOGD(TAG, "fan is on (gpio: %d)", (int)config.gpio_fan); | ||||
|     } | ||||
|     //otherwise turn fan off
 | ||||
|     else { | ||||
|         gpio_set_level(config.gpio_fan, 0);         | ||||
|         ESP_LOGD(TAG, "fan is off (gpio: %d)", (int)config.gpio_fan); | ||||
|     } | ||||
| 	ESP_LOGD(TAG, "fanState=%d, duty1=%f, duty2=%f, needsCooling=%d", fanRunning, motor1Status.duty, motor2Status.duty, needsCooling); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										23
									
								
								main/fan.hpp
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								main/fan.hpp
									
									
									
									
									
								
							| @ -8,12 +8,14 @@ extern "C" | ||||
| #include "motorctl.hpp" | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| //--- fan_config_t ---
 | ||||
| //struct with all config parameters for a fan
 | ||||
| typedef struct fan_config_t { | ||||
|     gpio_num_t gpio_fan; | ||||
|     uint32_t msRun; | ||||
|     float dutyThreshold; | ||||
| 	uint32_t minOnMs; | ||||
| 	uint32_t minOffMs; | ||||
| 	uint32_t turnOffDelayMs; | ||||
| } fan_config; | ||||
| 
 | ||||
| 
 | ||||
| @ -24,17 +26,24 @@ typedef struct fan_config_t { | ||||
| class controlledFan { | ||||
|     public: | ||||
|         //--- constructor ---
 | ||||
|         controlledFan (fan_config_t config_f, controlledMotor* motor_f ); | ||||
|         controlledFan (fan_config_t config_f, controlledMotor* motor1_f, controlledMotor* motor2_f ); | ||||
| 
 | ||||
|         //--- functions ---
 | ||||
|         void handle(); | ||||
|         void handle(); //has to be run repeatedly in a slow loop
 | ||||
| 
 | ||||
| 
 | ||||
|     private: | ||||
|         //--- variables ---
 | ||||
|         uint32_t timestamp_lastThreshold; | ||||
| 		bool fanRunning = false; | ||||
| 		bool needsCooling = false; | ||||
| 		uint32_t timestamp_needsCoolingSet; | ||||
|         uint32_t timestamp_lastThreshold = 0; | ||||
| 		uint32_t timestamp_turnedOn = 0; | ||||
| 		uint32_t timestamp_turnedOff = 0; | ||||
|         fan_config_t config; | ||||
|         controlledMotor * motor; | ||||
|         controlledMotor * motor1; | ||||
|         controlledMotor * motor2; | ||||
| 
 | ||||
|         motorCommand_t motorStatus; | ||||
|         motorCommand_t motor1Status; | ||||
|         motorCommand_t motor2Status; | ||||
| }; | ||||
|  | ||||
| @ -22,12 +22,10 @@ static httpd_handle_t server = NULL; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| //joystickData_t http_readFromJoystickQueue
 | ||||
| 
 | ||||
| 
 | ||||
| //==============================
 | ||||
| //===== start mdns service =====
 | ||||
| //==============================
 | ||||
| //TODO: test this, not working?
 | ||||
| //function that initializes and starts mdns server for host discovery
 | ||||
| void start_mdns_service() | ||||
| { | ||||
| @ -39,7 +37,6 @@ void start_mdns_service() | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| //===========================
 | ||||
| //======= default url =======
 | ||||
| //===========================
 | ||||
| @ -96,7 +93,6 @@ static esp_err_t on_default_url(httpd_req_t *req) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| //==============================
 | ||||
| //===== httpJoystick class =====
 | ||||
| //==============================
 | ||||
| @ -106,8 +102,6 @@ static esp_err_t on_default_url(httpd_req_t *req) | ||||
| httpJoystick::httpJoystick( httpJoystick_config_t config_f ){ | ||||
|     //copy config struct
 | ||||
|     config = config_f; | ||||
|     //initialize queue for joystick data
 | ||||
|     QueueHandle_t joystickDataQueue = xQueueCreate( 1, sizeof( struct joystickData_t ) ); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @ -207,7 +201,6 @@ joystickData_t httpJoystick::getData(){ | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| //--------------------------------------------
 | ||||
| //--- receiveHttpData for httpJoystickMain ---
 | ||||
| //--------------------------------------------
 | ||||
| @ -223,7 +216,6 @@ esp_err_t on_joystick_url(httpd_req_t *req){ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| //============================
 | ||||
| //===== init http server =====
 | ||||
| //============================
 | ||||
| @ -231,30 +223,28 @@ esp_err_t on_joystick_url(httpd_req_t *req){ | ||||
| void http_init_server() | ||||
| { | ||||
| 
 | ||||
|     //configure webserver
 | ||||
|   //---- configure webserver ----
 | ||||
|   httpd_config_t config = HTTPD_DEFAULT_CONFIG(); | ||||
|   config.uri_match_fn = httpd_uri_match_wildcard; | ||||
| 
 | ||||
|   //start webserver
 | ||||
|   //---- start webserver ----
 | ||||
|   ESP_ERROR_CHECK(httpd_start(&server, &config)); | ||||
| 
 | ||||
| 
 | ||||
|   //---------------------------
 | ||||
|   //------- define URLs -------
 | ||||
|   //---------------------------
 | ||||
|   httpd_uri_t joystick_url = { | ||||
|       .uri = "/api/joystick", | ||||
|       .method = HTTP_POST, | ||||
|       .handler = on_joystick_url, | ||||
|       }; | ||||
|   //----- define URLs -----
 | ||||
|   httpd_uri_t joystick_url; | ||||
|   joystick_url.uri = "/api/joystick"; | ||||
|   joystick_url.method = HTTP_POST; | ||||
|   joystick_url.handler = on_joystick_url; | ||||
|   httpd_register_uri_handler(server, &joystick_url); | ||||
| 
 | ||||
|   httpd_uri_t default_url = { | ||||
|       .uri = "/*", | ||||
|       .method = HTTP_GET, | ||||
|       .handler = on_default_url}; | ||||
|   httpd_uri_t default_url; | ||||
|   default_url.uri = "/*"; | ||||
|   default_url.method = HTTP_GET; | ||||
|   default_url.handler = on_default_url; | ||||
|   httpd_register_uri_handler(server, &default_url); | ||||
| 
 | ||||
|   //previous approach with sockets:
 | ||||
|     //  httpd_uri_t socket_joystick_url = {
 | ||||
|     //      .uri = "/ws-api/joystick",
 | ||||
|     //      .method = HTTP_GET,
 | ||||
|  | ||||
| @ -9,7 +9,6 @@ extern "C" | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| //============================
 | ||||
| //===== init http server =====
 | ||||
| //============================
 | ||||
|  | ||||
| @ -1,3 +1,7 @@ | ||||
| extern "C" { | ||||
| #include "hal/timer_types.h" | ||||
| } | ||||
| 
 | ||||
| #include "joystick.hpp" | ||||
| 
 | ||||
| 
 | ||||
| @ -22,7 +26,6 @@ evaluatedJoystick::evaluatedJoystick(joystick_config_t config_f){ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| //----------------------------
 | ||||
| //---------- init ------------
 | ||||
| //----------------------------
 | ||||
| @ -34,7 +37,7 @@ void evaluatedJoystick::init(){ | ||||
|     //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
 | ||||
|     //when run in main function that does not happen -> move init from constructor to be called in main
 | ||||
|     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
 | ||||
| 
 | ||||
| @ -44,7 +47,6 @@ void evaluatedJoystick::init(){ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| //-----------------------------
 | ||||
| //--------- readAdc -----------
 | ||||
| //-----------------------------
 | ||||
| @ -54,6 +56,7 @@ int evaluatedJoystick::readAdc(adc1_channel_t adc_channel, bool inverted) { | ||||
|     int adc_reading = 0; | ||||
|     for (int i = 0; i < 16; i++) { | ||||
|         adc_reading += adc1_get_raw(adc_channel); | ||||
| 		ets_delay_us(50); | ||||
|     } | ||||
|     adc_reading = adc_reading / 16; | ||||
| 
 | ||||
| @ -67,7 +70,6 @@ int evaluatedJoystick::readAdc(adc1_channel_t adc_channel, bool inverted) { | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| //-------------------------------
 | ||||
| //---------- getData ------------
 | ||||
| //-------------------------------
 | ||||
| @ -75,7 +77,8 @@ int evaluatedJoystick::readAdc(adc1_channel_t adc_channel, bool inverted) { | ||||
| joystickData_t evaluatedJoystick::getData() { | ||||
|     //get coordinates
 | ||||
|     //TODO individual tolerances for each axis? Otherwise some parameters can be removed
 | ||||
|     ESP_LOGV(TAG, "getting X coodrinate..."); | ||||
| 	//TODO duplicate code for each axis below:
 | ||||
|     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); | ||||
| @ -83,7 +86,6 @@ joystickData_t evaluatedJoystick::getData() { | ||||
| 	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); | ||||
| 
 | ||||
| 
 | ||||
|     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); | ||||
| @ -103,12 +105,12 @@ joystickData_t evaluatedJoystick::getData() { | ||||
|     //define position
 | ||||
|     data.position = joystick_evaluatePosition(x, y); | ||||
| 
 | ||||
| 	ESP_LOGD(TAG, "X=%.2f  Y=%.2f  radius=%.2f  angle=%.2f", data.x, data.y, data.radius, data.angle); | ||||
|     return data; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| //----------------------------
 | ||||
| //------ defineCenter --------
 | ||||
| //----------------------------
 | ||||
| @ -124,8 +126,6 @@ void evaluatedJoystick::defineCenter(){ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| //==============================
 | ||||
| //====== scaleCoordinate =======
 | ||||
| //==============================
 | ||||
| @ -162,10 +162,9 @@ float scaleCoordinate(float input, float min, float max, float center, float tol | ||||
|         coordinate = -(center-input - tolerance_zero) / range; | ||||
|     } | ||||
| 
 | ||||
|     ESP_LOGD(TAG, "scaled coordinate from %.3f to %.3f, tolZero=%.3f, tolEnd=%.3f", input, coordinate, tolerance_zero, tolerance_end); | ||||
|     ESP_LOGD(TAG, "scaling: in=%.3f coordinate=%.3f, tolZero=%.3f, tolEnd=%.3f", input, coordinate, tolerance_zero, tolerance_end); | ||||
|     //return coordinate (-1 to 1)
 | ||||
|     return coordinate; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @ -222,17 +221,29 @@ float scaleLinPoint(float value, float pointX, float pointY){ | ||||
|         return -result; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| //function that updates a joystickData object with linear scaling applied to coordinates
 | ||||
| //e.g. use to use more joystick resolution for lower speeds
 | ||||
| //TODO rename this function to more general name (scales not only coordinates e.g. adjusts radius, in future angle...)
 | ||||
| void joystick_scaleCoordinatesLinear(joystickData_t * data, float pointX, float pointY){ | ||||
|     //scale x and y coordinate
 | ||||
|     // --- scale x and y coordinate --- DISABLED
 | ||||
| 	/*
 | ||||
|     data->x = scaleLinPoint(data->x, pointX, pointY); | ||||
|     data->y = scaleLinPoint(data->y, pointX, pointY); | ||||
|     //re-calculate radius
 | ||||
|     data->radius = sqrt(pow(data->x,2) + pow(data->y,2)); | ||||
|     if (data->radius > 1-0.07) {//FIXME hardcoded radius tolerance
 | ||||
|     if (data->radius > 1-0.1) {//FIXME hardcoded radius tolerance
 | ||||
|         data->radius = 1; | ||||
|     } | ||||
| 	*/ | ||||
| 	 | ||||
| 	//note: issue with scaling X, Y coordinates:
 | ||||
| 	//  - messed up radius calculation - radius never gets 1 at diagonal positions
 | ||||
| 	//==> only scaling radius as only speed should be more acurate at low radius:
 | ||||
| 	//TODO make that clear and rename function, since it does not scale coordinates - just radius
 | ||||
| 	 | ||||
| 	//--- scale radius ---
 | ||||
| 	data-> radius = scaleLinPoint(data->radius, pointX, pointY); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @ -288,7 +299,6 @@ joystickPos_t joystick_evaluatePosition(float x, float y){ | ||||
| //function that generates commands for both motors from the joystick data
 | ||||
| motorCommands_t joystick_generateCommandsDriving(joystickData_t data, bool altStickMapping){ | ||||
| 
 | ||||
| 
 | ||||
|     //struct with current data of the joystick
 | ||||
|     //typedef struct joystickData_t {
 | ||||
|     //    joystickPos_t position;
 | ||||
| @ -298,15 +308,25 @@ motorCommands_t joystick_generateCommandsDriving(joystickData_t data, bool altSt | ||||
|     //    float angle;
 | ||||
|     //} joystickData_t;
 | ||||
| 
 | ||||
| 
 | ||||
| 	//--- variables ---
 | ||||
|     motorCommands_t commands; | ||||
|     float dutyMax = 95; //TODO add this to config, make changeable during runtime
 | ||||
|     float dutyMax = 90; //TODO add this to config, make changeable during runtime
 | ||||
| 
 | ||||
|     float dutyOffset = 10; //immediately starts with this duty, TODO add this to config
 | ||||
|     float dutyOffset = 5; //immediately starts with this duty, TODO add this to config
 | ||||
|     float dutyRange = dutyMax - dutyOffset; | ||||
|     float ratio = fabs(data.angle) / 90; //90degree = x=0 || 0degree = y=0
 | ||||
| 	 | ||||
|     //experimental alternative control mode
 | ||||
| 	//--- snap ratio to max at angle threshold --- 
 | ||||
| 	//(-> more joystick area where inner wheel is off when turning)
 | ||||
| 	/*
 | ||||
| 	//FIXME works, but armchair unsusable because of current bug with motor driver (inner motor freezes after turn)
 | ||||
| 	float ratioClipThreshold = 0.3; | ||||
| 	if (ratio < ratioClipThreshold) ratio = 0; | ||||
| 	else if (ratio > 1-ratioClipThreshold) ratio = 1; | ||||
| 	//TODO subtract this clip threshold from available joystick range at ratio usage
 | ||||
| 	*/ | ||||
| 
 | ||||
|     //--- experimental alternative control mode ---
 | ||||
|     if (altStickMapping == true){ | ||||
|         //swap BOTTOM_LEFT and BOTTOM_RIGHT
 | ||||
|         if (data.position == joystickPos_t::BOTTOM_LEFT){ | ||||
| @ -317,6 +337,8 @@ motorCommands_t joystick_generateCommandsDriving(joystickData_t data, bool altSt | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 	//--- handle all positions ---
 | ||||
| 	//define target direction and duty according to position
 | ||||
|     switch (data.position){ | ||||
| 
 | ||||
|         case joystickPos_t::CENTER: | ||||
| @ -354,13 +376,13 @@ motorCommands_t joystick_generateCommandsDriving(joystickData_t data, bool altSt | ||||
|             commands.left.state = motorstate_t::FWD; | ||||
|             commands.right.state = motorstate_t::FWD; | ||||
|             commands.left.duty = data.radius * dutyRange + dutyOffset; | ||||
|             commands.right.duty = data.radius * dutyRange - data.radius*dutyRange*(1-ratio) + dutyOffset; | ||||
|             commands.right.duty = data.radius * dutyRange - (data.radius*dutyRange + dutyOffset)*(1-ratio) + dutyOffset; | ||||
|             break; | ||||
| 
 | ||||
|         case joystickPos_t::TOP_LEFT: | ||||
|             commands.left.state = motorstate_t::FWD; | ||||
|             commands.right.state = motorstate_t::FWD; | ||||
|             commands.left.duty =  data.radius * dutyRange - data.radius*dutyRange*(1-ratio) + dutyOffset; | ||||
|             commands.left.duty =  data.radius * dutyRange - (data.radius*dutyRange + dutyOffset)*(1-ratio) + dutyOffset; | ||||
|             commands.right.duty = data.radius * dutyRange + dutyOffset; | ||||
|             break; | ||||
| 
 | ||||
| @ -368,13 +390,13 @@ motorCommands_t joystick_generateCommandsDriving(joystickData_t data, bool altSt | ||||
|             commands.left.state = motorstate_t::REV; | ||||
|             commands.right.state = motorstate_t::REV; | ||||
|             commands.left.duty = data.radius * dutyRange + dutyOffset; | ||||
|             commands.right.duty = data.radius * dutyRange - data.radius*dutyRange*(1-ratio) + dutyOffset; //TODO remove offset? allow one motor only
 | ||||
|             commands.right.duty = data.radius * dutyRange - (data.radius*dutyRange + dutyOffset)*(1-ratio) + dutyOffset; | ||||
|             break; | ||||
| 
 | ||||
|         case joystickPos_t::BOTTOM_RIGHT: | ||||
|             commands.left.state = motorstate_t::REV; | ||||
|             commands.right.state = motorstate_t::REV; | ||||
|             commands.left.duty = data.radius * dutyRange - data.radius*dutyRange*(1-ratio) + dutyOffset; //TODO remove offset? allow one motor only
 | ||||
|             commands.left.duty = data.radius * dutyRange - (data.radius*dutyRange + dutyOffset)*(1-ratio) + dutyOffset; | ||||
|             commands.right.duty =  data.radius * dutyRange + dutyOffset; | ||||
|             break; | ||||
|     } | ||||
| @ -444,9 +466,6 @@ motorCommands_t joystick_generateCommandsShaking(joystickData_t data){ | ||||
|         shake_timestamp_turnedOff = esp_log_timestamp(); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     //struct with current data of the joystick
 | ||||
|     //typedef struct joystickData_t {
 | ||||
|     //    joystickPos_t position;
 | ||||
| @ -456,7 +475,6 @@ motorCommands_t joystick_generateCommandsShaking(joystickData_t data){ | ||||
|     //    float angle;
 | ||||
|     //} joystickData_t;
 | ||||
| 
 | ||||
| 
 | ||||
|     //--- evaluate stick position --- 
 | ||||
|     //4 quadrants and center only - with X and Y axis as hysteresis
 | ||||
|     switch (data.position){ | ||||
| @ -499,7 +517,6 @@ motorCommands_t joystick_generateCommandsShaking(joystickData_t data){ | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     //--- handle different modes (joystick in any of 4 quadrants) ---
 | ||||
|     switch (stickQuadrant){ | ||||
|         case joystickPos_t::CENTER: | ||||
|  | ||||
| @ -11,7 +11,7 @@ extern "C" | ||||
| } | ||||
| 
 | ||||
| #include <cmath> | ||||
| #include "motorctl.hpp" //for deklaration of motorCommands_t struct
 | ||||
| #include "motorctl.hpp" //for declaration of motorCommands_t struct
 | ||||
| 
 | ||||
| 
 | ||||
| //======================================
 | ||||
| @ -23,7 +23,7 @@ extern "C" | ||||
| // - defines an enum with position information
 | ||||
| 
 | ||||
| //--------------------------------------------
 | ||||
| //---- struct, enum, variable deklarations ---
 | ||||
| //---- struct, enum, variable declarations ---
 | ||||
| //--------------------------------------------
 | ||||
| //struct with all required configuration parameters
 | ||||
| typedef struct joystick_config_t { | ||||
| @ -51,13 +51,11 @@ typedef struct joystick_config_t { | ||||
| } 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; | ||||
| @ -100,8 +98,6 @@ class evaluatedJoystick { | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| //============================================
 | ||||
| //========= joystick_CommandsDriving =========
 | ||||
| //============================================
 | ||||
|  | ||||
| @ -61,6 +61,7 @@ void task_buzzer( void * pvParameters ){ | ||||
| //=======================================
 | ||||
| //============ control task =============
 | ||||
| //=======================================
 | ||||
| //task that controls the armchair modes and initiates commands generation and applies them to driver
 | ||||
| void task_control( void * pvParameters ){ | ||||
|     ESP_LOGI(TAG, "Initializing controlledArmchair and starting handle loop"); | ||||
|     //start handle loop (control object declared in config.hpp)
 | ||||
| @ -72,6 +73,7 @@ void task_control( void * pvParameters ){ | ||||
| //======================================
 | ||||
| //============ button task =============
 | ||||
| //======================================
 | ||||
| //task that handles the button interface/commands
 | ||||
| void task_button( void * pvParameters ){ | ||||
|     ESP_LOGI(TAG, "Initializing command-button and starting handle loop"); | ||||
|     //create button instance
 | ||||
| @ -85,16 +87,15 @@ void task_button( void * pvParameters ){ | ||||
| //=======================================
 | ||||
| //============== fan task ===============
 | ||||
| //=======================================
 | ||||
| //task that controlls fans for cooling the drivers
 | ||||
| void task_fans( void * pvParameters ){ | ||||
|     ESP_LOGI(TAG, "Initializing fans and starting fan handle loop"); | ||||
|     //create fan instances with config defined in config.cpp
 | ||||
|     controlledFan fanLeft(configFanLeft, &motorLeft); | ||||
|     controlledFan fanRight(configFanRight, &motorRight); | ||||
|     //repeatedly run fan handle functions in a slow loop
 | ||||
|     controlledFan fan(configCooling, &motorLeft, &motorRight); | ||||
|     //repeatedly run fan handle function in a slow loop
 | ||||
|     while(1){ | ||||
|         fanLeft.handle(); | ||||
|         fanRight.handle(); | ||||
|         vTaskDelay(1000 / portTICK_PERIOD_MS); | ||||
|         fan.handle(); | ||||
|         vTaskDelay(500 / portTICK_PERIOD_MS); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -123,6 +124,31 @@ void init_spiffs(){ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| //==================================
 | ||||
| //======== define loglevels ========
 | ||||
| //==================================
 | ||||
| void setLoglevels(void){ | ||||
|     //set loglevel for all tags:
 | ||||
|     esp_log_level_set("*", ESP_LOG_WARN); | ||||
| 
 | ||||
|     //--- set loglevel for individual tags ---
 | ||||
|     esp_log_level_set("main", ESP_LOG_INFO); | ||||
|     esp_log_level_set("buzzer", ESP_LOG_ERROR); | ||||
|     //esp_log_level_set("motordriver", ESP_LOG_INFO);
 | ||||
|     //esp_log_level_set("motor-control", ESP_LOG_DEBUG);
 | ||||
|     //esp_log_level_set("evaluatedJoystick", ESP_LOG_DEBUG);
 | ||||
|     //esp_log_level_set("joystickCommands", ESP_LOG_DEBUG);
 | ||||
|     esp_log_level_set("button", ESP_LOG_INFO); | ||||
|     esp_log_level_set("control", ESP_LOG_INFO); | ||||
|     esp_log_level_set("fan-control", ESP_LOG_INFO); | ||||
|     esp_log_level_set("wifi", ESP_LOG_INFO); | ||||
|     esp_log_level_set("http", ESP_LOG_INFO); | ||||
|     esp_log_level_set("automatedArmchair", ESP_LOG_DEBUG); | ||||
|     //esp_log_level_set("current-sensors", ESP_LOG_INFO);
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| //=================================
 | ||||
| //=========== app_main ============
 | ||||
| //=================================
 | ||||
| @ -132,28 +158,8 @@ extern "C" void app_main(void) { | ||||
|     gpio_set_direction(GPIO_NUM_17, GPIO_MODE_OUTPUT); | ||||
|     gpio_set_level(GPIO_NUM_17, 1);                                                       | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     //-------------------------------
 | ||||
|     //---------- log level ----------
 | ||||
|     //-------------------------------
 | ||||
|     //set loglevel for all tags:
 | ||||
|     esp_log_level_set("*", ESP_LOG_WARN); | ||||
| 
 | ||||
|     //--- set loglevel for individual tags ---
 | ||||
|     esp_log_level_set("main", ESP_LOG_INFO); | ||||
|     esp_log_level_set("buzzer", ESP_LOG_ERROR); | ||||
|     //esp_log_level_set("motordriver", ESP_LOG_DEBUG);
 | ||||
|     esp_log_level_set("motor-control", ESP_LOG_INFO); | ||||
|     //esp_log_level_set("evaluatedJoystick", ESP_LOG_DEBUG);
 | ||||
|     //esp_log_level_set("joystickCommands", ESP_LOG_DEBUG);
 | ||||
|     esp_log_level_set("button", ESP_LOG_INFO); | ||||
|     esp_log_level_set("control", ESP_LOG_INFO); | ||||
|     esp_log_level_set("fan-control", ESP_LOG_INFO); | ||||
|     esp_log_level_set("wifi", ESP_LOG_INFO); | ||||
|     esp_log_level_set("http", ESP_LOG_INFO); | ||||
|     esp_log_level_set("automatedArmchair", ESP_LOG_DEBUG); | ||||
| 
 | ||||
|     //---- define log levels ----
 | ||||
| 	setLoglevels(); | ||||
|      | ||||
|     //----------------------------------------------
 | ||||
|     //--- create task for controlling the motors ---
 | ||||
| @ -188,7 +194,6 @@ extern "C" void app_main(void) { | ||||
|     //beep at startup
 | ||||
|     buzzer.beep(3, 70, 50); | ||||
| 
 | ||||
| 
 | ||||
|     //--- initialize nvs-flash and netif (needed for wifi) ---
 | ||||
|     wifi_initNvs_initNetif(); | ||||
| 
 | ||||
| @ -216,18 +221,22 @@ extern "C" void app_main(void) { | ||||
|         //control.changeMode(controlMode_t::HTTP);
 | ||||
| 
 | ||||
| 
 | ||||
| 	//--- main loop ---
 | ||||
| 	//does nothing except for testing things
 | ||||
| 	while(1){ | ||||
| 		vTaskDelay(1000 / portTICK_PERIOD_MS); | ||||
| 
 | ||||
|        vTaskDelay(500 / portTICK_PERIOD_MS); | ||||
| 
 | ||||
|        // //--- testing functions at mode change HTTP ---
 | ||||
| 		//---------------------------------
 | ||||
| 		//-------- TESTING section --------
 | ||||
| 		//---------------------------------
 | ||||
| 		// //--- test functions at mode change HTTP ---
 | ||||
| 		// control.changeMode(controlMode_t::HTTP);
 | ||||
| 		// vTaskDelay(10000 / portTICK_PERIOD_MS);
 | ||||
| 		// control.changeMode(controlMode_t::IDLE);
 | ||||
| 		// vTaskDelay(10000 / portTICK_PERIOD_MS);
 | ||||
| 
 | ||||
| 
 | ||||
|         //--- testing wifi functions ---
 | ||||
| 		//--- test wifi functions ---
 | ||||
| 		// ESP_LOGI(TAG, "creating AP");
 | ||||
| 		// wifi_init_ap(); //start accesspoint
 | ||||
| 		// vTaskDelay(15000 / portTICK_PERIOD_MS);
 | ||||
| @ -242,8 +251,7 @@ extern "C" void app_main(void) { | ||||
| 		// vTaskDelay(5000 / portTICK_PERIOD_MS);
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|        //--- testing button ---
 | ||||
| 		//--- test button ---
 | ||||
| 		//buttonJoystick.handle();
 | ||||
| 		// if (buttonJoystick.risingEdge){
 | ||||
| 		//     ESP_LOGI(TAG, "button pressed, was released for %d ms", buttonJoystick.msReleased);
 | ||||
| @ -255,22 +263,19 @@ extern "C" void app_main(void) { | ||||
| 		// }
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|         //--- testing joystick commands ---
 | ||||
| 		//--- test joystick commands ---
 | ||||
| 		// motorCommands_t commands = joystick_generateCommandsDriving(joystick);
 | ||||
| 		// motorRight.setTarget(commands.right.state, commands.right.duty); //TODO make motorctl.setTarget also accept motorcommand struct directly
 | ||||
| 		// motorLeft.setTarget(commands.left.state, commands.left.duty); //TODO make motorctl.setTarget also accept motorcommand struct directly
 | ||||
| 		// //motorRight.setTarget(commands.right.state, commands.right.duty);
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|         //--- testing joystick class ---
 | ||||
| 		//--- test 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 ---
 | ||||
| 		//--- test the motor driver ---
 | ||||
| 		//fade up duty - forward
 | ||||
| 		//   for (int duty=0; duty<=100; duty+=5) {
 | ||||
| 		//       motorLeft.setTarget(motorstate_t::FWD, duty);
 | ||||
| @ -278,7 +283,7 @@ extern "C" void app_main(void) { | ||||
| 		//   }
 | ||||
| 
 | ||||
| 
 | ||||
|        //--- testing controlledMotor --- (ramp)
 | ||||
| 		//--- test controlledMotor --- (ramp)
 | ||||
| 		// //brake for 1 s
 | ||||
| 		// motorLeft.setTarget(motorstate_t::BRAKE);
 | ||||
| 		// vTaskDelay(1000 / portTICK_PERIOD_MS);
 | ||||
|  | ||||
| @ -7,8 +7,10 @@ static const char * TAG = "motor-control"; | ||||
| //=============================
 | ||||
| //======== constructor ========
 | ||||
| //=============================
 | ||||
| //constructor, simultaniously initialize instance of motor driver 'motor' with provided config (see below line after ':')
 | ||||
| controlledMotor::controlledMotor(single100a_config_t config_driver,  motorctl_config_t config_control): motor(config_driver) { | ||||
| //constructor, simultaniously initialize instance of motor driver 'motor' and current sensor 'cSensor' with provided config (see below lines after ':')
 | ||||
| controlledMotor::controlledMotor(single100a_config_t config_driver,  motorctl_config_t config_control):  | ||||
| 	motor(config_driver),  | ||||
| 	cSensor(config_control.currentSensor_adc, config_control.currentSensor_ratedCurrent) { | ||||
| 		//copy parameters for controlling the motor
 | ||||
| 		config = config_control; | ||||
| 		//copy configured default fading durations to actually used variables
 | ||||
| @ -17,6 +19,7 @@ controlledMotor::controlledMotor(single100a_config_t config_driver,  motorctl_co | ||||
| 
 | ||||
| 		init(); | ||||
| 		//TODO: add currentsensor object here
 | ||||
| 		//currentSensor cSensor(config.currentSensor_adc, config.currentSensor_ratedCurrent);
 | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| @ -26,6 +29,7 @@ controlledMotor::controlledMotor(single100a_config_t config_driver,  motorctl_co | ||||
| //============================
 | ||||
| void controlledMotor::init(){ | ||||
|     commandQueue = xQueueCreate( 1, sizeof( struct motorCommand_t ) ); | ||||
| 	//cSensor.calibrateZeroAmpere(); //currently done in currentsensor constructor TODO do this regularly e.g. in idle?
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @ -50,15 +54,25 @@ void fade(float * dutyNow, float dutyTarget, float dutyIncrement){ | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| //----------------------------
 | ||||
| //----- getStateFromDuty -----
 | ||||
| //----------------------------
 | ||||
| //local function that determines motor the direction from duty range -100 to 100
 | ||||
| motorstate_t getStateFromDuty(float duty){ | ||||
| 	if(duty > 0) return motorstate_t::FWD; | ||||
| 	if (duty < 0) return motorstate_t::REV; | ||||
| 	return motorstate_t::IDLE; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| //==============================
 | ||||
| //=========== handle ===========
 | ||||
| //==============================
 | ||||
| //function that controls the motor driver and handles fading/ramp and current limit
 | ||||
| //function that controls the motor driver and handles fading/ramp, current limit and deadtime
 | ||||
| void controlledMotor::handle(){ | ||||
| 
 | ||||
|     //TODO: current sensor
 | ||||
|     //TODO: delay when switching direction?
 | ||||
|     //TODO: History: skip fading when motor was running fast recently
 | ||||
|     //TODO: History: skip fading when motor was running fast recently / alternatively add rot-speed sensor
 | ||||
| 
 | ||||
|     //--- receive commands from queue ---
 | ||||
|     if( xQueueReceive( commandQueue, &commandReceive, ( TickType_t ) 0 ) ) | ||||
| @ -115,15 +129,14 @@ void controlledMotor::handle(){ | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     //--- calculate difference ---
 | ||||
|     dutyDelta = dutyTarget - dutyNow; | ||||
|     //positive: need to increase by that value
 | ||||
|     //negative: need to decrease
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     //--- fade duty to target (up and down) ---
 | ||||
| 	//----- FADING -----
 | ||||
|     //fade duty to target (up and down)
 | ||||
|     //TODO: this needs optimization (can be more clear and/or simpler)
 | ||||
|     if (dutyDelta > 0) { //difference positive -> increasing duty (-100 -> 100)
 | ||||
|         if (dutyNow < 0) { //reverse, decelerating
 | ||||
| @ -143,55 +156,69 @@ void controlledMotor::handle(){ | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     //previous approach: (resulted in bug where accel/decel fade is swaped in reverse)
 | ||||
| //    //--- fade up ---
 | ||||
| //    //dutyDelta is higher than IncrementUp -> fade up
 | ||||
| //    if(dutyDelta > dutyIncrementUp){
 | ||||
| //        ESP_LOGV(TAG, "*fading up*: target=%.2f%% - previous=%.2f%% - increment=%.6f%% - usSinceLastRun=%d", dutyTarget, dutyNow, dutyIncrementUp, (int)usPassed);
 | ||||
| //        dutyNow += dutyIncrementUp; //increase duty by increment
 | ||||
| //    }
 | ||||
| //
 | ||||
| //    //--- fade down ---
 | ||||
| //    //dutyDelta is more negative than -IncrementDown -> fade down
 | ||||
| //    else if (dutyDelta < -dutyIncrementDown){
 | ||||
| //        ESP_LOGV(TAG, "*fading down*: target=%.2f%% - previous=%.2f%% - increment=%.6f%% - usSinceLastRun=%d", dutyTarget, dutyNow, dutyIncrementDown, (int)usPassed);
 | ||||
| //
 | ||||
| //        dutyNow -= dutyIncrementDown; //decrease duty by increment
 | ||||
| //    }
 | ||||
| //
 | ||||
| //    //--- set to target ---
 | ||||
| //    //duty is already very close to target (closer than IncrementUp or IncrementDown)
 | ||||
| //    else{ 
 | ||||
| //        //immediately set to target duty
 | ||||
| //        dutyNow = dutyTarget;
 | ||||
| //    }
 | ||||
|      | ||||
| 
 | ||||
| 
 | ||||
|     //define motorstate from converted duty -100 to 100
 | ||||
|     //apply target duty and state to motor driver
 | ||||
|     //forward
 | ||||
|     if(dutyNow > 0){ | ||||
|         state = motorstate_t::FWD; | ||||
| 	//----- CURRENT LIMIT -----
 | ||||
| 	if ((config.currentLimitEnabled) && (dutyDelta != 0)){ | ||||
| 		currentNow = cSensor.read(); | ||||
| 		if (fabs(currentNow) > config.currentMax){ | ||||
| 			float dutyOld = dutyNow; | ||||
| 			//adaptive decrement:
 | ||||
| 			//Note current exceeded twice -> twice as much decrement: TODO: decrement calc needs finetuning, currently random values
 | ||||
| 			dutyIncrementDecel = (currentNow/config.currentMax) * ( usPassed / ((float)msFadeDecel * 1500) ) * 100;  | ||||
| 			float currentLimitDecrement = ( (float)usPassed / ((float)1000 * 1000) ) * 100; //1000ms from 100 to 0
 | ||||
| 			if (dutyNow < -currentLimitDecrement) { | ||||
| 				dutyNow += currentLimitDecrement; | ||||
| 			} else if (dutyNow > currentLimitDecrement) { | ||||
| 				dutyNow -= currentLimitDecrement; | ||||
| 			} | ||||
|     //reverse
 | ||||
|     else if (dutyNow < 0){ | ||||
|         state = motorstate_t::REV; | ||||
| 			ESP_LOGW(TAG, "current limit exceeded! now=%.3fA max=%.1fA => decreased duty from %.3f to %.3f", currentNow, config.currentMax, dutyOld, dutyNow); | ||||
| 		} | ||||
|     //idle
 | ||||
|     else { | ||||
| 	} | ||||
| 
 | ||||
| 	 | ||||
|     //--- define new motorstate --- (-100 to 100 => direction)
 | ||||
| 	state=getStateFromDuty(dutyNow); | ||||
| 
 | ||||
| 
 | ||||
| 	//--- DEAD TIME ----
 | ||||
| 	//ensure minimum idle time between direction change to prevent driver overload
 | ||||
| 	//FWD -> IDLE -> FWD  continue without waiting
 | ||||
| 	//FWD -> IDLE -> REV  wait for dead-time in IDLE
 | ||||
| 	//TODO check when changed only?
 | ||||
| 	if (	//not enough time between last direction state
 | ||||
| 			(   state == motorstate_t::FWD && (esp_log_timestamp() - timestampsModeLastActive[(int)motorstate_t::REV] < config.deadTimeMs)) | ||||
| 			|| (state == motorstate_t::REV && (esp_log_timestamp() - timestampsModeLastActive[(int)motorstate_t::FWD] < config.deadTimeMs)) | ||||
| 	   ){ | ||||
| 		ESP_LOGD(TAG, "waiting dead-time... dir change %s -> %s", motorstateStr[(int)statePrev], motorstateStr[(int)state]); | ||||
| 		if (!deadTimeWaiting){ //log start
 | ||||
| 			deadTimeWaiting = true; | ||||
| 			ESP_LOGW(TAG, "starting dead-time... %s -> %s", motorstateStr[(int)statePrev], motorstateStr[(int)state]); | ||||
| 		} | ||||
| 		//force IDLE state during wait
 | ||||
| 		state = motorstate_t::IDLE; | ||||
| 		dutyNow = 0; | ||||
| 	} else { | ||||
| 		if (deadTimeWaiting){ //log end
 | ||||
| 			deadTimeWaiting = false; | ||||
| 			ESP_LOGW(TAG, "dead-time ended - continue with %s", motorstateStr[(int)state]); | ||||
| 		} | ||||
| 		ESP_LOGV(TAG, "deadtime: no change below deadtime detected... dir=%s, duty=%.1f", motorstateStr[(int)state], dutyNow); | ||||
| 	} | ||||
| 			 | ||||
|     //--- apply to motor ---
 | ||||
| 
 | ||||
| 	//--- save current actual motorstate and timestamp ---
 | ||||
| 	//needed for deadtime
 | ||||
| 	timestampsModeLastActive[(int)getStateFromDuty(dutyNow)] = esp_log_timestamp(); | ||||
| 	//(-100 to 100 => direction)
 | ||||
| 	statePrev = getStateFromDuty(dutyNow); | ||||
| 
 | ||||
| 
 | ||||
|     //--- apply new target to motor ---
 | ||||
|     motor.set(state, fabs(dutyNow)); | ||||
|     //note: BRAKE state is handled earlier
 | ||||
|      | ||||
| 
 | ||||
|     //--- update timestamp ---
 | ||||
|     timestampLastRunUs = esp_timer_get_time(); //update timestamp last run with current timestamp in microseconds
 | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @ -249,7 +276,6 @@ void controlledMotor::setFade(fadeType_t fadeType, uint32_t msFadeNew){ | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| //enable (set to default value) or disable fading
 | ||||
| void controlledMotor::setFade(fadeType_t fadeType, bool enabled){ | ||||
|     uint32_t msFadeNew = 0; //define new fade time as default disabled
 | ||||
|  | ||||
| @ -10,11 +10,12 @@ extern "C" | ||||
| } | ||||
| 
 | ||||
| #include "motordrivers.hpp" | ||||
| #include "currentsensor.hpp" | ||||
| 
 | ||||
| 
 | ||||
| //-------------------------------------
 | ||||
| //-------- struct/type  declarations -------
 | ||||
| //-------------------------------------
 | ||||
| //=======================================
 | ||||
| //====== struct/type  declarations ======
 | ||||
| //=======================================
 | ||||
| 
 | ||||
| //struct for sending command for one motor in the queue
 | ||||
| struct motorCommand_t { | ||||
| @ -32,7 +33,11 @@ typedef struct motorCommands_t { | ||||
| typedef struct motorctl_config_t { | ||||
|     uint32_t msFadeAccel; //acceleration of the motor (ms it takes from 0% to 100%)
 | ||||
|     uint32_t msFadeDecel; //deceleration of the motor (ms it takes from 100% to 0%)
 | ||||
| 	bool currentLimitEnabled; | ||||
| 	adc1_channel_t currentSensor_adc; | ||||
| 	float currentSensor_ratedCurrent; | ||||
|     float currentMax; | ||||
| 	uint32_t deadTimeMs; //time motor stays in IDLE before direction change
 | ||||
| } motorctl_config_t; | ||||
| 
 | ||||
| //enum fade type (acceleration, deceleration)
 | ||||
| @ -41,6 +46,9 @@ enum class fadeType_t {ACCEL, DECEL}; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| //===================================
 | ||||
| //====== controlledMotor class ======
 | ||||
| //===================================
 | ||||
| class controlledMotor { | ||||
|     public: | ||||
|         //--- functions ---
 | ||||
| @ -53,22 +61,23 @@ class controlledMotor { | ||||
|         void setFade(fadeType_t fadeType, uint32_t msFadeNew); //set acceleration or deceleration fade time
 | ||||
|         bool toggleFade(fadeType_t fadeType); //toggle acceleration or deceleration on/off
 | ||||
| 											   | ||||
| 		//TODO set current limit method
 | ||||
| 
 | ||||
|     private: | ||||
|         //--- functions ---
 | ||||
|         void init(); //creates currentsensor objects, motordriver objects and queue
 | ||||
| 
 | ||||
|         //--- objects ---
 | ||||
|         //TODO: add currentsensor object
 | ||||
|         //motor driver
 | ||||
|         single100a motor; | ||||
|         //queue for sending commands to the separate task running the handle() function very fast
 | ||||
|         QueueHandle_t commandQueue = NULL; | ||||
| 		//current sensor
 | ||||
| 		currentSensor cSensor; | ||||
| 
 | ||||
|         //--- variables ---
 | ||||
|         //struct for storing control specific parameters
 | ||||
|         motorctl_config_t config; | ||||
|          | ||||
|         motorstate_t state = motorstate_t::IDLE; | ||||
| 
 | ||||
|         float currentMax; | ||||
| @ -86,7 +95,10 @@ class controlledMotor { | ||||
|         uint32_t ramp; | ||||
|         int64_t timestampLastRunUs; | ||||
| 
 | ||||
| 		bool deadTimeWaiting = false; | ||||
| 		uint32_t timestampsModeLastActive[4] = {}; | ||||
|         motorstate_t statePrev = motorstate_t::FWD; | ||||
| 
 | ||||
|         struct motorCommand_t commandReceive = {}; | ||||
|         struct motorCommand_t commandSend = {}; | ||||
| 
 | ||||
| }; | ||||
|  | ||||
| @ -79,19 +79,12 @@ void single100a::init(){ | ||||
| //function to put the h-bridge module in the desired state and duty cycle
 | ||||
| void single100a::set(motorstate_t state_f, float duty_f){ | ||||
| 
 | ||||
|     //define enabled signal state (gpio high/low) TODO: move this to constructor?
 | ||||
|     bool enabled; | ||||
|     if (config.abInverted) { | ||||
|         enabled = false; | ||||
|     } else { | ||||
|         enabled = true; | ||||
|     } | ||||
| 
 | ||||
|     //scale provided target duty in percent to available resolution for ledc
 | ||||
|     uint32_t dutyScaled; | ||||
|     if (duty_f > 100) { //target duty above 100%
 | ||||
|         dutyScaled = dutyMax; | ||||
|     } else if (duty_f < 0) { //target duty below 0%
 | ||||
|     } else if (duty_f <= 0) { //target at or below 0%
 | ||||
| 		state_f = motorstate_t::IDLE; | ||||
|         dutyScaled = 0; | ||||
|     } else { //target duty 0-100%
 | ||||
|              //scale duty to available resolution
 | ||||
| @ -105,29 +98,31 @@ void single100a::set(motorstate_t state_f, float duty_f){ | ||||
|             ledc_update_duty(LEDC_HIGH_SPEED_MODE, config.ledc_channel); | ||||
|             //TODO: to fix bugged state of h-bridge module when idle and start again, maybe try to leave pwm signal on for some time before updating a/b pins?
 | ||||
|             //no brake: (freewheel)
 | ||||
|             gpio_set_level(config.gpio_a, enabled); | ||||
|             gpio_set_level(config.gpio_b, enabled); | ||||
|             //gpio_set_level(config.gpio_a, config.aEnabledPinState);
 | ||||
|             //gpio_set_level(config.gpio_b, !config.bEnabledPinState);
 | ||||
|             gpio_set_level(config.gpio_a, config.aEnabledPinState); | ||||
|             gpio_set_level(config.gpio_b, config.bEnabledPinState); | ||||
|             break; | ||||
|         case motorstate_t::BRAKE: | ||||
|             ledc_set_duty(LEDC_HIGH_SPEED_MODE, config.ledc_channel, 0); | ||||
|             ledc_update_duty(LEDC_HIGH_SPEED_MODE, config.ledc_channel); | ||||
|             //brake:
 | ||||
|             gpio_set_level(config.gpio_a, !enabled); | ||||
|             gpio_set_level(config.gpio_b, !enabled); | ||||
|             gpio_set_level(config.gpio_a, !config.aEnabledPinState); | ||||
|             gpio_set_level(config.gpio_b, !config.bEnabledPinState); | ||||
|             break; | ||||
|         case motorstate_t::FWD: | ||||
|             ledc_set_duty(LEDC_HIGH_SPEED_MODE, config.ledc_channel, dutyScaled); | ||||
|             ledc_update_duty(LEDC_HIGH_SPEED_MODE, config.ledc_channel); | ||||
|             //forward:
 | ||||
|             gpio_set_level(config.gpio_a, enabled); | ||||
|             gpio_set_level(config.gpio_b, !enabled); | ||||
|             gpio_set_level(config.gpio_a, config.aEnabledPinState); | ||||
|             gpio_set_level(config.gpio_b, !config.bEnabledPinState); | ||||
|             break; | ||||
|         case motorstate_t::REV: | ||||
|             ledc_set_duty(LEDC_HIGH_SPEED_MODE, config.ledc_channel, dutyScaled); | ||||
|             ledc_update_duty(LEDC_HIGH_SPEED_MODE, config.ledc_channel); | ||||
|             //reverse:
 | ||||
|             gpio_set_level(config.gpio_a, !enabled); | ||||
|             gpio_set_level(config.gpio_b, enabled); | ||||
|             gpio_set_level(config.gpio_a, !config.aEnabledPinState); | ||||
|             gpio_set_level(config.gpio_b, config.bEnabledPinState); | ||||
|             break; | ||||
|     } | ||||
|     ESP_LOGD(TAG, "set module to state=%s, duty=%d/%d, duty_input=%.3f%%", motorstateStr[(int)state_f], dutyScaled, dutyMax, duty_f); | ||||
|  | ||||
| @ -19,7 +19,7 @@ extern "C" | ||||
| //====================================
 | ||||
| 
 | ||||
| //--------------------------------------------
 | ||||
| //---- struct, enum, variable deklarations ---
 | ||||
| //---- struct, enum, variable declarations ---
 | ||||
| //--------------------------------------------
 | ||||
| 
 | ||||
| //class which controls a motor using a 'single100a' h-bridge module
 | ||||
| @ -34,7 +34,8 @@ typedef struct single100a_config_t { | ||||
|     gpio_num_t gpio_b; | ||||
|     ledc_timer_t ledc_timer; | ||||
|     ledc_channel_t ledc_channel; | ||||
|     bool abInverted; | ||||
| 	bool aEnabledPinState; | ||||
| 	bool bEnabledPinState; | ||||
|     ledc_timer_bit_t resolution; | ||||
|     int pwmFreq; | ||||
| } single100a_config_t; | ||||
|  | ||||
| @ -123,13 +123,6 @@ void wifi_deinit_ap(void) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| //===========================================
 | ||||
| //=============== init client ===============
 | ||||
| //===========================================
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user