ajustes no calculo de risco do imu, autonomia de reservatorio, bateria e trajetoria.
This commit is contained in:
parent
ded951d733
commit
a59bee710d
|
|
@ -1763,7 +1763,7 @@ namespace AgroBase.Forms.Operacoes
|
||||||
}
|
}
|
||||||
|
|
||||||
// agrupar por tipo
|
// agrupar por tipo
|
||||||
var porTipo = dict.Where(x => x.Key.Contains("_")).GroupBy(kv => CandMpcKey.ParseKey(kv.Key).Tipo);
|
var porTipo = dict.Where(x => x.Key.Contains("_") && !x.Key.Contains("d")).GroupBy(kv => CandMpcKey.ParseKey(kv.Key).Tipo);
|
||||||
foreach (var g in porTipo.OrderBy(gr => gr.Key.ToString()))
|
foreach (var g in porTipo.OrderBy(gr => gr.Key.ToString()))
|
||||||
{
|
{
|
||||||
var tipoNode = tv.Nodes.Add(g.Key.ToString());
|
var tipoNode = tv.Nodes.Add(g.Key.ToString());
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -27,7 +27,7 @@ namespace AgroBase.Models
|
||||||
{
|
{
|
||||||
public class Variaveis
|
public class Variaveis
|
||||||
{
|
{
|
||||||
public static readonly bool IniciarWorkers = false;
|
public static readonly bool IniciarWorkers = true;
|
||||||
public static readonly bool Producao = false;
|
public static readonly bool Producao = false;
|
||||||
public static bool DebugMode { get; set; } = true;
|
public static bool DebugMode { get; set; } = true;
|
||||||
public static bool Fechando { get; set; } = false;
|
public static bool Fechando { get; set; } = false;
|
||||||
|
|
@ -873,7 +873,7 @@ namespace AgroBase.Models
|
||||||
}
|
}
|
||||||
public static double TensaoMinimaBateria { get; set; } = 30.0;
|
public static double TensaoMinimaBateria { get; set; } = 30.0;
|
||||||
public static double TensaoMaximaBateria { get; set; } = 42.0;
|
public static double TensaoMaximaBateria { get; set; } = 42.0;
|
||||||
public static double CorrenteMaximaBateria { get; set; } = 20.0;
|
public static double CorrenteMaximaBateria { get; set; } = 100.0;
|
||||||
public static double PercentualTensaoBateriaMin { get; set; } = 25.0;
|
public static double PercentualTensaoBateriaMin { get; set; } = 25.0;
|
||||||
public static double PercentualReservatorioMin { get; set; } = 8.0;
|
public static double PercentualReservatorioMin { get; set; } = 8.0;
|
||||||
public static double PercentualReservatorioMinCritio { get; set; } = 5.0;
|
public static double PercentualReservatorioMinCritio { get; set; } = 5.0;
|
||||||
|
|
@ -962,8 +962,8 @@ namespace AgroBase.Models
|
||||||
{ TipoMovimentoDirecional.MovimentoLateral, 90 },
|
{ TipoMovimentoDirecional.MovimentoLateral, 90 },
|
||||||
{ TipoMovimentoDirecional.Diagnostico, 25 },
|
{ TipoMovimentoDirecional.Diagnostico, 25 },
|
||||||
};
|
};
|
||||||
public static double AnguloInclinacaoRollMax { get; set; } = 45.0; // Frontal
|
public static double AnguloInclinacaoRollMax { get; set; } = 30.0; // Frontal 40 graus max
|
||||||
public static double AnguloInclinacaoPitchMax { get; set; } = 25.0; // Lateral
|
public static double AnguloInclinacaoPitchMax { get; set; } = 22.0; // Lateral
|
||||||
public static string VozAlerta { get; set; } = "Microsoft Maria Desktop";
|
public static string VozAlerta { get; set; } = "Microsoft Maria Desktop";
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -35,20 +35,28 @@ class CameraIMU(ModuloDiagnosticoBase):
|
||||||
timeout_imu_s=0.40,
|
timeout_imu_s=0.40,
|
||||||
timeout_camera_s=2.0,
|
timeout_camera_s=2.0,
|
||||||
max_disagreement_deg=4.0,
|
max_disagreement_deg=4.0,
|
||||||
roll_attention_deg=7.0,
|
|
||||||
roll_risk_deg=11.0,
|
# Limites principais vindos do equipamento.
|
||||||
roll_critical_deg=16.0,
|
# No rover:
|
||||||
roll_emergency_deg=22.0,
|
# roll = inclinação frontal
|
||||||
pitch_attention_deg=8.0,
|
# pitch = inclinação lateral
|
||||||
pitch_risk_deg=14.0,
|
roll_max_default_deg=45.0,
|
||||||
pitch_critical_deg=20.0,
|
pitch_max_default_deg=25.0,
|
||||||
pitch_emergency_deg=28.0,
|
|
||||||
|
# Níveis derivados do limite máximo configurado.
|
||||||
|
angulo_attention_factor=0.50,
|
||||||
|
angulo_risk_factor=0.75,
|
||||||
|
angulo_emergency_factor=1.20,
|
||||||
|
limites_refresh_s=1.0,
|
||||||
|
|
||||||
|
# Taxas continuam independentes do ângulo máximo.
|
||||||
roll_rate_attention_dps=25.0,
|
roll_rate_attention_dps=25.0,
|
||||||
roll_rate_risk_dps=40.0,
|
roll_rate_risk_dps=40.0,
|
||||||
roll_rate_critical_dps=65.0,
|
roll_rate_critical_dps=65.0,
|
||||||
pitch_rate_attention_dps=25.0,
|
pitch_rate_attention_dps=25.0,
|
||||||
pitch_rate_risk_dps=45.0,
|
pitch_rate_risk_dps=45.0,
|
||||||
pitch_rate_critical_dps=75.0,
|
pitch_rate_critical_dps=75.0,
|
||||||
|
|
||||||
filtro_alpha=0.35,
|
filtro_alpha=0.35,
|
||||||
historico_len=100,
|
historico_len=100,
|
||||||
modulos_imu=None,
|
modulos_imu=None,
|
||||||
|
|
@ -61,15 +69,35 @@ class CameraIMU(ModuloDiagnosticoBase):
|
||||||
self.timeout_camera_s = float(timeout_camera_s)
|
self.timeout_camera_s = float(timeout_camera_s)
|
||||||
self.max_disagreement_deg = float(max_disagreement_deg)
|
self.max_disagreement_deg = float(max_disagreement_deg)
|
||||||
|
|
||||||
self.roll_attention_deg = float(roll_attention_deg)
|
# ============================================================
|
||||||
self.roll_risk_deg = float(roll_risk_deg)
|
# Limites angulares do equipamento
|
||||||
self.roll_critical_deg = float(roll_critical_deg)
|
# ============================================================
|
||||||
self.roll_emergency_deg = float(roll_emergency_deg)
|
|
||||||
|
|
||||||
self.pitch_attention_deg = float(pitch_attention_deg)
|
self.roll_max_default_deg = float(roll_max_default_deg)
|
||||||
self.pitch_risk_deg = float(pitch_risk_deg)
|
self.pitch_max_default_deg = float(pitch_max_default_deg)
|
||||||
self.pitch_critical_deg = float(pitch_critical_deg)
|
|
||||||
self.pitch_emergency_deg = float(pitch_emergency_deg)
|
self.angulo_attention_factor = float(angulo_attention_factor)
|
||||||
|
self.angulo_risk_factor = float(angulo_risk_factor)
|
||||||
|
self.angulo_emergency_factor = float(angulo_emergency_factor)
|
||||||
|
|
||||||
|
self.limites_refresh_s = max(float(limites_refresh_s), 0.25)
|
||||||
|
self._ultimo_refresh_limites = 0.0
|
||||||
|
|
||||||
|
# Valores iniciais seguros. Serão substituídos pelos dados do Redis.
|
||||||
|
self.roll_max_deg = self.roll_max_default_deg
|
||||||
|
self.pitch_max_deg = self.pitch_max_default_deg
|
||||||
|
|
||||||
|
self.roll_attention_deg = 0.0
|
||||||
|
self.roll_risk_deg = 0.0
|
||||||
|
self.roll_critical_deg = 0.0
|
||||||
|
self.roll_emergency_deg = 0.0
|
||||||
|
|
||||||
|
self.pitch_attention_deg = 0.0
|
||||||
|
self.pitch_risk_deg = 0.0
|
||||||
|
self.pitch_critical_deg = 0.0
|
||||||
|
self.pitch_emergency_deg = 0.0
|
||||||
|
|
||||||
|
self._recalcular_faixas_angulares()
|
||||||
|
|
||||||
self.roll_rate_attention_dps = float(roll_rate_attention_dps)
|
self.roll_rate_attention_dps = float(roll_rate_attention_dps)
|
||||||
self.roll_rate_risk_dps = float(roll_rate_risk_dps)
|
self.roll_rate_risk_dps = float(roll_rate_risk_dps)
|
||||||
|
|
@ -108,6 +136,9 @@ class CameraIMU(ModuloDiagnosticoBase):
|
||||||
|
|
||||||
self.roll_rate_filtrado = 0.0
|
self.roll_rate_filtrado = 0.0
|
||||||
self.pitch_rate_filtrado = 0.0
|
self.pitch_rate_filtrado = 0.0
|
||||||
|
# Não usar self.last_data para controlar a inicialização.
|
||||||
|
# Pode existir last_data de uma condição "sem_imu".
|
||||||
|
self._filtro_fusao_inicializado = False
|
||||||
|
|
||||||
self.roll_hist = deque(maxlen=historico_len)
|
self.roll_hist = deque(maxlen=historico_len)
|
||||||
self.pitch_hist = deque(maxlen=historico_len)
|
self.pitch_hist = deque(maxlen=historico_len)
|
||||||
|
|
@ -596,6 +627,120 @@ class CameraIMU(ModuloDiagnosticoBase):
|
||||||
|
|
||||||
return fontes, ignoradas, desabilitadas
|
return fontes, ignoradas, desabilitadas
|
||||||
|
|
||||||
|
def _validar_limite_angulo(self, valor, valor_atual):
|
||||||
|
"""
|
||||||
|
Valida um limite angular vindo do Redis.
|
||||||
|
|
||||||
|
Em caso de valor ausente ou inválido, mantém o último valor válido.
|
||||||
|
Isso impede que uma falha momentânea no contexto altere a segurança.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
valor = float(valor)
|
||||||
|
|
||||||
|
if not math.isfinite(valor):
|
||||||
|
return float(valor_atual)
|
||||||
|
|
||||||
|
# Evita configurações claramente inválidas.
|
||||||
|
if valor < 5.0 or valor > 85.0:
|
||||||
|
return float(valor_atual)
|
||||||
|
|
||||||
|
return valor
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
return float(valor_atual)
|
||||||
|
|
||||||
|
def _recalcular_faixas_angulares(self):
|
||||||
|
"""
|
||||||
|
Deriva attention, risk, critical e emergency usando os dois
|
||||||
|
limites principais definidos pelo operador.
|
||||||
|
|
||||||
|
No contrato físico deste rover:
|
||||||
|
- roll = inclinação frontal
|
||||||
|
- pitch = inclinação lateral
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.roll_attention_deg = (
|
||||||
|
self.roll_max_deg * self.angulo_attention_factor
|
||||||
|
)
|
||||||
|
self.roll_risk_deg = (
|
||||||
|
self.roll_max_deg * self.angulo_risk_factor
|
||||||
|
)
|
||||||
|
self.roll_critical_deg = self.roll_max_deg
|
||||||
|
self.roll_emergency_deg = min(
|
||||||
|
89.0,
|
||||||
|
max(
|
||||||
|
self.roll_max_deg + 2.0,
|
||||||
|
self.roll_max_deg * self.angulo_emergency_factor,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.pitch_attention_deg = (
|
||||||
|
self.pitch_max_deg * self.angulo_attention_factor
|
||||||
|
)
|
||||||
|
self.pitch_risk_deg = (
|
||||||
|
self.pitch_max_deg * self.angulo_risk_factor
|
||||||
|
)
|
||||||
|
self.pitch_critical_deg = self.pitch_max_deg
|
||||||
|
self.pitch_emergency_deg = min(
|
||||||
|
89.0,
|
||||||
|
max(
|
||||||
|
self.pitch_max_deg + 2.0,
|
||||||
|
self.pitch_max_deg * self.angulo_emergency_factor,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def _atualizar_limites_equipamento(self, forcar=False):
|
||||||
|
"""
|
||||||
|
Atualiza periodicamente os limites definidos pelo equipamento.
|
||||||
|
|
||||||
|
Não consulta o Redis a 50 Hz, pois esses parâmetros mudam raramente.
|
||||||
|
"""
|
||||||
|
agora = time.perf_counter()
|
||||||
|
|
||||||
|
if (
|
||||||
|
not forcar
|
||||||
|
and (agora - self._ultimo_refresh_limites) < self.limites_refresh_s
|
||||||
|
):
|
||||||
|
return
|
||||||
|
|
||||||
|
self._ultimo_refresh_limites = agora
|
||||||
|
|
||||||
|
equipamento = ContextoGlobalRedis.get_equipamento() or {}
|
||||||
|
|
||||||
|
roll_anterior = self.roll_max_deg
|
||||||
|
pitch_anterior = self.pitch_max_deg
|
||||||
|
|
||||||
|
novo_roll_max = self._validar_limite_angulo(
|
||||||
|
equipamento.get("angulo_roll_max"),
|
||||||
|
self.roll_max_deg,
|
||||||
|
)
|
||||||
|
|
||||||
|
novo_pitch_max = self._validar_limite_angulo(
|
||||||
|
equipamento.get("angulo_pitch_max"),
|
||||||
|
self.pitch_max_deg,
|
||||||
|
)
|
||||||
|
|
||||||
|
mudou = (
|
||||||
|
abs(novo_roll_max - self.roll_max_deg) > 1e-6
|
||||||
|
or abs(novo_pitch_max - self.pitch_max_deg) > 1e-6
|
||||||
|
)
|
||||||
|
|
||||||
|
self.roll_max_deg = novo_roll_max
|
||||||
|
self.pitch_max_deg = novo_pitch_max
|
||||||
|
|
||||||
|
self._recalcular_faixas_angulares()
|
||||||
|
|
||||||
|
if mudou:
|
||||||
|
self.mostrar_log(
|
||||||
|
"Limites angulares atualizados | "
|
||||||
|
f"roll/frontal={roll_anterior:.1f}°→{self.roll_max_deg:.1f}° | "
|
||||||
|
f"pitch/lateral={pitch_anterior:.1f}°→{self.pitch_max_deg:.1f}° | "
|
||||||
|
f"critical=({self.roll_critical_deg:.1f}°, "
|
||||||
|
f"{self.pitch_critical_deg:.1f}°) | "
|
||||||
|
f"emergency=({self.roll_emergency_deg:.1f}°, "
|
||||||
|
f"{self.pitch_emergency_deg:.1f}°)"
|
||||||
|
)
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# Fusão
|
# Fusão
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
@ -695,6 +840,87 @@ class CameraIMU(ModuloDiagnosticoBase):
|
||||||
"single_source": False,
|
"single_source": False,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def _atualizar_filtro_fusao(self, fusao):
|
||||||
|
"""
|
||||||
|
Atualiza uma única vez por ciclo os valores filtrados da atitude final.
|
||||||
|
|
||||||
|
Os ângulos filtrados serão usados tanto:
|
||||||
|
- na decisão de risco;
|
||||||
|
- quanto na publicação e nos logs.
|
||||||
|
|
||||||
|
As taxas brutas continuam disponíveis para detectar movimentos rápidos.
|
||||||
|
"""
|
||||||
|
|
||||||
|
roll = float(fusao.get("roll", 0.0))
|
||||||
|
pitch = float(fusao.get("pitch", 0.0))
|
||||||
|
yaw = float(fusao.get("yaw", 0.0))
|
||||||
|
|
||||||
|
roll_rate = float(fusao.get("roll_rate_dps", 0.0))
|
||||||
|
pitch_rate = float(fusao.get("pitch_rate_dps", 0.0))
|
||||||
|
|
||||||
|
alpha = self.clamp(float(self.filtro_alpha), 0.0, 1.0)
|
||||||
|
|
||||||
|
if not self._filtro_fusao_inicializado:
|
||||||
|
self.roll_filtrado = roll
|
||||||
|
self.pitch_filtrado = pitch
|
||||||
|
self.yaw_filtrado = yaw
|
||||||
|
|
||||||
|
self.roll_rate_filtrado = roll_rate
|
||||||
|
self.pitch_rate_filtrado = pitch_rate
|
||||||
|
|
||||||
|
self._filtro_fusao_inicializado = True
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.roll_filtrado = self._ema(
|
||||||
|
self.roll_filtrado,
|
||||||
|
roll,
|
||||||
|
alpha,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.pitch_filtrado = self._ema(
|
||||||
|
self.pitch_filtrado,
|
||||||
|
pitch,
|
||||||
|
alpha,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Yaw precisa respeitar o wrap -180° / +180°.
|
||||||
|
dyaw = self._angle_delta_deg(
|
||||||
|
yaw,
|
||||||
|
self.yaw_filtrado,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.yaw_filtrado += alpha * dyaw
|
||||||
|
self.yaw_filtrado = (
|
||||||
|
self.yaw_filtrado + 180.0
|
||||||
|
) % 360.0 - 180.0
|
||||||
|
|
||||||
|
self.roll_rate_filtrado = self._ema(
|
||||||
|
self.roll_rate_filtrado,
|
||||||
|
roll_rate,
|
||||||
|
alpha,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.pitch_rate_filtrado = self._ema(
|
||||||
|
self.pitch_rate_filtrado,
|
||||||
|
pitch_rate,
|
||||||
|
alpha,
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"roll": float(self.roll_filtrado),
|
||||||
|
"pitch": float(self.pitch_filtrado),
|
||||||
|
"yaw": float(self.yaw_filtrado),
|
||||||
|
"roll_rate_dps": float(self.roll_rate_filtrado),
|
||||||
|
"pitch_rate_dps": float(self.pitch_rate_filtrado),
|
||||||
|
}
|
||||||
|
|
||||||
|
def _resetar_filtro_fusao(self):
|
||||||
|
"""
|
||||||
|
Faz a próxima leitura válida inicializar o filtro diretamente
|
||||||
|
com a atitude atual, evitando carregar valores antigos.
|
||||||
|
"""
|
||||||
|
self._filtro_fusao_inicializado = False
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# Risco e ação sugerida
|
# Risco e ação sugerida
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
@ -918,6 +1144,7 @@ class CameraIMU(ModuloDiagnosticoBase):
|
||||||
ignoradas,
|
ignoradas,
|
||||||
desabilitadas,
|
desabilitadas,
|
||||||
fusao,
|
fusao,
|
||||||
|
atitude_filtrada,
|
||||||
divergencia,
|
divergencia,
|
||||||
risco,
|
risco,
|
||||||
redundancia_disponivel,
|
redundancia_disponivel,
|
||||||
|
|
@ -931,24 +1158,12 @@ class CameraIMU(ModuloDiagnosticoBase):
|
||||||
pitch_rate = float(fusao["pitch_rate_dps"])
|
pitch_rate = float(fusao["pitch_rate_dps"])
|
||||||
yaw_rate = float(fusao["yaw_rate_dps"])
|
yaw_rate = float(fusao["yaw_rate_dps"])
|
||||||
|
|
||||||
a = self.filtro_alpha
|
roll_filtrado = float(atitude_filtrada["roll"])
|
||||||
|
pitch_filtrado = float(atitude_filtrada["pitch"])
|
||||||
|
yaw_filtrado = float(atitude_filtrada["yaw"])
|
||||||
|
|
||||||
if self.last_data is None:
|
roll_rate_filtrado = float(atitude_filtrada["roll_rate_dps"])
|
||||||
self.roll_filtrado = roll
|
pitch_rate_filtrado = float(atitude_filtrada["pitch_rate_dps"])
|
||||||
self.pitch_filtrado = pitch
|
|
||||||
self.yaw_filtrado = yaw
|
|
||||||
self.roll_rate_filtrado = roll_rate
|
|
||||||
self.pitch_rate_filtrado = pitch_rate
|
|
||||||
else:
|
|
||||||
self.roll_filtrado = self._ema(self.roll_filtrado, roll, a)
|
|
||||||
self.pitch_filtrado = self._ema(self.pitch_filtrado, pitch, a)
|
|
||||||
|
|
||||||
dyaw = self._angle_delta_deg(yaw, self.yaw_filtrado)
|
|
||||||
self.yaw_filtrado = self.yaw_filtrado + a * dyaw
|
|
||||||
self.yaw_filtrado = (self.yaw_filtrado + 180.0) % 360.0 - 180.0
|
|
||||||
|
|
||||||
self.roll_rate_filtrado = self._ema(self.roll_rate_filtrado, roll_rate, a)
|
|
||||||
self.pitch_rate_filtrado = self._ema(self.pitch_rate_filtrado, pitch_rate, a)
|
|
||||||
|
|
||||||
self.roll_hist.append(roll)
|
self.roll_hist.append(roll)
|
||||||
self.pitch_hist.append(pitch)
|
self.pitch_hist.append(pitch)
|
||||||
|
|
@ -988,21 +1203,21 @@ class CameraIMU(ModuloDiagnosticoBase):
|
||||||
"yaw": round(yaw, 3),
|
"yaw": round(yaw, 3),
|
||||||
|
|
||||||
# Dado levemente suavizado.
|
# Dado levemente suavizado.
|
||||||
"roll_filtrado": round(self.roll_filtrado, 3),
|
"roll_filtrado": round(roll_filtrado, 3),
|
||||||
"pitch_filtrado": round(self.pitch_filtrado, 3),
|
"pitch_filtrado": round(pitch_filtrado, 3),
|
||||||
"yaw_filtrado": round(self.yaw_filtrado, 3),
|
"yaw_filtrado": round(yaw_filtrado, 3),
|
||||||
|
|
||||||
# Compatibilidade com contrato antigo.
|
# Compatibilidade com contrato antigo.
|
||||||
"roll_seg": round(self.roll_filtrado, 3),
|
"roll_seg": round(roll_filtrado, 3),
|
||||||
"pitch_seg": round(self.pitch_filtrado, 3),
|
"pitch_seg": round(pitch_filtrado, 3),
|
||||||
|
|
||||||
# Tendência angular.
|
# Tendência angular.
|
||||||
"roll_rate_dps": round(roll_rate, 3),
|
"roll_rate_dps": round(roll_rate, 3),
|
||||||
"pitch_rate_dps": round(pitch_rate, 3),
|
"pitch_rate_dps": round(pitch_rate, 3),
|
||||||
"yaw_rate_dps": round(yaw_rate, 3),
|
"yaw_rate_dps": round(yaw_rate, 3),
|
||||||
|
|
||||||
"roll_rate_filtrado_dps": round(self.roll_rate_filtrado, 3),
|
"roll_rate_filtrado_dps": round(roll_rate_filtrado, 3),
|
||||||
"pitch_rate_filtrado_dps": round(self.pitch_rate_filtrado, 3),
|
"pitch_rate_filtrado_dps": round(pitch_rate_filtrado, 3),
|
||||||
|
|
||||||
# Segurança.
|
# Segurança.
|
||||||
"risk_level": risco["risk_level"],
|
"risk_level": risco["risk_level"],
|
||||||
|
|
@ -1016,6 +1231,43 @@ class CameraIMU(ModuloDiagnosticoBase):
|
||||||
"stop": risco["stop"],
|
"stop": risco["stop"],
|
||||||
"emergency_stop": risco["emergency_stop"],
|
"emergency_stop": risco["emergency_stop"],
|
||||||
|
|
||||||
|
"convencao_eixos": {
|
||||||
|
"roll": "frontal",
|
||||||
|
"pitch": "lateral",
|
||||||
|
},
|
||||||
|
|
||||||
|
"limites_angulo": {
|
||||||
|
"roll": {
|
||||||
|
"semantica": "frontal",
|
||||||
|
"attention_deg": round(self.roll_attention_deg, 3),
|
||||||
|
"risk_deg": round(self.roll_risk_deg, 3),
|
||||||
|
"critical_deg": round(self.roll_critical_deg, 3),
|
||||||
|
"emergency_deg": round(self.roll_emergency_deg, 3),
|
||||||
|
"max_configurado_deg": round(self.roll_max_deg, 3),
|
||||||
|
},
|
||||||
|
"pitch": {
|
||||||
|
"semantica": "lateral",
|
||||||
|
"attention_deg": round(self.pitch_attention_deg, 3),
|
||||||
|
"risk_deg": round(self.pitch_risk_deg, 3),
|
||||||
|
"critical_deg": round(self.pitch_critical_deg, 3),
|
||||||
|
"emergency_deg": round(self.pitch_emergency_deg, 3),
|
||||||
|
"max_configurado_deg": round(self.pitch_max_deg, 3),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"roll_max_configurado_deg": round(self.roll_max_deg, 3),
|
||||||
|
"pitch_max_configurado_deg": round(self.pitch_max_deg, 3),
|
||||||
|
|
||||||
|
"roll_attention_deg": round(self.roll_attention_deg, 3),
|
||||||
|
"roll_risk_deg": round(self.roll_risk_deg, 3),
|
||||||
|
"roll_critical_deg": round(self.roll_critical_deg, 3),
|
||||||
|
"roll_emergency_deg": round(self.roll_emergency_deg, 3),
|
||||||
|
|
||||||
|
"pitch_attention_deg": round(self.pitch_attention_deg, 3),
|
||||||
|
"pitch_risk_deg": round(self.pitch_risk_deg, 3),
|
||||||
|
"pitch_critical_deg": round(self.pitch_critical_deg, 3),
|
||||||
|
"pitch_emergency_deg": round(self.pitch_emergency_deg, 3),
|
||||||
|
|
||||||
# Diagnóstico de fusão.
|
# Diagnóstico de fusão.
|
||||||
"confidence": round(float(fusao.get("confidence", 0.0)), 3),
|
"confidence": round(float(fusao.get("confidence", 0.0)), 3),
|
||||||
"fonte_principal": fonte_principal,
|
"fonte_principal": fonte_principal,
|
||||||
|
|
@ -1102,6 +1354,8 @@ class CameraIMU(ModuloDiagnosticoBase):
|
||||||
try:
|
try:
|
||||||
agora = time.time()
|
agora = time.time()
|
||||||
|
|
||||||
|
self._atualizar_limites_equipamento()
|
||||||
|
|
||||||
fontes, ignoradas, desabilitadas = self._ler_fontes_imu()
|
fontes, ignoradas, desabilitadas = self._ler_fontes_imu()
|
||||||
|
|
||||||
modulos_validos = {
|
modulos_validos = {
|
||||||
|
|
@ -1115,6 +1369,7 @@ class CameraIMU(ModuloDiagnosticoBase):
|
||||||
)
|
)
|
||||||
|
|
||||||
if len(fontes) <= 0:
|
if len(fontes) <= 0:
|
||||||
|
self._resetar_filtro_fusao()
|
||||||
data = self._montar_saida_sem_imu(
|
data = self._montar_saida_sem_imu(
|
||||||
ignoradas,
|
ignoradas,
|
||||||
desabilitadas,
|
desabilitadas,
|
||||||
|
|
@ -1124,11 +1379,20 @@ class CameraIMU(ModuloDiagnosticoBase):
|
||||||
fusao = self._fundir_fontes(fontes)
|
fusao = self._fundir_fontes(fontes)
|
||||||
divergencia = self._calcular_divergencia(fontes)
|
divergencia = self._calcular_divergencia(fontes)
|
||||||
|
|
||||||
|
# Atualiza o filtro antes de avaliar o risco.
|
||||||
|
atitude_filtrada = self._atualizar_filtro_fusao(fusao)
|
||||||
|
|
||||||
risco = self._avaliar_risco(
|
risco = self._avaliar_risco(
|
||||||
roll=fusao["roll"],
|
# Ângulos filtrados evitam parada por um único pico de leitura.
|
||||||
pitch=fusao["pitch"],
|
roll=atitude_filtrada["roll"],
|
||||||
|
pitch=atitude_filtrada["pitch"],
|
||||||
|
|
||||||
|
# Taxas brutas continuam rápidas.
|
||||||
|
# Se o robô começar a tombar rapidamente, a segurança não fica
|
||||||
|
# esperando o filtro angular acompanhar.
|
||||||
roll_rate=fusao["roll_rate_dps"],
|
roll_rate=fusao["roll_rate_dps"],
|
||||||
pitch_rate=fusao["pitch_rate_dps"],
|
pitch_rate=fusao["pitch_rate_dps"],
|
||||||
|
|
||||||
sensores_agree=divergencia["sensors_agree"],
|
sensores_agree=divergencia["sensors_agree"],
|
||||||
redundancia_disponivel=redundancia_disponivel,
|
redundancia_disponivel=redundancia_disponivel,
|
||||||
)
|
)
|
||||||
|
|
@ -1138,6 +1402,7 @@ class CameraIMU(ModuloDiagnosticoBase):
|
||||||
ignoradas=ignoradas,
|
ignoradas=ignoradas,
|
||||||
desabilitadas=desabilitadas,
|
desabilitadas=desabilitadas,
|
||||||
fusao=fusao,
|
fusao=fusao,
|
||||||
|
atitude_filtrada=atitude_filtrada,
|
||||||
divergencia=divergencia,
|
divergencia=divergencia,
|
||||||
risco=risco,
|
risco=risco,
|
||||||
redundancia_disponivel=redundancia_disponivel,
|
redundancia_disponivel=redundancia_disponivel,
|
||||||
|
|
|
||||||
|
|
@ -441,6 +441,10 @@ class CameraManager:
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def reiniciar_deteccoes(self):
|
||||||
|
self._reset_runtime_state()
|
||||||
|
return True, "estado operacional limpo"
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# Warmup
|
# Warmup
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
|
||||||
|
|
@ -81,8 +81,12 @@ def main():
|
||||||
tipos = dados.get("params", {}).get("tipos", [])
|
tipos = dados.get("params", {}).get("tipos", [])
|
||||||
get_camera_manager().salvar_frames(tipos, nome, pasta)
|
get_camera_manager().salvar_frames(tipos, nome, pasta)
|
||||||
elif acao == WeedWorkerCommandType.ReiniciarDeteccoes:
|
elif acao == WeedWorkerCommandType.ReiniciarDeteccoes:
|
||||||
if get_camera_manager().weed_detector is not None:
|
manager = get_camera_manager()
|
||||||
get_camera_manager().weed_detector._reiniciar_deteccoes()
|
ok, motivo = manager.reiniciar_deteccoes()
|
||||||
|
if ok:
|
||||||
|
mostrar_log(f"[weed] Detecções reiniciadas: {motivo}")
|
||||||
|
else:
|
||||||
|
mostrar_log(f"[weed] Não foi possível reiniciar detecções: {motivo}")
|
||||||
else:
|
else:
|
||||||
mostrar_log(f"⚠️ Comando desconhecido: {acao.name}")
|
mostrar_log(f"⚠️ Comando desconhecido: {acao.name}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue