Add deadTime support (time off between dir change)

add config option for minimum time motor has to be in IDLE before
changing direction. Try to prevent drivers from obvious extreme
overload. At least prevent full speed switch

Untested but simulated via log output
This commit is contained in:
jonny_l480 2023-08-22 11:11:22 +02:00
parent 4731f9253e
commit 884c00e3d9
3 changed files with 61 additions and 20 deletions

View File

@ -38,7 +38,8 @@ motorctl_config_t configMotorControlLeft = {
.currentLimitEnabled = true,
.currentSensor_adc = ADC1_CHANNEL_6, //GPIO34
.currentSensor_ratedCurrent = 50,
.currentMax = 30
.currentMax = 30,
.deadTimeMs = 900 //minimum time motor is off between direction change
};
//--- configure right motor (contol) ---
@ -48,7 +49,8 @@ motorctl_config_t configMotorControlRight = {
.currentLimitEnabled = true,
.currentSensor_adc = ADC1_CHANNEL_4, //GPIO32
.currentSensor_ratedCurrent = 50,
.currentMax = 30
.currentMax = 30,
.deadTimeMs = 900 //minimum time motor is off between direction change
};

View File

@ -54,13 +54,24 @@ 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: delay when switching direction?
//TODO: History: skip fading when motor was running fast recently / alternatively add rot-speed sensor
//--- receive commands from queue ---
@ -124,7 +135,7 @@ void controlledMotor::handle(){
//negative: need to decrease
//----- fading -----
//----- 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)
@ -145,7 +156,7 @@ void controlledMotor::handle(){
}
//----- current limit -----
//----- CURRENT LIMIT -----
if ((config.currentLimitEnabled) && (dutyDelta != 0)){
currentNow = cSensor.read();
if (fabs(currentNow) > config.currentMax){
@ -163,26 +174,49 @@ void controlledMotor::handle(){
}
}
//--- 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);
}
//--- save current actual motorstate and timestamp ---
//needed for deadtime
timestampsModeLastActive[(int)getStateFromDuty(dutyNow)] = esp_log_timestamp();
//(-100 to 100 => direction)
statePrev = getStateFromDuty(dutyNow);
//--- define motorstate ---
//from converted duty -100 to 100
//forward
if(dutyNow > 0){
state = motorstate_t::FWD;
}
//reverse
else if (dutyNow < 0){
state = motorstate_t::REV;
}
//idle
else {
state = motorstate_t::IDLE;
}
//--- 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
}

View File

@ -37,6 +37,7 @@ typedef struct motorctl_config_t {
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)
@ -94,6 +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 = {};
};