ajuste regras do IMU, fps da camera, desligamento dos bicos ao desligar pulverizador automatico, atualizado autonomia de herbicida

This commit is contained in:
Diego Freitas 2026-06-18 13:38:44 -03:00
parent 632f672ce1
commit 809c0412e3
7 changed files with 201 additions and 45 deletions

View File

@ -763,6 +763,11 @@ namespace AgroBase.Forms.Operacoes
private void chbPulverizador_CheckedChanged(object sender, EventArgs e)
{
Variaveis.OperacaoEmAndamento.Parametros.Controle.PulverizadorAutomatico = ((CheckBox)sender).Checked;
if (!Variaveis.OperacaoEmAndamento.Parametros.Controle.PulverizadorAutomatico && Variaveis.OperacaoEmAndamento.Controle.Bicos.Any(x => x.ComandoAtuar))
{
Variaveis.OperacaoEmAndamento.Controle.Bicos.ForEach(b => b.ComandoAtuar = false);
}
}
private void chbSonarAtivado_CheckedChanged(object sender, EventArgs e)

View File

@ -593,6 +593,7 @@ namespace AgroBase.Models.Modules
Sensor_ID_Num = 11,
ComandoAtuar = false,
PressaoSP = 100,
PotenciaSP = 100,
Componente = S_Code.sBMB,
Comandar = true,
Mandatorio = true,

View File

@ -200,6 +200,12 @@ namespace AgroBase.Models
{
CorredorAtual?.AtualizarDados();
//AtualizarDadosAutonomiaCorredor(idxCorredor: idxNovoCorredor);
}
bool mudouCorredor = (CorredorAtual?.Idx ?? -1) != idxNovoCorredor;
if (mudouCorredor || !AutonomiaCorredor.Liberado)
{
AtualizarDadosAutonomiaCorredor(idxCorredor: idxNovoCorredor);
}

View File

@ -98,7 +98,7 @@ namespace AgroBase.Services
public static async Task ConfigurarModulo()
{
Variaveis.MostrarLog($"[GPSService.ConfigurarModulo] Iniciando configuração do módulo GPS...");
await ConfigurarModuloRover(comprimento_antena: 130);
await ConfigurarModuloRover(comprimento_antena: 100);
}
private static async Task ConfigurarModuloRover(string porta_usb = "com3", string porta_entrada = "com2", int comprimento_antena = 100, int tolerancia_antena = 5)

View File

@ -377,18 +377,40 @@ namespace AgroBase.Services
private double CalcularLPorMetroReferencia(double velocidadeAtual_m_s)
{
// 1. Histórico real já consolidado
if (LPorMetroHistorico > 0)
return LPorMetroHistorico;
// 2. Janela atual real
if (LPorMetro > 0)
return LPorMetro;
double velocidade_m_min = velocidadeAtual_m_s * 60.0;
// 3. Pré-cálculo enquanto o robô ainda está parado
double velocidadeReferencia_m_s = velocidadeAtual_m_s;
if (velocidade_m_min > 0.1 && LPorMinutoEstimadoBicos > 0)
return LPorMinutoEstimadoBicos / velocidade_m_min;
if (velocidadeReferencia_m_s < 0.10)
{
velocidadeReferencia_m_s =
FuncoesMatematicas.CalculaVelocidadeMsPercentual(
Variaveis.OperacaoEmAndamento
.Parametros
.Controle
.MovVelocidadeCErvasPercent
);
}
return LPorMetroBase;
// Para a verificação pré-corredor, usar o pior caso:
// todos os bicos pulverizando.
double vazaoReferencia_LMin = VazaoTotalTodosBicos_LMin;
if (velocidadeReferencia_m_s > 0.01 &&
vazaoReferencia_LMin > 0)
{
double velocidade_m_min = velocidadeReferencia_m_s * 60.0;
return vazaoReferencia_LMin / velocidade_m_min;
}
return 0;
}
public bool ConseguePulverizarRua(double comprimentoRua_m)

View File

@ -65,75 +65,187 @@ class RegrasTaticas:
_imu = ContextoGlobalRedis.get_modulo(T_Code.Imu) or {}
_imu_saude = StatusModulo(
_imu.get("saude", {}).get("status", StatusModulo.DESCONECTADO.value)
_imu.get("saude", {}).get(
"status",
StatusModulo.DESCONECTADO.value
)
)
imu_operante = _imu_saude in [StatusModulo.OPERANTE, StatusModulo.ALERTA]
imu_operante = _imu_saude in [
StatusModulo.OPERANTE,
StatusModulo.ALERTA,
]
imu_ts = float(_imu.get("timestamp", 0.0) or 0.0)
imu_ts_s = imu_ts / 1000.0 if imu_ts > 100000000000.0 else imu_ts
imu_atualizada = (time.time() - imu_ts_s) <= 1.0 if imu_ts_s > 0 else False
# ============================================================
# Atualidade do dado
# ============================================================
try:
imu_ts = float(_imu.get("timestamp", 0.0) or 0.0)
except (TypeError, ValueError):
imu_ts = 0.0
imu_ts_s = (
imu_ts / 1000.0
if imu_ts > 100000000000.0
else imu_ts
)
imu_atualizada = (
(time.time() - imu_ts_s) <= 1.0
if imu_ts_s > 0
else False
)
imu_valido = bool(_imu.get("valido", False))
risk_level = str(_imu.get("risk_level", "unknown") or "unknown")
risk_level_num = int(_imu.get("risk_level_num", 4) or 4)
# ============================================================
# Estado de risco
# ============================================================
risk_level = str(
_imu.get("risk_level", "unknown") or "unknown"
).strip().lower()
risk_level_num_raw = _imu.get("risk_level_num", None)
if risk_level_num_raw is None:
# Fallback pelo campo textual caso o número não tenha sido publicado.
mapa_niveis = {
"normal": 0,
"attention": 1,
"risk": 2,
"critical": 3,
"emergency": 4,
}
risk_level_num = mapa_niveis.get(risk_level, 4)
else:
try:
risk_level_num = int(risk_level_num_raw)
except (TypeError, ValueError):
risk_level_num = 4
# Impede valores fora do contrato.
risk_level_num = max(0, min(4, risk_level_num))
stop = bool(_imu.get("stop", False))
emergency_stop = bool(_imu.get("emergency_stop", False))
bloquear_avanco = bool(_imu.get("bloquear_avanco", False))
roll = float(_imu.get("roll_filtrado", _imu.get("roll_seg", _imu.get("roll", 0.0))) or 0.0)
pitch = float(_imu.get("pitch_filtrado", _imu.get("pitch_seg", _imu.get("pitch", 0.0))) or 0.0)
try:
roll = float(
_imu.get(
"roll_filtrado",
_imu.get("roll_seg", _imu.get("roll", 0.0))
) or 0.0
)
except (TypeError, ValueError):
roll = 0.0
roll_rate = float(_imu.get("roll_rate_dps", 0.0) or 0.0)
pitch_rate = float(_imu.get("pitch_rate_dps", 0.0) or 0.0)
try:
pitch = float(
_imu.get(
"pitch_filtrado",
_imu.get("pitch_seg", _imu.get("pitch", 0.0))
) or 0.0
)
except (TypeError, ValueError):
pitch = 0.0
try:
roll_rate = float(
_imu.get("roll_rate_dps", 0.0) or 0.0
)
except (TypeError, ValueError):
roll_rate = 0.0
try:
pitch_rate = float(
_imu.get("pitch_rate_dps", 0.0) or 0.0
)
except (TypeError, ValueError):
pitch_rate = 0.0
motivos_risco = _imu.get("motivos_risco", []) or []
acao_sugerida = str(_imu.get("acao_sugerida", "") or "")
imu_bloqueio_bruto = (
not imu_operante
or not imu_atualizada
or not imu_valido
or emergency_stop
or stop
or bloquear_avanco
or risk_level_num >= 3
acao_sugerida = str(
_imu.get("acao_sugerida", "") or ""
)
inclinacao_persistente = self._avaliar_persistencia(
nome="inclinacao_perigosa",
estado_bruto=imu_bloqueio_bruto,
tempo_acionar=0.10 if emergency_stop else 0.20,
tempo_liberar=1.2
)
# ============================================================
# Primeiro valida a disponibilidade da IMU
# ============================================================
if not imu_operante:
self._resetar_persistencia("inclinacao_perigosa")
motivos.append(
f"IMU mandatória por [ Parada por Inclinação ] não operante: {_imu_saude.name}"
"IMU mandatória por [ Parada por Inclinação ] "
f"não operante: {_imu_saude.name}"
)
freio_necessario = True
elif not imu_atualizada:
motivos.append("IMU mandatória por [ Parada por Inclinação ] desatualizada")
self._resetar_persistencia("inclinacao_perigosa")
motivos.append(
"IMU mandatória por [ Parada por Inclinação ] "
"desatualizada"
)
freio_necessario = True
elif not imu_valido:
motivos.append("IMU mandatória por [ Parada por Inclinação ] sem leitura válida")
freio_necessario = True
self._resetar_persistencia("inclinacao_perigosa")
elif inclinacao_persistente:
motivos.append(
f"IMU bloqueou movimento: {risk_level} | ação={acao_sugerida} | "
f"roll={roll:.2f}°, pitch={pitch:.2f}°, "
f"roll_rate={roll_rate:.1f}°/s, pitch_rate={pitch_rate:.1f}°/s"
"IMU mandatória por [ Parada por Inclinação ] "
"sem leitura válida"
)
if motivos_risco:
motivos.append(f"Motivos IMU: {', '.join(map(str, motivos_risco))}")
freio_necessario = True
freio_necessario = bool(emergency_stop or stop or risk_level_num >= 3)
else:
# A persistência passa a tratar somente perigo de inclinação,
# e não falhas de comunicação ou saúde.
perigo_inclinacao_bruto = bool(
emergency_stop
or stop
or bloquear_avanco
or risk_level_num >= 3
)
inclinacao_persistente = self._avaliar_persistencia(
nome="inclinacao_perigosa",
estado_bruto=perigo_inclinacao_bruto,
tempo_acionar=0.10 if emergency_stop else 0.20,
tempo_liberar=1.2,
)
if inclinacao_persistente:
motivos.append(
f"IMU bloqueou movimento: {risk_level} | "
f"nível={risk_level_num} | "
f"ação={acao_sugerida} | "
f"roll={roll:.2f}°, pitch={pitch:.2f}°, "
f"roll_rate={roll_rate:.1f}°/s, "
f"pitch_rate={pitch_rate:.1f}°/s"
)
if motivos_risco:
motivos.append(
f"Motivos IMU: "
f"{', '.join(map(str, motivos_risco))}"
)
# Se a persistência está ativa, o bloqueio também deve estar.
# Não devemos recalcular usando somente o estado instantâneo.
freio_necessario = True
else:
# Evita que um bloqueio antigo sobreviva ao recurso ser desligado
# e ligado novamente.
self._resetar_persistencia("inclinacao_perigosa")
pulverizador_automatico = _controle.get("pulverizador_automatico", False)
if pulverizador_automatico:
@ -159,7 +271,6 @@ class RegrasTaticas:
f"Cavitação na bomba pressurizadora da linha! "
f"Pressão: {pressao_sp}/{pressao_atual} psi"
)
freio_necessario = False
mov_assistido_sonar = _controle.get("mov_auxilio_sonar", False)
dir_assistido_sonar = _controle.get("dir_auxilio_sonar", False)
@ -205,3 +316,14 @@ class RegrasTaticas:
p["ultimo_estado_bruto"] = estado_bruto
return p["ativo"]
def _resetar_persistencia(self, nome):
p = self.persistencias.get(nome)
if p is None:
return
p["ativo"] = False
p["ts_inicio_true"] = None
p["ts_inicio_false"] = None
p["ultimo_estado_bruto"] = False

View File

@ -73,7 +73,7 @@ WEED_DEFAULT_CONFIG = {
"camera_height": 800,
# FPS solicitado na câmera/OAK. Pode ser maior que o pipeline.
"camera_fps": 25,
"camera_fps": 40,
# Tamanho final do tensor entregue ao modelo: [W, H].
"ia_resolution": [640, 400],