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;
|
||||
};
|
77
main/fan.cpp
77
main/fan.cpp
@ -15,15 +15,15 @@ static const char * TAG = "fan-control";
|
||||
//-----------------------------
|
||||
//-------- constructor --------
|
||||
//-----------------------------
|
||||
controlledFan::controlledFan(fan_config_t config_f, controlledMotor* motor_f ){
|
||||
//copy config
|
||||
config = config_f;
|
||||
//copy pointer to motor object
|
||||
motor = motor_f;
|
||||
|
||||
//initialize gpio pin
|
||||
gpio_pad_select_gpio(config.gpio_fan);
|
||||
gpio_set_direction(config.gpio_fan, GPIO_MODE_OUTPUT);
|
||||
controlledFan::controlledFan (fan_config_t config_f, controlledMotor* motor1_f, controlledMotor* motor2_f ){
|
||||
//copy config
|
||||
config = config_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();
|
||||
|
||||
//TODO Add statemachine for more specific control? Exponential average?
|
||||
//update timestamp if threshold exceeded
|
||||
if (motorStatus.duty > config.dutyThreshold){
|
||||
timestamp_lastThreshold = esp_log_timestamp();
|
||||
}
|
||||
//--- 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 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);
|
||||
}
|
||||
//--- 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?
|
||||
//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
|
||||
|
||||
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,36 +223,34 @@ 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);
|
||||
|
||||
// httpd_uri_t socket_joystick_url = {
|
||||
// .uri = "/ws-api/joystick",
|
||||
// .method = HTTP_GET,
|
||||
// .handler = on_socket_joystick_url,
|
||||
// .is_websocket = true};
|
||||
// httpd_register_uri_handler(server, &socket_joystick_url);
|
||||
//previous approach with sockets:
|
||||
// httpd_uri_t socket_joystick_url = {
|
||||
// .uri = "/ws-api/joystick",
|
||||
// .method = HTTP_GET,
|
||||
// .handler = on_socket_joystick_url,
|
||||
// .is_websocket = true};
|
||||
// httpd_register_uri_handler(server, &socket_joystick_url);
|
||||
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
//--- 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
|
||||
//--- 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 =========
|
||||
//============================================
|
||||
|
187
main/main.cpp
187
main/main.cpp
@ -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,79 +221,79 @@ extern "C" void app_main(void) {
|
||||
//control.changeMode(controlMode_t::HTTP);
|
||||
|
||||
|
||||
while(1){
|
||||
//--- 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 ---
|
||||
// control.changeMode(controlMode_t::HTTP);
|
||||
// vTaskDelay(10000 / portTICK_PERIOD_MS);
|
||||
// control.changeMode(controlMode_t::IDLE);
|
||||
// vTaskDelay(10000 / portTICK_PERIOD_MS);
|
||||
//---------------------------------
|
||||
//-------- 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 ---
|
||||
// ESP_LOGI(TAG, "creating AP");
|
||||
// wifi_init_ap(); //start accesspoint
|
||||
// vTaskDelay(15000 / portTICK_PERIOD_MS);
|
||||
// ESP_LOGI(TAG, "stopping wifi");
|
||||
// wifi_deinit_ap(); //stop wifi access point
|
||||
// vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
// ESP_LOGI(TAG, "connecting to wifi");
|
||||
// wifi_init_client(); //connect to existing wifi
|
||||
// vTaskDelay(10000 / portTICK_PERIOD_MS);
|
||||
// ESP_LOGI(TAG, "stopping wifi");
|
||||
// wifi_deinit_client(); //stop wifi client
|
||||
// vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
//--- test wifi functions ---
|
||||
// ESP_LOGI(TAG, "creating AP");
|
||||
// wifi_init_ap(); //start accesspoint
|
||||
// vTaskDelay(15000 / portTICK_PERIOD_MS);
|
||||
// ESP_LOGI(TAG, "stopping wifi");
|
||||
// wifi_deinit_ap(); //stop wifi access point
|
||||
// vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
// ESP_LOGI(TAG, "connecting to wifi");
|
||||
// wifi_init_client(); //connect to existing wifi
|
||||
// vTaskDelay(10000 / portTICK_PERIOD_MS);
|
||||
// ESP_LOGI(TAG, "stopping wifi");
|
||||
// wifi_deinit_client(); //stop wifi client
|
||||
// vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
|
||||
|
||||
//--- test button ---
|
||||
//buttonJoystick.handle();
|
||||
// if (buttonJoystick.risingEdge){
|
||||
// ESP_LOGI(TAG, "button pressed, was released for %d ms", buttonJoystick.msReleased);
|
||||
// buzzer.beep(2, 100, 50);
|
||||
|
||||
//--- testing button ---
|
||||
//buttonJoystick.handle();
|
||||
// if (buttonJoystick.risingEdge){
|
||||
// ESP_LOGI(TAG, "button pressed, was released for %d ms", buttonJoystick.msReleased);
|
||||
// buzzer.beep(2, 100, 50);
|
||||
|
||||
// }else if (buttonJoystick.fallingEdge){
|
||||
// ESP_LOGI(TAG, "button released, was pressed for %d ms", buttonJoystick.msPressed);
|
||||
// buzzer.beep(1, 200, 0);
|
||||
// }
|
||||
// }else if (buttonJoystick.fallingEdge){
|
||||
// ESP_LOGI(TAG, "button released, was pressed for %d ms", buttonJoystick.msPressed);
|
||||
// buzzer.beep(1, 200, 0);
|
||||
// }
|
||||
|
||||
|
||||
|
||||
//--- testing 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);
|
||||
|
||||
|
||||
//--- 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 ---
|
||||
//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);
|
||||
//--- 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 ---
|
||||
//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);
|
||||
//--- test 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);
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
//--- test 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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,17 +7,20 @@ 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) {
|
||||
//copy parameters for controlling the motor
|
||||
config = config_control;
|
||||
//copy configured default fading durations to actually used variables
|
||||
msFadeAccel = config.msFadeAccel;
|
||||
msFadeDecel = config.msFadeDecel;
|
||||
//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
|
||||
msFadeAccel = config.msFadeAccel;
|
||||
msFadeDecel = config.msFadeDecel;
|
||||
|
||||
init();
|
||||
//TODO: add currentsensor object here
|
||||
}
|
||||
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(){
|
||||
}
|
||||
|
||||
|
||||
//----- 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;
|
||||
}
|
||||
ESP_LOGW(TAG, "current limit exceeded! now=%.3fA max=%.1fA => decreased duty from %.3f to %.3f", currentNow, config.currentMax, dutyOld, dutyNow);
|
||||
}
|
||||
}
|
||||
|
||||
//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 new motorstate --- (-100 to 100 => direction)
|
||||
state=getStateFromDuty(dutyNow);
|
||||
|
||||
|
||||
//define motorstate from converted duty -100 to 100
|
||||
//apply target duty and state to motor driver
|
||||
//forward
|
||||
if(dutyNow > 0){
|
||||
state = motorstate_t::FWD;
|
||||
}
|
||||
//reverse
|
||||
else if (dutyNow < 0){
|
||||
state = motorstate_t::REV;
|
||||
}
|
||||
//idle
|
||||
else {
|
||||
state = motorstate_t::IDLE;
|
||||
}
|
||||
//--- 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 ---
|
||||
@ -52,23 +60,24 @@ class controlledMotor {
|
||||
void setFade(fadeType_t fadeType, bool enabled); //enable/disable acceleration or deceleration fading
|
||||
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