From 2325d866fee8f3a8676306661b2533a9af6ebb8f Mon Sep 17 00:00:00 2001 From: Diego Freitas Date: Thu, 18 Dec 2025 17:14:27 -0300 Subject: [PATCH] Ajustes no calculo de vazao por bico --- .../Forms/Operacoes/frmOperacaoManual.cs | 2 +- .../Forms/Operacoes/frmOperacaoMapaGPS.cs | 2 +- .../AgroBase/Models/Modules/AtuadorModel.cs | 123 +++++++++++------- .../Models/Modules/SensoriamentoModel.cs | 11 +- .../Models/Operacoes/OperacaoModel.cs | 5 +- .../Operacoes/OperacaoParametrosModel.cs | 8 +- .../Windows/MainWindow.xaml.cs | 6 +- Firmware/Modulos/SensorMassaModel.h | 3 +- Firmware/Modulos/SinaleiroModel.h | 5 +- 9 files changed, 101 insertions(+), 64 deletions(-) diff --git a/AgroBase/AgroBase/Forms/Operacoes/frmOperacaoManual.cs b/AgroBase/AgroBase/Forms/Operacoes/frmOperacaoManual.cs index 79ac3be7a..351a35c5a 100644 --- a/AgroBase/AgroBase/Forms/Operacoes/frmOperacaoManual.cs +++ b/AgroBase/AgroBase/Forms/Operacoes/frmOperacaoManual.cs @@ -668,7 +668,7 @@ namespace AgroBase.Forms.Operacoes Atuado = x.ComandoAtuar, Comandar = x.Comandar, Inicializado = x.Inicializado, - MediaNivelFluxo = x.MediaNivelFluxo, + MediaNivelFluxo = x.VazaoMediaMLs, Posicao = x.Posicao, StatusBico = x._EstadoLeitura == Estado.Ligado, TempoAtuado = x.TempoAtuado, diff --git a/AgroBase/AgroBase/Forms/Operacoes/frmOperacaoMapaGPS.cs b/AgroBase/AgroBase/Forms/Operacoes/frmOperacaoMapaGPS.cs index 6aeedffb9..03ebd2634 100644 --- a/AgroBase/AgroBase/Forms/Operacoes/frmOperacaoMapaGPS.cs +++ b/AgroBase/AgroBase/Forms/Operacoes/frmOperacaoMapaGPS.cs @@ -176,7 +176,7 @@ namespace AgroBase.Forms.Operacoes Atuado = x.ComandoAtuar, Comandar = x.Comandar, Inicializado = x.Inicializado, - MediaNivelFluxo = x.MediaNivelFluxo, + MediaNivelFluxo = x.VazaoMediaMLs, Posicao = x.Posicao, StatusBico = x._EstadoLeitura == Enums.Estado.Ligado, TempoAtuado = x.TempoAtuado, diff --git a/AgroBase/AgroBase/Models/Modules/AtuadorModel.cs b/AgroBase/AgroBase/Models/Modules/AtuadorModel.cs index 742565dc7..8046ad621 100644 --- a/AgroBase/AgroBase/Models/Modules/AtuadorModel.cs +++ b/AgroBase/AgroBase/Models/Modules/AtuadorModel.cs @@ -124,36 +124,57 @@ namespace AgroBase.Models.Modules private double _somaVazao; // Acumula a soma da vazão para calcular a média private int _contadorLeituras; // Conta o número de leituras feitas private DateTime _ultimoRegistroVazao; // Armazena o horário da última atualização + private readonly Dictionary _tempoAtuadoBicoSeg = new Dictionary(); public double VazaoFluxoMLpSMedia { get; set; } public double VolumeVazaoML { get; set; } public DateTime InicioAtuacao { get; set; } = DateTime.MinValue; public double TempoAtuado { get; set; } = 0; + private bool bicoAtivoAnterior = false; public void AtualizaTempoAtuadoGeral() { - bool algumBicoAtivo = BicosPulverizadores.Any(x => x.Inicializado && x.ComandoAtuar); + DateTime agora = DateTime.Now; - if (algumBicoAtivo) + // Quem está ativo AGORA + var bicosAtivos = BicosPulverizadores.Where(x => x.Inicializado && x.ComandoAtuar).ToList(); + + bool algumBicoAtivo = bicosAtivos.Count > 0; + + // Início de uma "sessão" (transição OFF -> ON) + if (algumBicoAtivo && !bicoAtivoAnterior) { - if (InicioAtuacao == DateTime.MinValue) - { - InicioAtuacao = DateTime.Now; - } - else - { - TempoAtuado += (DateTime.Now - InicioAtuacao).TotalMilliseconds; - InicioAtuacao = DateTime.Now; - } - } - else if (InicioAtuacao != DateTime.MinValue) - { - TempoAtuado += (DateTime.Now - InicioAtuacao).TotalMilliseconds; - InicioAtuacao = DateTime.MinValue; + InicioAtuacao = agora; + _ultimoRegistroVazao = agora; // inicia integração a partir daqui + + // (opcional) se você quer métricas por sessão, zere volumes/médias aqui + // foreach (var b in BicosPulverizadores) { b.VolumeVazadoML = 0; b.VazaoMediaMLs = 0; } + // _tempoAtuadoBicoSeg.Clear(); } + // Fim de sessão (transição ON -> OFF) + if (!algumBicoAtivo && bicoAtivoAnterior) + { + if (InicioAtuacao != DateTime.MinValue) + { + TempoAtuado += (agora - InicioAtuacao).TotalMilliseconds; + InicioAtuacao = DateTime.MinValue; + } + + _ultimoRegistroVazao = DateTime.MinValue; + + // zera instantânea quando não tem bico ativo + foreach (var b in BicosPulverizadores) + b.VazaoInstantaneaMLs = 0; + } + + // Atualiza indicadores AtualizaPercentualErvas(); - AtualizaVazaoEVolume(); + + // Integra vazão/volume enquanto tiver bico ativo + AtualizaVazaoEVolume(bicosAtivos, agora); + + bicoAtivoAnterior = algumBicoAtivo; } - public void AtualizaPercentualErvas() + private void AtualizaPercentualErvas() { //double tempoTotalOperacao = Variaveis.OperacaoEmAndamento.Sensoriamento.TempoDecorridoSeg * 1000.0; double tempoTotalOperacao = (Variaveis.OperacaoEmAndamento.Sensoriamento?.Movimentacao?.TempoMovimentoSegs ?? 0) * 1000.0; @@ -168,38 +189,50 @@ namespace AgroBase.Models.Modules PercentualErvasTerreno = 0; } } - public void AtualizaVazaoEVolume() + private void AtualizaVazaoEVolume(List bicosAtivos, DateTime agora) { - // Captura a vazão instantânea - double vazaoInstantanea = VazaoFluxoMLpSInstantanea; + // Só integra se houver bicos ativos + if (bicosAtivos == null || bicosAtivos.Count == 0) + return; + // Captura vazão total instantânea (ml/s) + double vazaoTotalInst = VazaoFluxoMLpSInstantanea; + + // Primeiro tick: arma o relógio if (_ultimoRegistroVazao == DateTime.MinValue) { - _ultimoRegistroVazao = DateTime.Now; + _ultimoRegistroVazao = agora; return; } - // Calcula o tempo decorrido desde a última atualização (em segundos) - double intervaloSegundos = (DateTime.Now - _ultimoRegistroVazao).TotalSeconds; - _ultimoRegistroVazao = DateTime.Now; + // dt em segundos + double dt = (agora - _ultimoRegistroVazao).TotalSeconds; + _ultimoRegistroVazao = agora; - if (intervaloSegundos > 0) + if (dt <= 0) + return; + + // Vazão instantânea por bico (distribuição uniforme) + double vazaoPorBicoInst = vazaoTotalInst / bicosAtivos.Count; + + foreach (var bico in bicosAtivos) { - // Atualiza o volume total vazado - VolumeVazaoML += vazaoInstantanea * intervaloSegundos; + // Instantânea por bico + bico.VazaoInstantaneaMLs = vazaoPorBicoInst; - // Acumula a vazão para o cálculo da média - _somaVazao += vazaoInstantanea; - _contadorLeituras++; - } + // Volume por bico (ml) = (ml/s) * s + bico.VolumeVazadoML += vazaoPorBicoInst * dt; - VazaoFluxoMLpSMedia = TempoAtuado == 0 ? 0 : VolumeVazaoML / TempoAtuado; + // Tempo atuado por bico (seg) + string key = bico.ID; // ou bico.ID_Num.ToString() + if (!_tempoAtuadoBicoSeg.ContainsKey(key)) + _tempoAtuadoBicoSeg[key] = 0; - var BicosAtuados = BicosPulverizadores.Where(x => x.Inicializado && x.ComandoAtuar).ToList(); - double vazaoInstantaneaBico = vazaoInstantanea / ((double)BicosAtuados.Count()); - foreach (var Bico in BicosAtuados) - { - Bico.MediaNivelFluxo = vazaoInstantaneaBico; + _tempoAtuadoBicoSeg[key] += dt; + + // Média por bico (ml/s) = volume / tempo + double tempoBico = _tempoAtuadoBicoSeg[key]; + bico.VazaoMediaMLs = tempoBico > 0 ? (bico.VolumeVazadoML / tempoBico) : 0; } } @@ -747,7 +780,7 @@ namespace AgroBase.Models.Modules { FuncoesPinout.Solenoide, }, - MediaNivelFluxo = 0, + VazaoMediaMLs = 0, ValoresLeituras = new List() { new SensorValoresLeituraModel() @@ -1304,7 +1337,9 @@ namespace AgroBase.Models.Modules } } public List Funcoes { get; set; } - public double MediaNivelFluxo { get; set; } + public double VazaoMediaMLs { get; set; } + public double VazaoInstantaneaMLs { get; set; } + public double VolumeVazadoML { get; set; } public bool Inicializado { get; set; } public DateTime UltimaLeitura { @@ -1380,12 +1415,6 @@ namespace AgroBase.Models.Modules InicioAtuacao = DateTime.MinValue; } } - - if (Variaveis.OperacaoEmAndamento.DispAtu != null) - { - Variaveis.OperacaoEmAndamento.DispAtu.Dados.AtualizaTempoAtuadoGeral(); - } - _estadoLeituraAnterior = estado_atual; } @@ -1408,7 +1437,7 @@ namespace AgroBase.Models.Modules ID_Num = ID_Num, InicioAtuacao = InicioAtuacao, ValoresLeituras = new List(ValoresLeituras), - MediaNivelFluxo = MediaNivelFluxo, + VazaoMediaMLs = VazaoMediaMLs, Posicao = Posicao, TempoAtuado = TempoAtuado }; diff --git a/AgroBase/AgroBase/Models/Modules/SensoriamentoModel.cs b/AgroBase/AgroBase/Models/Modules/SensoriamentoModel.cs index 47a5ccf5b..4bf933f1c 100644 --- a/AgroBase/AgroBase/Models/Modules/SensoriamentoModel.cs +++ b/AgroBase/AgroBase/Models/Modules/SensoriamentoModel.cs @@ -10,7 +10,6 @@ using static AgroBase.Services.LoRaEspService; using AgroBase.Services.Operadores; using AgroBase.Models.Operadores; using System.Diagnostics; -using StackExchange.Redis; namespace AgroBase.Models.Modules { @@ -2394,9 +2393,9 @@ namespace AgroBase.Models.Modules public void AtualizarStatusSinaleiros(ModoOperacao Modo, StatusOperacao _statusOperacao) { - Sinaleiros.First(x => x.ID == "LEDMN").Comportamento.statusLED = Modo == ModoOperacao.Manual ? StatusLED.Aceso : StatusLED.Apagado; - Sinaleiros.First(x => x.ID == "LEDAT").Comportamento.statusLED = Modo == ModoOperacao.Manual ? StatusLED.Apagado : StatusLED.Aceso; - Sinaleiros.First(x => x.ID == "LEDOP").Comportamento = VariaveisEquipamento.ComportamentoLedPorStatus(status_operacao: _statusOperacao); + Sinaleiros.First(x => x.ID == "LEDMN").Comportamento = VariaveisEquipamento.ComportamentoLedPorStatus(Modo == ModoOperacao.Manual ? StatusLED.Aceso : StatusLED.Apagado); + Sinaleiros.First(x => x.ID == "LEDAT").Comportamento = VariaveisEquipamento.ComportamentoLedPorStatus(Modo == ModoOperacao.Manual ? StatusLED.Apagado : StatusLED.Aceso); + Sinaleiros.First(x => x.ID == "LEDOP").Comportamento = VariaveisEquipamento.ComportamentoLedPorStatus(StatusLED.Piscando, status_operacao: _statusOperacao); } } @@ -2479,8 +2478,8 @@ namespace AgroBase.Models.Modules } } public List ValoresLeituras { get; set; } - public int _StatusLedId => ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.StatusLedID)?.atual?.valor ?? 99; - public StatusLED _StatusLed => ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.StatusLedLeitura)?.atual?.valor ?? StatusLED.Apagado; + public int _StatusLedId => (int)(ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.StatusLedID)?.atual?.valor ?? 99); + public StatusLED _StatusLed => (StatusLED)(ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.StatusLedLeitura)?.atual?.valor ?? StatusLED.Apagado); public (CanMessagePosicaoDados, byte[]) ProtocoloConfiguracao(PinoutDataModel pinout, bool conectar) { diff --git a/AgroBase/AgroBase/Models/Operacoes/OperacaoModel.cs b/AgroBase/AgroBase/Models/Operacoes/OperacaoModel.cs index 408ed9056..f97862395 100644 --- a/AgroBase/AgroBase/Models/Operacoes/OperacaoModel.cs +++ b/AgroBase/AgroBase/Models/Operacoes/OperacaoModel.cs @@ -1790,7 +1790,7 @@ namespace AgroBase.Models Inicializado = Bico.Inicializado, Comandar = Bico.Comandar, Atuado = Bico.ComandoAtuar, - MediaNivelFluxo = Bico.MediaNivelFluxo, + MediaNivelFluxo = Bico.VazaoMediaMLs, Posicao = Bico.Posicao, StatusBico = Bico._EstadoLeitura == Estado.Ligado, Atuacoes = Bico.Atuacoes, @@ -2320,6 +2320,7 @@ namespace AgroBase.Models double tmp_max = Math.Max(Variaveis.OperacaoEmAndamento.DadosPerformance?.GPU_temp ?? 0, Variaveis.OperacaoEmAndamento.DadosPerformance?.CPU_temp ?? 0); _DispMvd?.Dados?.AtualizarDadosFreio(); _DispSen?.Dados?.AtualizarStatusSinaleiros(Variaveis.OperacaoEmAndamento.Modo, Variaveis.OperacaoEmAndamento.StatusAtual); + _DispAtu?.Dados?.AtualizaTempoAtuadoGeral(); _Cooler?.Atualizar(tmp_max, DateTime.Now); _Bateria?.AtualizarConsumo(_DispMvd?.Dados?.DistanciaPercorridaTotal ?? 0); _Reservatorio?.AtualizarConsumo(_DispMvd?.Dados?.DistanciaPercorridaTotal ?? 0, Variaveis.OperacaoEmAndamento.TempoDecorridoSegs); @@ -2373,7 +2374,7 @@ namespace AgroBase.Models Inicializado = Bico.Inicializado, Comandar = Bico.Comandar, Atuado = Bico.ComandoAtuar, - MediaNivelFluxo = Bico.MediaNivelFluxo, + MediaNivelFluxo = Bico.VazaoMediaMLs, Posicao = Bico.Posicao, StatusBico = Bico._EstadoLeitura == Estado.Ligado, Atuacoes = Bico.Atuacoes, diff --git a/AgroBase/AgroBase/Models/Operacoes/OperacaoParametrosModel.cs b/AgroBase/AgroBase/Models/Operacoes/OperacaoParametrosModel.cs index d96ea2805..204fa32e2 100644 --- a/AgroBase/AgroBase/Models/Operacoes/OperacaoParametrosModel.cs +++ b/AgroBase/AgroBase/Models/Operacoes/OperacaoParametrosModel.cs @@ -156,7 +156,9 @@ namespace AgroBase.Models.Operacoes LeituraAngulo = x._AnguloBicoLeitura, ComandoEstado = x.ComandoAtuar, LeituraEstado = x._EstadoLeitura == Estado.Ligado, - MediaVazaoMLs = x.MediaNivelFluxo, + VazaoMediaMLs = x.VazaoMediaMLs, + VazaoInstantaneaMLs = x.VazaoInstantaneaMLs, + VolumeVazadoML = x.VolumeVazadoML, QtdAtuacoes = x.Atuacoes, TempoAtuado = x.TempoAtuado, TrechosPulverizando = new List>(x.TrechosAtuado ?? new List>()), @@ -428,7 +430,9 @@ namespace AgroBase.Models.Operacoes public int LeituraAngulo { get; set; } public int QtdAtuacoes { get; set; } public double TempoAtuado { get; set; } - public double MediaVazaoMLs { get; set; } + public double VazaoMediaMLs { get; set; } + public double VazaoInstantaneaMLs { get; set; } + public double VolumeVazadoML { get; set; } public double AnguloAbertura { get; set; } public List> TrechosPulverizando { get; set; } public DateTime UltimoComandoRespondido { get; set; } diff --git a/AgroBase/OperationControl/Windows/MainWindow.xaml.cs b/AgroBase/OperationControl/Windows/MainWindow.xaml.cs index a76c4d1ab..74938fa3e 100644 --- a/AgroBase/OperationControl/Windows/MainWindow.xaml.cs +++ b/AgroBase/OperationControl/Windows/MainWindow.xaml.cs @@ -836,7 +836,7 @@ namespace OperationControl.Windows { Label = "Vazão", Unidade = "mL/s", - Valor = b?.MediaVazaoMLs + Valor = b?.VazaoInstantaneaMLs }, }); break; @@ -1127,7 +1127,7 @@ namespace OperationControl.Windows txtBico_Comando.Text = comando ? "Ligado" : "Desligado"; txtBico_StatusReal.Text = leitura ? "Ligado" : "Desligado"; txtBico_TempoLigado.Text = (bico?.TempoAtuado ?? 0).ToString("0.00") + " ms"; - txtBico_Vazao.Text = (bico?.MediaVazaoMLs ?? 0).ToString("0.00") + " Ml/s"; + txtBico_Vazao.Text = (bico?.VazaoInstantaneaMLs ?? 0).ToString("0.00") + " Ml/s"; txtBico_Pressao.Text = (rover?.Atuador?.PressaoLinhaPsi ?? 0).ToString("0.00") + " psi"; txtBico_Atuacoes.Text = (bico?.QtdAtuacoes ?? 0).ToString(); @@ -2028,7 +2028,7 @@ namespace OperationControl.Windows bico.AnguloControle = _bc.ComandoAngulo; bico.IsCommandOn = _bc.ComandoEstado; bico.IsSpraying = _bc.LeituraEstado; - bico.Vazao = _bc.MediaVazaoMLs; + bico.Vazao = _bc.VazaoInstantaneaMLs; bico.Atuacoes = _bc.QtdAtuacoes; bico.TempoAtuado = _bc.TempoAtuado / 1000.0; } diff --git a/Firmware/Modulos/SensorMassaModel.h b/Firmware/Modulos/SensorMassaModel.h index 9cdeac33b..df36c7c46 100644 --- a/Firmware/Modulos/SensorMassaModel.h +++ b/Firmware/Modulos/SensorMassaModel.h @@ -86,7 +86,8 @@ class SensorMassa : public ComponenteCAN { } case CanMessagePosicaoDados::Dados1: { uint16_t massaEscalada = (uint16_t)(Massa * 100); - data.push_back(leitura >> 8); data.push_back(leitura & 0xFF); + uint16_t leituraEscalada = (uint16_t)(leitura * 100); + data.push_back(leituraEscalada >> 8); data.push_back(leituraEscalada & 0xFF); data.push_back(massaEscalada >> 8); data.push_back(massaEscalada & 0xFF); break; } diff --git a/Firmware/Modulos/SinaleiroModel.h b/Firmware/Modulos/SinaleiroModel.h index 67522d304..fb9967826 100644 --- a/Firmware/Modulos/SinaleiroModel.h +++ b/Firmware/Modulos/SinaleiroModel.h @@ -66,7 +66,10 @@ class Sinaleiro : public ComponenteCAN { void AtualizarLeitura() { if (Iniciado) { - _StatusLeitura = (StatusLED)_pino.get(); + if (_Qtd == 0) + _StatusLeitura = (StatusLED)_pino.get(); + else + _StatusLeitura = StatusLED::Piscando; } }