ajustes na saude do atuador; regras de controle de movimento;

This commit is contained in:
Diego Freitas 2026-07-08 10:49:18 -03:00
parent 84f6882d51
commit e59b40bbdd
4 changed files with 69 additions and 24 deletions

View File

@ -185,7 +185,11 @@ namespace AgroBase.Services.Operadores
motivo_bat = _t.AutonomiaCooredor?.Motivos?.FirstOrDefault(x => x.Contains("Bateria")) ?? "", motivo_bat = _t.AutonomiaCooredor?.Motivos?.FirstOrDefault(x => x.Contains("Bateria")) ?? "",
bateria_ok = _t.AutonomiaCooredor?.BateriaSuficiente ?? false, bateria_ok = _t.AutonomiaCooredor?.BateriaSuficiente ?? false,
motivo_hrb = _t.AutonomiaCooredor?.Motivos?.FirstOrDefault(x => x.Contains("Herbicida")) ?? "", motivo_hrb = _t.AutonomiaCooredor?.Motivos?.FirstOrDefault(x => x.Contains("Herbicida")) ?? "",
herbicida_ok = _t.AutonomiaCooredor?.HerbicidaSuficiente ?? false herbicida_ok = _t.AutonomiaCooredor?.HerbicidaSuficiente ?? false,
autonomia_liberada = _t.AutonomiaCooredor?.Liberado ?? false,
autonomia_status = (int)(_t.AutonomiaCooredor?.Status ?? AutonomiaCorredorStatus.Desconhecido),
autonomia_motivo = _t.AutonomiaCooredor?.Motivo ?? "",
autonomia_ok_supervisionado = _t.AutonomiaCooredor?.Status == AutonomiaCorredorStatus.OkSupervisionado,
}, },
} : null } : null
), ),
@ -308,6 +312,8 @@ namespace AgroBase.Services.Operadores
{ {
percent_vel_max = pControle.MovVelocidadeSErvasPercent, percent_vel_max = pControle.MovVelocidadeSErvasPercent,
percent_vel_min = pControle.MovVelocidadeCErvasPercent, percent_vel_min = pControle.MovVelocidadeCErvasPercent,
percent_vel_curva = 20.0,
rampa_partida_pct = VariaveisEquipamento.PercentualVelMin,
rampa_aceleracao_pct_s = 12.0, rampa_aceleracao_pct_s = 12.0,
rampa_desaceleracao_pct_s = 18.0, rampa_desaceleracao_pct_s = 18.0,
rampa_desaceleracao_seguranca_pct_s = 35.0, rampa_desaceleracao_seguranca_pct_s = 35.0,

View File

@ -325,6 +325,16 @@ class ModuloAtuador(ModuloDiagnosticoBase):
self._float(self._get(b["dados"], "potencia", self._campo_atual(b["dados"], "Potencia", 0)), 0) > self.POTENCIA_MIN_BOMBA_LIGADA self._float(self._get(b["dados"], "potencia", self._campo_atual(b["dados"], "Potencia", 0)), 0) > self.POTENCIA_MIN_BOMBA_LIGADA
] ]
corredor_liberado = self._bool(corredor.get("liberado", False))
autonomia_ok_supervisionado = self._bool(
corredor.get("autonomia_ok_supervisionado", False)
)
autonomia_motivo = self._texto_ou_padrao(
corredor.get("autonomia_motivo"),
corredor.get("motivo_hrb"),
padrao="Herbicida insuficiente para pulverizar o corredor completo."
)
return { return {
"pulverizador_automatico": pulverizador_automatico, "pulverizador_automatico": pulverizador_automatico,
"calibrando": calibrando, "calibrando": calibrando,
@ -347,6 +357,9 @@ class ModuloAtuador(ModuloDiagnosticoBase):
"bicos_ligados": bicos_ligados, "bicos_ligados": bicos_ligados,
"bombas_comandadas": bombas_comandadas, "bombas_comandadas": bombas_comandadas,
"bombas_ligadas": bombas_ligadas, "bombas_ligadas": bombas_ligadas,
"corredor_liberado": corredor_liberado,
"autonomia_ok_supervisionado": autonomia_ok_supervisionado,
"autonomia_motivo": autonomia_motivo,
"debug": { "debug": {
"pulverizador_automatico": pulverizador_automatico, "pulverizador_automatico": pulverizador_automatico,
"calibrando": calibrando, "calibrando": calibrando,
@ -1061,13 +1074,19 @@ class ModuloAtuador(ModuloDiagnosticoBase):
if not ctx["herbicida_ok_corredor"]: if not ctx["herbicida_ok_corredor"]:
motivo = self._texto_ou_padrao( motivo = self._texto_ou_padrao(
ctx.get("autonomia_motivo"),
ctx.get("motivo_herbicida_corredor"), ctx.get("motivo_herbicida_corredor"),
padrao="Herbicida insuficiente para pulverizar o corredor completo." padrao="Herbicida insuficiente para pulverizar o corredor completo."
) )
motivos.append(motivo) motivos.append(motivo)
if herbicida_pode_bloquear: autonomia_liberada_supervisionada = bool(
ctx.get("corredor_liberado", False) or
ctx.get("autonomia_ok_supervisionado", False)
)
if herbicida_pode_bloquear and not autonomia_liberada_supervisionada:
condicoes.append({ condicoes.append({
"label": "Autonomia de herbicida", "label": "Autonomia de herbicida",
"valor": ctx["percent_reservatorio"], "valor": ctx["percent_reservatorio"],
@ -1076,6 +1095,7 @@ class ModuloAtuador(ModuloDiagnosticoBase):
"descricao": motivo, "descricao": motivo,
"acoes": [ "acoes": [
"Reabastecer ou reduzir distância do corredor planejado.", "Reabastecer ou reduzir distância do corredor planejado.",
"Liberar manualmente pela base se o operador assumir a supervisão.",
], ],
}) })
score = min(score, 80) score = min(score, 80)
@ -1085,9 +1105,10 @@ class ModuloAtuador(ModuloDiagnosticoBase):
"valor": ctx["percent_reservatorio"], "valor": ctx["percent_reservatorio"],
"severidade": 35, "severidade": 35,
"classe": "recurso_operacional", "classe": "recurso_operacional",
"descricao": f"{motivo} Pulverização automática desligada; condição informativa, sem bloqueio de deslocamento.", "descricao": f"{motivo} Corredor liberado supervisionado; condição informativa, sem bloqueio estrutural.",
"acoes": [ "acoes": [
"Reabastecer antes de habilitar a pulverização automática.", "Monitorar consumo durante o corredor.",
"Reabastecer antes da próxima operação de pulverização.",
], ],
}) })
score = min(score, 90) score = min(score, 90)

View File

@ -187,24 +187,26 @@ def definir_comando(filtro_vel: FiltroVelocidade, erro_orientacao: float = None)
debug["weed"] = info_ervas debug["weed"] = info_ervas
velocidade_livre = calcular_velocidade_relativa(
vel_min=vel_com_ervas,
vel_max=vel_sem_ervas,
ang_max=ang_max,
erro_orientacao=erro_angular,
k=1.0,
curva=0.70,
dead=5.0
)
if reduzir_para_pulverizar: if reduzir_para_pulverizar:
velocidade_sp = min(velocidade_sp, vel_com_ervas) velocidade_sp = min(velocidade_livre, vel_com_ervas)
debug["motivos"].append("ervas no radar: reduzindo para pulverizar") debug["motivos"].append("ervas no radar: reduzindo para pulverizar")
elif reduzir_para_fim_corredor: elif reduzir_para_fim_corredor:
velocidade_sp = min(velocidade_sp, vel_com_ervas) velocidade_sp = min(velocidade_livre, vel_com_ervas)
debug["motivos"].append("fim de corredor próximo: reduzindo") debug["motivos"].append("fim de corredor próximo: reduzindo")
else: else:
velocidade_sp = calcular_velocidade_relativa( velocidade_sp = velocidade_livre
vel_min=vel_com_ervas,
vel_max=vel_sem_ervas,
ang_max=ang_max,
erro_orientacao=erro_angular,
k=1.0,
curva=0.70,
dead=5.0
)
debug["motivos"].append("caminhando rua livre") debug["motivos"].append("caminhando rua livre")
else: else:
@ -328,7 +330,8 @@ def definir_comando(filtro_vel: FiltroVelocidade, erro_orientacao: float = None)
# Aceleração normal é filtrada para não dar tranco. # Aceleração normal é filtrada para não dar tranco.
reducao_seguranca = bool( reducao_seguranca = bool(
reduzir_para_fim_corredor reduzir_para_pulverizar
or reduzir_para_fim_corredor
or reduzir_por_curva or reduzir_por_curva
or reduzir_por_ipb or reduzir_por_ipb
or debug.get("visual", {}).get("mode") in ["caution", "slowdown"] or debug.get("visual", {}).get("mode") in ["caution", "slowdown"]
@ -782,18 +785,32 @@ def _aplicar_rampa_velocidade(
ultimo_ts = 0.0 ultimo_ts = 0.0
if ultimo_ts <= 0.0: if ultimo_ts <= 0.0:
ultimo = 0.0 partida_pct = _float(
ultimo_ts = agora mov_cfg.get(
"rampa_partida_pct",
mov_cfg.get("percent_vel_min", 15.0)
),
15.0
)
partida_pct = max(1.0, partida_pct)
saida = min(float(velocidade_alvo), partida_pct)
try: try:
filtro_vel._ultimo_sp_campo = ultimo filtro_vel._ultimo_sp_campo = saida
filtro_vel._ultimo_ts_campo = ultimo_ts filtro_vel._ultimo_ts_campo = agora
except Exception: except Exception:
pass pass
if debug is not None: if debug is not None:
debug["rampa_velocidade_init"] = "inicializada_em_zero" debug["rampa_velocidade_init"] = {
"modo": "partida_nao_zero",
"alvo": round(float(velocidade_alvo), 2),
"saida": round(float(saida), 2),
"partida_pct": round(float(partida_pct), 2),
}
return 0.0 return saida
dt = _clamp(agora - ultimo_ts, 0.02, 0.5) dt = _clamp(agora - ultimo_ts, 0.02, 0.5)

View File

@ -216,11 +216,12 @@ class RegrasTaticas:
) )
parar = self._bool(decision.get("parar", False)) parar = self._bool(decision.get("parar", False))
mode = str(decision.get("mode", "") or "").lower() mode = str(decision.get("mode", "") or "").strip().lower()
parar_hard = bool(parar and mode == "stop")
obstaculo_persistente = self._avaliar_persistencia( obstaculo_persistente = self._avaliar_persistencia(
nome="oak_obstaculo", nome="oak_obstaculo",
estado_bruto=parar, estado_bruto=parar_hard,
tempo_acionar=0.15, tempo_acionar=0.15,
tempo_liberar=0.80 tempo_liberar=0.80
) )