Ajustes no calculo de vazao por bico

This commit is contained in:
Diego Freitas 2025-12-18 17:14:27 -03:00
parent ff4e6116d6
commit 2325d866fe
9 changed files with 101 additions and 64 deletions

View File

@ -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,

View File

@ -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,

View File

@ -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<string, double> _tempoAtuadoBicoSeg = new Dictionary<string, double>();
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<AtuadorBicoModel> 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<SensorValoresLeituraModel>()
{
new SensorValoresLeituraModel()
@ -1304,7 +1337,9 @@ namespace AgroBase.Models.Modules
}
}
public List<FuncoesPinout> 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<SensorValoresLeituraModel>(ValoresLeituras),
MediaNivelFluxo = MediaNivelFluxo,
VazaoMediaMLs = VazaoMediaMLs,
Posicao = Posicao,
TempoAtuado = TempoAtuado
};

View File

@ -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<SensorValoresLeituraModel> 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)
{

View File

@ -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,

View File

@ -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<List<double[]>>(x.TrechosAtuado ?? new List<List<double[]>>()),
@ -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<List<double[]>> TrechosPulverizando { get; set; }
public DateTime UltimoComandoRespondido { get; set; }

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}
}