Fixed Tilt Movement + Enhancement PWM Servo

Optimized venetian tilt operation when position was not exactly captured during operation. Shutter tried to find correct position and moves up and down because of the tilt.
Enhancement to PWM Servos. no minimum movement is required. Every Position can be reached directly
This commit is contained in:
stefanbode 2021-11-14 22:17:28 +01:00 committed by GitHub
parent 5a4838bb50
commit 48685c2d42
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 68 additions and 43 deletions

View File

@ -94,11 +94,14 @@ struct SHUTTER {
uint16_t close_velocity_max; // maximum of PWM change during closeing. Defines velocity on opening. Steppers and Servos only
int32_t accelerator; // speed of ramp-up, ramp down of shutters with velocity control. Steppers and Servos only
int8_t tilt_config[5]; // tilt_min, tilt_max, duration, tilt_closed_value, tilt_opened_value
int8_t tilt_real_pos; // -90 to 90
int16_t tilt_target_pos;
int16_t tilt_start_pos;
int8_t tilt_real_pos; // -90 to 90
int8_t tilt_target_pos; // target positon for movements of the tilt
int8_t tilt_start_pos; // saved start position before shutter moves
uint8_t tilt_velocity; // degree rotation per step 0.05sec
uint16_t venetian_delay = 0; // Delay in steps before venetian shutter start physical moving. Based on tilt position
int8_t tiltmoving; // 0 operating move, 1 = operating tilt
uint16_t venetian_delay = 0; // Delay in steps before venetian shutter start physical moving. Based on tilt position
uint16_t min_realPositionChange = 0; // minimum change of the position before the shutter operates. different for PWM and time based operations
uint16_t min_TiltChange = 0; // minimum change of the tilt before the shutter operates. different for PWM and time based operations
} Shutter[MAX_SHUTTERS];
struct SHUTTERGLOBAL {
@ -108,8 +111,7 @@ struct SHUTTERGLOBAL {
uint8_t position_mode = 0; // how to calculate actual position: SHT_TIME, SHT_COUNTER, SHT_PWM_VALUE, SHT_PWM_TIME
uint8_t skip_relay_change; // avoid overrun at endstops
uint8_t start_reported = 0; // indicates of the shutter start was reported through MQTT JSON
uint16_t open_velocity_max = 1000; // maximum of PWM change during opening. Defines velocity on opening. Steppers and Servos only
uint16_t venetian_delay = 0;
uint16_t open_velocity_max = RESOLUTION; // maximum of PWM change during opening. Defines velocity on opening. Steppers and Servos only
} ShutterGlobal;
#define SHT_DIV_ROUND(__A, __B) (((__A) + (__B)/2) / (__B))
@ -327,6 +329,10 @@ void ShutterInit(void)
Shutter[i].tilt_real_pos = Settings->shutter_tilt_pos[i];
Shutter[i].tilt_velocity = Shutter[i].tilt_config[2] > 0 ? (Shutter[i].tilt_config[1]-Shutter[i].tilt_config[0])/Shutter[i].tilt_config[2] : 1;
Shutter[i].close_velocity_max = ShutterGlobal.open_velocity_max*Shutter[i].open_time / Shutter[i].close_time;
Shutter[i].min_realPositionChange = 2 * tmax(ShutterGlobal.open_velocity_max, Shutter[i].close_velocity_max);
Shutter[i].min_TiltChange = 2 * Shutter[i].tilt_velocity;
switch (ShutterGlobal.position_mode) {
case SHT_PWM_VALUE:
@ -334,14 +340,15 @@ void ShutterInit(void)
// Initiate pwm range with defaults if not already set.
Settings->shutter_pwmrange[0][i] = Settings->shutter_pwmrange[0][i] > 0 ? Settings->shutter_pwmrange[0][i] : pwm_servo_min;
Settings->shutter_pwmrange[1][i] = Settings->shutter_pwmrange[1][i] > 0 ? Settings->shutter_pwmrange[1][i] : pwm_servo_max;
Shutter[i].min_realPositionChange = 0;
Shutter[i].min_TiltChange = 0;
break;
}
Shutter[i].close_velocity_max = ShutterGlobal.open_velocity_max*Shutter[i].open_time / Shutter[i].close_time;
AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Shtr%d min realpos_chg: %d, min tilt_chg %d"),i+1,Shutter[i].min_realPositionChange,Shutter[i].min_TiltChange);
//AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d Openvel %d, Closevel: %d"),i, ShutterGlobal.open_velocity_max, Shutter[i].close_velocity_max);
AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Shtr%d Init. Pos %d, Inverted %d, Locked %d, End stop time enabled %d, webButtons inverted %d, delay: %d"),
AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Shtr%d Init. Pos %d, Inv %d, Locked %d, Endstop enab %d, webButt inv %d, Motordel: %d"),
i+1, Shutter[i].real_position,
(Settings->shutter_options[i]&1) ? 1 : 0, (Settings->shutter_options[i]&2) ? 1 : 0, (Settings->shutter_options[i]&4) ? 1 : 0, (Settings->shutter_options[i]&8) ? 1 : 0), Shutter[i].motordelay;
(Settings->shutter_options[i]&1) ? 1 : 0, (Settings->shutter_options[i]&2) ? 1 : 0, (Settings->shutter_options[i]&4) ? 1 : 0, (Settings->shutter_options[i]&8) ? 1 : 0, Shutter[i].motordelay);
} else {
// terminate loop at first INVALID Shutter[i].
@ -380,7 +387,8 @@ void ShutterReportPosition(bool always, uint32_t index)
//AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: rules_flag.shutter_moving: %d, moved %d"), TasmotaGlobal.rules_flag.shutter_moving, TasmotaGlobal.rules_flag.shutter_moved);
}
void ShutterLimitRealAndTargetPositions(uint32_t i) {
void ShutterLimitRealAndTargetPositions(uint32_t i)
{
if (Shutter[i].real_position<0) Shutter[i].real_position = 0;
if (Shutter[i].real_position>Shutter[i].open_max) Shutter[i].real_position = Shutter[i].open_max;
if (Shutter[i].target_position<0) Shutter[i].target_position = 0;
@ -461,7 +469,8 @@ void ShutterDecellerateForStop(uint8_t i)
}
}
void ShutterPowerOff(uint8_t i) {
void ShutterPowerOff(uint8_t i)
{
AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Stop Shutter %d. Switchmode %d"), i+1,Shutter[i].switch_mode); // fix log to indicate correct shutter number
ShutterDecellerateForStop(i);
switch (Shutter[i].switch_mode) {
@ -490,15 +499,18 @@ void ShutterPowerOff(uint8_t i) {
// Store current PWM value to ensure proper position after reboot.
switch (ShutterGlobal.position_mode) {
case SHT_PWM_VALUE:
char scmnd[20];
#ifdef SHUTTER_CLEAR_PWM_ONSTOP
// free the PWM servo lock on stop.
snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_PWM "%d 0" ), i+1);
#else
snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_PWM "%d %d" ), i+1,Shutter[i].pwm_value);
#endif
ExecuteCommand(scmnd, SRC_BUTTON);
break;
Shutter[i].pwm_value = SHT_DIV_ROUND((Settings->shutter_pwmrange[1][i]-Settings->shutter_pwmrange[0][i]) * Shutter[i].target_position , Shutter[i].open_max)+Settings->shutter_pwmrange[0][i];
analogWrite(Pin(GPIO_PWM1, i), Shutter[i].pwm_value);
AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: PWM final %d"),Shutter[i].pwm_value);
char scmnd[20];
#ifdef SHUTTER_CLEAR_PWM_ONSTOP
// free the PWM servo lock on stop.
snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_PWM "%d 0" ), i+1);
#else
snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_PWM "%d %d" ), i+1,Shutter[i].pwm_value);
#endif
//ExecuteCommand(scmnd, SRC_BUTTON);
break;
}
if (Shutter[i].direction !=0) {
Shutter[i].direction = 0;
@ -508,7 +520,6 @@ void ShutterPowerOff(uint8_t i) {
void ShutterUpdatePosition(void)
{
char scommand[CMDSZ];
char stopic[TOPSZ];
for (uint32_t i = 0; i < TasmotaGlobal.shutters_present; i++) {
@ -518,12 +529,13 @@ void ShutterUpdatePosition(void)
XdrvRulesProcess(0);
ShutterGlobal.start_reported = 1;
}
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Time %d, cStop %d, cVelo %d, mVelo %d, aVelo %d, mRun %d, aPos %d, aPos2 %d, nStop %d, Trgt %d, mVelo %d, Dir %d, Tilt %d"),
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Time %d, cStop %d, cVelo %d, mVelo %d, aVelo %d, mRun %d, aPos %d, aPos2 %d, nStop %d, Trgt %d, mVelo %d, Dir %d, Tilt %d, TrgtTilt: %d, Tiltmove: %d"),
Shutter[i].time, current_stop_way, current_pwm_velocity, velocity_max, Shutter[i].accelerator, min_runtime_ms, current_real_position,Shutter[i].real_position,
next_possible_stop_position, Shutter[i].target_position, velocity_change_per_step_max, Shutter[i].direction,Shutter[i].tilt_real_pos);
next_possible_stop_position, Shutter[i].target_position, velocity_change_per_step_max, Shutter[i].direction,Shutter[i].tilt_real_pos, Shutter[i].tilt_target_pos,
Shutter[i].tiltmoving);
if ( (Shutter[i].real_position * Shutter[i].direction >= Shutter[i].target_position * Shutter[i].direction &&
Shutter[i].tilt_real_pos * Shutter[i].direction * Shutter[i].tilt_config[2] >= Shutter[i].tilt_target_pos * Shutter[i].direction * Shutter[i].tilt_config[2])
if ( ((Shutter[i].real_position * Shutter[i].direction >= Shutter[i].target_position * Shutter[i].direction && Shutter[i].tiltmoving==0) ||
((int16_t)Shutter[i].tilt_real_pos * Shutter[i].direction * Shutter[i].tilt_config[2] >= (int16_t)Shutter[i].tilt_target_pos * Shutter[i].direction * Shutter[i].tilt_config[2] && Shutter[i].tiltmoving==1))
|| (ShutterGlobal.position_mode == SHT_COUNTER && Shutter[i].accelerator <0 && Shutter[i].pwm_velocity+Shutter[i].accelerator<PWM_MIN)) {
if (Shutter[i].direction != 0) {
Shutter[i].lastdirection = Shutter[i].direction;
@ -536,12 +548,16 @@ void ShutterUpdatePosition(void)
// manage venetian blinds
Shutter[i].tilt_target_pos = Settings->shutter_position[i] == 0 ? Shutter[i].tilt_config[0] : Shutter[i].tilt_target_pos;
Shutter[i].tilt_target_pos = Settings->shutter_position[i] == 100 ? Shutter[i].tilt_config[1] : Shutter[i].tilt_target_pos;
if (abs(Shutter[i].tilt_real_pos - Shutter[i].tilt_target_pos) > 10) {
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Tilt does not match akt %d, target %d"),Shutter[i].tilt_real_pos,Shutter[i].tilt_target_pos);
if (abs(Shutter[i].tilt_real_pos - Shutter[i].tilt_target_pos) > Shutter[i].min_TiltChange) {
AddLog(LOG_LEVEL_INFO, PSTR("SHT: Tilt not match %d -> %d"),Shutter[i].tilt_real_pos,Shutter[i].tilt_target_pos);
XdrvMailbox.payload = -99;
XdrvMailbox.index = i+1;
Shutter[i].tiltmoving = 1;
CmndShutterPosition();
return;
} else {
Settings->shutter_tilt_pos[i] = Shutter[i].tilt_real_pos;
Shutter[i].tiltmoving = 0;
}
ShutterLogPos(i);
@ -558,7 +574,8 @@ void ShutterUpdatePosition(void)
}
}
bool ShutterState(uint32_t device) {
bool ShutterState(uint32_t device)
{
if (device > 4) { return false; }
device--;
device &= 3;
@ -583,9 +600,10 @@ void ShutterAllowPreStartProcedure(uint8_t i)
void ShutterStartInit(uint32_t i, int32_t direction, int32_t target_pos)
{
//AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: dir %d, delta1 %d, delta2 %d, grant %d"),direction, (Shutter[i].open_max - Shutter[i].real_position) / Shutter[i].close_velocity, Shutter[i].real_position / Shutter[i].close_velocity, 2+Shutter[i].motordelay);
if ( ( ( (1 == direction) && ((Shutter[i].open_max - Shutter[i].real_position) / 100 <= 2))
|| ( (-1 == direction) && (Shutter[i].real_position / Shutter[i].close_velocity <= 2)) ) && abs(Shutter[i].tilt_real_pos-Shutter[i].tilt_target_pos)/Shutter[i].tilt_velocity <= 2) {
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: dir %d, delta1 %d, delta2 %d"),direction, (Shutter[i].open_max - Shutter[i].real_position) / Shutter[i].close_velocity, Shutter[i].real_position / Shutter[i].close_velocity);
if ( ( ( (1 == direction) && ((Shutter[i].open_max - Shutter[i].real_position) <= Shutter[i].min_realPositionChange))
|| ( (-1 == direction) && (Shutter[i].real_position <= Shutter[i].min_realPositionChange)) )
&& abs(Shutter[i].tilt_real_pos-Shutter[i].tilt_target_pos) <= Shutter[i].min_TiltChange) {
ShutterGlobal.skip_relay_change = 1;
} else {
Shutter[i].pwm_velocity = 0;
@ -614,10 +632,10 @@ void ShutterStartInit(uint32_t i, int32_t direction, int32_t target_pos)
Shutter[i].venetian_delay = (Shutter[i].direction > 0 ? Shutter[i].tilt_config[1]-Shutter[i].tilt_real_pos : Shutter[i].tilt_real_pos-Shutter[i].tilt_config[0]) * Shutter[i].tilt_config[2] / (Shutter[i].tilt_config[1]-Shutter[i].tilt_config[0]);
//AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: real %d, start %d, counter %d,freq_max %d, dir %d, freq %d"),Shutter[i].real_position, Shutter[i].start_position ,RtcSettings.pulse_counter[i],ShutterGlobal.open_velocity_max , Shutter[i].direction ,ShutterGlobal.open_velocity_max );
//AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: %d VenetianDelay: %d, Pos: %d, Dir: %d, Delta: %d, Durat: %d, Start: %d, Target: %d"),
//i, Shutter[i].venetian_delay, Shutter[i].tilt_real_pos,Shutter[i].direction,(Shutter[i].tilt_config[1]-Shutter[i].tilt_config[0]), Shutter[i].tilt_config[2],Shutter[i].tilt_start_pos,Shutter[i].tilt_target_pos);
// i, Shutter[i].venetian_delay, Shutter[i].tilt_real_pos,Shutter[i].direction,(Shutter[i].tilt_config[1]-Shutter[i].tilt_config[0]), Shutter[i].tilt_config[2],Shutter[i].tilt_start_pos,Shutter[i].tilt_target_pos);
}
}
//AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Start shtr%d from %d to %d in direction %d"), i, Shutter[i].start_position, Shutter[i].target_position, Shutter[i].direction);
AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Start shtr%d from %d to %d in direction %d"), i, Shutter[i].start_position, Shutter[i].target_position, Shutter[i].direction);
}
int32_t ShutterCalculatePosition(uint32_t i)
@ -636,7 +654,7 @@ int32_t ShutterCalculatePosition(uint32_t i)
Shutter[i].tilt_real_pos = (Shutter[i].tilt_start_pos + ((Shutter[i].direction * (int16_t)Shutter[i].time * (Shutter[i].tilt_config[1]-Shutter[i].tilt_config[0])) / Shutter[i].tilt_config[2]));
} else {
Shutter[i].tilt_real_pos = Shutter[i].direction == 1 ? Shutter[i].tilt_config[1] : Shutter[i].tilt_config[0];
}
}
}
return Shutter[i].start_position + ( (Shutter[i].time - tmin(Shutter[i].venetian_delay+Shutter[i].motordelay, Shutter[i].time)) * (Shutter[i].direction > 0 ? RESOLUTION : -Shutter[i].close_velocity));
break;
@ -691,6 +709,7 @@ void ShutterRelayChanged(void)
case SHT_COUNTER:
case SHT_PWM_VALUE:
case SHT_PWM_TIME:
//AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: power off manual change"));
ShutterPowerOff(i);
switch (powerstate_local) {
case 1:
@ -734,7 +753,8 @@ void ShutterRelayChanged(void)
} // for (uint32_t i = 0; i < TasmotaGlobal.shutters_present; i++)
}
bool ShutterButtonIsSimultaneousHold(uint32_t button_index, uint32_t shutter_index) {
bool ShutterButtonIsSimultaneousHold(uint32_t button_index, uint32_t shutter_index)
{
// check for simultaneous shutter button hold
uint32 min_shutterbutton_hold_timer = -1; // -1 == max(uint32)
for (uint32_t i = 0; i < MAX_SHUTTER_KEYS; i++) {
@ -1074,7 +1094,6 @@ void CmndShutterIncDec(void)
}
}
void CmndShutterPosition(void)
{
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present)) {
@ -1121,17 +1140,21 @@ void CmndShutterPosition(void)
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: lastsource %d:, real %d, target %d, tiltreal: %d, tilttarget: %d, payload %d"), TasmotaGlobal.last_source, Shutter[index].real_position ,Shutter[index].target_position,Shutter[index].tilt_real_pos, Shutter[index].tilt_target_pos,target_pos_percent);
}
if ( (target_pos_percent >= 0) && (target_pos_percent <= 100) &&
(abs(Shutter[index].target_position - Shutter[index].real_position ) / Shutter[index].close_velocity > 2 ||
abs(Shutter[index].tilt_target_pos - Shutter[index].tilt_real_pos ) / Shutter[index].tilt_velocity > 2) ) {
(abs(Shutter[index].target_position - Shutter[index].real_position ) > Shutter[index].min_realPositionChange ||
abs(Shutter[index].tilt_target_pos - Shutter[index].tilt_real_pos ) > Shutter[index].min_TiltChange) ) {
if (Settings->shutter_options[index] & 4) {
if (0 == target_pos_percent) Shutter[index].target_position -= 1 * RESOLUTION * STEPS_PER_SECOND;
if (100 == target_pos_percent) Shutter[index].target_position += 1 * RESOLUTION * STEPS_PER_SECOND;
}
int8_t new_shutterdirection = Shutter[index].real_position < Shutter[index].target_position ? 1 : -1;
if (Shutter[index].real_position == Shutter[index].target_position) {
int8_t new_shutterdirection;
if (abs(Shutter[index].target_position - Shutter[index].real_position ) > Shutter[index].min_realPositionChange) {
new_shutterdirection = Shutter[index].real_position < Shutter[index].target_position ? 1 : -1;
} else {
new_shutterdirection = Shutter[index].tilt_real_pos < Shutter[index].tilt_target_pos ? 1 : -1;
}
if (Shutter[index].direction == -new_shutterdirection) {
//AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Stop shutter to reverse direction"));
ShutterPowerOff(index);
}
if (Shutter[index].direction != new_shutterdirection) {
@ -1203,6 +1226,7 @@ void CmndShutterStopPosition(void)
}
}
}
void CmndShutterOpenTime(void)
{
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present)) {
@ -1423,8 +1447,8 @@ void CmndShutterSetHalfway(void)
void CmndShutterSetTilt(void)
{
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present)) {
if (XdrvMailbox.payload != -99 && XdrvMailbox.payload >= Shutter[XdrvMailbox.index -1].tilt_config[0] && XdrvMailbox.payload <= Shutter[XdrvMailbox.index -1].tilt_config[1] ) {
Shutter[XdrvMailbox.index -1].tilt_target_pos = XdrvMailbox.payload;
if (XdrvMailbox.payload != -99 ) {
Shutter[XdrvMailbox.index -1].tilt_target_pos = tmin(tmax(XdrvMailbox.payload, Shutter[XdrvMailbox.index -1].tilt_config[0]), Shutter[XdrvMailbox.index -1].tilt_config[1]);
XdrvMailbox.payload = -99;
}
if ((XdrvMailbox.data_len > 1) && (XdrvMailbox.payload <= 0)) {
@ -1440,6 +1464,7 @@ void CmndShutterSetTilt(void)
}
XdrvMailbox.data[0] = '\0';
ResponseCmndNumber(Shutter[XdrvMailbox.index -1].tilt_target_pos);
Shutter[XdrvMailbox.index -1].tiltmoving = 1;
CmndShutterPosition();
}