ajustes no imu, filtro temperatura motor, alarmes npc, offset temperatura sensoriamento, metodo que abre curva ao final do corredor
This commit is contained in:
parent
6242d8b3dc
commit
742aac3f5d
|
|
@ -232,7 +232,8 @@ namespace AgroBase.Models.Modules
|
||||||
maximo = 80,
|
maximo = 80,
|
||||||
minimo = 5,
|
minimo = 5,
|
||||||
nominal = 25,
|
nominal = 25,
|
||||||
unidade_medida = "ºC"
|
unidade_medida = "ºC",
|
||||||
|
offset = -39.9,
|
||||||
},
|
},
|
||||||
new SensorValoresLeituraModel()
|
new SensorValoresLeituraModel()
|
||||||
{
|
{
|
||||||
|
|
@ -288,7 +289,8 @@ namespace AgroBase.Models.Modules
|
||||||
maximo = 80,
|
maximo = 80,
|
||||||
minimo = 5,
|
minimo = 5,
|
||||||
nominal = 25,
|
nominal = 25,
|
||||||
unidade_medida = "ºC"
|
unidade_medida = "ºC",
|
||||||
|
offset = -0.5,
|
||||||
},
|
},
|
||||||
new SensorValoresLeituraModel()
|
new SensorValoresLeituraModel()
|
||||||
{
|
{
|
||||||
|
|
@ -344,7 +346,8 @@ namespace AgroBase.Models.Modules
|
||||||
maximo = 80,
|
maximo = 80,
|
||||||
minimo = 5,
|
minimo = 5,
|
||||||
nominal = 25,
|
nominal = 25,
|
||||||
unidade_medida = "ºC"
|
unidade_medida = "ºC",
|
||||||
|
offset = -15.9,
|
||||||
},
|
},
|
||||||
new SensorValoresLeituraModel()
|
new SensorValoresLeituraModel()
|
||||||
{
|
{
|
||||||
|
|
@ -400,7 +403,8 @@ namespace AgroBase.Models.Modules
|
||||||
maximo = 80,
|
maximo = 80,
|
||||||
minimo = 5,
|
minimo = 5,
|
||||||
nominal = 25,
|
nominal = 25,
|
||||||
unidade_medida = "ºC"
|
unidade_medida = "ºC",
|
||||||
|
offset = -3.6,
|
||||||
},
|
},
|
||||||
new SensorValoresLeituraModel()
|
new SensorValoresLeituraModel()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ namespace AgroBase.Models
|
||||||
public AutonomiaCorredorModel AutonomiaCorredor { get; set; }
|
public AutonomiaCorredorModel AutonomiaCorredor { get; set; }
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
private GPSModel GPSPosicaoAtual => Variaveis.OperacaoEmAndamento.Sensoriamento?.Gps?.Clone();
|
private GPSModel GPSPosicaoAtual => GPSService.UltimaLeitura?.Clone();
|
||||||
|
|
||||||
[JsonProperty]
|
[JsonProperty]
|
||||||
public double TempoEntreLeituras { get; private set; }
|
public double TempoEntreLeituras { get; private set; }
|
||||||
|
|
@ -2155,8 +2155,6 @@ namespace AgroBase.Models
|
||||||
int idxEsq = 0;
|
int idxEsq = 0;
|
||||||
int idxDir = 0;
|
int idxDir = 0;
|
||||||
|
|
||||||
double anguloAcrescentar = direcaoAtual == DirecaoCarroRua.Ida ? AnguloAberturaCurva : -AnguloAberturaCurva;
|
|
||||||
|
|
||||||
for (int idx = 0; idx < Corredores.Count(); idx++)
|
for (int idx = 0; idx < Corredores.Count(); idx++)
|
||||||
{
|
{
|
||||||
double _FatorLarguraCorredor = CorredoresLarguras[idx] / LarguraCorredorPadrao;
|
double _FatorLarguraCorredor = CorredoresLarguras[idx] / LarguraCorredorPadrao;
|
||||||
|
|
@ -2282,15 +2280,29 @@ namespace AgroBase.Models
|
||||||
_trajetoriaFixa.Add(PontoTrajetoria);
|
_trajetoriaFixa.Add(PontoTrajetoria);
|
||||||
}
|
}
|
||||||
|
|
||||||
double anguloProjetar2 = GPSUtils.CalcularOrientacao(CorredorAtual.Skip(CorredorAtual.Count() - 2).First(), CorredorAtual.Last());
|
double percentualAcrescimoPontoAberturaCurva = 0.8;
|
||||||
|
double distancia_projetar = !ultimoCorredor ? (DistanciaProjecaoRua * percentualAcrescimoPontoAberturaCurva) : (DistanciaProjecaoRua * percentualAcrescimoPontoAberturaCurva);
|
||||||
|
|
||||||
|
GPSModel ultimoPontoCorredorAtual = CorredorAtual.Last();
|
||||||
|
double anguloProjetar2 = GPSUtils.CalcularOrientacao(CorredorAtual.Skip(CorredorAtual.Count() - 2).First(), ultimoPontoCorredorAtual);
|
||||||
|
GPSModel UltimoPonto = GPSUtils.ProjetarPontoDeslocado(ultimoPontoCorredorAtual, distancia_projetar, anguloProjetar2);
|
||||||
|
|
||||||
// Realiza um acréscimo no angulo à projetar, permitindo que o equipamento faça uma curva mais aberta entre corredores
|
// Realiza um acréscimo no angulo à projetar, permitindo que o equipamento faça uma curva mais aberta entre corredores
|
||||||
if (!ultimoCorredor && !_FatorLarguraElevado)
|
if (!ultimoCorredor && !_FatorLarguraElevado)
|
||||||
{
|
{
|
||||||
anguloProjetar2 += anguloAcrescentar;
|
GPSModel up_pos = GPSUtils.ProjetarPontoDeslocado(ultimoPontoCorredorAtual, distancia_projetar, anguloProjetar2 + AnguloAberturaCurva);
|
||||||
anguloAcrescentar *= -1;
|
GPSModel up_neg = GPSUtils.ProjetarPontoDeslocado(ultimoPontoCorredorAtual, distancia_projetar, anguloProjetar2 - AnguloAberturaCurva);
|
||||||
|
|
||||||
|
GPSModel pp_proximoCorredor = direcaoAtual == DirecaoCarroRua.Volta ? Corredores[idx + 1].FirstOrDefault() : Corredores[idx + 1].LastOrDefault();
|
||||||
|
|
||||||
|
double d_pos = GPSUtils.DistanciaEntrePontos(pp_proximoCorredor, up_pos);
|
||||||
|
double d_neg = GPSUtils.DistanciaEntrePontos(pp_proximoCorredor, up_neg);
|
||||||
|
|
||||||
|
if (d_pos > d_neg)
|
||||||
|
UltimoPonto = GPSUtils.ProjetarPontoDeslocado(ultimoPontoCorredorAtual, distancia_projetar, anguloProjetar2 + AnguloAberturaCurva);
|
||||||
|
else
|
||||||
|
UltimoPonto = GPSUtils.ProjetarPontoDeslocado(ultimoPontoCorredorAtual, distancia_projetar, anguloProjetar2 - AnguloAberturaCurva);
|
||||||
}
|
}
|
||||||
double percentualAcrescimoPontoAberturaCurva = 0.8;
|
|
||||||
GPSModel UltimoPonto = GPSUtils.ProjetarPontoDeslocado(CorredorAtual.Last(), !ultimoCorredor ? (DistanciaProjecaoRua * percentualAcrescimoPontoAberturaCurva) : (DistanciaProjecaoRua * percentualAcrescimoPontoAberturaCurva), anguloProjetar2);
|
|
||||||
|
|
||||||
PontoTrajetoriaModel PontoFinal = new PontoTrajetoriaModel(TipoPontoRua.LigacaoSaida)
|
PontoTrajetoriaModel PontoFinal = new PontoTrajetoriaModel(TipoPontoRua.LigacaoSaida)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -86,8 +86,13 @@ class IMUCamera(ModuloDiagnosticoBase):
|
||||||
self.calibrado = False
|
self.calibrado = False
|
||||||
self.calibrando = False
|
self.calibrando = False
|
||||||
self.calib_inicio_ts = 0.0
|
self.calib_inicio_ts = 0.0
|
||||||
|
self.calib_primeira_amostra_quat_ts = None
|
||||||
|
self.calib_min_amostras_quat = max(30, int(self.freq * 0.50))
|
||||||
|
self.calib_max_std_deg = 1.50
|
||||||
self.calib_quats_xyzw = []
|
self.calib_quats_xyzw = []
|
||||||
self.q_ref_inv = None
|
self.q_ref_inv = None
|
||||||
|
self.rotation_accuracy_rad = None
|
||||||
|
self.rotation_accuracy_max_rad = math.radians(20.0)
|
||||||
|
|
||||||
# Estado angular
|
# Estado angular
|
||||||
self.roll_deg = 0.0
|
self.roll_deg = 0.0
|
||||||
|
|
@ -176,7 +181,9 @@ class IMUCamera(ModuloDiagnosticoBase):
|
||||||
|
|
||||||
self.calibrado = False
|
self.calibrado = False
|
||||||
self.calibrando = True
|
self.calibrando = True
|
||||||
self.calib_inicio_ts = time.perf_counter()
|
# A janela útil começa somente quando chegar a primeira amostra válida.
|
||||||
|
self.calib_inicio_ts = 0.0
|
||||||
|
self.calib_primeira_amostra_quat_ts = None
|
||||||
|
|
||||||
self.calib_quats_xyzw.clear()
|
self.calib_quats_xyzw.clear()
|
||||||
self._calib_roll_hist.clear()
|
self._calib_roll_hist.clear()
|
||||||
|
|
@ -580,7 +587,12 @@ class IMUCamera(ModuloDiagnosticoBase):
|
||||||
if not self.calibrando:
|
if not self.calibrando:
|
||||||
return
|
return
|
||||||
|
|
||||||
self.calib_quats_xyzw.append(q_xyzw)
|
agora = time.perf_counter()
|
||||||
|
if self.calib_primeira_amostra_quat_ts is None:
|
||||||
|
self.calib_primeira_amostra_quat_ts = agora
|
||||||
|
self.calib_inicio_ts = agora
|
||||||
|
|
||||||
|
self.calib_quats_xyzw.append(np.asarray(q_xyzw, dtype=np.float64))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
roll_abs, pitch_abs, _ = R.from_quat(q_xyzw).as_euler("xyz", degrees=True)
|
roll_abs, pitch_abs, _ = R.from_quat(q_xyzw).as_euler("xyz", degrees=True)
|
||||||
|
|
@ -589,9 +601,28 @@ class IMUCamera(ModuloDiagnosticoBase):
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
elapsed = time.perf_counter() - self.calib_inicio_ts
|
elapsed = agora - self.calib_primeira_amostra_quat_ts
|
||||||
|
|
||||||
if elapsed < self.calibracao_segundos:
|
if (
|
||||||
|
elapsed < self.calibracao_segundos
|
||||||
|
or len(self.calib_quats_xyzw) < self.calib_min_amostras_quat
|
||||||
|
):
|
||||||
|
return
|
||||||
|
|
||||||
|
roll_std = float(np.std(self._calib_roll_hist)) if self._calib_roll_hist else 999.0
|
||||||
|
pitch_std = float(np.std(self._calib_pitch_hist)) if self._calib_pitch_hist else 999.0
|
||||||
|
|
||||||
|
# Não aceita como zero uma janela em que o rover/câmera se moveu.
|
||||||
|
if roll_std > self.calib_max_std_deg or pitch_std > self.calib_max_std_deg:
|
||||||
|
self.mostrar_log(
|
||||||
|
f"Calibração rejeitada por movimento | std_roll={roll_std:.3f}° | "
|
||||||
|
f"std_pitch={pitch_std:.3f}°. Reiniciando janela."
|
||||||
|
)
|
||||||
|
self.calib_quats_xyzw.clear()
|
||||||
|
self._calib_roll_hist.clear()
|
||||||
|
self._calib_pitch_hist.clear()
|
||||||
|
self.calib_primeira_amostra_quat_ts = None
|
||||||
|
self.calib_inicio_ts = 0.0
|
||||||
return
|
return
|
||||||
|
|
||||||
q_ref = self._media_quaternion_xyzw(self.calib_quats_xyzw)
|
q_ref = self._media_quaternion_xyzw(self.calib_quats_xyzw)
|
||||||
|
|
@ -607,9 +638,6 @@ class IMUCamera(ModuloDiagnosticoBase):
|
||||||
self.calibrando = False
|
self.calibrando = False
|
||||||
self.calibrado = True
|
self.calibrado = True
|
||||||
|
|
||||||
roll_std = float(np.std(self._calib_roll_hist)) if self._calib_roll_hist else 0.0
|
|
||||||
pitch_std = float(np.std(self._calib_pitch_hist)) if self._calib_pitch_hist else 0.0
|
|
||||||
|
|
||||||
self.mostrar_log(
|
self.mostrar_log(
|
||||||
f"Calibração concluída | amostras={len(self.calib_quats_xyzw)} | "
|
f"Calibração concluída | amostras={len(self.calib_quats_xyzw)} | "
|
||||||
f"std_roll={roll_std:.3f}° | std_pitch={pitch_std:.3f}°"
|
f"std_roll={roll_std:.3f}° | std_pitch={pitch_std:.3f}°"
|
||||||
|
|
@ -762,7 +790,6 @@ class IMUCamera(ModuloDiagnosticoBase):
|
||||||
if q_xyzw is None:
|
if q_xyzw is None:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
agora = time.perf_counter()
|
|
||||||
agora_wall = time.time()
|
agora_wall = time.time()
|
||||||
|
|
||||||
self.last_packet_ts = agora_wall
|
self.last_packet_ts = agora_wall
|
||||||
|
|
@ -770,6 +797,8 @@ class IMUCamera(ModuloDiagnosticoBase):
|
||||||
|
|
||||||
self._processar_calibracao(q_xyzw)
|
self._processar_calibracao(q_xyzw)
|
||||||
|
|
||||||
|
self.rotation_accuracy_rad = accuracy_rad
|
||||||
|
|
||||||
roll, pitch, yaw = self._quat_relativo_para_euler(q_xyzw)
|
roll, pitch, yaw = self._quat_relativo_para_euler(q_xyzw)
|
||||||
|
|
||||||
self.roll_deg = roll
|
self.roll_deg = roll
|
||||||
|
|
@ -825,6 +854,11 @@ class IMUCamera(ModuloDiagnosticoBase):
|
||||||
|
|
||||||
# Metadados do rotation vector.
|
# Metadados do rotation vector.
|
||||||
"rotation_accuracy_rad": accuracy_rad,
|
"rotation_accuracy_rad": accuracy_rad,
|
||||||
|
"rotation_accuracy_ok": bool(
|
||||||
|
accuracy_rad is not None
|
||||||
|
and math.isfinite(float(accuracy_rad))
|
||||||
|
and 0.0 <= float(accuracy_rad) <= self.rotation_accuracy_max_rad
|
||||||
|
),
|
||||||
|
|
||||||
# Saúde operacional básica.
|
# Saúde operacional básica.
|
||||||
"timestamp": agora_wall * 1000.0,
|
"timestamp": agora_wall * 1000.0,
|
||||||
|
|
|
||||||
|
|
@ -808,18 +808,26 @@ class CameraMultispectral:
|
||||||
)
|
)
|
||||||
performance["device_metrics"] = metrics
|
performance["device_metrics"] = metrics
|
||||||
|
|
||||||
temp = float(metrics.get("temperature_average_c", 0.0) or 0.0)
|
temp_raw = metrics.get("temperature_average_c")
|
||||||
performance["temperatura"] = temp
|
if temp_raw is None:
|
||||||
|
performance["temperatura"] = None
|
||||||
if temp >= 80:
|
motivos.append("Temperatura interna indisponível")
|
||||||
motivos.append(f"Temperatura crítica: {temp:.1f} °C")
|
saude -= 10
|
||||||
saude -= 30
|
else:
|
||||||
elif temp >= 70:
|
temp = float(temp_raw)
|
||||||
motivos.append(f"Temperatura elevada: {temp:.1f} °C")
|
performance["temperatura"] = temp
|
||||||
saude -= 15
|
if temp >= 100:
|
||||||
elif temp >= 60:
|
motivos.append(f"Temperatura de emergência: {temp:.1f} °C")
|
||||||
motivos.append(f"Temperatura acima do ideal: {temp:.1f} °C")
|
saude = min(saude, 10)
|
||||||
saude -= 5
|
elif temp >= 95:
|
||||||
|
motivos.append(f"Temperatura crítica: {temp:.1f} °C")
|
||||||
|
saude = min(saude, 35)
|
||||||
|
elif temp >= 85:
|
||||||
|
motivos.append(f"Temperatura elevada: {temp:.1f} °C")
|
||||||
|
saude -= 15
|
||||||
|
elif temp >= 75:
|
||||||
|
motivos.append(f"Aquecimento preventivo: {temp:.1f} °C")
|
||||||
|
saude -= 5
|
||||||
|
|
||||||
ddr = float(metrics.get("ddr_used_bytes", 0) or 0) / 1024.0 / 1024.0
|
ddr = float(metrics.get("ddr_used_bytes", 0) or 0) / 1024.0 / 1024.0
|
||||||
performance["memoria_usada"] = ddr
|
performance["memoria_usada"] = ddr
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,7 @@ class CameraOak:
|
||||||
nome_sensor=f"{self.modelo}_imu",
|
nome_sensor=f"{self.modelo}_imu",
|
||||||
modo=self.imu_modo,
|
modo=self.imu_modo,
|
||||||
gyro_unidade="rad_s",
|
gyro_unidade="rad_s",
|
||||||
referencial_robo="r,p,y",
|
referencial_robo="y,r,p",
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.modelo_ia_seg is not None:
|
if self.modelo_ia_seg is not None:
|
||||||
|
|
@ -634,15 +634,24 @@ class CameraOak:
|
||||||
"velocidade": speed
|
"velocidade": speed
|
||||||
}
|
}
|
||||||
# 🔸 Temperatura (> 60 °C começa a penalizar)
|
# 🔸 Temperatura (> 60 °C começa a penalizar)
|
||||||
if temp >= 80:
|
if temp is None:
|
||||||
motivos.append(f"Temperatura crítica: {temp:.1f} °C")
|
performance["temperatura"] = None
|
||||||
saude -= 30
|
motivos.append("Temperatura interna indisponível")
|
||||||
elif temp >= 70:
|
saude -= 10
|
||||||
motivos.append(f"Temperatura elevada: {temp:.1f} °C")
|
else:
|
||||||
saude -= 15
|
temp = float(temp)
|
||||||
elif temp >= 60:
|
if temp >= 100:
|
||||||
motivos.append(f"Temperatura acima do ideal: {temp:.1f} °C")
|
motivos.append(f"Temperatura de emergência: {temp:.1f} °C")
|
||||||
saude -= 5
|
saude = min(saude, 10)
|
||||||
|
elif temp >= 95:
|
||||||
|
motivos.append(f"Temperatura crítica: {temp:.1f} °C")
|
||||||
|
saude = min(saude, 35)
|
||||||
|
elif temp >= 85:
|
||||||
|
motivos.append(f"Temperatura elevada: {temp:.1f} °C")
|
||||||
|
saude -= 15
|
||||||
|
elif temp >= 75:
|
||||||
|
motivos.append(f"Aquecimento preventivo: {temp:.1f} °C")
|
||||||
|
saude -= 5
|
||||||
|
|
||||||
# 🔸 Memória DDR (> 300 MB começa a penalizar)
|
# 🔸 Memória DDR (> 300 MB começa a penalizar)
|
||||||
if ddr >= 500:
|
if ddr >= 500:
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ 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,
|
||||||
|
rotation_accuracy_max_rad=0.35,
|
||||||
|
|
||||||
# Limites principais vindos do equipamento.
|
# Limites principais vindos do equipamento.
|
||||||
# No rover:
|
# No rover:
|
||||||
|
|
@ -68,6 +69,7 @@ class CameraIMU(ModuloDiagnosticoBase):
|
||||||
self.timeout_imu_s = float(timeout_imu_s)
|
self.timeout_imu_s = float(timeout_imu_s)
|
||||||
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.rotation_accuracy_max_rad = float(rotation_accuracy_max_rad)
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# Limites angulares do equipamento
|
# Limites angulares do equipamento
|
||||||
|
|
@ -429,14 +431,13 @@ class CameraIMU(ModuloDiagnosticoBase):
|
||||||
# timestamp pode vir em ms.
|
# timestamp pode vir em ms.
|
||||||
ts_s = ts_ms / 1000.0 if ts_ms > 100000000000.0 else ts_ms
|
ts_s = ts_ms / 1000.0 if ts_ms > 100000000000.0 else ts_ms
|
||||||
|
|
||||||
candidatos_ts = [
|
# Todos os campos acima devem estar no relógio de parede (Unix epoch).
|
||||||
ts_s if ts_s > 0 else 0.0,
|
# Não usa max() cegamente: um timestamp monotônico misturado ao epoch
|
||||||
last_packet_ts if last_packet_ts > 0 else 0.0,
|
# pode esconder uma fonte velha ou produzir idade negativa.
|
||||||
last_publish_ts if last_publish_ts > 0 else 0.0,
|
ts_ref = ts_s if ts_s > 0 else last_packet_ts
|
||||||
]
|
if ts_ref <= 0:
|
||||||
|
ts_ref = last_publish_ts
|
||||||
ts_ref = max(candidatos_ts)
|
idade_s = max(0.0, agora - ts_ref) if ts_ref > 0 else 999.0
|
||||||
idade_s = (agora - ts_ref) if ts_ref > 0 else 999.0
|
|
||||||
|
|
||||||
roll = self._safe_float(imu, "roll", 0.0)
|
roll = self._safe_float(imu, "roll", 0.0)
|
||||||
pitch = self._safe_float(imu, "pitch", 0.0)
|
pitch = self._safe_float(imu, "pitch", 0.0)
|
||||||
|
|
@ -450,6 +451,9 @@ class CameraIMU(ModuloDiagnosticoBase):
|
||||||
pitch_rate = self._safe_float(imu, "pitch_rate_dps", 0.0)
|
pitch_rate = self._safe_float(imu, "pitch_rate_dps", 0.0)
|
||||||
yaw_rate = self._safe_float(imu, "yaw_rate_dps", 0.0)
|
yaw_rate = self._safe_float(imu, "yaw_rate_dps", 0.0)
|
||||||
|
|
||||||
|
modo = str(imu.get("modo", "") or "").lower()
|
||||||
|
accuracy_rad = self._safe_float(imu, "rotation_accuracy_rad", float("nan"))
|
||||||
|
|
||||||
imu_saude = None
|
imu_saude = None
|
||||||
try:
|
try:
|
||||||
saude_obj = imu.get("saude")
|
saude_obj = imu.get("saude")
|
||||||
|
|
@ -491,6 +495,29 @@ class CameraIMU(ModuloDiagnosticoBase):
|
||||||
confiavel = False
|
confiavel = False
|
||||||
motivos.append(f"peso_base_baixo")
|
motivos.append(f"peso_base_baixo")
|
||||||
|
|
||||||
|
valores = (roll_filtrado, pitch_filtrado, yaw_filtrado,
|
||||||
|
roll_rate, pitch_rate, yaw_rate)
|
||||||
|
if not all(math.isfinite(v) for v in valores):
|
||||||
|
confiavel = False
|
||||||
|
motivos.append("imu_valor_nao_finito")
|
||||||
|
|
||||||
|
accuracy_score = 1.0
|
||||||
|
if modo in ("rotation_vector", "game_rotation_vector"):
|
||||||
|
if not math.isfinite(accuracy_rad) or accuracy_rad < 0.0:
|
||||||
|
confiavel = False
|
||||||
|
accuracy_score = 0.0
|
||||||
|
motivos.append("rotation_accuracy_indisponivel")
|
||||||
|
elif accuracy_rad > self.rotation_accuracy_max_rad:
|
||||||
|
confiavel = False
|
||||||
|
accuracy_score = 0.0
|
||||||
|
motivos.append(f"rotation_accuracy_ruim_{accuracy_rad:.3f}rad")
|
||||||
|
else:
|
||||||
|
accuracy_score = self.clamp(
|
||||||
|
1.0 - accuracy_rad / self.rotation_accuracy_max_rad,
|
||||||
|
0.25,
|
||||||
|
1.0,
|
||||||
|
)
|
||||||
|
|
||||||
freshness = 1.0 - self.norm_to_100(idade_s, 0.0, self.timeout_imu_s) / 100.0
|
freshness = 1.0 - self.norm_to_100(idade_s, 0.0, self.timeout_imu_s) / 100.0
|
||||||
freshness = self.clamp(freshness, 0.0, 1.0)
|
freshness = self.clamp(freshness, 0.0, 1.0)
|
||||||
|
|
||||||
|
|
@ -501,7 +528,10 @@ class CameraIMU(ModuloDiagnosticoBase):
|
||||||
if imu_saude is not None:
|
if imu_saude is not None:
|
||||||
saude_score = self.clamp(imu_saude / 100.0, 0.0, 1.0)
|
saude_score = self.clamp(imu_saude / 100.0, 0.0, 1.0)
|
||||||
|
|
||||||
confidence = peso_base * freshness * calib_score * valido_score * saude_score
|
confidence = (
|
||||||
|
peso_base * freshness * calib_score * valido_score
|
||||||
|
* saude_score * accuracy_score
|
||||||
|
)
|
||||||
|
|
||||||
if not confiavel:
|
if not confiavel:
|
||||||
confidence = 0.0
|
confidence = 0.0
|
||||||
|
|
@ -525,9 +555,11 @@ class CameraIMU(ModuloDiagnosticoBase):
|
||||||
"confidence": float(confidence),
|
"confidence": float(confidence),
|
||||||
"peso_base": float(peso_base),
|
"peso_base": float(peso_base),
|
||||||
|
|
||||||
"roll": float(roll),
|
# O módulo final consome uma atitude coerente: os três ângulos
|
||||||
"pitch": float(pitch),
|
# filtrados pertencem à mesma fonte e ao mesmo instante publicado.
|
||||||
"yaw": float(yaw),
|
"roll": float(roll_filtrado),
|
||||||
|
"pitch": float(pitch_filtrado),
|
||||||
|
"yaw": float(yaw_filtrado),
|
||||||
|
|
||||||
"roll_filtrado": float(roll_filtrado),
|
"roll_filtrado": float(roll_filtrado),
|
||||||
"pitch_filtrado": float(pitch_filtrado),
|
"pitch_filtrado": float(pitch_filtrado),
|
||||||
|
|
@ -536,6 +568,7 @@ class CameraIMU(ModuloDiagnosticoBase):
|
||||||
"roll_rate_dps": float(roll_rate),
|
"roll_rate_dps": float(roll_rate),
|
||||||
"pitch_rate_dps": float(pitch_rate),
|
"pitch_rate_dps": float(pitch_rate),
|
||||||
"yaw_rate_dps": float(yaw_rate),
|
"yaw_rate_dps": float(yaw_rate),
|
||||||
|
"rotation_accuracy_rad": accuracy_rad if math.isfinite(accuracy_rad) else None,
|
||||||
|
|
||||||
"timestamp": ts_ms,
|
"timestamp": ts_ms,
|
||||||
"last_packet_ts": last_packet_ts,
|
"last_packet_ts": last_packet_ts,
|
||||||
|
|
@ -790,11 +823,18 @@ class CameraIMU(ModuloDiagnosticoBase):
|
||||||
"divergentes": [],
|
"divergentes": [],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def maior_distancia_circular(valores):
|
||||||
|
maior = 0.0
|
||||||
|
for i, a in enumerate(valores):
|
||||||
|
for b in valores[i + 1:]:
|
||||||
|
maior = max(maior, abs(self._angle_delta_deg(a, b)))
|
||||||
|
return float(maior)
|
||||||
|
|
||||||
rolls = [float(f["roll"]) for f in fontes]
|
rolls = [float(f["roll"]) for f in fontes]
|
||||||
pitchs = [float(f["pitch"]) for f in fontes]
|
pitchs = [float(f["pitch"]) for f in fontes]
|
||||||
|
|
||||||
roll_dis = float(max(rolls) - min(rolls))
|
roll_dis = maior_distancia_circular(rolls)
|
||||||
pitch_dis = float(max(pitchs) - min(pitchs))
|
pitch_dis = maior_distancia_circular(pitchs)
|
||||||
max_dis = max(roll_dis, pitch_dis)
|
max_dis = max(roll_dis, pitch_dis)
|
||||||
|
|
||||||
sensores_agree = max_dis <= self.max_disagreement_deg
|
sensores_agree = max_dis <= self.max_disagreement_deg
|
||||||
|
|
@ -817,17 +857,6 @@ class CameraIMU(ModuloDiagnosticoBase):
|
||||||
"divergentes": divergentes,
|
"divergentes": divergentes,
|
||||||
}
|
}
|
||||||
|
|
||||||
def _valor_mais_conservador(self, fontes, key):
|
|
||||||
fonte = max(
|
|
||||||
fontes,
|
|
||||||
key=lambda f: abs(float(f.get(key, 0.0))),
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
|
||||||
float(fonte.get(key, 0.0)),
|
|
||||||
fonte["mx_id"],
|
|
||||||
)
|
|
||||||
|
|
||||||
def _fundir_fontes(self, fontes, sensores_agree=True):
|
def _fundir_fontes(self, fontes, sensores_agree=True):
|
||||||
if not fontes:
|
if not fontes:
|
||||||
return None
|
return None
|
||||||
|
|
@ -879,41 +908,26 @@ class CameraIMU(ModuloDiagnosticoBase):
|
||||||
"estrategia_fusao": "weighted_agreement",
|
"estrategia_fusao": "weighted_agreement",
|
||||||
}
|
}
|
||||||
|
|
||||||
roll, fonte_roll = self._valor_mais_conservador(
|
# Em divergência, não cria uma orientação artificial misturando eixos.
|
||||||
fontes,
|
# Isola as fontes secundárias e usa o pacote completo da mais confiável.
|
||||||
"roll",
|
|
||||||
)
|
|
||||||
pitch, fonte_pitch = self._valor_mais_conservador(
|
|
||||||
fontes,
|
|
||||||
"pitch",
|
|
||||||
)
|
|
||||||
roll_rate, fonte_roll_rate = self._valor_mais_conservador(
|
|
||||||
fontes,
|
|
||||||
"roll_rate_dps",
|
|
||||||
)
|
|
||||||
pitch_rate, fonte_pitch_rate = self._valor_mais_conservador(
|
|
||||||
fontes,
|
|
||||||
"pitch_rate_dps",
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"roll": roll,
|
"roll": fonte_principal["roll"],
|
||||||
"pitch": pitch,
|
"pitch": fonte_principal["pitch"],
|
||||||
"yaw": fonte_principal["yaw"],
|
"yaw": fonte_principal["yaw"],
|
||||||
"roll_rate_dps": roll_rate,
|
"roll_rate_dps": fonte_principal["roll_rate_dps"],
|
||||||
"pitch_rate_dps": pitch_rate,
|
"pitch_rate_dps": fonte_principal["pitch_rate_dps"],
|
||||||
"yaw_rate_dps": fonte_principal["yaw_rate_dps"],
|
"yaw_rate_dps": fonte_principal["yaw_rate_dps"],
|
||||||
"confidence": min(
|
"confidence": min(
|
||||||
float(fonte_principal["confidence"]),
|
float(fonte_principal["confidence"]),
|
||||||
1.0,
|
1.0,
|
||||||
),
|
),
|
||||||
"fonte_principal": fonte_principal["mx_id"],
|
"fonte_principal": fonte_principal["mx_id"],
|
||||||
"fonte_roll": fonte_roll,
|
"fonte_roll": fonte_principal["mx_id"],
|
||||||
"fonte_pitch": fonte_pitch,
|
"fonte_pitch": fonte_principal["mx_id"],
|
||||||
"fonte_roll_rate": fonte_roll_rate,
|
"fonte_roll_rate": fonte_principal["mx_id"],
|
||||||
"fonte_pitch_rate": fonte_pitch_rate,
|
"fonte_pitch_rate": fonte_principal["mx_id"],
|
||||||
"single_source": False,
|
"single_source": False,
|
||||||
"estrategia_fusao": "conservative_disagreement",
|
"estrategia_fusao": "primary_source_on_disagreement",
|
||||||
}
|
}
|
||||||
|
|
||||||
def _atualizar_filtro_fusao(self, fusao):
|
def _atualizar_filtro_fusao(self, fusao):
|
||||||
|
|
@ -1747,4 +1761,4 @@ class CameraIMU(ModuloDiagnosticoBase):
|
||||||
return dict(self.last_data)
|
return dict(self.last_data)
|
||||||
|
|
||||||
def mostrar_log(self, mensagem):
|
def mostrar_log(self, mensagem):
|
||||||
print(f"{time.time()} - [CameraIMUFinal][id={id(self)}] {mensagem}")
|
print(f"{time.time()} - [CameraIMUFinal][id={id(self)}] {mensagem}")
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,33 @@ class ModuloMovimentacao(ModuloDiagnosticoBase):
|
||||||
PENALIDADE_FREQ_MAX_PADRAO = 4
|
PENALIDADE_FREQ_MAX_PADRAO = 4
|
||||||
PENALIDADE_FREQ_MAX_CRITICA = 8
|
PENALIDADE_FREQ_MAX_CRITICA = 8
|
||||||
|
|
||||||
|
# Temperatura MOV
|
||||||
|
TEMP_ALERTA_C = 70.0
|
||||||
|
TEMP_FALHA_C = 85.0
|
||||||
|
TEMP_EMERGENCIA_C = 100.0
|
||||||
|
|
||||||
|
TEMP_RECUPERA_ALERTA_C = 67.0
|
||||||
|
TEMP_RECUPERA_FALHA_C = 80.0
|
||||||
|
TEMP_RECUPERA_EMERGENCIA_C = 90.0
|
||||||
|
|
||||||
|
TEMP_ALERTA_INTERMEDIARIO_S = 3.0
|
||||||
|
TEMP_ALERTA_CONFIRMADO_S = 10.0
|
||||||
|
|
||||||
|
TEMP_FALHA_INTERMEDIARIO_S = 2.0
|
||||||
|
TEMP_FALHA_CONFIRMADO_S = 5.0
|
||||||
|
|
||||||
|
TEMP_EMERGENCIA_CONFIRMADO_S = 1.0
|
||||||
|
TEMP_RECUPERACAO_S = 10.0
|
||||||
|
|
||||||
|
# Elétricos
|
||||||
|
TENSAO_FALHA_PERSISTENCIA_S = 2.0
|
||||||
|
CORRENTE_MOTOR_FALHA_PERSISTENCIA_S = 1.0
|
||||||
|
CORRENTE_BARRAMENTO_FALHA_PERSISTENCIA_S = 1.0
|
||||||
|
|
||||||
|
# Freio/comando
|
||||||
|
FREIO_RPM_FALHA_PERSISTENCIA_S = 1.0
|
||||||
|
ALARME_COMANDO_PERSISTENCIA_S = 2.0
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.t_code = T_Code.Mov
|
self.t_code = T_Code.Mov
|
||||||
self.nome = "Movimentacao"
|
self.nome = "Movimentacao"
|
||||||
|
|
@ -89,6 +116,8 @@ class ModuloMovimentacao(ModuloDiagnosticoBase):
|
||||||
19: ("Sinal Z não encontrado", 25, False),
|
19: ("Sinal Z não encontrado", 25, False),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self._estados_persistencia = {}
|
||||||
|
|
||||||
def atualizar_saude(self):
|
def atualizar_saude(self):
|
||||||
try:
|
try:
|
||||||
dados_mov = ContextoGlobalRedis.get_modulo(self.t_code) or {}
|
dados_mov = ContextoGlobalRedis.get_modulo(self.t_code) or {}
|
||||||
|
|
@ -543,7 +572,7 @@ class ModuloMovimentacao(ModuloDiagnosticoBase):
|
||||||
|
|
||||||
# Faixas absolutas. Ajustar depois com logs reais.
|
# Faixas absolutas. Ajustar depois com logs reais.
|
||||||
if tensao > 0:
|
if tensao > 0:
|
||||||
if tensao < 24 or tensao > 50:
|
if tensao < 25 or tensao > 45:
|
||||||
motivos.append(f"Tensão MOV em faixa perigosa: {tensao:.1f} V")
|
motivos.append(f"Tensão MOV em faixa perigosa: {tensao:.1f} V")
|
||||||
condicoes.append({
|
condicoes.append({
|
||||||
"label": "Tensão MOV",
|
"label": "Tensão MOV",
|
||||||
|
|
@ -554,7 +583,7 @@ class ModuloMovimentacao(ModuloDiagnosticoBase):
|
||||||
})
|
})
|
||||||
score -= 70
|
score -= 70
|
||||||
risco_eletrico_termico = True
|
risco_eletrico_termico = True
|
||||||
elif tensao < 28 or tensao > 45:
|
elif tensao < 30 or tensao > 43:
|
||||||
motivos.append(f"Tensão MOV fora da faixa esperada: {tensao:.1f} V")
|
motivos.append(f"Tensão MOV fora da faixa esperada: {tensao:.1f} V")
|
||||||
condicoes.append({
|
condicoes.append({
|
||||||
"label": "Tensão MOV",
|
"label": "Tensão MOV",
|
||||||
|
|
@ -579,7 +608,7 @@ class ModuloMovimentacao(ModuloDiagnosticoBase):
|
||||||
})
|
})
|
||||||
score -= 75
|
score -= 75
|
||||||
risco_eletrico_termico = True
|
risco_eletrico_termico = True
|
||||||
elif abs(corrente_motor) > 45:
|
elif abs(corrente_motor) > 50:
|
||||||
motivos.append(f"Corrente do motor elevada: {corrente_motor:.1f} A")
|
motivos.append(f"Corrente do motor elevada: {corrente_motor:.1f} A")
|
||||||
condicoes.append({
|
condicoes.append({
|
||||||
"label": "Corrente motor",
|
"label": "Corrente motor",
|
||||||
|
|
@ -615,37 +644,38 @@ class ModuloMovimentacao(ModuloDiagnosticoBase):
|
||||||
})
|
})
|
||||||
score -= 20
|
score -= 20
|
||||||
|
|
||||||
temp_max = max(temperatura_motor, temperatura_driver)
|
# Temperatura do driver
|
||||||
|
_penalidade_d, _motivos_d, _condicoes_d, _risco_d = (
|
||||||
|
self._avaliar_temperatura(
|
||||||
|
endereco=endereco,
|
||||||
|
temperatura=temperatura_driver,
|
||||||
|
regra_desc="driver",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
motivos.extend(_motivos_d)
|
||||||
|
condicoes.extend(_condicoes_d)
|
||||||
|
|
||||||
if temp_max > 85:
|
# Temperatura do motor
|
||||||
motivos.append(f"Temperatura MOV perigosa: {temp_max:.1f} °C")
|
_penalidade_m, _motivos_m, _condicoes_m, _risco_m = (
|
||||||
condicoes.append({
|
self._avaliar_temperatura(
|
||||||
"label": "Temperatura MOV",
|
endereco=endereco,
|
||||||
"valor": temp_max,
|
temperatura=temperatura_motor,
|
||||||
"severidade": 95,
|
regra_desc="motor",
|
||||||
"descricao": f"Temperatura em faixa perigosa ({temp_max:.1f} °C)",
|
)
|
||||||
"acoes": [
|
)
|
||||||
"Reduzir carga dos motores.",
|
motivos.extend(_motivos_m)
|
||||||
"Verificar ventilação do compartimento.",
|
condicoes.extend(_condicoes_m)
|
||||||
"Pausar operação se persistir.",
|
|
||||||
],
|
|
||||||
})
|
|
||||||
score -= 80
|
|
||||||
risco_eletrico_termico = True
|
|
||||||
elif temp_max > 70:
|
|
||||||
motivos.append(f"Temperatura MOV elevada: {temp_max:.1f} °C")
|
|
||||||
condicoes.append({
|
|
||||||
"label": "Temperatura MOV",
|
|
||||||
"valor": temp_max,
|
|
||||||
"severidade": 60,
|
|
||||||
"descricao": f"Temperatura elevada ({temp_max:.1f} °C)",
|
|
||||||
"acoes": [
|
|
||||||
"Reduzir carga dos motores.",
|
|
||||||
"Verificar ventilação do compartimento dos drivers.",
|
|
||||||
],
|
|
||||||
})
|
|
||||||
score -= 25
|
|
||||||
|
|
||||||
|
# Aplica somente a maior penalidade térmica.
|
||||||
|
score -= max(_penalidade_d, _penalidade_m)
|
||||||
|
|
||||||
|
risco_eletrico_termico = (
|
||||||
|
risco_eletrico_termico
|
||||||
|
or _risco_d
|
||||||
|
or _risco_m
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# Padrões dinâmicos: úteis para diagnóstico, mas não travam operação.
|
# Padrões dinâmicos: úteis para diagnóstico, mas não travam operação.
|
||||||
self._avaliar_padroes_dinamicos(
|
self._avaliar_padroes_dinamicos(
|
||||||
padroes,
|
padroes,
|
||||||
|
|
@ -752,6 +782,399 @@ class ModuloMovimentacao(ModuloDiagnosticoBase):
|
||||||
"parametros": parametros_debug,
|
"parametros": parametros_debug,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def _temperatura_valida(self, temperatura):
|
||||||
|
try:
|
||||||
|
valor = float(temperatura)
|
||||||
|
return 0.0 < valor < 200.0
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _avaliar_temperatura(
|
||||||
|
self,
|
||||||
|
endereco,
|
||||||
|
temperatura,
|
||||||
|
regra_desc,
|
||||||
|
):
|
||||||
|
motivos = []
|
||||||
|
condicoes = []
|
||||||
|
penalidade = 0
|
||||||
|
risco_eletrico_termico = False
|
||||||
|
|
||||||
|
nome_origem = (
|
||||||
|
"driver de movimento"
|
||||||
|
if regra_desc == "driver"
|
||||||
|
else "motor de tração"
|
||||||
|
)
|
||||||
|
|
||||||
|
label = f"Temperatura do {nome_origem}"
|
||||||
|
|
||||||
|
if not self._temperatura_valida(temperatura):
|
||||||
|
motivos.append(
|
||||||
|
f"Temperatura do {nome_origem} inválida: "
|
||||||
|
f"{temperatura} °C"
|
||||||
|
)
|
||||||
|
|
||||||
|
condicoes.append({
|
||||||
|
"label": label,
|
||||||
|
"valor": temperatura,
|
||||||
|
"severidade": 50,
|
||||||
|
"descricao": (
|
||||||
|
"Leitura de temperatura inválida"
|
||||||
|
),
|
||||||
|
"acoes": [
|
||||||
|
"Verificar sensor de temperatura.",
|
||||||
|
],
|
||||||
|
})
|
||||||
|
return (
|
||||||
|
penalidade,
|
||||||
|
motivos,
|
||||||
|
condicoes,
|
||||||
|
risco_eletrico_termico,
|
||||||
|
)
|
||||||
|
|
||||||
|
estado_temp_emergencia = self._estado_limite_alto(
|
||||||
|
driver=endereco,
|
||||||
|
regra=f"temperatura_emergencia_{regra_desc}",
|
||||||
|
valor=temperatura,
|
||||||
|
limite_entrada=self.TEMP_EMERGENCIA_C,
|
||||||
|
limite_saida=self.TEMP_RECUPERA_EMERGENCIA_C,
|
||||||
|
tempo_intermediario_s=0.0,
|
||||||
|
tempo_confirmacao_s=self.TEMP_EMERGENCIA_CONFIRMADO_S,
|
||||||
|
tempo_recuperacao_s=self.TEMP_RECUPERACAO_S,
|
||||||
|
)
|
||||||
|
|
||||||
|
estado_temp_falha = self._estado_limite_alto(
|
||||||
|
driver=endereco,
|
||||||
|
regra=f"temperatura_falha_{regra_desc}",
|
||||||
|
valor=temperatura,
|
||||||
|
limite_entrada=self.TEMP_FALHA_C,
|
||||||
|
limite_saida=self.TEMP_RECUPERA_FALHA_C,
|
||||||
|
tempo_intermediario_s=self.TEMP_FALHA_INTERMEDIARIO_S,
|
||||||
|
tempo_confirmacao_s=self.TEMP_FALHA_CONFIRMADO_S,
|
||||||
|
tempo_recuperacao_s=self.TEMP_RECUPERACAO_S,
|
||||||
|
)
|
||||||
|
|
||||||
|
estado_temp_alerta = self._estado_limite_alto(
|
||||||
|
driver=endereco,
|
||||||
|
regra=f"temperatura_alerta_{regra_desc}",
|
||||||
|
valor=temperatura,
|
||||||
|
limite_entrada=self.TEMP_ALERTA_C,
|
||||||
|
limite_saida=self.TEMP_RECUPERA_ALERTA_C,
|
||||||
|
tempo_intermediario_s=self.TEMP_ALERTA_INTERMEDIARIO_S,
|
||||||
|
tempo_confirmacao_s=self.TEMP_ALERTA_CONFIRMADO_S,
|
||||||
|
tempo_recuperacao_s=self.TEMP_RECUPERACAO_S,
|
||||||
|
)
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# EMERGÊNCIA CONFIRMADA
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
if estado_temp_emergencia["nivel"] == "confirmado":
|
||||||
|
motivos.append(
|
||||||
|
f"Temperatura do {nome_origem} em nível de emergência "
|
||||||
|
f"confirmado: {temperatura:.1f} °C"
|
||||||
|
)
|
||||||
|
|
||||||
|
condicoes.append({
|
||||||
|
"label": label,
|
||||||
|
"valor": temperatura,
|
||||||
|
"severidade": 98,
|
||||||
|
"descricao": (
|
||||||
|
"Temperatura de emergência confirmada após "
|
||||||
|
f"{estado_temp_emergencia['duracao_s']:.1f} s"
|
||||||
|
),
|
||||||
|
"acoes": [
|
||||||
|
"Interromper imediatamente o esforço dos motores.",
|
||||||
|
"Verificar ventilação, motor, driver e sensor térmico.",
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
penalidade = 90
|
||||||
|
risco_eletrico_termico = True
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# RECUPERANDO DE EMERGÊNCIA
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
elif estado_temp_emergencia["nivel"] == "recuperando":
|
||||||
|
motivos.append(
|
||||||
|
f"Temperatura do {nome_origem} normalizando após emergência: "
|
||||||
|
f"{temperatura:.1f} °C. Aguardando estabilidade para liberação."
|
||||||
|
)
|
||||||
|
|
||||||
|
condicoes.append({
|
||||||
|
"label": label,
|
||||||
|
"valor": temperatura,
|
||||||
|
"severidade": 98,
|
||||||
|
"descricao": (
|
||||||
|
"Temperatura caiu abaixo do limite de recuperação da "
|
||||||
|
"emergência, mas ainda aguarda estabilidade por "
|
||||||
|
f"{self.TEMP_RECUPERACAO_S:.1f} s "
|
||||||
|
f"({estado_temp_emergencia['duracao_s']:.1f} s decorridos)"
|
||||||
|
),
|
||||||
|
"acoes": [
|
||||||
|
"Manter o equipamento sem esforço.",
|
||||||
|
"Aguardar a conclusão da recuperação térmica.",
|
||||||
|
"Verificar se a temperatura continua diminuindo.",
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
# Mantém exatamente a proteção da emergência enquanto recupera.
|
||||||
|
penalidade = 90
|
||||||
|
risco_eletrico_termico = True
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# EMERGÊNCIA DETECTADA, AINDA NÃO CONFIRMADA
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
elif estado_temp_emergencia["ativa"]:
|
||||||
|
motivos.append(
|
||||||
|
f"Temperatura de emergência do {nome_origem} detectada: "
|
||||||
|
f"{temperatura:.1f} °C "
|
||||||
|
f"({estado_temp_emergencia['duracao_s']:.1f} s)"
|
||||||
|
)
|
||||||
|
|
||||||
|
condicoes.append({
|
||||||
|
"label": label,
|
||||||
|
"valor": temperatura,
|
||||||
|
"severidade": 89,
|
||||||
|
"descricao": (
|
||||||
|
"Temperatura em nível de emergência, aguardando "
|
||||||
|
"confirmação da leitura"
|
||||||
|
),
|
||||||
|
"acoes": [
|
||||||
|
"Acompanhar imediatamente as próximas leituras.",
|
||||||
|
"Preparar a interrupção do esforço dos motores.",
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
# Ainda não bloqueia, pois não passou pela confirmação.
|
||||||
|
penalidade = 45
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# FALHA TÉRMICA CONFIRMADA
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
elif estado_temp_falha["nivel"] == "confirmado":
|
||||||
|
motivos.append(
|
||||||
|
f"Temperatura perigosa do {nome_origem} confirmada: "
|
||||||
|
f"{temperatura:.1f} °C"
|
||||||
|
)
|
||||||
|
|
||||||
|
condicoes.append({
|
||||||
|
"label": label,
|
||||||
|
"valor": temperatura,
|
||||||
|
"severidade": 95,
|
||||||
|
"descricao": (
|
||||||
|
"Temperatura perigosa persistiu por "
|
||||||
|
f"{estado_temp_falha['duracao_s']:.1f} s"
|
||||||
|
),
|
||||||
|
"acoes": [
|
||||||
|
"Interromper ou reduzir o esforço dos motores.",
|
||||||
|
"Verificar a ventilação do compartimento.",
|
||||||
|
"Inspecionar motor, driver e sensor térmico.",
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
penalidade = 80
|
||||||
|
risco_eletrico_termico = True
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# RECUPERANDO DE FALHA TÉRMICA
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
elif estado_temp_falha["nivel"] == "recuperando":
|
||||||
|
motivos.append(
|
||||||
|
f"Temperatura do {nome_origem} normalizando após condição "
|
||||||
|
f"perigosa: {temperatura:.1f} °C. "
|
||||||
|
"Aguardando estabilidade para liberação."
|
||||||
|
)
|
||||||
|
|
||||||
|
condicoes.append({
|
||||||
|
"label": label,
|
||||||
|
"valor": temperatura,
|
||||||
|
"severidade": 95,
|
||||||
|
"descricao": (
|
||||||
|
"Temperatura caiu abaixo do limite de recuperação da "
|
||||||
|
"falha, mas ainda aguarda estabilidade por "
|
||||||
|
f"{self.TEMP_RECUPERACAO_S:.1f} s "
|
||||||
|
f"({estado_temp_falha['duracao_s']:.1f} s decorridos)"
|
||||||
|
),
|
||||||
|
"acoes": [
|
||||||
|
"Manter a carga reduzida.",
|
||||||
|
"Aguardar a conclusão da recuperação térmica.",
|
||||||
|
"Verificar se a temperatura permanece estável.",
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
# Continua bloqueante até terminar a recuperação.
|
||||||
|
penalidade = 80
|
||||||
|
risco_eletrico_termico = True
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# FALHA TÉRMICA PERSISTINDO
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
elif estado_temp_falha["nivel"] == "persistente":
|
||||||
|
motivos.append(
|
||||||
|
f"Temperatura perigosa do {nome_origem} persistindo: "
|
||||||
|
f"{temperatura:.1f} °C "
|
||||||
|
f"({estado_temp_falha['duracao_s']:.1f} s)"
|
||||||
|
)
|
||||||
|
|
||||||
|
condicoes.append({
|
||||||
|
"label": label,
|
||||||
|
"valor": temperatura,
|
||||||
|
"severidade": 85,
|
||||||
|
"descricao": (
|
||||||
|
"Temperatura perigosa persistindo, aguardando "
|
||||||
|
"confirmação de segurança"
|
||||||
|
),
|
||||||
|
"acoes": [
|
||||||
|
"Acompanhar as próximas leituras.",
|
||||||
|
"Reduzir a carga se a temperatura continuar aumentando.",
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
penalidade = 35
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# PRIMEIRA DETECÇÃO DE FALHA TÉRMICA
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
elif estado_temp_falha["nivel"] == "detectado":
|
||||||
|
motivos.append(
|
||||||
|
f"Pico de temperatura perigosa do {nome_origem} detectado: "
|
||||||
|
f"{temperatura:.1f} °C"
|
||||||
|
)
|
||||||
|
|
||||||
|
condicoes.append({
|
||||||
|
"label": label,
|
||||||
|
"valor": temperatura,
|
||||||
|
"severidade": 70,
|
||||||
|
"descricao": (
|
||||||
|
"Temperatura perigosa detectada, ainda sem persistência"
|
||||||
|
),
|
||||||
|
"acoes": [
|
||||||
|
"Acompanhar a confirmação da leitura térmica.",
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
penalidade = 10
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# ALERTA TÉRMICO CONFIRMADO
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
elif estado_temp_alerta["nivel"] == "confirmado":
|
||||||
|
motivos.append(
|
||||||
|
f"Temperatura elevada do {nome_origem} confirmada: "
|
||||||
|
f"{temperatura:.1f} °C"
|
||||||
|
)
|
||||||
|
|
||||||
|
condicoes.append({
|
||||||
|
"label": label,
|
||||||
|
"valor": temperatura,
|
||||||
|
"severidade": 60,
|
||||||
|
"descricao": (
|
||||||
|
"Temperatura elevada persistiu por "
|
||||||
|
f"{estado_temp_alerta['duracao_s']:.1f} s"
|
||||||
|
),
|
||||||
|
"acoes": [
|
||||||
|
"Reduzir a carga dos motores.",
|
||||||
|
"Verificar a ventilação.",
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
penalidade = 25
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# RECUPERANDO DE ALERTA TÉRMICO
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
elif estado_temp_alerta["nivel"] == "recuperando":
|
||||||
|
motivos.append(
|
||||||
|
f"Temperatura do {nome_origem} normalizando após alerta: "
|
||||||
|
f"{temperatura:.1f} °C"
|
||||||
|
)
|
||||||
|
|
||||||
|
condicoes.append({
|
||||||
|
"label": label,
|
||||||
|
"valor": temperatura,
|
||||||
|
"severidade": 60,
|
||||||
|
"descricao": (
|
||||||
|
"Temperatura caiu abaixo do limite de recuperação do "
|
||||||
|
"alerta, aguardando estabilidade por "
|
||||||
|
f"{self.TEMP_RECUPERACAO_S:.1f} s "
|
||||||
|
f"({estado_temp_alerta['duracao_s']:.1f} s decorridos)"
|
||||||
|
),
|
||||||
|
"acoes": [
|
||||||
|
"Acompanhar a estabilização da temperatura.",
|
||||||
|
"Manter a carga moderada durante a recuperação.",
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
# Mantém a penalidade do alerta até concluir a recuperação,
|
||||||
|
# mas não caracteriza risco elétrico/térmico bloqueante.
|
||||||
|
penalidade = 25
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# ALERTA PERSISTINDO
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
elif estado_temp_alerta["nivel"] == "persistente":
|
||||||
|
motivos.append(
|
||||||
|
f"Aquecimento do {nome_origem} persistindo: "
|
||||||
|
f"{temperatura:.1f} °C "
|
||||||
|
f"({estado_temp_alerta['duracao_s']:.1f} s)"
|
||||||
|
)
|
||||||
|
|
||||||
|
condicoes.append({
|
||||||
|
"label": label,
|
||||||
|
"valor": temperatura,
|
||||||
|
"severidade": 50,
|
||||||
|
"descricao": (
|
||||||
|
"Temperatura elevada persistindo, aguardando confirmação"
|
||||||
|
),
|
||||||
|
"acoes": [
|
||||||
|
"Acompanhar a evolução da temperatura.",
|
||||||
|
"Verificar a ventilação se continuar aumentando.",
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
penalidade = 15
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# PRIMEIRA DETECÇÃO DE ALERTA
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
elif estado_temp_alerta["nivel"] == "detectado":
|
||||||
|
motivos.append(
|
||||||
|
f"Aquecimento do {nome_origem} detectado: "
|
||||||
|
f"{temperatura:.1f} °C"
|
||||||
|
)
|
||||||
|
|
||||||
|
condicoes.append({
|
||||||
|
"label": label,
|
||||||
|
"valor": temperatura,
|
||||||
|
"severidade": 40,
|
||||||
|
"descricao": (
|
||||||
|
"Temperatura acima da faixa ideal, aguardando persistência"
|
||||||
|
),
|
||||||
|
"acoes": [
|
||||||
|
"Acompanhar a evolução da temperatura.",
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
penalidade = 5
|
||||||
|
|
||||||
|
return (
|
||||||
|
penalidade,
|
||||||
|
motivos,
|
||||||
|
condicoes,
|
||||||
|
risco_eletrico_termico,
|
||||||
|
)
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# Frequência / contrato
|
# Frequência / contrato
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
@ -835,16 +1258,13 @@ class ModuloMovimentacao(ModuloDiagnosticoBase):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _penalizar_frequencia(freq, base, minimo, max_penalidade):
|
def _penalizar_frequencia(freq, base, minimo, max_penalidade):
|
||||||
try:
|
if base <= 0:
|
||||||
return float(penalizar_frequencia(freq, base, minimo, max_penalidade) or 0)
|
return 0.0
|
||||||
except Exception:
|
if freq >= minimo:
|
||||||
if base <= 0:
|
return 0.0
|
||||||
return 0.0
|
if freq <= 0:
|
||||||
if freq >= minimo:
|
return float(max_penalidade)
|
||||||
return 0.0
|
return float(max_penalidade) * (1.0 - max(0.0, min(1.0, freq / max(minimo, 0.001))))
|
||||||
if freq <= 0:
|
|
||||||
return float(max_penalidade)
|
|
||||||
return float(max_penalidade) * (1.0 - max(0.0, min(1.0, freq / max(minimo, 0.001))))
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# Padrões dinâmicos
|
# Padrões dinâmicos
|
||||||
|
|
@ -903,6 +1323,117 @@ class ModuloMovimentacao(ModuloDiagnosticoBase):
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def _estado_persistencia(
|
||||||
|
self,
|
||||||
|
driver,
|
||||||
|
regra,
|
||||||
|
ativa,
|
||||||
|
tempo_intermediario_s,
|
||||||
|
tempo_confirmacao_s,
|
||||||
|
tempo_recuperacao_s=0.0,
|
||||||
|
):
|
||||||
|
agora = time.monotonic()
|
||||||
|
chave = (str(driver), str(regra))
|
||||||
|
|
||||||
|
estado = self._estados_persistencia.setdefault(chave, {
|
||||||
|
"ativa_desde": None,
|
||||||
|
"normal_desde": None,
|
||||||
|
"confirmada": False,
|
||||||
|
})
|
||||||
|
|
||||||
|
if ativa:
|
||||||
|
estado["normal_desde"] = None
|
||||||
|
|
||||||
|
if estado["ativa_desde"] is None:
|
||||||
|
estado["ativa_desde"] = agora
|
||||||
|
|
||||||
|
duracao_s = max(0.0, agora - estado["ativa_desde"])
|
||||||
|
|
||||||
|
if duracao_s >= tempo_confirmacao_s:
|
||||||
|
estado["confirmada"] = True
|
||||||
|
|
||||||
|
if estado["confirmada"]:
|
||||||
|
nivel = "confirmado"
|
||||||
|
elif duracao_s >= tempo_intermediario_s:
|
||||||
|
nivel = "persistente"
|
||||||
|
else:
|
||||||
|
nivel = "detectado"
|
||||||
|
|
||||||
|
return {
|
||||||
|
"ativa": True,
|
||||||
|
"nivel": nivel,
|
||||||
|
"duracao_s": duracao_s,
|
||||||
|
"confirmada": estado["confirmada"],
|
||||||
|
}
|
||||||
|
|
||||||
|
estado["ativa_desde"] = None
|
||||||
|
|
||||||
|
if not estado["confirmada"]:
|
||||||
|
estado["normal_desde"] = None
|
||||||
|
return {
|
||||||
|
"ativa": False,
|
||||||
|
"nivel": "normal",
|
||||||
|
"duracao_s": 0.0,
|
||||||
|
"confirmada": False,
|
||||||
|
}
|
||||||
|
|
||||||
|
if estado["normal_desde"] is None:
|
||||||
|
estado["normal_desde"] = agora
|
||||||
|
|
||||||
|
normal_ha_s = max(0.0, agora - estado["normal_desde"])
|
||||||
|
|
||||||
|
if normal_ha_s >= tempo_recuperacao_s:
|
||||||
|
estado["confirmada"] = False
|
||||||
|
estado["normal_desde"] = None
|
||||||
|
|
||||||
|
return {
|
||||||
|
"ativa": False,
|
||||||
|
"nivel": "normal",
|
||||||
|
"duracao_s": 0.0,
|
||||||
|
"confirmada": False,
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
"ativa": True,
|
||||||
|
"nivel": "recuperando",
|
||||||
|
"duracao_s": normal_ha_s,
|
||||||
|
"confirmada": True,
|
||||||
|
}
|
||||||
|
|
||||||
|
def _estado_limite_alto(
|
||||||
|
self,
|
||||||
|
driver,
|
||||||
|
regra,
|
||||||
|
valor,
|
||||||
|
limite_entrada,
|
||||||
|
limite_saida,
|
||||||
|
tempo_intermediario_s,
|
||||||
|
tempo_confirmacao_s,
|
||||||
|
tempo_recuperacao_s,
|
||||||
|
):
|
||||||
|
chave = (str(driver), str(regra))
|
||||||
|
persistencia = self._estados_persistencia.get(chave, {})
|
||||||
|
confirmada = bool(persistencia.get("confirmada", False))
|
||||||
|
|
||||||
|
# Histerese:
|
||||||
|
# ainda não confirmou -> entra no limite_entrada
|
||||||
|
# já confirmou -> permanece até cair abaixo do limite_saida
|
||||||
|
ativa = (
|
||||||
|
valor >= limite_saida
|
||||||
|
if confirmada
|
||||||
|
else valor >= limite_entrada
|
||||||
|
)
|
||||||
|
|
||||||
|
return self._estado_persistencia(
|
||||||
|
driver=driver,
|
||||||
|
regra=regra,
|
||||||
|
ativa=ativa,
|
||||||
|
tempo_intermediario_s=tempo_intermediario_s,
|
||||||
|
tempo_confirmacao_s=tempo_confirmacao_s,
|
||||||
|
tempo_recuperacao_s=tempo_recuperacao_s,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# Status/publicação
|
# Status/publicação
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
|
||||||
|
|
@ -148,7 +148,7 @@ class ModuloPC(ModuloDiagnosticoBase):
|
||||||
# Processo C#
|
# Processo C#
|
||||||
"process_private_mem_warn_mb": 6000.0,
|
"process_private_mem_warn_mb": 6000.0,
|
||||||
"process_private_mem_fail_mb": 10000.0,
|
"process_private_mem_fail_mb": 10000.0,
|
||||||
"process_threads_warn": 120,
|
"process_threads_warn": 160,
|
||||||
"process_threads_fail": 220,
|
"process_threads_fail": 220,
|
||||||
|
|
||||||
# ThreadPool
|
# ThreadPool
|
||||||
|
|
@ -615,19 +615,6 @@ class ModuloPC(ModuloDiagnosticoBase):
|
||||||
],
|
],
|
||||||
))
|
))
|
||||||
|
|
||||||
if st_gpu_mem_load != StatusModulo.OPERANTE:
|
|
||||||
gpu_cond.append(self._cond(
|
|
||||||
"Carga da Memória do GPU",
|
|
||||||
raw["gpu_memory_load_percent"],
|
|
||||||
80,
|
|
||||||
"Controlador/memória da GPU sob carga elevada.",
|
|
||||||
[
|
|
||||||
"Verificar tamanho dos tensores",
|
|
||||||
"Reduzir cópias CPU/GPU",
|
|
||||||
"Avaliar TensorRT/ONNX",
|
|
||||||
],
|
|
||||||
))
|
|
||||||
|
|
||||||
if gpu_power is not None and gpu_power >= C["gpu_power_warn_w"]:
|
if gpu_power is not None and gpu_power >= C["gpu_power_warn_w"]:
|
||||||
gpu_cond.append(self._cond(
|
gpu_cond.append(self._cond(
|
||||||
"Potência do GPU",
|
"Potência do GPU",
|
||||||
|
|
@ -654,6 +641,23 @@ class ModuloPC(ModuloDiagnosticoBase):
|
||||||
else StatusModulo.OPERANTE
|
else StatusModulo.OPERANTE
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if st_gpu_memory_block != StatusModulo.OPERANTE:
|
||||||
|
gpu_memory_value = max(
|
||||||
|
x for x in [gpu_mem_load, gpu_fb_load]
|
||||||
|
if x is not None
|
||||||
|
) if gpu_mem_load is not None or gpu_fb_load is not None else None
|
||||||
|
gpu_cond.append(self._cond(
|
||||||
|
"Carga da Memória do GPU",
|
||||||
|
gpu_memory_value,
|
||||||
|
80,
|
||||||
|
"Controlador/memória da GPU sob carga elevada.",
|
||||||
|
[
|
||||||
|
"Verificar tamanho dos tensores",
|
||||||
|
"Reduzir cópias CPU/GPU",
|
||||||
|
"Avaliar TensorRT/ONNX",
|
||||||
|
],
|
||||||
|
))
|
||||||
|
|
||||||
saude_individual.append(self._item(
|
saude_individual.append(self._item(
|
||||||
"gpu_temp",
|
"gpu_temp",
|
||||||
"Temperatura do GPU",
|
"Temperatura do GPU",
|
||||||
|
|
@ -692,7 +696,7 @@ class ModuloPC(ModuloDiagnosticoBase):
|
||||||
"Carga de Memória/Framebuffer GPU",
|
"Carga de Memória/Framebuffer GPU",
|
||||||
st_gpu_memory_block,
|
st_gpu_memory_block,
|
||||||
sc_gpu_memory_block,
|
sc_gpu_memory_block,
|
||||||
self._motivo("gpu_memory_load", st_gpu_memory_block, min(
|
self._motivo("gpu_memory_load", st_gpu_memory_block, max(
|
||||||
x for x in [gpu_mem_load, gpu_fb_load] if x is not None
|
x for x in [gpu_mem_load, gpu_fb_load] if x is not None
|
||||||
) if gpu_mem_load is not None or gpu_fb_load is not None else None, "%"),
|
) if gpu_mem_load is not None or gpu_fb_load is not None else None, "%"),
|
||||||
[c for c in gpu_cond if c["label"] == "Carga da Memória do GPU"],
|
[c for c in gpu_cond if c["label"] == "Carga da Memória do GPU"],
|
||||||
|
|
@ -877,29 +881,78 @@ class ModuloPC(ModuloDiagnosticoBase):
|
||||||
)
|
)
|
||||||
|
|
||||||
sc_process = min(sc_proc_mem, sc_proc_threads, sc_tp)
|
sc_process = min(sc_proc_mem, sc_proc_threads, sc_tp)
|
||||||
st_process = (
|
status_processos = [st_proc_mem, st_proc_threads, st_tp]
|
||||||
StatusModulo.FALHA
|
|
||||||
if StatusModulo.FALHA in [st_proc_mem, st_proc_threads, st_tp]
|
if StatusModulo.FALHA in status_processos:
|
||||||
else StatusModulo.ALERTA
|
st_process = StatusModulo.FALHA
|
||||||
if StatusModulo.ALERTA in [st_proc_mem, st_proc_threads, st_tp]
|
elif StatusModulo.ALERTA in status_processos:
|
||||||
else StatusModulo.OPERANTE
|
st_process = StatusModulo.ALERTA
|
||||||
)
|
elif StatusModulo.DESCONECTADO in status_processos:
|
||||||
|
st_process = StatusModulo.DESCONECTADO
|
||||||
|
else:
|
||||||
|
st_process = StatusModulo.OPERANTE
|
||||||
|
|
||||||
process_cond = []
|
process_cond = []
|
||||||
if st_process != StatusModulo.OPERANTE:
|
process_motivos = []
|
||||||
|
|
||||||
|
if st_proc_mem != StatusModulo.OPERANTE:
|
||||||
|
process_motivos += self._motivo(
|
||||||
|
"process_memory",
|
||||||
|
st_proc_mem,
|
||||||
|
proc_private,
|
||||||
|
"MB",
|
||||||
|
)
|
||||||
process_cond.append(self._cond(
|
process_cond.append(self._cond(
|
||||||
"Processo C#",
|
"Memória do Processo",
|
||||||
raw["process_private_memory_mb"],
|
raw["process_private_memory_mb"],
|
||||||
100 if st_process == StatusModulo.FALHA else 70,
|
100 if st_proc_mem == StatusModulo.FALHA else 70,
|
||||||
"Processo principal com uso elevado de memória, threads ou ThreadPool.",
|
"Uso elevado de memória privada pelo processo principal.",
|
||||||
[
|
[
|
||||||
"Verificar vazamento de memória",
|
"Verificar crescimento contínuo da memória",
|
||||||
"Revisar criação de threads",
|
"Verificar retenção de imagens e buffers",
|
||||||
"Verificar tasks longas no C#",
|
"Verificar objetos gráficos não descartados",
|
||||||
],
|
],
|
||||||
))
|
))
|
||||||
|
|
||||||
motivos += self._motivo("process", st_process, proc_private, "MB")
|
if st_proc_threads != StatusModulo.OPERANTE:
|
||||||
|
process_motivos += self._motivo(
|
||||||
|
"process_threads",
|
||||||
|
st_proc_threads,
|
||||||
|
proc_threads,
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
process_cond.append(self._cond(
|
||||||
|
"Threads do Processo",
|
||||||
|
raw["process_thread_count"],
|
||||||
|
100 if st_proc_threads == StatusModulo.FALHA else 70,
|
||||||
|
"Quantidade elevada de threads no processo principal.",
|
||||||
|
[
|
||||||
|
"Verificar criação recorrente de threads e timers",
|
||||||
|
"Verificar ciclos de reconexão de dispositivos",
|
||||||
|
"Verificar threads que não estão sendo finalizadas",
|
||||||
|
],
|
||||||
|
))
|
||||||
|
|
||||||
|
if st_tp != StatusModulo.OPERANTE:
|
||||||
|
process_motivos += self._motivo(
|
||||||
|
"threadpool_worker",
|
||||||
|
st_tp,
|
||||||
|
tp_worker,
|
||||||
|
"%",
|
||||||
|
)
|
||||||
|
process_cond.append(self._cond(
|
||||||
|
"Uso do ThreadPool",
|
||||||
|
raw["threadpool_used_worker_percent"],
|
||||||
|
100 if st_tp == StatusModulo.FALHA else 70,
|
||||||
|
"Ocupação elevada das threads worker do ThreadPool.",
|
||||||
|
[
|
||||||
|
"Verificar tarefas bloqueantes",
|
||||||
|
"Verificar operações síncronas demoradas",
|
||||||
|
"Verificar tasks de longa duração",
|
||||||
|
],
|
||||||
|
))
|
||||||
|
|
||||||
|
motivos += process_motivos
|
||||||
condicoes += process_cond
|
condicoes += process_cond
|
||||||
|
|
||||||
saude_individual.append(self._item(
|
saude_individual.append(self._item(
|
||||||
|
|
@ -907,10 +960,10 @@ class ModuloPC(ModuloDiagnosticoBase):
|
||||||
"Processo Principal",
|
"Processo Principal",
|
||||||
st_process,
|
st_process,
|
||||||
sc_process,
|
sc_process,
|
||||||
self._motivo("process", st_process, proc_private, "MB"),
|
process_motivos,
|
||||||
process_cond,
|
process_cond,
|
||||||
valor=raw["process_private_memory_mb"],
|
valor=None,
|
||||||
unidade="MB",
|
unidade="",
|
||||||
))
|
))
|
||||||
|
|
||||||
# ======================================================
|
# ======================================================
|
||||||
|
|
@ -979,17 +1032,21 @@ class ModuloPC(ModuloDiagnosticoBase):
|
||||||
st_ram == StatusModulo.FALHA,
|
st_ram == StatusModulo.FALHA,
|
||||||
st_vram == StatusModulo.FALHA,
|
st_vram == StatusModulo.FALHA,
|
||||||
st_disk == StatusModulo.FALHA,
|
st_disk == StatusModulo.FALHA,
|
||||||
|
st_process == StatusModulo.FALHA,
|
||||||
])
|
])
|
||||||
|
|
||||||
any_alert = any(
|
any_problem = any(
|
||||||
item.get("status") == StatusModulo.ALERTA.value
|
item.get("status") in (
|
||||||
|
StatusModulo.ALERTA.value,
|
||||||
|
StatusModulo.FALHA.value,
|
||||||
|
)
|
||||||
for item in saude_individual
|
for item in saude_individual
|
||||||
)
|
)
|
||||||
|
|
||||||
if hard_fail:
|
if hard_fail:
|
||||||
status = StatusModulo.FALHA
|
status = StatusModulo.FALHA
|
||||||
score_total = min(score_total, 35.0)
|
score_total = min(score_total, 35.0)
|
||||||
elif score_total < 80.0 or any_alert:
|
elif score_total < 80.0 or any_problem:
|
||||||
status = StatusModulo.ALERTA
|
status = StatusModulo.ALERTA
|
||||||
else:
|
else:
|
||||||
status = StatusModulo.OPERANTE
|
status = StatusModulo.OPERANTE
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue