From a7f04f4016cc01faf866bd38e257c2f7fc58dcdd Mon Sep 17 00:00:00 2001 From: Diego Freitas Date: Tue, 11 Aug 2026 18:53:34 -0300 Subject: [PATCH] ajustes no alarme de comando leitura do mov, inversao do heading no operation contro, ajuste de lever arm direto na camera frontal --- .../Models/Modules/MovimentacaoModel.cs | 151 +++++++++++++++--- AgroBase/AgroBase/Services/SerialService.cs | 37 +++-- .../Controls/AttitudeIndicator.xaml.cs | 4 +- .../ViewModels/Windows/DockWindowViewModel.cs | 4 +- .../Monitoramento/MonitoramentoView.xaml | 56 ++++++- .../Monitoramento/MonitoramentoView.xaml.cs | 21 +++ 6 files changed, 235 insertions(+), 38 deletions(-) diff --git a/AgroBase/AgroBase/Models/Modules/MovimentacaoModel.cs b/AgroBase/AgroBase/Models/Modules/MovimentacaoModel.cs index 9e436c538..f0640fa92 100644 --- a/AgroBase/AgroBase/Models/Modules/MovimentacaoModel.cs +++ b/AgroBase/AgroBase/Models/Modules/MovimentacaoModel.cs @@ -22,19 +22,12 @@ namespace AgroBase.Models.Modules return Variaveis.OperacaoEmAndamento.DispMvd?.Dados?.Modulos?.FirstOrDefault(x => x.MovMotor._EnderecoCAN_Tx == _EnderecoCAN_Tx)?.Modulo_ID ?? ""; } } - public bool LeituraLigado - { - get - { - return Leitura?.CorrenteMotor?.valor != 0; - } - } public double LeituraRPM { get; set; } = 0; public bool ComandoLigado { get { - return RPM_SP > 0; + return Math.Abs(RPM_SP) > 0; } } //public bool Freio { get; set; } = false; @@ -67,31 +60,143 @@ namespace AgroBase.Models.Modules public int CorrenteTorqueMaximo { get; set; } = 40; public int CorrenteFreio { get; set; } = 5; public double OffsetLeitura { get; set; } = 1.0; + + private const double IDADE_MAX_TELEMETRIA_S = 3.0; + + // Valores iniciais conservadores. + // Ajustar depois conforme o ruído real observado nos logs. + private const double CORRENTE_MOTOR_ATIVA_A = 0.15; + private const double CORRENTE_BARRAMENTO_ATIVA_A = 0.10; + private const double POTENCIA_ATIVA_W = 3.0; + private const double CICLO_ATIVO = 1.0; + + private static bool DadoFresco(CanCommandFreqModel dado, DateTime agora) + { + return dado != null + && dado.lidoEm != DateTime.MinValue + && (agora - dado.lidoEm).TotalSeconds >= 0 + && (agora - dado.lidoEm).TotalSeconds <= IDADE_MAX_TELEMETRIA_S; + } + + private bool HaEvidenciaAtuacao(DateTime agora) + { + var leitura = Leitura; + + if (leitura == null) + return false; + + return + (DadoFresco(leitura.CorrenteMotor, agora) && + Math.Abs(leitura.CorrenteMotor.valor) >= CORRENTE_MOTOR_ATIVA_A) + + || + + (DadoFresco(leitura.CorrenteBarramento, agora) && + Math.Abs(leitura.CorrenteBarramento.valor) >= CORRENTE_BARRAMENTO_ATIVA_A) + + || + + (DadoFresco(leitura.Potencia, agora) && + Math.Abs(leitura.Potencia.valor) >= POTENCIA_ATIVA_W) + + || + + (DadoFresco(leitura.CicloTrabalho, agora) && + Math.Abs(leitura.CicloTrabalho.valor) >= CICLO_ATIVO); + } + + private bool HaEvidenciaSuficienteDeAusencia(DateTime agora) + { + var leitura = Leitura; + + if (leitura == null) + return false; + + int sinaisFrescos = 0; + bool algumIndicaAtuacao = false; + + if (DadoFresco(leitura.CorrenteMotor, agora)) + { + sinaisFrescos++; + + if (Math.Abs(leitura.CorrenteMotor.valor) >= CORRENTE_MOTOR_ATIVA_A) + algumIndicaAtuacao = true; + } + + if (DadoFresco(leitura.CorrenteBarramento, agora)) + { + sinaisFrescos++; + + if (Math.Abs(leitura.CorrenteBarramento.valor) >= CORRENTE_BARRAMENTO_ATIVA_A) + algumIndicaAtuacao = true; + } + + if (DadoFresco(leitura.Potencia, agora)) + { + sinaisFrescos++; + + if (Math.Abs(leitura.Potencia.valor) >= POTENCIA_ATIVA_W) + algumIndicaAtuacao = true; + } + + if (DadoFresco(leitura.CicloTrabalho, agora)) + { + sinaisFrescos++; + + if (Math.Abs(leitura.CicloTrabalho.valor) >= CICLO_ATIVO) + algumIndicaAtuacao = true; + } + + // Só afirma ausência quando pelo menos dois sinais atuais + // concordam que não existe atuação. + return sinaisFrescos >= 2 && !algumIndicaAtuacao; + } + + public bool LeituraLigado + { + get + { + return HaEvidenciaAtuacao(DateTime.Now); + } + } + private DateTime UltimoAlarmeComando { get; set; } = DateTime.MinValue; + public bool AlarmeComando { get { - bool _alarme = ComandoLigado && !LeituraLigado; + DateTime agora = DateTime.Now; - if (_alarme) - { - if (UltimoAlarmeComando == DateTime.MinValue) - { - UltimoAlarmeComando = DateTime.Now; - } - - if (UltimoAlarmeComando.AddSeconds(5) < DateTime.Now) - { - return true; - } - } - else + if (!ComandoLigado) { UltimoAlarmeComando = DateTime.MinValue; + return false; } - return false; + if (HaEvidenciaAtuacao(agora)) + { + UltimoAlarmeComando = DateTime.MinValue; + return false; + } + + bool ausenciaConfirmada = HaEvidenciaSuficienteDeAusencia(agora); + + if (!ausenciaConfirmada) + { + // Telemetria insuficiente ou velha: + // situação inconclusiva, tratada pela saúde de comunicação. + UltimoAlarmeComando = DateTime.MinValue; + return false; + } + + if (UltimoAlarmeComando == DateTime.MinValue) + { + UltimoAlarmeComando = agora; + return false; + } + + return (agora - UltimoAlarmeComando).TotalSeconds >= 5.0; } } diff --git a/AgroBase/AgroBase/Services/SerialService.cs b/AgroBase/AgroBase/Services/SerialService.cs index 8c023cb10..d85688a2b 100644 --- a/AgroBase/AgroBase/Services/SerialService.cs +++ b/AgroBase/AgroBase/Services/SerialService.cs @@ -91,6 +91,7 @@ namespace AgroBase.Services private static readonly ConcurrentDictionary _portIoLocks = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); private static readonly ConcurrentDictionary _missingPortConfirmations = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private static readonly ConcurrentDictionary _usbDisconnectedConfirmations = new ConcurrentDictionary(); public static int ConfirmacoesPortaAusente { get; set; } = 2; private static CancellationTokenSource _lifetimeCts = new CancellationTokenSource(); @@ -893,19 +894,35 @@ namespace AgroBase.Services bool connected = health.status != StatusModulo.Desconectado; - if (mapped == null && connected) + if (connected) { - AdicionarOuAtualizarDispositivoMapeado( - new DispositivoDetalhesModel - { - Dispositivo = - camera.dispositivo, - Endereco = "USB", - Versao = camera.versao - } + _usbDisconnectedConfirmations.TryRemove( + camera.dispositivo, + out _ ); + + if (mapped == null) + { + AdicionarOuAtualizarDispositivoMapeado( + new DispositivoDetalhesModel + { + Dispositivo = camera.dispositivo, + Endereco = "USB", + Versao = camera.versao + } + ); + } + + continue; } - else if (mapped != null && !connected) + + int confirmacoes = _usbDisconnectedConfirmations.AddOrUpdate( + camera.dispositivo, + 1, + (_, atual) => atual + 1 + ); + + if (mapped != null && confirmacoes >= 2) { RemoverDispositivoMapeado(mapped); } diff --git a/AgroBase/OperationControl/Controls/AttitudeIndicator.xaml.cs b/AgroBase/OperationControl/Controls/AttitudeIndicator.xaml.cs index 3d5b5442f..9e37f38b9 100644 --- a/AgroBase/OperationControl/Controls/AttitudeIndicator.xaml.cs +++ b/AgroBase/OperationControl/Controls/AttitudeIndicator.xaml.cs @@ -131,8 +131,8 @@ namespace OperationControl.Controls // Derivados public double MaxAbsAngle => Math.Max(Math.Abs(RollDeg), Math.Abs(PitchDeg)); - public string RollTexto => $"FRT {FormatSignedDeg(RollDeg)}"; - public string PitchTexto => $"LAT {FormatSignedDeg(PitchDeg)}"; + public string RollTexto => $"LAT {FormatSignedDeg(RollDeg)}"; + public string PitchTexto => $"FRT {FormatSignedDeg(PitchDeg)}"; private static string FormatSignedDeg(double value) { diff --git a/AgroBase/OperationControl/ViewModels/Windows/DockWindowViewModel.cs b/AgroBase/OperationControl/ViewModels/Windows/DockWindowViewModel.cs index 1af807d16..dbd7c6577 100644 --- a/AgroBase/OperationControl/ViewModels/Windows/DockWindowViewModel.cs +++ b/AgroBase/OperationControl/ViewModels/Windows/DockWindowViewModel.cs @@ -1048,8 +1048,8 @@ namespace OperationControl.ViewModels // ATTITUDE var IMU = _viewOperacaoCenter.Monitoramento.Attitude; - if (obj?.Imu?.InclinacaoLateral != null) IMU.PitchDeg = (double)obj.Imu.InclinacaoLateral; - if (obj?.Imu?.InclinacaoFrontal != null) IMU.RollDeg = (double)obj.Imu.InclinacaoFrontal; + if (obj?.Imu?.InclinacaoLateral != null) IMU.RollDeg = (double)obj.Imu.InclinacaoLateral; + if (obj?.Imu?.InclinacaoFrontal != null) IMU.PitchDeg = (double)obj.Imu.InclinacaoFrontal; IMU.LateralError = erroLateral; diff --git a/AgroBase/OperationControl/Views/Operacao/Monitoramento/MonitoramentoView.xaml b/AgroBase/OperationControl/Views/Operacao/Monitoramento/MonitoramentoView.xaml index bfcaa10ec..99cc5ed74 100644 --- a/AgroBase/OperationControl/Views/Operacao/Monitoramento/MonitoramentoView.xaml +++ b/AgroBase/OperationControl/Views/Operacao/Monitoramento/MonitoramentoView.xaml @@ -43,10 +43,64 @@ - + + + +