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")) ?? "",
bateria_ok = _t.AutonomiaCooredor?.BateriaSuficiente ?? false,
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
),
@ -308,6 +312,8 @@ namespace AgroBase.Services.Operadores
{
percent_vel_max = pControle.MovVelocidadeSErvasPercent,
percent_vel_min = pControle.MovVelocidadeCErvasPercent,
percent_vel_curva = 20.0,
rampa_partida_pct = VariaveisEquipamento.PercentualVelMin,
rampa_aceleracao_pct_s = 12.0,
rampa_desaceleracao_pct_s = 18.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
]
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 {
"pulverizador_automatico": pulverizador_automatico,
"calibrando": calibrando,
@ -347,6 +357,9 @@ class ModuloAtuador(ModuloDiagnosticoBase):
"bicos_ligados": bicos_ligados,
"bombas_comandadas": bombas_comandadas,
"bombas_ligadas": bombas_ligadas,
"corredor_liberado": corredor_liberado,
"autonomia_ok_supervisionado": autonomia_ok_supervisionado,
"autonomia_motivo": autonomia_motivo,
"debug": {
"pulverizador_automatico": pulverizador_automatico,
"calibrando": calibrando,
@ -1061,13 +1074,19 @@ class ModuloAtuador(ModuloDiagnosticoBase):
if not ctx["herbicida_ok_corredor"]:
motivo = self._texto_ou_padrao(
ctx.get("autonomia_motivo"),
ctx.get("motivo_herbicida_corredor"),
padrao="Herbicida insuficiente para pulverizar o corredor completo."
)
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({
"label": "Autonomia de herbicida",
"valor": ctx["percent_reservatorio"],
@ -1076,6 +1095,7 @@ class ModuloAtuador(ModuloDiagnosticoBase):
"descricao": motivo,
"acoes": [
"Reabastecer ou reduzir distância do corredor planejado.",
"Liberar manualmente pela base se o operador assumir a supervisão.",
],
})
score = min(score, 80)
@ -1085,9 +1105,10 @@ class ModuloAtuador(ModuloDiagnosticoBase):
"valor": ctx["percent_reservatorio"],
"severidade": 35,
"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": [
"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)

View File

@ -187,24 +187,26 @@ def definir_comando(filtro_vel: FiltroVelocidade, erro_orientacao: float = None)
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:
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")
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")
else:
velocidade_sp = 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
)
velocidade_sp = velocidade_livre
debug["motivos"].append("caminhando rua livre")
else:
@ -328,7 +330,8 @@ def definir_comando(filtro_vel: FiltroVelocidade, erro_orientacao: float = None)
# Aceleração normal é filtrada para não dar tranco.
reducao_seguranca = bool(
reduzir_para_fim_corredor
reduzir_para_pulverizar
or reduzir_para_fim_corredor
or reduzir_por_curva
or reduzir_por_ipb
or debug.get("visual", {}).get("mode") in ["caution", "slowdown"]
@ -782,18 +785,32 @@ def _aplicar_rampa_velocidade(
ultimo_ts = 0.0
if ultimo_ts <= 0.0:
ultimo = 0.0
ultimo_ts = agora
partida_pct = _float(
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:
filtro_vel._ultimo_sp_campo = ultimo
filtro_vel._ultimo_ts_campo = ultimo_ts
filtro_vel._ultimo_sp_campo = saida
filtro_vel._ultimo_ts_campo = agora
except Exception:
pass
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)

View File

@ -216,11 +216,12 @@ class RegrasTaticas:
)
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(
nome="oak_obstaculo",
estado_bruto=parar,
estado_bruto=parar_hard,
tempo_acionar=0.15,
tempo_liberar=0.80
)