agrobase
This commit is contained in:
parent
d42a7d4005
commit
7c8da7e435
|
|
@ -30,8 +30,8 @@ namespace AgroBase.Forms.Atuador
|
|||
nudPressaoSP.Value = Convert.ToInt32(Variaveis.OperacaoEmAndamento.Parametros.Controle.AtuPressaoLinha);
|
||||
txtPressaoVmin.Text = DispAtu.Dados._PressaoVmin.ToString();
|
||||
txtPressaoVmax.Text = DispAtu.Dados._PressaoVmax.ToString();
|
||||
txtMLRef.Text = DispAtu.Dados._FluxoMlRef.ToString();
|
||||
txtPulsosRef.Text = DispAtu.Dados._FluxoPulsoRef.ToString();
|
||||
txtMLRef.Text = DispAtu.Dados.VazaoFluxoMLpSReferencia.ToString();
|
||||
//txtPulsosRef.Text = DispAtu.Dados._FluxoPulsoRef.ToString();
|
||||
txtVolume.Text = DispAtu.Dados.VolumeVazaoAferido.ToString();
|
||||
|
||||
grdSensoriamento.Rows.Clear();
|
||||
|
|
@ -207,8 +207,8 @@ namespace AgroBase.Forms.Atuador
|
|||
Variaveis.OperacaoEmAndamento.Parametros.Controle.AtuPressaoLinha = Convert.ToDouble(nudPressaoSP.Value);
|
||||
DispAtu.Dados._PressaoVmin = Convert.ToDouble(txtPressaoVmin.Text);
|
||||
DispAtu.Dados._PressaoVmax = Convert.ToDouble(txtPressaoVmax.Text);
|
||||
DispAtu.Dados._FluxoMlRef = Convert.ToDouble(txtMLRef.Text);
|
||||
DispAtu.Dados._FluxoPulsoRef = Convert.ToDouble(txtPulsosRef.Text);
|
||||
//DispAtu.Dados._FluxoMlRef = Convert.ToDouble(txtMLRef.Text);
|
||||
//DispAtu.Dados._FluxoPulsoRef = Convert.ToDouble(txtPulsosRef.Text);
|
||||
DispAtu.Dados.VolumeVazaoAferido = Convert.ToDouble(txtVolume.Text);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
using AgroBase.Models;
|
||||
using AgroBase.Models.Components;
|
||||
using AgroBase.Models.Operadores;
|
||||
using AgroBase.Services;
|
||||
using AgroBase.Services.Operadores;
|
||||
using Assimp;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
|
|
@ -264,14 +261,14 @@ namespace AgroBase.Forms.IHM
|
|||
var cameras = CameraWorkerService.GetListaCameras();
|
||||
ListaCameras = cameras.Select(x => new OAKCameraModel()
|
||||
{
|
||||
Index = 0,
|
||||
Index = cameras.IndexOf(x),
|
||||
Dispositivo = x.dispositivo,
|
||||
Version = x.versao,
|
||||
Name = x.modelo,
|
||||
Id = x.mx_id,
|
||||
}).ToList();
|
||||
|
||||
CameraCaminho = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho.Clone();
|
||||
CameraCaminho = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho?.Clone();
|
||||
CamerasSolo = new List<OAKCameraModel>(Variaveis.OperacaoEmAndamento.DispSen.Dados.CamerasSolo);
|
||||
|
||||
for (int i = 0; i < Variaveis.OperacaoEmAndamento.Parametros.QtdCamerasSolo; i++)
|
||||
|
|
@ -281,7 +278,7 @@ namespace AgroBase.Forms.IHM
|
|||
|
||||
cmbCameraCaminho.Items.Clear();
|
||||
cmbCameraCaminho.Items.AddRange(ListaCameras.Select(x => x.Description).ToArray());
|
||||
var cameraSelecionada = ListaCameras.FirstOrDefault(x => x.Id == CameraCaminho.Id);
|
||||
var cameraSelecionada = ListaCameras.FirstOrDefault(x => x.Id == CameraCaminho?.Id);
|
||||
if (cameraSelecionada != null)
|
||||
{
|
||||
cmbCameraCaminho.SelectedIndex = cmbCameraCaminho.Items.IndexOf(cameraSelecionada.Description);
|
||||
|
|
@ -344,7 +341,7 @@ namespace AgroBase.Forms.IHM
|
|||
CamerasSolo.Add(new OAKCameraModel());
|
||||
}
|
||||
|
||||
var cameraSelecionada = ListaCameras.FirstOrDefault(x => x.Id == CamerasSolo[idx].Id);
|
||||
var cameraSelecionada = ListaCameras.FirstOrDefault(x => x.Id == CamerasSolo[idx]?.Id);
|
||||
|
||||
if (cameraSelecionada != null)
|
||||
{
|
||||
|
|
@ -410,11 +407,11 @@ namespace AgroBase.Forms.IHM
|
|||
{
|
||||
if (idx == -1)
|
||||
{
|
||||
emUso = CamerasSolo.Any(x => x.Id == cam.Id);
|
||||
emUso = CamerasSolo.Any(x => cam.Id != null && x.Id == cam.Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
emUso = (CameraCaminho.Id == cam.Id) || (CamerasSolo.Any(x => x.Index != idx && x.Id == cam.Id));
|
||||
emUso = cam.Id != null && ((CameraCaminho?.Id == cam.Id) || (CamerasSolo.Any(x => x?.Index != idx && x?.Id == cam.Id)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@
|
|||
this.flwCamerasSolo = new System.Windows.Forms.FlowLayoutPanel();
|
||||
this.chbSonarAtivado = new System.Windows.Forms.CheckBox();
|
||||
this.lblPressao = new System.Windows.Forms.Label();
|
||||
this.lblStatusCarroMapa = new System.Windows.Forms.Label();
|
||||
((System.ComponentModel.ISupportInitialize)(this.chartGraficos)).BeginInit();
|
||||
this.tabControl1.SuspendLayout();
|
||||
this.tabMapa.SuspendLayout();
|
||||
|
|
@ -352,6 +353,7 @@
|
|||
//
|
||||
// tabDeteccoes
|
||||
//
|
||||
this.tabDeteccoes.Controls.Add(this.lblStatusCarroMapa);
|
||||
this.tabDeteccoes.Controls.Add(this.pnlDeteccoesRua);
|
||||
this.tabDeteccoes.Location = new System.Drawing.Point(4, 22);
|
||||
this.tabDeteccoes.Margin = new System.Windows.Forms.Padding(2);
|
||||
|
|
@ -721,6 +723,16 @@
|
|||
this.lblPressao.TabIndex = 38;
|
||||
this.lblPressao.Text = "80 psi";
|
||||
//
|
||||
// lblStatusCarroMapa
|
||||
//
|
||||
this.lblStatusCarroMapa.AutoSize = true;
|
||||
this.lblStatusCarroMapa.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.lblStatusCarroMapa.Location = new System.Drawing.Point(10, 269);
|
||||
this.lblStatusCarroMapa.Name = "lblStatusCarroMapa";
|
||||
this.lblStatusCarroMapa.Size = new System.Drawing.Size(168, 16);
|
||||
this.lblStatusCarroMapa.TabIndex = 1;
|
||||
this.lblStatusCarroMapa.Text = "Status: Parado | Conf: 1.000";
|
||||
//
|
||||
// frmOperacaoManual
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
|
|
@ -763,6 +775,7 @@
|
|||
this.tabInformacoes.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.gridDados)).EndInit();
|
||||
this.tabDeteccoes.ResumeLayout(false);
|
||||
this.tabDeteccoes.PerformLayout();
|
||||
this.tabPulverizador.ResumeLayout(false);
|
||||
this.tabPulverizador.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.nudPotenciaSP)).EndInit();
|
||||
|
|
@ -835,5 +848,6 @@
|
|||
private System.Windows.Forms.Label lblPotenciaSP;
|
||||
private System.Windows.Forms.NumericUpDown nudPotenciaSP;
|
||||
private System.Windows.Forms.Label lblPressao;
|
||||
private System.Windows.Forms.Label lblStatusCarroMapa;
|
||||
}
|
||||
}
|
||||
|
|
@ -219,6 +219,9 @@ namespace AgroBase.Forms.Operacoes
|
|||
|
||||
//var frameSeg = await VisualWorkerService.GetCameraFrame(CameraFrameType.Segmentacao);
|
||||
//AtualizarImagemPainel(pnlDeteccoesRua, frameSeg?.image());
|
||||
|
||||
var dadosSeg = Variaveis.OperacaoEmAndamento.Sensoriamento?.OperadorVisual?.Analises?.segmentacao;
|
||||
lblStatusCarroMapa.Text = $"Status: {dadosSeg?.status_corredor ?? StatusCarroMapa.Indefinido} | Conf: {dadosSeg?.status_corredor_debug?.status_modelo_conf ?? 0}";
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
|
|||
|
|
@ -736,65 +736,44 @@ namespace AgroBase.Forms.Operacoes
|
|||
{
|
||||
new GraficoInterativoSerieModel()
|
||||
{
|
||||
Titulo = "CPU %",
|
||||
Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.CPU_load ?? 0)).ToList(),
|
||||
Titulo = "GPU Geral %",
|
||||
Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.GPU_load_percent ?? 0)).ToList(),
|
||||
Visivel = true,
|
||||
MostrarValor = true
|
||||
},
|
||||
new GraficoInterativoSerieModel()
|
||||
{
|
||||
Titulo = "GPU %",
|
||||
Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.GPU_load ?? 0)).ToList(),
|
||||
Titulo = "GPU Core %",
|
||||
Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.GPU_core_load_percent ?? 0)).ToList(),
|
||||
Visivel = true,
|
||||
MostrarValor = true
|
||||
},
|
||||
new GraficoInterativoSerieModel()
|
||||
{
|
||||
Titulo = "HDD %",
|
||||
Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.HDD_load ?? 0)).ToList(),
|
||||
Titulo = "GPU Memory %",
|
||||
Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.GPU_memory_load_percent ?? 0)).ToList(),
|
||||
Visivel = true,
|
||||
MostrarValor = true
|
||||
},
|
||||
new GraficoInterativoSerieModel()
|
||||
{
|
||||
Titulo = "RAM %",
|
||||
Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.RAM_usage ?? 0)).ToList(),
|
||||
Titulo = "GPU Frame Buffer %",
|
||||
Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.GPU_frame_buffer_load_percent ?? 0)).ToList(),
|
||||
Visivel = true,
|
||||
MostrarValor = true
|
||||
},
|
||||
new GraficoInterativoSerieModel()
|
||||
{
|
||||
Titulo = "CPU Temp",
|
||||
Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.CPU_temp ?? 0)).ToList(),
|
||||
Visivel = true,
|
||||
Titulo = "GPU Video Engine %",
|
||||
Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.GPU_video_engine_load_percent ?? 0)).ToList(),
|
||||
Visivel = false,
|
||||
MostrarValor = true
|
||||
},
|
||||
new GraficoInterativoSerieModel()
|
||||
{
|
||||
Titulo = "GPU Temp",
|
||||
Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.GPU_temp ?? 0)).ToList(),
|
||||
Visivel = true,
|
||||
MostrarValor = true
|
||||
},
|
||||
new GraficoInterativoSerieModel()
|
||||
{
|
||||
Titulo = "Threads Ativas",
|
||||
Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.ActiveThreads ?? 0)).ToList(),
|
||||
Visivel = true,
|
||||
MostrarValor = true
|
||||
},
|
||||
new GraficoInterativoSerieModel()
|
||||
{
|
||||
Titulo = "Threads de Trabalho %",
|
||||
Valores = LogsOperacao.Select(x => (double)((x?.DadosPerformance.MaxWorkerThreads ?? 1) - (x?.DadosPerformance.WorkerThreads ?? 0)) / (x?.DadosPerformance.MaxWorkerThreads ?? 1) * 100.0).ToList(),
|
||||
Visivel = true,
|
||||
MostrarValor = true
|
||||
},
|
||||
new GraficoInterativoSerieModel()
|
||||
{
|
||||
Titulo = "Threads de Portas %",
|
||||
Valores = LogsOperacao.Select(x => (double)((x?.DadosPerformance.MaxCompletionPortThreads ?? 1) - (x?.DadosPerformance.CompletionPortThreads ?? 0)) / (x?.DadosPerformance.MaxCompletionPortThreads ?? 1) * 100.0).ToList(),
|
||||
Visivel = true,
|
||||
Titulo = "GPU Bus Interface %",
|
||||
Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.GPU_bus_interface_load_percent ?? 0)).ToList(),
|
||||
Visivel = false,
|
||||
MostrarValor = true
|
||||
},
|
||||
});
|
||||
|
|
@ -1148,11 +1127,6 @@ namespace AgroBase.Forms.Operacoes
|
|||
var Log = LogsOperacao[idxMomentoAtual];
|
||||
var LogAtu = LogsAtuador[idxMomentoAtual];
|
||||
|
||||
double herbicidaConsumido = Log.Atuador.HerbicidaConsumido != 0 ? Log.Atuador.HerbicidaConsumido : LogAtu.VolumeVazaoML;
|
||||
double percentualHerbicidaConsumido = FuncoesMatematicas.Clamp(((herbicidaConsumido / 1000.0) / LogsAtuador.FirstOrDefault().VolumeReservatorio) * 100.0, 0, 100);
|
||||
int totalAtuacoes = 0; // Log.Atuador.ErvasIdentificadas.Sum(dict => dict.Values.Sum());
|
||||
double herbicidaPorErva = Log.Atuador.HerbicidaPorErva != 0 ? Log.Atuador.HerbicidaPorErva : (herbicidaConsumido / (totalAtuacoes > 0 ? totalAtuacoes : 1));
|
||||
|
||||
lblPercentualBateria.Text = $"Bateria {Log.Bateria.PercentualBateria.ToString("0.00")}%";
|
||||
FuncoesGlobais.PreencheValorProgressBar(pgbPercentualBateria, Log.Bateria.PercentualBateria);
|
||||
|
||||
|
|
@ -1162,13 +1136,13 @@ namespace AgroBase.Forms.Operacoes
|
|||
lblPercentualReservatorio.Text = $"Reservatório {LogAtu.PercentualReservatorio.ToString("0.00")}%";
|
||||
FuncoesGlobais.PreencheValorProgressBar(pgbPercentualReservatorio, LogAtu.PercentualReservatorio);
|
||||
|
||||
lblHerbicidaConsumido.Text = $"Consumido {herbicidaConsumido.ToString("0.00")} ml";
|
||||
FuncoesGlobais.PreencheValorProgressBar(pgbHerbicidaConsumido, percentualHerbicidaConsumido);
|
||||
lblHerbicidaConsumido.Text = $"Consumido {LogAtu.PercentualHerbicidaConsumidoOperacao.ToString("0.00")} ml";
|
||||
FuncoesGlobais.PreencheValorProgressBar(pgbHerbicidaConsumido, LogAtu.PercentualHerbicidaConsumidoOperacao);
|
||||
|
||||
txtTempoMovimento.Text = FuncoesGlobais.ConverterSegundosParaHHmmss((int)Log.Movimentacao.TempoMovimentoSegs);
|
||||
txtStatusOperacao.Text = Log.StatusOperacao.ToString();
|
||||
txtStatusCarro.Text = $"{Log.Trajetoria.StatusCarro}";
|
||||
txtHerbicidaPorErva.Text = herbicidaPorErva.ToString("0.00") + " ml";
|
||||
txtHerbicidaPorErva.Text = LogAtu.HerbicidaPorAtuacao.ToString("0.00") + " ml";
|
||||
txtDentroRua.Text = Log.Trajetoria.CorredorAtual.Dentro ? "Sim" : "Não";
|
||||
txtDirecaoCarro.Text = Log.Trajetoria.DirecaoCaminho.ToString() + " (" + Log.Trajetoria.CorredorAtual.Idx + " - " + Log.Trajetoria.ProximoPonto.idxPonto + " - " + Log.Trajetoria.ProximoPonto.idxPontoCorredor + ")";
|
||||
txtErvasNoRadar.Text = Log.Atuador.ErvasNoRadar.ToString() + " (" + (Log.Atuador.PercentualErvasNoRadar * 100).ToString("0.00") + "%)";
|
||||
|
|
@ -1177,7 +1151,7 @@ namespace AgroBase.Forms.Operacoes
|
|||
txtVelocidade.Text = (Log.Movimentacao.VelocidadeMedia * 3.6).ToString("0.00") + " km/h (" + Log.Movimentacao.VelocidadeMedia.ToString("0.00") + " m/s)";
|
||||
txtDirecaoControle.Text = (Log.Controle?.TiposControle?.FirstOrDefault(x => x.Tipo == Enums.T_Code.Dir)?.DirecaoAtual ?? Enums.Direcao.Parado).ToString() + " (" + (Log.Controle?.Latencia ?? 0).ToString("0.00") + " s)";
|
||||
txtVelocidadeControle.Text = ((Log.Controle?.PercentualVelocidadeSP ?? 0) / VariaveisEquipamento.RPM_Max_Roda * 100).ToString() + " rpm";
|
||||
txtErvasIdentificadas.Text = $"{totalAtuacoes}";
|
||||
txtErvasIdentificadas.Text = $"{Log.Controle?.Bicos?.Sum(x => x.Atuacoes) ?? 0}";
|
||||
|
||||
txtDistanciasLaterais.Text = (Log.Trajetoria.DistanciaEsquerda * 100.0).ToString("0.00") + " cm / " + (Log.Trajetoria.DistanciaDireita * 100.0).ToString("0.00") + " cm";
|
||||
txtErroLateral.Text = (Log.Controle.ErroLateral * 100.0).ToString("0.00") + " cm";
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@
|
|||
this.cmbAlgoritmo = new System.Windows.Forms.ComboBox();
|
||||
this.lblAlgoritmo = new System.Windows.Forms.Label();
|
||||
this.btnSalvarAlgoritmo = new System.Windows.Forms.Button();
|
||||
this.label4 = new System.Windows.Forms.Label();
|
||||
this.cmbDispositivo = new System.Windows.Forms.ComboBox();
|
||||
((System.ComponentModel.ISupportInitialize)(this.gridDados)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.picBussola)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
|
|
@ -218,12 +220,34 @@
|
|||
this.btnSalvarAlgoritmo.UseVisualStyleBackColor = true;
|
||||
this.btnSalvarAlgoritmo.Click += new System.EventHandler(this.btnSalvarAlgoritmo_Click);
|
||||
//
|
||||
// label4
|
||||
//
|
||||
this.label4.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.label4.AutoSize = true;
|
||||
this.label4.Location = new System.Drawing.Point(575, 629);
|
||||
this.label4.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
|
||||
this.label4.Name = "label4";
|
||||
this.label4.Size = new System.Drawing.Size(58, 13);
|
||||
this.label4.TabIndex = 62;
|
||||
this.label4.Text = "Dispositivo";
|
||||
//
|
||||
// cmbDispositivo
|
||||
//
|
||||
this.cmbDispositivo.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.cmbDispositivo.FormattingEnabled = true;
|
||||
this.cmbDispositivo.Location = new System.Drawing.Point(638, 625);
|
||||
this.cmbDispositivo.Name = "cmbDispositivo";
|
||||
this.cmbDispositivo.Size = new System.Drawing.Size(121, 21);
|
||||
this.cmbDispositivo.TabIndex = 61;
|
||||
//
|
||||
// frmWT901C
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.BackColor = System.Drawing.Color.White;
|
||||
this.ClientSize = new System.Drawing.Size(1088, 660);
|
||||
this.Controls.Add(this.label4);
|
||||
this.Controls.Add(this.cmbDispositivo);
|
||||
this.Controls.Add(this.btnSalvarAlgoritmo);
|
||||
this.Controls.Add(this.lblAlgoritmo);
|
||||
this.Controls.Add(this.cmbAlgoritmo);
|
||||
|
|
@ -270,5 +294,7 @@
|
|||
private System.Windows.Forms.ComboBox cmbAlgoritmo;
|
||||
private System.Windows.Forms.Label lblAlgoritmo;
|
||||
private System.Windows.Forms.Button btnSalvarAlgoritmo;
|
||||
private System.Windows.Forms.Label label4;
|
||||
private System.Windows.Forms.ComboBox cmbDispositivo;
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,9 @@ using System.Windows.Forms;
|
|||
using System.Drawing.Drawing2D;
|
||||
using System.Threading.Tasks;
|
||||
using System.Linq;
|
||||
using AgroBase.Services.Operadores;
|
||||
using System.Collections.Generic;
|
||||
using AgroBase.Models.Operadores;
|
||||
|
||||
namespace AgroBase.Forms
|
||||
{
|
||||
|
|
@ -17,6 +20,7 @@ namespace AgroBase.Forms
|
|||
double AnguloZ = 0;
|
||||
private Visualizador3DService visualizador3D;
|
||||
AsyncTaskTimerModel tmrLeitura;
|
||||
List<CameraWorkerItemModel> ListaCameras = new List<CameraWorkerItemModel>();
|
||||
//WT901C485 WT901C = Variaveis.WT901C;
|
||||
|
||||
public frmWT901C()
|
||||
|
|
@ -50,6 +54,8 @@ namespace AgroBase.Forms
|
|||
|
||||
cmbAlgoritmo.Items.Clear();
|
||||
cmbAlgoritmo.Items.AddRange(new string[] { "6 Eixos", "9 Eixos" });
|
||||
|
||||
AtualizarListaCameras();
|
||||
}
|
||||
|
||||
private void frmWT901C_FormClosing(object sender, FormClosingEventArgs e)
|
||||
|
|
@ -59,7 +65,24 @@ namespace AgroBase.Forms
|
|||
|
||||
private async Task tmrLeitura_Tick()
|
||||
{
|
||||
var Imu = Variaveis.OperacaoEmAndamento.Sensoriamento.IMU;
|
||||
if (cmbDispositivo.SelectedIndex < 0 || cmbDispositivo.SelectedIndex >= ListaCameras.Count) return;
|
||||
|
||||
var Camera = ListaCameras[cmbDispositivo.SelectedIndex];
|
||||
if (Camera.imu == null) return;
|
||||
|
||||
if (Camera.mx_id == Variaveis.OperacaoEmAndamento.DispSen?.Dados?.CameraCaminho?.Id)
|
||||
Camera.imu = Variaveis.OperacaoEmAndamento.DispSen.Dados?.CameraCaminho?.cam?.imu;
|
||||
else if (Variaveis.OperacaoEmAndamento.DispSen.Dados?.CamerasSolo?.Any(x => x?.Id == Camera.mx_id) ?? false)
|
||||
Camera.imu = Variaveis.OperacaoEmAndamento.DispSen.Dados?.CamerasSolo?.FirstOrDefault(x => x?.Id == Camera.mx_id)?.cam?.imu;
|
||||
|
||||
//OperacaoSensoriamentoLogImuModel Imu = Variaveis.OperacaoEmAndamento.Sensoriamento.IMU;
|
||||
OperacaoSensoriamentoLogImuModel Imu = new OperacaoSensoriamentoLogImuModel()
|
||||
{
|
||||
InclinacaoFrontal = Camera.imu.pitch,
|
||||
InclinacaoLateral = Camera.imu.roll,
|
||||
Rotacao = Camera.imu.yaw,
|
||||
RotacaoCorrigida = Camera.imu.yaw,
|
||||
};
|
||||
AnguloX = Imu.InclinacaoFrontal;
|
||||
AnguloY = Imu.InclinacaoLateral;
|
||||
AnguloZ = Imu.Rotacao;
|
||||
|
|
@ -68,6 +91,13 @@ namespace AgroBase.Forms
|
|||
AtualizarDadosTela();
|
||||
}
|
||||
|
||||
private void AtualizarListaCameras()
|
||||
{
|
||||
ListaCameras = CameraWorkerService.GetListaCameras();
|
||||
cmbDispositivo.Items.Clear();
|
||||
cmbDispositivo.Items.AddRange(ListaCameras.Select(x => x.modelo).ToArray());
|
||||
}
|
||||
|
||||
private void PopularDadosGrid()
|
||||
{
|
||||
gridDados.Rows.Clear();
|
||||
|
|
@ -371,6 +401,5 @@ namespace AgroBase.Forms
|
|||
{
|
||||
await WT901CService.AlterarAlgoritmo(cmbAlgoritmo.SelectedIndex == 1);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,134 +86,144 @@ namespace AgroBase.Models.Modules
|
|||
public HerbicideCounterService ContadorCarga = new HerbicideCounterService(VariaveisEquipamento.CapacidadeReservatorio, VariaveisEquipamento.DensidadeHerbicida);
|
||||
|
||||
#region VAZAO
|
||||
|
||||
private SensorModel SensorFluxoLinha => Sensores.FirstOrDefault(x => x.Componente == S_Code.sFLX && x.ID == "FLXLN");
|
||||
|
||||
public double VolumeVazaoAferido { get; set; } = 0;
|
||||
public double _FluxoMlRef { get; set; } = 600;
|
||||
public double _FluxoPulsoRef { get; set; } = 538;
|
||||
|
||||
public double VazaoMaximaSensor_LMin { get; set; } = 20.0;
|
||||
|
||||
public double VazaoFluxoMLpSInstantanea => SensorFluxoLinha?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Fluxo)?.atual?.valor ?? 0;
|
||||
|
||||
public double VazaoFluxoMLpSInstantaneaCalc
|
||||
{
|
||||
get
|
||||
{
|
||||
int pulsos = (int)(SensorFluxoLinha?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.QtdPulsos)?.atual?.valor ?? 0.0);
|
||||
int periodo = (int)(SensorFluxoLinha?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Periodo)?.atual?.valor ?? 0.0);
|
||||
if (pulsos <= 0 || periodo <= 0) return 0.0;
|
||||
|
||||
double frequencia = (double)pulsos / (double)periodo * 1000.0; // Hz
|
||||
|
||||
// Equação do fabricante: F = 8.1*q - 3 (q em L/min)
|
||||
int periodo = (int)(SensorFluxoLinha?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Periodo)?.atual?.valor ?? 0.0);
|
||||
|
||||
if (pulsos <= 0 || periodo <= 0)
|
||||
return 0.0;
|
||||
|
||||
double frequencia = (double)pulsos / periodo * 1000.0;
|
||||
|
||||
// Fabricante: F = 8.1*q - 3, q em L/min
|
||||
double q_L_min = (frequencia + 3.0) / 8.1;
|
||||
// Limites físicos do sensor (do próprio anúncio): 0.3–10 L/min
|
||||
if (q_L_min < 0) q_L_min = 0; // evita negativo perto do zero
|
||||
if (q_L_min > 10.0) q_L_min = 10.0; // opcional: clamp no máximo
|
||||
// Converte para mL/s
|
||||
double q_mL_s = q_L_min * (1000.0 / 60.0);
|
||||
return q_mL_s;
|
||||
|
||||
if (q_L_min < 0)
|
||||
q_L_min = 0;
|
||||
|
||||
if (q_L_min > VazaoMaximaSensor_LMin)
|
||||
q_L_min = VazaoMaximaSensor_LMin;
|
||||
|
||||
return q_L_min * 1000.0 / 60.0;
|
||||
}
|
||||
}
|
||||
private DateTime _ultimoRegistroVazao; // Armazena o horário da última atualização
|
||||
|
||||
public double VazaoFluxoMLpSReferencia
|
||||
{
|
||||
get
|
||||
{
|
||||
double direta = VazaoFluxoMLpSInstantanea;
|
||||
|
||||
if (direta > 0)
|
||||
return direta;
|
||||
|
||||
return VazaoFluxoMLpSInstantaneaCalc;
|
||||
}
|
||||
}
|
||||
|
||||
private DateTime _ultimoRegistroVazao = DateTime.MinValue;
|
||||
|
||||
public double VazaoMediaMLs { get; set; }
|
||||
public double VolumeVazadoML { get; set; }
|
||||
public double TempoAtuado { get; set; }
|
||||
private List<AtuadorBicoModel> bicosAtivosAnterior;
|
||||
|
||||
private List<AtuadorBicoModel> bicosAtivosAnterior = new List<AtuadorBicoModel>();
|
||||
|
||||
public void AtualizaTempoAtuadoGeral()
|
||||
{
|
||||
DateTime agora = DateTime.Now;
|
||||
|
||||
// Quem está ativo AGORA
|
||||
var bicosAtivos = BicosPulverizadores.Where(x => x.Inicializado && x._EstadoLeitura == Estado.Ligado).ToList();
|
||||
var bicosAtivos = BicosPulverizadores.Where(x => x.Inicializado && x.ComandoAtuar).ToList();
|
||||
|
||||
bool algumBicoAtivo = bicosAtivos.Count > 0;
|
||||
|
||||
bool algumBicoAtivoAnterior = bicosAtivosAnterior?.Any() ?? false;
|
||||
|
||||
// Início de uma "sessão" (transição OFF -> ON)
|
||||
if (algumBicoAtivo && !algumBicoAtivoAnterior)
|
||||
{
|
||||
_ultimoRegistroVazao = agora; // inicia integração a partir daqui
|
||||
_ultimoRegistroVazao = agora;
|
||||
|
||||
// (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 && algumBicoAtivoAnterior)
|
||||
{
|
||||
AtualizaVazaoEVolume(bicosAtivosAnterior, agora);
|
||||
|
||||
_ultimoRegistroVazao = DateTime.MinValue;
|
||||
VazaoMediaMLs = TempoAtuado > 0 ? (VolumeVazadoML / TempoAtuado) : 0;
|
||||
|
||||
// zera instantânea quando não tem bico ativo
|
||||
foreach (var b in BicosPulverizadores)
|
||||
b.VazaoInstantaneaMLs = 0;
|
||||
}
|
||||
|
||||
// Integra vazão/volume enquanto tiver bico ativo
|
||||
AtualizaVazaoEVolume(bicosAtivos, agora);
|
||||
if (algumBicoAtivo)
|
||||
AtualizaVazaoEVolume(bicosAtivos, agora);
|
||||
|
||||
VazaoMediaMLs = TempoAtuado > 0 ? VolumeVazadoML / TempoAtuado : 0;
|
||||
|
||||
// Atualiza indicadores
|
||||
AtualizaPercentualErvas();
|
||||
|
||||
bicosAtivosAnterior = new List<AtuadorBicoModel>(bicosAtivos);
|
||||
}
|
||||
|
||||
private void AtualizaVazaoEVolume(List<AtuadorBicoModel> bicosAtivos, DateTime agora)
|
||||
{
|
||||
// Só integra se houver bicos ativos
|
||||
if (bicosAtivos == null || bicosAtivos.Count == 0)
|
||||
return;
|
||||
|
||||
// Captura vazão total instantânea (ml/s)
|
||||
double vazaoTotalInst = VazaoFluxoMLpSInstantanea;
|
||||
|
||||
if (_ultimoRegistroVazao == default || _ultimoRegistroVazao == DateTime.MinValue)
|
||||
if (_ultimoRegistroVazao == DateTime.MinValue)
|
||||
{
|
||||
_ultimoRegistroVazao = agora;
|
||||
return;
|
||||
}
|
||||
|
||||
// dt em segundos
|
||||
double dt = (agora - _ultimoRegistroVazao).TotalSeconds;
|
||||
_ultimoRegistroVazao = agora;
|
||||
|
||||
if (dt <= 0) return;
|
||||
if (dt <= 0 || dt > 2.0)
|
||||
return;
|
||||
|
||||
double vazaoTotalInst = VazaoFluxoMLpSReferencia;
|
||||
|
||||
if (vazaoTotalInst <= 0)
|
||||
{
|
||||
foreach (var bico in bicosAtivos)
|
||||
bico.VazaoInstantaneaMLs = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// ======== GERAL ========
|
||||
VolumeVazadoML += vazaoTotalInst * dt;
|
||||
TempoAtuado += dt;
|
||||
VazaoMediaMLs = TempoAtuado > 0 ? (VolumeVazadoML / TempoAtuado) : 0;
|
||||
|
||||
// ======== POR BICO (divide por ativos) ========
|
||||
double vazaoPorBicoInst = vazaoTotalInst / bicosAtivos.Count;
|
||||
|
||||
foreach (var bico in bicosAtivos)
|
||||
{
|
||||
// Instantânea por bico
|
||||
bico.VazaoInstantaneaMLs = vazaoPorBicoInst;
|
||||
|
||||
// Volume por bico (ml) = (ml/s) * s
|
||||
bico.VolumeVazadoML += vazaoPorBicoInst * dt;
|
||||
|
||||
bico.TempoAtuado += dt;
|
||||
|
||||
bico.VazaoMediaMLs = bico.TempoAtuado > 0 ? (bico.VolumeVazadoML / bico.TempoAtuado) : 0;
|
||||
bico.VazaoMediaMLs = bico.TempoAtuado > 0
|
||||
? bico.VolumeVazadoML / bico.TempoAtuado
|
||||
: 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void AtualizaPercentualErvas()
|
||||
{
|
||||
//double tempoTotalOperacao = Variaveis.OperacaoEmAndamento.Sensoriamento.TempoDecorridoSeg * 1000.0;
|
||||
double tempoTotalOperacao = (Variaveis.OperacaoEmAndamento.Sensoriamento?.Movimentacao?.TempoMovimentoSegs ?? 0) * 1000.0;
|
||||
|
||||
if (tempoTotalOperacao > 0)
|
||||
{
|
||||
var percentual = Math.Round((TempoAtuado / tempoTotalOperacao) * 100.0, 2);
|
||||
PercentualErvasTerreno = percentual;
|
||||
}
|
||||
else
|
||||
{
|
||||
PercentualErvasTerreno = 0;
|
||||
}
|
||||
double tempoTotalOperacao = Variaveis.OperacaoEmAndamento.Sensoriamento?.Movimentacao?.TempoMovimentoSegs ?? 0;
|
||||
PercentualErvasTerreno = tempoTotalOperacao > 0 ? Math.Round((TempoAtuado / tempoTotalOperacao) * 100.0, 2) : 0;
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region PRESSAO
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ using System.Data;
|
|||
using static AgroBase.Services.LoRaEspService;
|
||||
using AgroBase.Services.Operadores;
|
||||
using System.Diagnostics;
|
||||
using AgroBase.Models.Operadores;
|
||||
|
||||
namespace AgroBase.Models.Modules
|
||||
{
|
||||
|
|
@ -86,7 +87,7 @@ namespace AgroBase.Models.Modules
|
|||
_TaxaAmostragem = 1000,
|
||||
RequisitarDados = true,
|
||||
CameraCaminho = new OAKCameraModel(),
|
||||
CamerasSolo = new List<OAKCameraModel>(),
|
||||
CamerasSolo = new List<OAKCameraModel>(Variaveis.OperacaoEmAndamento.Parametros.QtdCamerasSolo ?? VariaveisEquipamento.QuantidadeCamerasSolo),
|
||||
// 21 ~ 23
|
||||
Sinaleiros = new List<SensorSinaleiroModel>()
|
||||
{
|
||||
|
|
@ -2034,11 +2035,6 @@ namespace AgroBase.Models.Modules
|
|||
},
|
||||
};
|
||||
|
||||
for (int i = 0; i < Variaveis.OperacaoEmAndamento.Parametros.QtdCamerasSolo; i++)
|
||||
{
|
||||
obj.CamerasSolo.Add(new OAKCameraModel());
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
|
@ -2408,6 +2404,24 @@ namespace AgroBase.Models.Modules
|
|||
Sinaleiros.First(x => x.ID == "LEDOP").Comportamento = VariaveisEquipamento.ComportamentoLedPorStatus(StatusLED.Piscando, status_operacao: _statusOperacao);
|
||||
}
|
||||
|
||||
public void AtualizarDadosCameras()
|
||||
{
|
||||
if (CameraCaminho?.Id != null)
|
||||
{
|
||||
var att = CameraWorkerService.AtualizarDadosCamera(CameraCaminho.Id);
|
||||
if (att != null) CameraCaminho = att;
|
||||
}
|
||||
for (int i = 0; i < CamerasSolo?.Count; i++)
|
||||
{
|
||||
if (CamerasSolo[i]?.Id != null)
|
||||
{
|
||||
var att = CameraWorkerService.AtualizarDadosCamera(CamerasSolo[i].Id);
|
||||
if (att != null) CamerasSolo[i] = att;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class SensorModel
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ namespace AgroBase.Models
|
|||
public double fx { get; set; }
|
||||
public double baseline { get; set; }
|
||||
|
||||
public CameraWorkerItemModel cam { get; set; }
|
||||
|
||||
public double DistanciaMaximaVisao { get; set; } = 5000;
|
||||
public double DistanciaMinimaVisao { get; set; } = 500;
|
||||
public double PercentualAlturaSolo { get; set; } = 30;
|
||||
|
|
@ -100,6 +102,7 @@ namespace AgroBase.Models
|
|||
Version = Version,
|
||||
fx = fx,
|
||||
baseline = baseline,
|
||||
cam = cam,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -167,6 +170,12 @@ namespace AgroBase.Models
|
|||
}
|
||||
|
||||
public class OAKImuModel
|
||||
{
|
||||
public OAKImuDataModel dados { get; set; }
|
||||
public ManagerWorkerMessageResponseModulosPendentesModel saude { get; set; }
|
||||
}
|
||||
|
||||
public class OAKImuDataModel
|
||||
{
|
||||
public double timestamp { get; set; }
|
||||
public double roll { get; set; }
|
||||
|
|
|
|||
|
|
@ -1197,7 +1197,12 @@ namespace AgroBase.Models
|
|||
|
||||
Controle.Reiniciar();
|
||||
ControleAnterior.Reiniciar();
|
||||
DispSen?.Dados?.ContadorCarga?.IniciarOperacao();
|
||||
|
||||
double distanciaPercorrida = DispMvd?.Dados?.DistanciaPercorridaTotal ?? 0;
|
||||
double tempoAtuado = DispAtu?.Dados?.TempoAtuado ?? 0;
|
||||
DispSen?.Dados?.ContadorCarga?.AtualizarConsumo(distanciaPercorrida);
|
||||
DispSen?.Dados?.ContadorCarga?.IniciarOperacao(distanciaPercorrida);
|
||||
DispAtu?.Dados?.ContadorCarga?.IniciarOperacao(distanciaPercorrida, tempoAtuado);
|
||||
|
||||
GPSTrajetoria = new List<GPSModel>();
|
||||
|
||||
|
|
@ -1234,6 +1239,7 @@ namespace AgroBase.Models
|
|||
Variaveis.OperacaoEmAndamento.Finalizando = false;
|
||||
Variaveis.OperacaoEmAndamento.Trajetoria?.AutonomiaCorredor?.Parar();
|
||||
Variaveis.OperacaoEmAndamento.DispSen?.Dados?.ContadorCarga?.FinalizarOperacao();
|
||||
Variaveis.OperacaoEmAndamento.DispAtu?.Dados?.ContadorCarga?.FinalizarOperacao();
|
||||
|
||||
if (Variaveis.OperacaoEmAndamento.Parametros.Modo == ModoOperacao.RetornoBase)
|
||||
{
|
||||
|
|
@ -2026,6 +2032,9 @@ namespace AgroBase.Models
|
|||
MassaReservatorio = Variaveis.OperacaoEmAndamento.DispAtu.Dados.ContadorCarga.MassaAtual_Kg,
|
||||
PercentualReservatorio = Variaveis.OperacaoEmAndamento.DispAtu.Dados.ContadorCarga.PercentualAtual,
|
||||
VolumeReservatorio = Variaveis.OperacaoEmAndamento.DispAtu.Dados.ContadorCarga.VolumeAtual_L,
|
||||
PercentualHerbicidaConsumido = Variaveis.OperacaoEmAndamento.DispAtu.Dados.ContadorCarga.PercentualConsumidoTotal,
|
||||
PercentualHerbicidaConsumidoOperacao = Variaveis.OperacaoEmAndamento.DispAtu.Dados.ContadorCarga.PercentualConsumidoOperacao,
|
||||
HerbicidaPorAtuacao = Variaveis.OperacaoEmAndamento.DispAtu.Dados.ContadorCarga.HerbicidaPorAtuacao_L,
|
||||
PressaoLinha_SP = Variaveis.OperacaoEmAndamento.Parametros.Controle.AtuPressaoLinha,
|
||||
PressaoLinha = Variaveis.OperacaoEmAndamento.DispAtu.Dados.PressaoLinha,
|
||||
PotenciaBomba = Variaveis.OperacaoEmAndamento.DispAtu.Dados.BombasPressurizadoras.FirstOrDefault()?._Potencia ?? 0,
|
||||
|
|
@ -2689,16 +2698,17 @@ 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.Parametros?.Modo ?? ModoOperacao.NaoDefinido, Variaveis.OperacaoEmAndamento.StatusAtual);
|
||||
_DispSen?.Dados?.AtualizarDadosCameras();
|
||||
_DispAtu?.Dados?.AtualizaTempoAtuadoGeral();
|
||||
_Cooler?.Atualizar(tmp_max, DateTime.Now);
|
||||
_Bateria?.AtualizarConsumo(_DispMvd?.Dados?.DistanciaPercorridaTotal ?? 0);
|
||||
_Reservatorio?.AtualizarConsumo(_DispMvd?.Dados?.DistanciaPercorridaTotal ?? 0, Variaveis.OperacaoEmAndamento.TempoDecorridoSegs);
|
||||
_Reservatorio?.AtualizarConsumo(_DispMvd?.Dados?.DistanciaPercorridaTotal ?? 0, Variaveis.OperacaoEmAndamento.TempoDecorridoSegs, _DispMvd?.Dados?.VelocidadeMedia ?? 0);
|
||||
_Reservatorio?.AtualizarAgitadorCalda(pControle?.AtuAgitadorModo ?? ModoAgitadorCalda.SemAgitacao);
|
||||
_Trajetoria?.AtualizarDadosAutonomiaCorredor();
|
||||
|
||||
//var sIMU = LivoxManagerProcess.DadosLeitura.imu;
|
||||
string imu = RedisService.Get(RedisService.ModKey(T_Code.Imu)) ?? "";
|
||||
var sIMU = JsonConvert.DeserializeObject<OAKImuModel>(imu);
|
||||
var sIMU = JsonConvert.DeserializeObject<OAKImuDataModel>(imu);
|
||||
bool imu_iniciado = sIMU?.timestamp > 0 && HealthWorkerService.ModulosSaude.FirstOrDefault(x => x.modulo == T_Code.Imu)?.status != StatusModulo.Desconectado;
|
||||
var dadosIMU = sIMU != null ? new OperacaoSensoriamentoLogImuModel()
|
||||
{
|
||||
|
|
@ -2719,9 +2729,12 @@ namespace AgroBase.Models
|
|||
{
|
||||
QtdCamerasSolo = _DispSen.Dados.CamerasSolo.Count,
|
||||
CapacidadeReservatorio = VariaveisEquipamento.CapacidadeReservatorio,
|
||||
HerbicidaConsumido = _DispAtu.Dados.VolumeVazadoML,
|
||||
HerbicidaConsumido = _Reservatorio.VolumeConsumidoTotal_L,
|
||||
HerbicidaConsumidoOperacao = _Reservatorio.VolumeConsumidoOperacao_L,
|
||||
PercentualHerbicidaConsumido = _Reservatorio.PercentualConsumidoTotal,
|
||||
PercentualHerbicidaConsumidoOperacao = _Reservatorio.PercentualConsumidoOperacao,
|
||||
PercentualErvasTerreno = _DispAtu.Dados.PercentualErvasTerreno,
|
||||
HerbicidaPorErva = _Reservatorio.HerbicidaPorAtuacao,
|
||||
HerbicidaPorErva = _Reservatorio.HerbicidaPorAtuacao_L,
|
||||
ErvasNoRadar = WeedWorkerService.DadosLeitura?.Analise?.ervas_no_radar ?? false,
|
||||
PercentualErvasNoRadar = WeedWorkerService.DadosLeitura?.Analise?.estatisticas?.erva?.ema_global ?? 0,
|
||||
PercentualReservatorio = _Reservatorio.PercentualAtual,
|
||||
|
|
@ -3029,6 +3042,9 @@ namespace AgroBase.Models
|
|||
public int QtdCamerasSolo { get; set; }
|
||||
public double CapacidadeReservatorio { get; set; }
|
||||
public double HerbicidaConsumido { get; set; }
|
||||
public double HerbicidaConsumidoOperacao { get; set; }
|
||||
public double PercentualHerbicidaConsumido { get; set; }
|
||||
public double PercentualHerbicidaConsumidoOperacao { get; set; }
|
||||
public double PercentualErvasTerreno { get; set; }
|
||||
public double HerbicidaPorErva { get; set; }
|
||||
public bool ErvasNoRadar { get; set; }
|
||||
|
|
@ -3066,6 +3082,9 @@ namespace AgroBase.Models
|
|||
ErvasNoRadar = ErvasNoRadar,
|
||||
PercentualErvasNoRadar = PercentualErvasNoRadar,
|
||||
HerbicidaConsumido = HerbicidaConsumido,
|
||||
HerbicidaConsumidoOperacao = HerbicidaConsumidoOperacao,
|
||||
PercentualHerbicidaConsumido = PercentualHerbicidaConsumido,
|
||||
PercentualHerbicidaConsumidoOperacao = PercentualHerbicidaConsumidoOperacao,
|
||||
HerbicidaPorErva = HerbicidaPorErva,
|
||||
PercentualErvasTerreno = PercentualErvasTerreno,
|
||||
PercentualReservatorio = PercentualReservatorio,
|
||||
|
|
@ -3352,6 +3371,9 @@ namespace AgroBase.Models
|
|||
public double PressaoLinha { get; set; }
|
||||
public double VolumeReservatorio { get; set; }
|
||||
public double PercentualReservatorio { get; set; }
|
||||
public double PercentualHerbicidaConsumido { get; set; }
|
||||
public double PercentualHerbicidaConsumidoOperacao { get; set; }
|
||||
public double HerbicidaPorAtuacao { get; set; }
|
||||
public double PotenciaBomba { get; set; }
|
||||
public bool BombaLigada { get; set; }
|
||||
public double VazaoFluxoMLpSInstantanea { get; set; }
|
||||
|
|
|
|||
|
|
@ -52,6 +52,19 @@ namespace AgroBase.Models.Operadores
|
|||
|
||||
public SaudeWorkerModel saude { get; set; }
|
||||
public CameraWorkerItemPerformanceModel performance { get; set; }
|
||||
public OAKImuDataModel imu { get; set; }
|
||||
|
||||
public OAKCameraModel ToOAK()
|
||||
{
|
||||
return new OAKCameraModel()
|
||||
{
|
||||
Id = mx_id,
|
||||
Dispositivo = dispositivo,
|
||||
Version = versao,
|
||||
Name = modelo,
|
||||
cam = this
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class CameraWorkerItemPerformanceModel
|
||||
|
|
|
|||
|
|
@ -592,10 +592,15 @@ namespace AgroBase.Models.Operadores
|
|||
|
||||
public class VisualWorkerMessageSegmentacaoSemanticaDebugCorredorModel
|
||||
{
|
||||
public double nav_global { get; set; }
|
||||
public double nav_near { get; set; }
|
||||
public double nav_mid { get; set; }
|
||||
public double nav_far { get; set; }
|
||||
public string origem_status { get; set; }
|
||||
public StatusCarroMapa status_modelo { get; set; }
|
||||
public string status_modelo_nome { get; set; }
|
||||
public string status_modelo_label_name { get; set; }
|
||||
public double status_modelo_conf { get; set; }
|
||||
public dynamic status_modelo_probs { get; set; }
|
||||
public StatusCarroMapa status_heuristico { get; set; }
|
||||
public string status_heuristico_nome { get; set; }
|
||||
public dynamic heuristica_debug { get; set; }
|
||||
}
|
||||
|
||||
public class VisualWorkerMessageMatrizConfiancaModel
|
||||
|
|
|
|||
|
|
@ -1,176 +1,778 @@
|
|||
using OpenHardwareMonitor.Hardware;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace AgroBase.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Snapshot rico de performance do PC.
|
||||
///
|
||||
/// Objetivo:
|
||||
/// - telemetria em tempo real;
|
||||
/// - replay de operação;
|
||||
/// - diagnóstico do health_worker;
|
||||
/// - correlação com performance dos workers Python.
|
||||
///
|
||||
/// Observação:
|
||||
/// - Disk_used_space_percent representa espaço usado, não atividade do disco.
|
||||
/// - GPU_load_percent é um agregado dos principais sensores de load disponíveis.
|
||||
/// </summary>
|
||||
public class PerformanceModel
|
||||
{
|
||||
private static readonly object ComputerLock = new object();
|
||||
private static Computer computer;
|
||||
|
||||
private DateTime _ultimaLeituraPerformance = DateTime.MinValue;
|
||||
|
||||
public PerformanceModel()
|
||||
{
|
||||
if (computer == null)
|
||||
InicializarComputer();
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Identificação / tempo
|
||||
// ============================================================
|
||||
|
||||
public DateTime Timestamp { get; set; } = DateTime.Now;
|
||||
public long TimestampUnixMs { get; set; }
|
||||
|
||||
// ============================================================
|
||||
// CPU
|
||||
// ============================================================
|
||||
|
||||
public float? CPU_load_percent { get; set; }
|
||||
public float? CPU_temp_package_c { get; set; }
|
||||
public float? CPU_power_package_w { get; set; }
|
||||
public float? CPU_power_cores_w { get; set; }
|
||||
public float? CPU_power_graphics_w { get; set; }
|
||||
public float? CPU_power_dram_w { get; set; }
|
||||
|
||||
public float? CPU_clock_avg_mhz { get; set; }
|
||||
public float? CPU_clock_max_mhz { get; set; }
|
||||
public float? CPU_bus_speed_mhz { get; set; }
|
||||
|
||||
// Compatibilidade conceitual, se você quiser usar nomes antigos depois.
|
||||
public float? CPU_load => CPU_load_percent;
|
||||
public float? CPU_temp => CPU_temp_package_c;
|
||||
|
||||
// ============================================================
|
||||
// RAM
|
||||
// ============================================================
|
||||
|
||||
public float? RAM_usage_percent { get; set; }
|
||||
public float? RAM_used_gb { get; set; }
|
||||
public float? RAM_available_gb { get; set; }
|
||||
public float? RAM_total_gb
|
||||
{
|
||||
get
|
||||
{
|
||||
if (RAM_used_gb.HasValue && RAM_available_gb.HasValue)
|
||||
return RAM_used_gb.Value + RAM_available_gb.Value;
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Compatibilidade conceitual
|
||||
public float? RAM_usage => RAM_usage_percent;
|
||||
|
||||
// ============================================================
|
||||
// GPU geral
|
||||
// ============================================================
|
||||
|
||||
/// <summary>
|
||||
/// Agregado dos sensores de carga da GPU.
|
||||
/// Calculado como o máximo entre core, frame buffer, memory,
|
||||
/// video engine e bus interface.
|
||||
/// </summary>
|
||||
public float? GPU_load_percent { get; set; }
|
||||
|
||||
public float? GPU_core_load_percent { get; set; }
|
||||
public float? GPU_frame_buffer_load_percent { get; set; }
|
||||
public float? GPU_memory_load_percent { get; set; }
|
||||
public float? GPU_video_engine_load_percent { get; set; }
|
||||
public float? GPU_bus_interface_load_percent { get; set; }
|
||||
|
||||
public float? GPU_temp_core_c { get; set; }
|
||||
|
||||
public float? GPU_power_w { get; set; }
|
||||
|
||||
public float? GPU_core_clock_mhz { get; set; }
|
||||
public float? GPU_memory_clock_mhz { get; set; }
|
||||
public float? GPU_shader_clock_mhz { get; set; }
|
||||
|
||||
public float? GPU_fan_percent { get; set; }
|
||||
public float? GPU_fan_rpm { get; set; }
|
||||
|
||||
public float? GPU_pcie_rx { get; set; }
|
||||
public float? GPU_pcie_tx { get; set; }
|
||||
|
||||
// Compatibilidade conceitual
|
||||
public float? GPU_load => GPU_load_percent;
|
||||
public float? GPU_temp => GPU_temp_core_c;
|
||||
|
||||
// ============================================================
|
||||
// GPU memória / VRAM
|
||||
// ============================================================
|
||||
|
||||
public float? GPU_vram_total_mb { get; set; }
|
||||
public float? GPU_vram_used_mb { get; set; }
|
||||
public float? GPU_vram_free_mb { get; set; }
|
||||
|
||||
public float? GPU_vram_used_percent
|
||||
{
|
||||
get
|
||||
{
|
||||
if (GPU_vram_total_mb.HasValue &&
|
||||
GPU_vram_total_mb.Value > 0 &&
|
||||
GPU_vram_used_mb.HasValue)
|
||||
{
|
||||
return 100.0f * GPU_vram_used_mb.Value / GPU_vram_total_mb.Value;
|
||||
}
|
||||
|
||||
return GPU_memory_load_percent;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Disco
|
||||
// ============================================================
|
||||
|
||||
/// <summary>
|
||||
/// Espaço usado no disco.
|
||||
/// Isso NÃO é atividade do disco.
|
||||
/// </summary>
|
||||
public float? Disk_used_space_percent { get; set; }
|
||||
|
||||
// Nome antigo, mas agora intencionalmente apontando para espaço usado.
|
||||
public float? HDD_load => Disk_used_space_percent;
|
||||
|
||||
// ============================================================
|
||||
// Processo atual
|
||||
// ============================================================
|
||||
|
||||
public int Process_thread_count { get; set; }
|
||||
public long Process_working_set_mb { get; set; }
|
||||
public long Process_private_memory_mb { get; set; }
|
||||
public long Process_virtual_memory_mb { get; set; }
|
||||
public double Process_cpu_time_total_s { get; set; }
|
||||
|
||||
// ============================================================
|
||||
// ThreadPool
|
||||
// ============================================================
|
||||
|
||||
public int ThreadPool_available_worker_threads { get; set; }
|
||||
public int ThreadPool_available_completion_port_threads { get; set; }
|
||||
|
||||
public int ThreadPool_max_worker_threads { get; set; }
|
||||
public int ThreadPool_max_completion_port_threads { get; set; }
|
||||
|
||||
public int ThreadPool_used_worker_threads
|
||||
{
|
||||
get
|
||||
{
|
||||
return Math.Max(0, ThreadPool_max_worker_threads - ThreadPool_available_worker_threads);
|
||||
}
|
||||
}
|
||||
|
||||
public int ThreadPool_used_completion_port_threads
|
||||
{
|
||||
get
|
||||
{
|
||||
return Math.Max(0, ThreadPool_max_completion_port_threads - ThreadPool_available_completion_port_threads);
|
||||
}
|
||||
}
|
||||
|
||||
public float ThreadPool_used_worker_percent
|
||||
{
|
||||
get
|
||||
{
|
||||
if (ThreadPool_max_worker_threads <= 0)
|
||||
return 0;
|
||||
|
||||
return 100.0f * ThreadPool_used_worker_threads / ThreadPool_max_worker_threads;
|
||||
}
|
||||
}
|
||||
|
||||
public float ThreadPool_used_completion_port_percent
|
||||
{
|
||||
get
|
||||
{
|
||||
if (ThreadPool_max_completion_port_threads <= 0)
|
||||
return 0;
|
||||
|
||||
return 100.0f * ThreadPool_used_completion_port_threads / ThreadPool_max_completion_port_threads;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ============================================================
|
||||
// String resumida para debug rápido
|
||||
// ============================================================
|
||||
|
||||
public string PerformanceStr
|
||||
{
|
||||
get
|
||||
{
|
||||
return
|
||||
$"CPU={Fmt(CPU_load_percent)}% " +
|
||||
$"CPU_T={Fmt(CPU_temp_package_c)}C " +
|
||||
$"RAM={Fmt(RAM_usage_percent)}% " +
|
||||
$"GPU={Fmt(GPU_load_percent)}% " +
|
||||
$"GPU_Core={Fmt(GPU_core_load_percent)}% " +
|
||||
$"GPU_Mem={Fmt(GPU_memory_load_percent)}% " +
|
||||
$"VRAM={Fmt(GPU_vram_used_mb)}/{Fmt(GPU_vram_total_mb)}MB " +
|
||||
$"GPU_T={Fmt(GPU_temp_core_c)}C " +
|
||||
$"GPU_P={Fmt(GPU_power_w)}W";
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Inicialização
|
||||
// ============================================================
|
||||
|
||||
private static void InicializarComputer()
|
||||
{
|
||||
if (computer != null)
|
||||
return;
|
||||
|
||||
lock (ComputerLock)
|
||||
{
|
||||
if (computer != null)
|
||||
return;
|
||||
|
||||
computer = new Computer()
|
||||
{
|
||||
CPUEnabled = true,
|
||||
GPUEnabled = true,
|
||||
RAMEnabled = true,
|
||||
HDDEnabled = true,
|
||||
MainboardEnabled = false,
|
||||
FanControllerEnabled = false,
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
computer.Open();
|
||||
}
|
||||
catch (ArgumentOutOfRangeException ex)
|
||||
{
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch
|
||||
{
|
||||
computer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float? CPU_load { get; set; }
|
||||
public float? GPU_load { get; set; }
|
||||
public float? HDD_load { get; set; }
|
||||
public float? RAM_usage { get; set; }
|
||||
public float? CPU_temp { get; set; }
|
||||
public float? GPU_temp { get; set; }
|
||||
public int ActiveThreads { get; set; }
|
||||
public int WorkerThreads { get; set; }
|
||||
public int CompletionPortThreads { get; set; }
|
||||
public int MaxWorkerThreads { get; set; }
|
||||
public int MaxCompletionPortThreads { get; set; }
|
||||
public string PerformanceStr
|
||||
{
|
||||
get
|
||||
{
|
||||
return FuncoesGlobais.MontarStringPerformance(
|
||||
GPU_load,
|
||||
CPU_load,
|
||||
RAM_usage,
|
||||
GPU_temp,
|
||||
CPU_temp,
|
||||
HDD_load
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
DateTime UltimaLeituraPerformance = DateTime.Now;
|
||||
// ============================================================
|
||||
// Atualização principal
|
||||
// ============================================================
|
||||
|
||||
public void AtualizarDadosPerformance()
|
||||
{
|
||||
AtualizarDadosPerformance(TimeSpan.FromSeconds(1));
|
||||
}
|
||||
|
||||
public void AtualizarDadosPerformance(TimeSpan intervaloMinimo)
|
||||
{
|
||||
if (DateTime.Now < _ultimaLeituraPerformance.Add(intervaloMinimo))
|
||||
return;
|
||||
|
||||
_ultimaLeituraPerformance = DateTime.Now;
|
||||
Timestamp = DateTime.Now;
|
||||
TimestampUnixMs = DateTimeOffset.Now.ToUnixTimeMilliseconds();
|
||||
|
||||
if (computer == null || computer.Hardware == null)
|
||||
{
|
||||
return;
|
||||
InicializarComputer();
|
||||
if (computer == null || computer.Hardware == null)
|
||||
return;
|
||||
}
|
||||
|
||||
if (DateTime.Now > UltimaLeituraPerformance.AddSeconds(1))
|
||||
// Variáveis locais, para só atualizar propriedades no final.
|
||||
float? cpuLoad = null;
|
||||
float? cpuTempPackage = null;
|
||||
float? cpuPowerPackage = null;
|
||||
float? cpuPowerCores = null;
|
||||
float? cpuPowerGraphics = null;
|
||||
float? cpuPowerDram = null;
|
||||
float? cpuClockAvg = null;
|
||||
float? cpuClockMax = null;
|
||||
float? cpuBusSpeed = null;
|
||||
|
||||
float? ramUsage = null;
|
||||
float? ramUsedGb = null;
|
||||
float? ramAvailableGb = null;
|
||||
|
||||
float? gpuCoreLoad = null;
|
||||
float? gpuFrameBufferLoad = null;
|
||||
float? gpuMemoryLoad = null;
|
||||
float? gpuVideoEngineLoad = null;
|
||||
float? gpuBusInterfaceLoad = null;
|
||||
|
||||
float? gpuTempCore = null;
|
||||
float? gpuPower = null;
|
||||
|
||||
float? gpuCoreClock = null;
|
||||
float? gpuMemoryClock = null;
|
||||
float? gpuShaderClock = null;
|
||||
|
||||
float? gpuFanPercent = null;
|
||||
float? gpuFanRpm = null;
|
||||
|
||||
float? gpuVramTotalMb = null;
|
||||
float? gpuVramUsedMb = null;
|
||||
float? gpuVramFreeMb = null;
|
||||
|
||||
float? gpuPcieRx = null;
|
||||
float? gpuPcieTx = null;
|
||||
|
||||
float? diskUsedSpace = null;
|
||||
|
||||
try
|
||||
{
|
||||
UltimaLeituraPerformance = DateTime.Now;
|
||||
|
||||
float? cpuLoad = null;
|
||||
float? gpuLoad = null;
|
||||
float? hddLoad = null;
|
||||
float? ramUsage = null;
|
||||
float? cpuTemp = null;
|
||||
float? gpuTemp = null;
|
||||
|
||||
foreach (var hardwareItem in computer.Hardware)
|
||||
lock (ComputerLock)
|
||||
{
|
||||
hardwareItem.Update();
|
||||
|
||||
if (hardwareItem.HardwareType == HardwareType.CPU)
|
||||
foreach (var hardwareItem in computer.Hardware)
|
||||
{
|
||||
foreach (var sensor in hardwareItem.Sensors)
|
||||
{
|
||||
if (sensor.SensorType == SensorType.Load && sensor.Name == "CPU Total")
|
||||
{
|
||||
cpuLoad = sensor.Value;
|
||||
}
|
||||
if (sensor.SensorType == SensorType.Temperature && sensor.Name == "CPU Package")
|
||||
{
|
||||
cpuTemp = sensor.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
hardwareItem.Update();
|
||||
|
||||
if (hardwareItem.HardwareType == HardwareType.GpuNvidia || hardwareItem.HardwareType == HardwareType.GpuAti)
|
||||
{
|
||||
foreach (var sensor in hardwareItem.Sensors)
|
||||
switch (hardwareItem.HardwareType)
|
||||
{
|
||||
if (sensor.SensorType == SensorType.Load && sensor.Name == "GPU Core")
|
||||
{
|
||||
gpuLoad = sensor.Value;
|
||||
}
|
||||
if (sensor.SensorType == SensorType.Temperature && sensor.Name == "GPU Core")
|
||||
{
|
||||
gpuTemp = sensor.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
case HardwareType.CPU:
|
||||
LerCpu(hardwareItem,
|
||||
ref cpuLoad,
|
||||
ref cpuTempPackage,
|
||||
ref cpuPowerPackage,
|
||||
ref cpuPowerCores,
|
||||
ref cpuPowerGraphics,
|
||||
ref cpuPowerDram,
|
||||
ref cpuClockAvg,
|
||||
ref cpuClockMax,
|
||||
ref cpuBusSpeed);
|
||||
break;
|
||||
|
||||
if (hardwareItem.HardwareType == HardwareType.RAM)
|
||||
{
|
||||
foreach (var sensor in hardwareItem.Sensors)
|
||||
{
|
||||
if (sensor.SensorType == SensorType.Load && sensor.Name == "Memory")
|
||||
{
|
||||
ramUsage = sensor.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
case HardwareType.RAM:
|
||||
LerRam(hardwareItem,
|
||||
ref ramUsage,
|
||||
ref ramUsedGb,
|
||||
ref ramAvailableGb);
|
||||
break;
|
||||
|
||||
if (hardwareItem.HardwareType == HardwareType.HDD)
|
||||
{
|
||||
foreach (var sensor in hardwareItem.Sensors)
|
||||
{
|
||||
if (sensor.SensorType == SensorType.Load && sensor.Name == "Used Space")
|
||||
{
|
||||
hddLoad = sensor.Value;
|
||||
}
|
||||
case HardwareType.GpuNvidia:
|
||||
case HardwareType.GpuAti:
|
||||
LerGpu(hardwareItem,
|
||||
ref gpuCoreLoad,
|
||||
ref gpuFrameBufferLoad,
|
||||
ref gpuMemoryLoad,
|
||||
ref gpuVideoEngineLoad,
|
||||
ref gpuBusInterfaceLoad,
|
||||
ref gpuTempCore,
|
||||
ref gpuPower,
|
||||
ref gpuCoreClock,
|
||||
ref gpuMemoryClock,
|
||||
ref gpuShaderClock,
|
||||
ref gpuFanPercent,
|
||||
ref gpuFanRpm,
|
||||
ref gpuVramTotalMb,
|
||||
ref gpuVramUsedMb,
|
||||
ref gpuVramFreeMb,
|
||||
ref gpuPcieRx,
|
||||
ref gpuPcieTx);
|
||||
break;
|
||||
|
||||
case HardwareType.HDD:
|
||||
LerDisco(hardwareItem, ref diskUsedSpace);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int activeThreads = Process.GetCurrentProcess().Threads.Count;
|
||||
ThreadPool.GetAvailableThreads(out int workerThreads, out int completionPortThreads);
|
||||
ThreadPool.GetMaxThreads(out int maxWorkerThreads, out int maxCompletionPortThreads);
|
||||
CPU_load_percent = cpuLoad;
|
||||
CPU_temp_package_c = cpuTempPackage;
|
||||
CPU_power_package_w = cpuPowerPackage;
|
||||
CPU_power_cores_w = cpuPowerCores;
|
||||
CPU_power_graphics_w = cpuPowerGraphics;
|
||||
CPU_power_dram_w = cpuPowerDram;
|
||||
CPU_clock_avg_mhz = cpuClockAvg;
|
||||
CPU_clock_max_mhz = cpuClockMax;
|
||||
CPU_bus_speed_mhz = cpuBusSpeed;
|
||||
|
||||
CPU_load = cpuLoad;
|
||||
GPU_load = gpuLoad;
|
||||
HDD_load = hddLoad;
|
||||
RAM_usage = ramUsage;
|
||||
CPU_temp = cpuTemp;
|
||||
GPU_temp = gpuTemp;
|
||||
ActiveThreads = activeThreads;
|
||||
WorkerThreads = workerThreads;
|
||||
MaxWorkerThreads = maxWorkerThreads;
|
||||
CompletionPortThreads = completionPortThreads;
|
||||
MaxCompletionPortThreads = maxCompletionPortThreads;
|
||||
RAM_usage_percent = ramUsage;
|
||||
RAM_used_gb = ramUsedGb;
|
||||
RAM_available_gb = ramAvailableGb;
|
||||
|
||||
GPU_core_load_percent = gpuCoreLoad;
|
||||
GPU_frame_buffer_load_percent = gpuFrameBufferLoad;
|
||||
GPU_memory_load_percent = gpuMemoryLoad;
|
||||
GPU_video_engine_load_percent = gpuVideoEngineLoad;
|
||||
GPU_bus_interface_load_percent = gpuBusInterfaceLoad;
|
||||
|
||||
GPU_load_percent = MaxNullable(
|
||||
gpuCoreLoad,
|
||||
gpuFrameBufferLoad,
|
||||
gpuMemoryLoad,
|
||||
gpuVideoEngineLoad,
|
||||
gpuBusInterfaceLoad
|
||||
);
|
||||
|
||||
GPU_temp_core_c = gpuTempCore;
|
||||
GPU_power_w = gpuPower;
|
||||
|
||||
GPU_core_clock_mhz = gpuCoreClock;
|
||||
GPU_memory_clock_mhz = gpuMemoryClock;
|
||||
GPU_shader_clock_mhz = gpuShaderClock;
|
||||
|
||||
GPU_fan_percent = gpuFanPercent;
|
||||
GPU_fan_rpm = gpuFanRpm;
|
||||
|
||||
GPU_vram_total_mb = gpuVramTotalMb;
|
||||
GPU_vram_used_mb = gpuVramUsedMb;
|
||||
GPU_vram_free_mb = gpuVramFreeMb;
|
||||
|
||||
GPU_pcie_rx = gpuPcieRx;
|
||||
GPU_pcie_tx = gpuPcieTx;
|
||||
|
||||
Disk_used_space_percent = diskUsedSpace;
|
||||
|
||||
AtualizarDadosProcesso();
|
||||
AtualizarDadosThreadPool();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Mantém último snapshot válido.
|
||||
// Se quiser, depois podemos adicionar um campo:
|
||||
// LastError, ErrorCount, LastErrorTimestamp.
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Leitores por hardware
|
||||
// ============================================================
|
||||
|
||||
private static void LerCpu(
|
||||
IHardware hardwareItem,
|
||||
ref float? cpuLoad,
|
||||
ref float? cpuTempPackage,
|
||||
ref float? cpuPowerPackage,
|
||||
ref float? cpuPowerCores,
|
||||
ref float? cpuPowerGraphics,
|
||||
ref float? cpuPowerDram,
|
||||
ref float? cpuClockAvg,
|
||||
ref float? cpuClockMax,
|
||||
ref float? cpuBusSpeed)
|
||||
{
|
||||
float clockSum = 0;
|
||||
int clockCount = 0;
|
||||
float? clockMax = null;
|
||||
|
||||
foreach (var sensor in hardwareItem.Sensors)
|
||||
{
|
||||
if (!sensor.Value.HasValue)
|
||||
continue;
|
||||
|
||||
string name = sensor.Name ?? "";
|
||||
|
||||
if (sensor.SensorType == SensorType.Load && name == "CPU Total")
|
||||
cpuLoad = sensor.Value;
|
||||
|
||||
else if (sensor.SensorType == SensorType.Temperature && name == "CPU Package")
|
||||
cpuTempPackage = sensor.Value;
|
||||
|
||||
else if (sensor.SensorType == SensorType.Power && name == "CPU Package")
|
||||
cpuPowerPackage = sensor.Value;
|
||||
|
||||
else if (sensor.SensorType == SensorType.Power && name == "CPU Cores")
|
||||
cpuPowerCores = sensor.Value;
|
||||
|
||||
else if (sensor.SensorType == SensorType.Power && name == "CPU Graphics")
|
||||
cpuPowerGraphics = sensor.Value;
|
||||
|
||||
else if (sensor.SensorType == SensorType.Power && name == "CPU DRAM")
|
||||
cpuPowerDram = sensor.Value;
|
||||
|
||||
else if (sensor.SensorType == SensorType.Clock && name.StartsWith("CPU Core"))
|
||||
{
|
||||
float v = sensor.Value.Value;
|
||||
clockSum += v;
|
||||
clockCount++;
|
||||
|
||||
if (!clockMax.HasValue || v > clockMax.Value)
|
||||
clockMax = v;
|
||||
}
|
||||
|
||||
else if (sensor.SensorType == SensorType.Clock && name == "Bus Speed")
|
||||
cpuBusSpeed = sensor.Value;
|
||||
}
|
||||
|
||||
if (clockCount > 0)
|
||||
cpuClockAvg = clockSum / clockCount;
|
||||
|
||||
cpuClockMax = clockMax;
|
||||
}
|
||||
|
||||
private static void LerRam(
|
||||
IHardware hardwareItem,
|
||||
ref float? ramUsage,
|
||||
ref float? ramUsedGb,
|
||||
ref float? ramAvailableGb)
|
||||
{
|
||||
foreach (var sensor in hardwareItem.Sensors)
|
||||
{
|
||||
if (!sensor.Value.HasValue)
|
||||
continue;
|
||||
|
||||
string name = sensor.Name ?? "";
|
||||
|
||||
if (sensor.SensorType == SensorType.Load && name == "Memory")
|
||||
ramUsage = sensor.Value;
|
||||
|
||||
else if (sensor.SensorType == SensorType.Data && name == "Used Memory")
|
||||
ramUsedGb = sensor.Value;
|
||||
|
||||
else if (sensor.SensorType == SensorType.Data && name == "Available Memory")
|
||||
ramAvailableGb = sensor.Value;
|
||||
}
|
||||
}
|
||||
|
||||
private static void LerGpu(
|
||||
IHardware hardwareItem,
|
||||
ref float? gpuCoreLoad,
|
||||
ref float? gpuFrameBufferLoad,
|
||||
ref float? gpuMemoryLoad,
|
||||
ref float? gpuVideoEngineLoad,
|
||||
ref float? gpuBusInterfaceLoad,
|
||||
ref float? gpuTempCore,
|
||||
ref float? gpuPower,
|
||||
ref float? gpuCoreClock,
|
||||
ref float? gpuMemoryClock,
|
||||
ref float? gpuShaderClock,
|
||||
ref float? gpuFanPercent,
|
||||
ref float? gpuFanRpm,
|
||||
ref float? gpuVramTotalMb,
|
||||
ref float? gpuVramUsedMb,
|
||||
ref float? gpuVramFreeMb,
|
||||
ref float? gpuPcieRx,
|
||||
ref float? gpuPcieTx)
|
||||
{
|
||||
foreach (var sensor in hardwareItem.Sensors)
|
||||
{
|
||||
if (!sensor.Value.HasValue)
|
||||
continue;
|
||||
|
||||
string name = sensor.Name ?? "";
|
||||
|
||||
if (sensor.SensorType == SensorType.Temperature && name == "GPU Core")
|
||||
gpuTempCore = sensor.Value;
|
||||
|
||||
else if (sensor.SensorType == SensorType.Load && name == "GPU Core")
|
||||
gpuCoreLoad = sensor.Value;
|
||||
|
||||
else if (sensor.SensorType == SensorType.Load && name == "GPU Frame Buffer")
|
||||
gpuFrameBufferLoad = sensor.Value;
|
||||
|
||||
else if (sensor.SensorType == SensorType.Load && name == "GPU Memory")
|
||||
gpuMemoryLoad = sensor.Value;
|
||||
|
||||
else if (sensor.SensorType == SensorType.Load && name == "GPU Video Engine")
|
||||
gpuVideoEngineLoad = sensor.Value;
|
||||
|
||||
else if (sensor.SensorType == SensorType.Load && name == "GPU Bus Interface")
|
||||
gpuBusInterfaceLoad = sensor.Value;
|
||||
|
||||
else if (sensor.SensorType == SensorType.Clock && name == "GPU Core")
|
||||
gpuCoreClock = sensor.Value;
|
||||
|
||||
else if (sensor.SensorType == SensorType.Clock && name == "GPU Memory")
|
||||
gpuMemoryClock = sensor.Value;
|
||||
|
||||
else if (sensor.SensorType == SensorType.Clock && name == "GPU Shader")
|
||||
gpuShaderClock = sensor.Value;
|
||||
|
||||
else if (sensor.SensorType == SensorType.Control && name == "GPU Fan")
|
||||
gpuFanPercent = sensor.Value;
|
||||
|
||||
else if (sensor.SensorType == SensorType.Fan && name == "GPU")
|
||||
gpuFanRpm = sensor.Value;
|
||||
|
||||
else if (sensor.SensorType == SensorType.SmallData && name == "GPU Memory Total")
|
||||
gpuVramTotalMb = sensor.Value;
|
||||
|
||||
else if (sensor.SensorType == SensorType.SmallData && name == "GPU Memory Used")
|
||||
gpuVramUsedMb = sensor.Value;
|
||||
|
||||
else if (sensor.SensorType == SensorType.SmallData && name == "GPU Memory Free")
|
||||
gpuVramFreeMb = sensor.Value;
|
||||
|
||||
else if (sensor.SensorType == SensorType.Power && name == "GPU Power")
|
||||
gpuPower = sensor.Value;
|
||||
|
||||
else if (sensor.SensorType == SensorType.Throughput && name == "GPU PCIE Rx")
|
||||
gpuPcieRx = sensor.Value;
|
||||
|
||||
else if (sensor.SensorType == SensorType.Throughput && name == "GPU PCIE Tx")
|
||||
gpuPcieTx = sensor.Value;
|
||||
}
|
||||
}
|
||||
|
||||
private static void LerDisco(IHardware hardwareItem, ref float? diskUsedSpace)
|
||||
{
|
||||
foreach (var sensor in hardwareItem.Sensors)
|
||||
{
|
||||
if (!sensor.Value.HasValue)
|
||||
continue;
|
||||
|
||||
string name = sensor.Name ?? "";
|
||||
|
||||
if (sensor.SensorType == SensorType.Load && name == "Used Space")
|
||||
diskUsedSpace = sensor.Value;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Processo / ThreadPool
|
||||
// ============================================================
|
||||
|
||||
private void AtualizarDadosProcesso()
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var proc = Process.GetCurrentProcess())
|
||||
{
|
||||
Process_thread_count = proc.Threads.Count;
|
||||
Process_working_set_mb = BytesToMb(proc.WorkingSet64);
|
||||
Process_private_memory_mb = BytesToMb(proc.PrivateMemorySize64);
|
||||
Process_virtual_memory_mb = BytesToMb(proc.VirtualMemorySize64);
|
||||
Process_cpu_time_total_s = proc.TotalProcessorTime.TotalSeconds;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Mantém último valor.
|
||||
}
|
||||
}
|
||||
|
||||
private void AtualizarDadosThreadPool()
|
||||
{
|
||||
try
|
||||
{
|
||||
ThreadPool.GetAvailableThreads(
|
||||
out int availableWorkerThreads,
|
||||
out int availableCompletionPortThreads
|
||||
);
|
||||
|
||||
ThreadPool.GetMaxThreads(
|
||||
out int maxWorkerThreads,
|
||||
out int maxCompletionPortThreads
|
||||
);
|
||||
|
||||
ThreadPool_available_worker_threads = availableWorkerThreads;
|
||||
ThreadPool_available_completion_port_threads = availableCompletionPortThreads;
|
||||
|
||||
ThreadPool_max_worker_threads = maxWorkerThreads;
|
||||
ThreadPool_max_completion_port_threads = maxCompletionPortThreads;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Mantém último valor.
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Clone / Snapshot
|
||||
// ============================================================
|
||||
|
||||
public PerformanceModel Clone()
|
||||
{
|
||||
return new PerformanceModel()
|
||||
{
|
||||
ActiveThreads = ActiveThreads,
|
||||
CompletionPortThreads = CompletionPortThreads,
|
||||
MaxWorkerThreads = MaxWorkerThreads,
|
||||
MaxCompletionPortThreads = MaxCompletionPortThreads,
|
||||
CPU_load = CPU_load,
|
||||
GPU_load = GPU_load,
|
||||
RAM_usage = RAM_usage,
|
||||
CPU_temp = CPU_temp,
|
||||
GPU_temp = GPU_temp,
|
||||
HDD_load = HDD_load,
|
||||
WorkerThreads = WorkerThreads
|
||||
Timestamp = this.Timestamp,
|
||||
TimestampUnixMs = this.TimestampUnixMs,
|
||||
|
||||
CPU_load_percent = this.CPU_load_percent,
|
||||
CPU_temp_package_c = this.CPU_temp_package_c,
|
||||
CPU_power_package_w = this.CPU_power_package_w,
|
||||
CPU_power_cores_w = this.CPU_power_cores_w,
|
||||
CPU_power_graphics_w = this.CPU_power_graphics_w,
|
||||
CPU_power_dram_w = this.CPU_power_dram_w,
|
||||
CPU_clock_avg_mhz = this.CPU_clock_avg_mhz,
|
||||
CPU_clock_max_mhz = this.CPU_clock_max_mhz,
|
||||
CPU_bus_speed_mhz = this.CPU_bus_speed_mhz,
|
||||
|
||||
RAM_usage_percent = this.RAM_usage_percent,
|
||||
RAM_used_gb = this.RAM_used_gb,
|
||||
RAM_available_gb = this.RAM_available_gb,
|
||||
|
||||
GPU_load_percent = this.GPU_load_percent,
|
||||
GPU_core_load_percent = this.GPU_core_load_percent,
|
||||
GPU_frame_buffer_load_percent = this.GPU_frame_buffer_load_percent,
|
||||
GPU_memory_load_percent = this.GPU_memory_load_percent,
|
||||
GPU_video_engine_load_percent = this.GPU_video_engine_load_percent,
|
||||
GPU_bus_interface_load_percent = this.GPU_bus_interface_load_percent,
|
||||
|
||||
GPU_temp_core_c = this.GPU_temp_core_c,
|
||||
GPU_power_w = this.GPU_power_w,
|
||||
|
||||
GPU_core_clock_mhz = this.GPU_core_clock_mhz,
|
||||
GPU_memory_clock_mhz = this.GPU_memory_clock_mhz,
|
||||
GPU_shader_clock_mhz = this.GPU_shader_clock_mhz,
|
||||
|
||||
GPU_fan_percent = this.GPU_fan_percent,
|
||||
GPU_fan_rpm = this.GPU_fan_rpm,
|
||||
|
||||
GPU_vram_total_mb = this.GPU_vram_total_mb,
|
||||
GPU_vram_used_mb = this.GPU_vram_used_mb,
|
||||
GPU_vram_free_mb = this.GPU_vram_free_mb,
|
||||
|
||||
GPU_pcie_rx = this.GPU_pcie_rx,
|
||||
GPU_pcie_tx = this.GPU_pcie_tx,
|
||||
|
||||
Disk_used_space_percent = this.Disk_used_space_percent,
|
||||
|
||||
Process_thread_count = this.Process_thread_count,
|
||||
Process_working_set_mb = this.Process_working_set_mb,
|
||||
Process_private_memory_mb = this.Process_private_memory_mb,
|
||||
Process_virtual_memory_mb = this.Process_virtual_memory_mb,
|
||||
Process_cpu_time_total_s = this.Process_cpu_time_total_s,
|
||||
|
||||
ThreadPool_available_worker_threads = this.ThreadPool_available_worker_threads,
|
||||
ThreadPool_available_completion_port_threads = this.ThreadPool_available_completion_port_threads,
|
||||
ThreadPool_max_worker_threads = this.ThreadPool_max_worker_threads,
|
||||
ThreadPool_max_completion_port_threads = this.ThreadPool_max_completion_port_threads,
|
||||
};
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Helpers
|
||||
// ============================================================
|
||||
|
||||
private static float? MaxNullable(params float?[] values)
|
||||
{
|
||||
float? max = null;
|
||||
|
||||
foreach (float? value in values)
|
||||
{
|
||||
if (!value.HasValue)
|
||||
continue;
|
||||
|
||||
if (!max.HasValue || value.Value > max.Value)
|
||||
max = value.Value;
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
private static long BytesToMb(long bytes)
|
||||
{
|
||||
return bytes / (1024L * 1024L);
|
||||
}
|
||||
|
||||
private static string Fmt(float? value, int casas = 1)
|
||||
{
|
||||
if (!value.HasValue)
|
||||
return "-";
|
||||
|
||||
return value.Value.ToString($"F{casas}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,88 +8,93 @@ namespace AgroBase.Services
|
|||
{
|
||||
public class CoulombCounterService
|
||||
{
|
||||
public CoulombCounterService(double max_Ah, double w_m_base = 0.1167)
|
||||
public CoulombCounterService(double max_Ah, double wh_m_base = 0.1167)
|
||||
{
|
||||
CargaMaxima_C = max_Ah * 3600.0; // Ah -> Coulombs
|
||||
WhPorMetroBase = w_m_base;
|
||||
|
||||
Iniciado = false;
|
||||
BmsLigado = false;
|
||||
|
||||
_estadoInicializado = false;
|
||||
_ultimaLeituraIntegrada = null;
|
||||
|
||||
CargaAtual_C = 0;
|
||||
ConsumidoTotal_C = 0;
|
||||
EnergiaConsumidaTotal_Wh = 0;
|
||||
|
||||
_socInicialInstancia = 0;
|
||||
_cargaInicialInstancia_C = 0;
|
||||
|
||||
_socInicialOperacao = 0;
|
||||
_cargaInicioOperacao_C = 0;
|
||||
_consumidoTotalNoInicioOperacao_C = 0;
|
||||
_energiaTotalNoInicioOperacao_Wh = 0;
|
||||
CapacidadeMaxima_Ah = max_Ah;
|
||||
CargaMaxima_C = max_Ah * 3600.0;
|
||||
WhPorMetroBase = wh_m_base;
|
||||
|
||||
MargemSegurancaAutonomia = 0.30;
|
||||
|
||||
ResetarHistoricosAutonomia();
|
||||
ResetarTudo();
|
||||
}
|
||||
|
||||
public bool Iniciado { get; private set; }
|
||||
public bool BmsLigado { get; private set; }
|
||||
public bool OperacaoAtiva { get; private set; }
|
||||
public bool OperacaoFinalizada { get; private set; }
|
||||
|
||||
private bool _estadoInicializado;
|
||||
private DateTime? _ultimaLeituraIntegrada;
|
||||
|
||||
// Capacidade e estado absoluto do pack
|
||||
private double CargaMaxima_C { get; set; } // Coulombs
|
||||
private double CargaAtual_C { get; set; } // Coulombs
|
||||
public double CapacidadeMaxima_Ah { get; private set; }
|
||||
private double CargaMaxima_C { get; set; }
|
||||
|
||||
// Snapshot inicial da instância
|
||||
private double _socInicialInstancia { get; set; }
|
||||
private double _cargaInicialInstancia_C { get; set; }
|
||||
public double CargaAtual_C { get; private set; }
|
||||
public double CargaAtualAmp => CargaAtual_C / 3600.0;
|
||||
|
||||
private double _socInicialInstancia;
|
||||
private double _socInicialOperacao;
|
||||
|
||||
private double _distanciaInicioOperacao_m;
|
||||
|
||||
private double _consumidoIntegradoTotal_C;
|
||||
private double _consumidoIntegradoOperacao_C;
|
||||
|
||||
// Acumuladores totais desde a criação da instância
|
||||
private double ConsumidoTotal_C { get; set; }
|
||||
public double ConsumidoTotal_Ah => ConsumidoTotal_C / 3600.0;
|
||||
public double ConsumidoOperacao_Ah => ConsumidoOperacao_C / 3600.0;
|
||||
|
||||
public double ConsumidoTotal_C
|
||||
{
|
||||
get
|
||||
{
|
||||
if (BmsLigado)
|
||||
return Math.Max(0, (_socInicialInstancia - PercentualBateria) / 100.0 * CargaMaxima_C);
|
||||
|
||||
return _consumidoIntegradoTotal_C;
|
||||
}
|
||||
}
|
||||
|
||||
public double ConsumidoOperacao_C
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!OperacaoAtiva && !OperacaoFinalizada)
|
||||
return 0;
|
||||
|
||||
if (BmsLigado)
|
||||
return Math.Max(0, (_socInicialOperacao - PercentualBateria) / 100.0 * CargaMaxima_C);
|
||||
|
||||
return _consumidoIntegradoOperacao_C;
|
||||
}
|
||||
}
|
||||
|
||||
public double PercentualConsumidoTotal
|
||||
{
|
||||
get
|
||||
{
|
||||
if (CargaMaxima_C <= 0) return 0;
|
||||
double calc = (ConsumidoTotal_C / CargaMaxima_C) * 100.0;
|
||||
return FuncoesMatematicas.Clamp(calc, 0, 100);
|
||||
|
||||
if (BmsLigado)
|
||||
return Clamp(_socInicialInstancia - PercentualBateria, 0, 100);
|
||||
|
||||
return Clamp((_consumidoIntegradoTotal_C / CargaMaxima_C) * 100.0, 0, 100);
|
||||
}
|
||||
}
|
||||
|
||||
public double EnergiaConsumidaTotal_Wh { get; private set; }
|
||||
|
||||
// Snapshot do início da operação
|
||||
private double _socInicialOperacao { get; set; }
|
||||
private double _cargaInicioOperacao_C { get; set; }
|
||||
private double _consumidoTotalNoInicioOperacao_C { get; set; }
|
||||
private double _energiaTotalNoInicioOperacao_Wh { get; set; }
|
||||
public bool OperacaoAtiva { get; private set; }
|
||||
public bool OperacaoFinalizada { get; private set; }
|
||||
|
||||
private double _consumidoTotalNoFimOperacao_C;
|
||||
private double _energiaTotalNoFimOperacao_Wh;
|
||||
|
||||
// Derivados da operação
|
||||
public double ConsumidoOperacao_C { get; set; }
|
||||
public double ConsumidoOperacao_Ah => ConsumidoOperacao_C / 3600.0;
|
||||
|
||||
public double PercentualConsumidoOperacao
|
||||
{
|
||||
get
|
||||
{
|
||||
if (CargaMaxima_C <= 0)
|
||||
if (!OperacaoAtiva && !OperacaoFinalizada)
|
||||
return 0;
|
||||
|
||||
double calc = (ConsumidoOperacao_C / CargaMaxima_C) * 100.0;
|
||||
return FuncoesMatematicas.Clamp(calc, 0, 100);
|
||||
if (CargaMaxima_C <= 0) return 0;
|
||||
|
||||
if (BmsLigado)
|
||||
return Clamp(_socInicialOperacao - PercentualBateria, 0, 100);
|
||||
|
||||
return Clamp((_consumidoIntegradoOperacao_C / CargaMaxima_C) * 100.0, 0, 100);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -97,12 +102,65 @@ namespace AgroBase.Services
|
|||
{
|
||||
get
|
||||
{
|
||||
if (_cargaInicioOperacao_C <= 0) return 0;
|
||||
double calc = (ConsumidoOperacao_C / _cargaInicioOperacao_C) * 100.0;
|
||||
return FuncoesMatematicas.Clamp(calc, 0, 100);
|
||||
if (_socInicialOperacao <= 0) return 0;
|
||||
|
||||
double consumido = PercentualConsumidoOperacao;
|
||||
return Clamp((consumido / _socInicialOperacao) * 100.0, 0, 100);
|
||||
}
|
||||
}
|
||||
|
||||
public double PercentualConsumidoTotalIntegrado
|
||||
{
|
||||
get
|
||||
{
|
||||
if (CargaMaxima_C <= 0) return 0;
|
||||
return Clamp((_consumidoIntegradoTotal_C / CargaMaxima_C) * 100.0, 0, 100);
|
||||
}
|
||||
}
|
||||
|
||||
public double PercentualConsumidoOperacaoIntegrado
|
||||
{
|
||||
get
|
||||
{
|
||||
if (CargaMaxima_C <= 0) return 0;
|
||||
return Clamp((_consumidoIntegradoOperacao_C / CargaMaxima_C) * 100.0, 0, 100);
|
||||
}
|
||||
}
|
||||
|
||||
public double DiferencaSocBmsVsIntegrado_Total
|
||||
{
|
||||
get
|
||||
{
|
||||
return PercentualConsumidoTotalIntegrado - PercentualConsumidoTotal;
|
||||
}
|
||||
}
|
||||
|
||||
public double PercentualAtual
|
||||
{
|
||||
get
|
||||
{
|
||||
if (BmsLigado)
|
||||
return PercentualBateria;
|
||||
|
||||
if (CargaMaxima_C <= 0) return 0;
|
||||
return Clamp((CargaAtual_C / CargaMaxima_C) * 100.0, 0, 100);
|
||||
}
|
||||
}
|
||||
|
||||
public double PercentualBateria { get; private set; }
|
||||
public double Temperatura { get; private set; }
|
||||
public double CorrenteInstantanea { get; private set; }
|
||||
public double CorrenteDescarga_A { get; private set; }
|
||||
public double TensaoInstantanea { get; private set; }
|
||||
public double PotenciaInstantanea { get; private set; }
|
||||
public double PotenciaDescarga_W { get; private set; }
|
||||
public double TempoEstimadoMinutos { get; private set; }
|
||||
public double _dt { get; private set; }
|
||||
|
||||
public double EnergiaConsumidaTotal_Wh { get; private set; }
|
||||
private double _energiaConsumidaInicioOperacao_Wh;
|
||||
private double _energiaConsumidaFimOperacao_Wh;
|
||||
|
||||
public double EnergiaConsumidaOperacao_Wh
|
||||
{
|
||||
get
|
||||
|
|
@ -110,32 +168,16 @@ namespace AgroBase.Services
|
|||
if (!OperacaoAtiva && !OperacaoFinalizada)
|
||||
return 0;
|
||||
|
||||
double referenciaFim = OperacaoFinalizada
|
||||
? _energiaTotalNoFimOperacao_Wh
|
||||
double fim = OperacaoFinalizada
|
||||
? _energiaConsumidaFimOperacao_Wh
|
||||
: EnergiaConsumidaTotal_Wh;
|
||||
|
||||
return Math.Max(0, referenciaFim - _energiaTotalNoInicioOperacao_Wh);
|
||||
return Math.Max(0, fim - _energiaConsumidaInicioOperacao_Wh);
|
||||
}
|
||||
}
|
||||
|
||||
// Estado atual
|
||||
public double PercentualAtual
|
||||
{
|
||||
get
|
||||
{
|
||||
if (CargaMaxima_C <= 0) return 0;
|
||||
return FuncoesMatematicas.Clamp((CargaAtual_C / CargaMaxima_C) * 100.0, 0, 100);
|
||||
}
|
||||
}
|
||||
|
||||
public double CargaAtualAmp => CargaAtual_C / 3600.0;
|
||||
public double PercentualBateria { get; private set; }
|
||||
public double Temperatura { get; private set; }
|
||||
public double CorrenteInstantanea { get; private set; }
|
||||
public double TensaoInstantanea { get; private set; }
|
||||
public double PotenciaInstantanea { get; private set; }
|
||||
public double TempoEstimadoMinutos { get; private set; }
|
||||
public double _dt { get; private set; }
|
||||
public double EnergiaConsumidaTotal_kWh => EnergiaConsumidaTotal_Wh / 1000.0;
|
||||
public double EnergiaConsumidaOperacao_kWh => EnergiaConsumidaOperacao_Wh / 1000.0;
|
||||
|
||||
public double WhRestante
|
||||
{
|
||||
|
|
@ -149,12 +191,14 @@ namespace AgroBase.Services
|
|||
}
|
||||
}
|
||||
|
||||
// Histórico para suavização de corrente
|
||||
private const int BufferSize = 30;
|
||||
private readonly Queue<double> _historicoCorrente = new Queue<double>();
|
||||
public double kWhRestante => WhRestante / 1000.0;
|
||||
|
||||
private const int BufferSize = 30;
|
||||
private readonly Queue<double> _historicoCorrenteDescarga = new Queue<double>();
|
||||
private readonly Queue<double> _historicoPotenciaDescarga = new Queue<double>();
|
||||
|
||||
// Autonomia
|
||||
public double WhPorMetro { get; private set; }
|
||||
public double kWhPorMetro => WhPorMetro / 1000.0;
|
||||
public double WhPorMetroBase { get; set; }
|
||||
public double WhPorMetroHistorico { get; private set; }
|
||||
|
||||
|
|
@ -181,18 +225,17 @@ namespace AgroBase.Services
|
|||
private double _distanciaTotalMetrosAnterior;
|
||||
private double _energiaConsumidaAnterior_Wh_Total;
|
||||
|
||||
public void IniciarOperacao()
|
||||
public void IniciarOperacao(double distanciaTotalMetrosAtual = 0)
|
||||
{
|
||||
if (!_estadoInicializado)
|
||||
return;
|
||||
|
||||
_socInicialOperacao = PercentualBateria;
|
||||
_cargaInicioOperacao_C = CargaAtual_C;
|
||||
_consumidoTotalNoInicioOperacao_C = ConsumidoTotal_C;
|
||||
_energiaTotalNoInicioOperacao_Wh = EnergiaConsumidaTotal_Wh;
|
||||
_distanciaInicioOperacao_m = distanciaTotalMetrosAtual;
|
||||
|
||||
_consumidoTotalNoFimOperacao_C = 0;
|
||||
_energiaTotalNoFimOperacao_Wh = 0;
|
||||
_consumidoIntegradoOperacao_C = 0;
|
||||
_energiaConsumidaInicioOperacao_Wh = EnergiaConsumidaTotal_Wh;
|
||||
_energiaConsumidaFimOperacao_Wh = 0;
|
||||
|
||||
OperacaoAtiva = true;
|
||||
OperacaoFinalizada = false;
|
||||
|
|
@ -203,8 +246,7 @@ namespace AgroBase.Services
|
|||
if (!OperacaoAtiva)
|
||||
return;
|
||||
|
||||
_consumidoTotalNoFimOperacao_C = ConsumidoTotal_C;
|
||||
_energiaTotalNoFimOperacao_Wh = EnergiaConsumidaTotal_Wh;
|
||||
_energiaConsumidaFimOperacao_Wh = EnergiaConsumidaTotal_Wh;
|
||||
|
||||
OperacaoAtiva = false;
|
||||
OperacaoFinalizada = true;
|
||||
|
|
@ -212,63 +254,22 @@ namespace AgroBase.Services
|
|||
|
||||
public void AtualizarConsumo(double distanciaTotalMetrosAtual)
|
||||
{
|
||||
var dalyBms = DalyBMSService.DadosLeitura;
|
||||
bool bms_iniciado = dalyBms?.Iniciado ?? false;
|
||||
DateTime? bms_ultima_leitura = dalyBms?.UltimoComandoRecebido;
|
||||
double bms_tensao = dalyBms?.Pack?.TensaoTotal_V ?? 0;
|
||||
double bms_corrente = dalyBms?.Pack?.Corrente_A ?? 0;
|
||||
double bms_soc = dalyBms?.Pack?.SOC_percent ?? 0;
|
||||
double bms_tmp = dalyBms?.TemperaturaMax ?? 0;
|
||||
|
||||
var sensor = Variaveis.OperacaoEmAndamento.DispSen?.Dados?.Sensores?.FirstOrDefault(x => x.ID == "AB36V");
|
||||
bool sen_iniciado = sensor?.Inicializado ?? false;
|
||||
DateTime? sen_ultima_leitura = sensor?.UltimaLeitura;
|
||||
double sen_tensao = sensor?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Tensao)?.atual?.valor ?? 0;
|
||||
double sen_corrente = (sensor?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Corrente)?.atual?.valor ?? 0) / 1000.0;
|
||||
double sen_soc = Math.Round(
|
||||
FuncoesMatematicas.Map(
|
||||
sen_tensao,
|
||||
VariaveisEquipamento.TensaoMinimaBateria,
|
||||
VariaveisEquipamento.TensaoMaximaBateria,
|
||||
0.0,
|
||||
100.0), 2);
|
||||
double sen_tmp = sensor?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Temperatura)?.atual?.valor ?? 0;
|
||||
|
||||
Iniciado = bms_iniciado || sen_iniciado;
|
||||
BmsLigado = bms_iniciado;
|
||||
LerFontes();
|
||||
|
||||
if (!Iniciado)
|
||||
return;
|
||||
|
||||
DateTime? leituraAtual = BmsLigado ? bms_ultima_leitura : sen_ultima_leitura;
|
||||
TensaoInstantanea = BmsLigado ? bms_tensao : sen_tensao;
|
||||
CorrenteInstantanea = BmsLigado ? bms_corrente : sen_corrente;
|
||||
PotenciaInstantanea = TensaoInstantanea * CorrenteInstantanea;
|
||||
PercentualBateria = FuncoesMatematicas.Clamp(BmsLigado ? bms_soc : sen_soc, 0, 100);
|
||||
Temperatura = BmsLigado ? bms_tmp : sen_tmp;
|
||||
DateTime? leituraAtual = ObterDataLeituraAtual();
|
||||
|
||||
if (!leituraAtual.HasValue || leituraAtual.Value == DateTime.MinValue)
|
||||
return;
|
||||
|
||||
// Primeira leitura válida da instância
|
||||
if (!_estadoInicializado)
|
||||
{
|
||||
_socInicialInstancia = PercentualBateria;
|
||||
_cargaInicialInstancia_C = CargaMaxima_C * (PercentualBateria / 100.0);
|
||||
CargaAtual_C = _cargaInicialInstancia_C;
|
||||
|
||||
ConsumidoTotal_C = 0;
|
||||
EnergiaConsumidaTotal_Wh = 0;
|
||||
|
||||
_ultimaLeituraIntegrada = leituraAtual.Value;
|
||||
_estadoInicializado = true;
|
||||
|
||||
_dt = 0;
|
||||
AtualizarAutonomia(distanciaTotalMetrosAtual);
|
||||
InicializarEstado(leituraAtual.Value, distanciaTotalMetrosAtual);
|
||||
return;
|
||||
}
|
||||
|
||||
// Só integra se chegou leitura nova
|
||||
if (_ultimaLeituraIntegrada.HasValue && leituraAtual.Value <= _ultimaLeituraIntegrada.Value)
|
||||
{
|
||||
_dt = 0;
|
||||
|
|
@ -282,45 +283,160 @@ namespace AgroBase.Services
|
|||
if (_dt <= 0 || _dt > 10)
|
||||
{
|
||||
Console.WriteLine($"[COULOMB COUNTER] dt inválido: {_dt:F3}s");
|
||||
AtualizarCargaAtualPeloSocOuIntegrador();
|
||||
AtualizarAutonomia(distanciaTotalMetrosAtual);
|
||||
return;
|
||||
}
|
||||
|
||||
// Assumindo descarga positiva. Se no Daly a descarga vier negativa, inverter aqui.
|
||||
double correnteDescarga_A = Math.Max(0, CorrenteInstantanea);
|
||||
CorrenteDescarga_A = NormalizarCorrenteDescarga(CorrenteInstantanea);
|
||||
PotenciaDescarga_W = Math.Max(0, TensaoInstantanea * CorrenteDescarga_A);
|
||||
|
||||
double deltaCoulombs = CorrenteDescarga_A * _dt;
|
||||
double deltaEnergia_Wh = PotenciaDescarga_W * _dt / 3600.0;
|
||||
|
||||
_consumidoIntegradoTotal_C = Clamp(_consumidoIntegradoTotal_C + deltaCoulombs, 0, CargaMaxima_C);
|
||||
|
||||
double deltaCoulombs = correnteDescarga_A * _dt;
|
||||
ConsumidoTotal_C += deltaCoulombs;
|
||||
ConsumidoTotal_C = FuncoesMatematicas.Clamp(ConsumidoTotal_C, 0, CargaMaxima_C);
|
||||
if (OperacaoAtiva && !OperacaoFinalizada)
|
||||
{
|
||||
ConsumidoOperacao_C += deltaCoulombs;
|
||||
ConsumidoOperacao_C = FuncoesMatematicas.Clamp(ConsumidoOperacao_C, 0, CargaMaxima_C);
|
||||
}
|
||||
_consumidoIntegradoOperacao_C = Clamp(_consumidoIntegradoOperacao_C + deltaCoulombs, 0, CargaMaxima_C);
|
||||
|
||||
// Estado absoluto do pack sempre baseado no total da instância
|
||||
double cargaAtualCalculada = _cargaInicialInstancia_C - ConsumidoTotal_C;
|
||||
CargaAtual_C = FuncoesMatematicas.Clamp(cargaAtualCalculada, 0, CargaMaxima_C);
|
||||
|
||||
double deltaEnergia_Wh = PotenciaInstantanea * _dt / 3600.0;
|
||||
if (deltaEnergia_Wh > 0)
|
||||
EnergiaConsumidaTotal_Wh += deltaEnergia_Wh;
|
||||
|
||||
_historicoCorrente.Enqueue(correnteDescarga_A);
|
||||
if (_historicoCorrente.Count > BufferSize)
|
||||
_historicoCorrente.Dequeue();
|
||||
AtualizarCargaAtualPeloSocOuIntegrador();
|
||||
AtualizarHistoricos();
|
||||
AtualizarTempoRestante();
|
||||
AtualizarAutonomia(distanciaTotalMetrosAtual);
|
||||
}
|
||||
|
||||
double correnteMedia = _historicoCorrente.Count > 0
|
||||
? _historicoCorrente.Average()
|
||||
: 0;
|
||||
private void LerFontes()
|
||||
{
|
||||
var dalyBms = DalyBMSService.DadosLeitura;
|
||||
|
||||
if (correnteMedia > 0 && CargaAtualAmp > 0)
|
||||
TempoEstimadoMinutos = (CargaAtualAmp / correnteMedia) * 60.0;
|
||||
else
|
||||
TempoEstimadoMinutos = 0;
|
||||
bool bms_iniciado = dalyBms?.Iniciado ?? false;
|
||||
DateTime? bms_ultima_leitura = dalyBms?.UltimoComandoRecebido;
|
||||
double bms_tensao = dalyBms?.Pack?.TensaoTotal_V ?? 0;
|
||||
double bms_corrente = dalyBms?.Pack?.Corrente_A ?? 0;
|
||||
double bms_soc = dalyBms?.Pack?.SOC_percent ?? 0;
|
||||
double bms_tmp = dalyBms?.TemperaturaMax ?? 0;
|
||||
|
||||
var sensor = Variaveis.OperacaoEmAndamento.DispSen?.Dados?.Sensores?
|
||||
.FirstOrDefault(x => x.ID == "AB36V");
|
||||
|
||||
bool sen_iniciado = sensor?.Inicializado ?? false;
|
||||
DateTime? sen_ultima_leitura = sensor?.UltimaLeitura;
|
||||
double sen_tensao = sensor?.ValoresLeituras?
|
||||
.FirstOrDefault(x => x.funcao == FuncoesPinout.Tensao)?.atual?.valor ?? 0;
|
||||
|
||||
double sen_corrente = (sensor?.ValoresLeituras?
|
||||
.FirstOrDefault(x => x.funcao == FuncoesPinout.Corrente)?.atual?.valor ?? 0) / 1000.0;
|
||||
|
||||
double sen_soc = Math.Round(
|
||||
FuncoesMatematicas.Map(
|
||||
sen_tensao,
|
||||
VariaveisEquipamento.TensaoMinimaBateria,
|
||||
VariaveisEquipamento.TensaoMaximaBateria,
|
||||
0.0,
|
||||
100.0), 2);
|
||||
|
||||
double sen_tmp = sensor?.ValoresLeituras?
|
||||
.FirstOrDefault(x => x.funcao == FuncoesPinout.Temperatura)?.atual?.valor ?? 0;
|
||||
|
||||
Iniciado = bms_iniciado || sen_iniciado;
|
||||
BmsLigado = bms_iniciado;
|
||||
|
||||
TensaoInstantanea = BmsLigado ? bms_tensao : sen_tensao;
|
||||
CorrenteInstantanea = BmsLigado ? bms_corrente : sen_corrente;
|
||||
PotenciaInstantanea = TensaoInstantanea * CorrenteInstantanea;
|
||||
PercentualBateria = Clamp(BmsLigado ? bms_soc : sen_soc, 0, 100);
|
||||
Temperatura = BmsLigado ? bms_tmp : sen_tmp;
|
||||
}
|
||||
|
||||
private DateTime? ObterDataLeituraAtual()
|
||||
{
|
||||
var dalyBms = DalyBMSService.DadosLeitura;
|
||||
|
||||
if (BmsLigado)
|
||||
return dalyBms?.UltimoComandoRecebido;
|
||||
|
||||
var sensor = Variaveis.OperacaoEmAndamento.DispSen?.Dados?.Sensores?
|
||||
.FirstOrDefault(x => x.ID == "AB36V");
|
||||
|
||||
return sensor?.UltimaLeitura;
|
||||
}
|
||||
|
||||
private void InicializarEstado(DateTime leituraAtual, double distanciaTotalMetrosAtual)
|
||||
{
|
||||
_socInicialInstancia = PercentualBateria;
|
||||
|
||||
AtualizarCargaAtualPeloSocOuIntegrador();
|
||||
|
||||
_consumidoIntegradoTotal_C = 0;
|
||||
_consumidoIntegradoOperacao_C = 0;
|
||||
EnergiaConsumidaTotal_Wh = 0;
|
||||
|
||||
_ultimaLeituraIntegrada = leituraAtual;
|
||||
_estadoInicializado = true;
|
||||
|
||||
_distanciaTotalMetrosAnterior = distanciaTotalMetrosAtual;
|
||||
_energiaConsumidaAnterior_Wh_Total = EnergiaConsumidaTotal_Wh;
|
||||
|
||||
_dt = 0;
|
||||
|
||||
AtualizarAutonomia(distanciaTotalMetrosAtual);
|
||||
}
|
||||
|
||||
private void AtualizarCargaAtualPeloSocOuIntegrador()
|
||||
{
|
||||
if (CargaMaxima_C <= 0)
|
||||
{
|
||||
CargaAtual_C = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (BmsLigado)
|
||||
{
|
||||
CargaAtual_C = CargaMaxima_C * (PercentualBateria / 100.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
double cargaInicial = CargaMaxima_C * (_socInicialInstancia / 100.0);
|
||||
CargaAtual_C = Clamp(cargaInicial - _consumidoIntegradoTotal_C, 0, CargaMaxima_C);
|
||||
}
|
||||
}
|
||||
|
||||
private double NormalizarCorrenteDescarga(double corrente)
|
||||
{
|
||||
if (Math.Abs(corrente) < 0.05)
|
||||
return 0;
|
||||
|
||||
// Daly normalmente pode reportar descarga negativa.
|
||||
// Para autonomia, queremos magnitude da descarga.
|
||||
return Math.Abs(corrente);
|
||||
}
|
||||
|
||||
private void AtualizarHistoricos()
|
||||
{
|
||||
_historicoCorrenteDescarga.Enqueue(CorrenteDescarga_A);
|
||||
if (_historicoCorrenteDescarga.Count > BufferSize)
|
||||
_historicoCorrenteDescarga.Dequeue();
|
||||
|
||||
_historicoPotenciaDescarga.Enqueue(PotenciaDescarga_W);
|
||||
if (_historicoPotenciaDescarga.Count > BufferSize)
|
||||
_historicoPotenciaDescarga.Dequeue();
|
||||
}
|
||||
|
||||
private void AtualizarTempoRestante()
|
||||
{
|
||||
double potenciaMedia_W = _historicoPotenciaDescarga.Count > 0
|
||||
? _historicoPotenciaDescarga.Average()
|
||||
: 0;
|
||||
|
||||
if (potenciaMedia_W > 1 && WhRestante > 0)
|
||||
TempoEstimadoMinutos = (WhRestante / potenciaMedia_W) * 60.0;
|
||||
else
|
||||
TempoEstimadoMinutos = 0;
|
||||
}
|
||||
|
||||
private void AtualizarAutonomia(double distanciaTotalMetrosAtual)
|
||||
{
|
||||
if (!_estadoInicializado)
|
||||
|
|
@ -337,6 +453,7 @@ namespace AgroBase.Services
|
|||
{
|
||||
_historicoDeltaDist_m.Enqueue(deltaDist_m);
|
||||
_historicoDeltaWh.Enqueue(deltaWh);
|
||||
|
||||
_somaDistanciaJanela_m += deltaDist_m;
|
||||
_somaEnergiaJanela_Wh += deltaWh;
|
||||
|
||||
|
|
@ -366,38 +483,12 @@ namespace AgroBase.Services
|
|||
}
|
||||
}
|
||||
|
||||
private void ResetarHistoricosAutonomia()
|
||||
{
|
||||
_historicoCorrente.Clear();
|
||||
|
||||
_historicoDeltaDist_m.Clear();
|
||||
_historicoDeltaWh.Clear();
|
||||
_somaDistanciaJanela_m = 0;
|
||||
_somaEnergiaJanela_Wh = 0;
|
||||
|
||||
_distanciaTotalMetrosAnterior = 0;
|
||||
_energiaConsumidaAnterior_Wh_Total = EnergiaConsumidaTotal_Wh;
|
||||
|
||||
WhPorMetro = 0;
|
||||
WhPorMetroHistorico = 0;
|
||||
DistanciaMaximaTeorica_m = 0;
|
||||
DistanciaMaximaSegura_m = 0;
|
||||
DistanciaEstimadaRestante_m = 0;
|
||||
|
||||
TempoEstimadoMinutos = 0;
|
||||
_dt = 0;
|
||||
}
|
||||
|
||||
public void AtualizarValorConsumidoTotal(double consumoTotal_Ah)
|
||||
{
|
||||
double coulombsConsumidos = consumoTotal_Ah * 3600.0;
|
||||
ConsumidoTotal_C = FuncoesMatematicas.Clamp(coulombsConsumidos, 0, CargaMaxima_C);
|
||||
_consumidoIntegradoTotal_C = Clamp(coulombsConsumidos, 0, CargaMaxima_C);
|
||||
|
||||
if (_estadoInicializado)
|
||||
{
|
||||
double cargaAtualCalculada = _cargaInicialInstancia_C - ConsumidoTotal_C;
|
||||
CargaAtual_C = FuncoesMatematicas.Clamp(cargaAtualCalculada, 0, CargaMaxima_C);
|
||||
}
|
||||
AtualizarCargaAtualPeloSocOuIntegrador();
|
||||
}
|
||||
|
||||
public bool ConseguePercorrer(double distanciaRequerida_m)
|
||||
|
|
@ -408,5 +499,65 @@ namespace AgroBase.Services
|
|||
return DistanciaMaximaSegura_m >= distanciaRequerida_m;
|
||||
}
|
||||
|
||||
private void ResetarTudo()
|
||||
{
|
||||
Iniciado = false;
|
||||
BmsLigado = false;
|
||||
OperacaoAtiva = false;
|
||||
OperacaoFinalizada = false;
|
||||
|
||||
_estadoInicializado = false;
|
||||
_ultimaLeituraIntegrada = null;
|
||||
|
||||
CargaAtual_C = 0;
|
||||
_socInicialInstancia = 0;
|
||||
_socInicialOperacao = 0;
|
||||
|
||||
_consumidoIntegradoTotal_C = 0;
|
||||
_consumidoIntegradoOperacao_C = 0;
|
||||
|
||||
EnergiaConsumidaTotal_Wh = 0;
|
||||
_energiaConsumidaInicioOperacao_Wh = 0;
|
||||
_energiaConsumidaFimOperacao_Wh = 0;
|
||||
|
||||
PercentualBateria = 0;
|
||||
Temperatura = 0;
|
||||
CorrenteInstantanea = 0;
|
||||
CorrenteDescarga_A = 0;
|
||||
TensaoInstantanea = 0;
|
||||
PotenciaInstantanea = 0;
|
||||
PotenciaDescarga_W = 0;
|
||||
TempoEstimadoMinutos = 0;
|
||||
_dt = 0;
|
||||
|
||||
ResetarHistoricosAutonomia();
|
||||
}
|
||||
|
||||
private void ResetarHistoricosAutonomia()
|
||||
{
|
||||
_historicoCorrenteDescarga.Clear();
|
||||
_historicoPotenciaDescarga.Clear();
|
||||
|
||||
_historicoDeltaDist_m.Clear();
|
||||
_historicoDeltaWh.Clear();
|
||||
|
||||
_somaDistanciaJanela_m = 0;
|
||||
_somaEnergiaJanela_Wh = 0;
|
||||
|
||||
_distanciaTotalMetrosAnterior = 0;
|
||||
_energiaConsumidaAnterior_Wh_Total = 0;
|
||||
|
||||
WhPorMetro = 0;
|
||||
WhPorMetroHistorico = 0;
|
||||
|
||||
DistanciaMaximaTeorica_m = 0;
|
||||
DistanciaMaximaSegura_m = 0;
|
||||
DistanciaEstimadaRestante_m = 0;
|
||||
}
|
||||
|
||||
private static double Clamp(double value, double min, double max)
|
||||
{
|
||||
return FuncoesMatematicas.Clamp(value, min, max);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -107,8 +107,8 @@ namespace AgroBase.Services
|
|||
string[] comandos = {
|
||||
// Bauds
|
||||
$"config com1 115200\r\n",
|
||||
$"config {porta_usb} 115200\r\n",
|
||||
$"config {porta_entrada} 115200\r\n",
|
||||
$"config com2 115200\r\n",
|
||||
$"config com3 115200\r\n",
|
||||
|
||||
// limpa logs das portas
|
||||
$"unlog com1\r\n",
|
||||
|
|
@ -158,8 +158,9 @@ namespace AgroBase.Services
|
|||
string distancia_min = "0";
|
||||
string[] comandos = {
|
||||
// Bauds
|
||||
$"config {porta_usb} 115200\r\n",
|
||||
$"config {porta_saida} 115200\r\n",
|
||||
$"config com1 115200\r\n",
|
||||
$"config com2 115200\r\n",
|
||||
$"config com3 115200\r\n",
|
||||
|
||||
// limpa logs das portas
|
||||
$"unlog com1\r\n",
|
||||
|
|
|
|||
|
|
@ -9,138 +9,129 @@ namespace AgroBase.Services
|
|||
{
|
||||
public class HerbicideCounterService
|
||||
{
|
||||
public HerbicideCounterService(double capacidadeLitros, double densidadeProduto, double l_m_base = 0.1188) // 3km/h ~ 3x 33 ml/s
|
||||
public HerbicideCounterService(double capacidadeLitros, double densidadeProduto, double vazaoPorBicoBase_mLs = 33.0)
|
||||
{
|
||||
CapacidadeLitros = capacidadeLitros;
|
||||
VolumeAtual_L = 0;
|
||||
VolumeConsumido_L = 0;
|
||||
DensidadeProduto = densidadeProduto;
|
||||
LPorMetroBase = l_m_base;
|
||||
|
||||
MargemSegurancaAutonomia = 0.30; // 30% por padrão
|
||||
QuantidadeBicos = VariaveisEquipamento.QuantidadeBicosPulverizadores;
|
||||
|
||||
VazaoPorBicoBase_mLs = vazaoPorBicoBase_mLs;
|
||||
VazaoPorBicoBase_LMin = vazaoPorBicoBase_mLs * 60.0 / 1000.0;
|
||||
VazaoTotalTodosBicos_LMin = VazaoPorBicoBase_LMin * QuantidadeBicos;
|
||||
|
||||
MargemSegurancaAutonomia = 0.30;
|
||||
|
||||
ResetarTudo();
|
||||
}
|
||||
|
||||
public bool Iniciado { get; private set; }
|
||||
public bool OperacaoAtiva { get; private set; }
|
||||
public bool OperacaoFinalizada { get; private set; }
|
||||
|
||||
// ---------- CONFIGURAÇÕES / ESTADO BÁSICO ----------
|
||||
|
||||
/// <summary>
|
||||
/// Capacidade máxima do reservatório em litros.
|
||||
/// </summary>
|
||||
public double CapacidadeLitros { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Densidade do produto.
|
||||
/// </summary>
|
||||
public double DensidadeProduto { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Massa atual lida no reservatório (Kg).
|
||||
/// </summary>
|
||||
|
||||
public int QuantidadeBicos { get; }
|
||||
|
||||
public double VazaoPorBicoBase_mLs { get; }
|
||||
public double VazaoPorBicoBase_LMin { get; }
|
||||
public double VazaoTotalTodosBicos_LMin { get; }
|
||||
|
||||
public double MassaAtual_Kg { get; private set; }
|
||||
public double MassaAtual_Kg_Calc { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Volume atual estimado no reservatório (L).
|
||||
/// </summary>
|
||||
public double VolumeAtual_L { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Volume total consumido desde o início (L).
|
||||
/// </summary>
|
||||
public double VolumeConsumido_L { get; private set; }
|
||||
private double _volumeInicialInstancia_L;
|
||||
private double _volumeInicialOperacao_L;
|
||||
|
||||
public double VolumeConsumidoTotal_L => Math.Max(0, _volumeInicialInstancia_L - VolumeAtual_L);
|
||||
|
||||
public double VolumeConsumidoOperacao_L
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!OperacaoAtiva && !OperacaoFinalizada)
|
||||
return 0;
|
||||
|
||||
return Math.Max(0, _volumeInicialOperacao_L - VolumeAtual_L);
|
||||
}
|
||||
}
|
||||
|
||||
public double PercentualAtual
|
||||
{
|
||||
get
|
||||
{
|
||||
if (CapacidadeLitros <= 0) return 0;
|
||||
var p = (VolumeAtual_L / CapacidadeLitros) * 100.0;
|
||||
return FuncoesMatematicas.Clamp(p, 0, 100);
|
||||
return Clamp((VolumeAtual_L / CapacidadeLitros) * 100.0, 0, 100);
|
||||
}
|
||||
}
|
||||
|
||||
public double PercentualConsumido
|
||||
public double PercentualConsumidoTotal
|
||||
{
|
||||
get
|
||||
{
|
||||
return 100.0 - PercentualAtual;
|
||||
if (CapacidadeLitros <= 0) return 0;
|
||||
return Clamp((VolumeConsumidoTotal_L / CapacidadeLitros) * 100.0, 0, 100);
|
||||
}
|
||||
}
|
||||
|
||||
public double HerbicidaPorAtuacao { get; private set; }
|
||||
public double PercentualConsumidoOperacao
|
||||
{
|
||||
get
|
||||
{
|
||||
if (CapacidadeLitros <= 0) return 0;
|
||||
return Clamp((VolumeConsumidoOperacao_L / CapacidadeLitros) * 100.0, 0, 100);
|
||||
}
|
||||
}
|
||||
|
||||
public double PercentualConsumidoOperacaoDaCargaInicial
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_volumeInicialOperacao_L <= 0) return 0;
|
||||
return Clamp((VolumeConsumidoOperacao_L / _volumeInicialOperacao_L) * 100.0, 0, 100);
|
||||
}
|
||||
}
|
||||
|
||||
public int BicosAtivos { get; private set; }
|
||||
public bool Pulverizando { get; private set; }
|
||||
public bool PulverizadorLiberado { get; private set; }
|
||||
|
||||
public double VazaoFluxoAtual_mLs { get; private set; }
|
||||
public double VazaoFluxoAtual_LMin => VazaoFluxoAtual_mLs * 60.0 / 1000.0;
|
||||
|
||||
public double VazaoEstimativaBicos_mLs { get; private set; }
|
||||
public double VazaoReferencia_mLs { get; private set; }
|
||||
|
||||
public double LPorMinuto { get; private set; }
|
||||
public double LPorMinutoEstimadoBicos { get; private set; }
|
||||
|
||||
public double LPorMetro { get; private set; }
|
||||
public double LPorMetroHistorico { get; private set; }
|
||||
public double LPorMetroBase { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Margem de segurança para estimativa (0.30 = 30%).
|
||||
/// </summary>
|
||||
public double MargemSegurancaAutonomia { get; set; }
|
||||
|
||||
// ---------- AUTONOMIA EM METROS (L/m) ----------
|
||||
|
||||
/// <summary>
|
||||
/// Consumo médio de herbicida por metro pulverizado (L/m),
|
||||
/// calculado numa janela móvel de distância.
|
||||
/// </summary>
|
||||
public double LPorMetro { get; private set; }
|
||||
|
||||
public double LPorMetroBase { get; set; }
|
||||
public double LPorMetroHistorico { get; private set; }
|
||||
|
||||
public double LPorMetroReferencia
|
||||
{
|
||||
get
|
||||
{
|
||||
if (LPorMetro > 0) return LPorMetro;
|
||||
if (LPorMetroHistorico > 0) return LPorMetroHistorico;
|
||||
return LPorMetroBase;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Distância máxima teórica que ainda pode ser pulverizada (sem margem), em metros.
|
||||
/// </summary>
|
||||
public double DistanciaMaximaTeorica_m { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Distância máxima segura que ainda pode ser pulverizada (com margem), em metros.
|
||||
/// </summary>
|
||||
public double DistanciaMaximaSegura_m { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Alias mais descritivo para uso direto pelo Manager.
|
||||
/// </summary>
|
||||
public double DistanciaEstimadaRestantePulverizando_m => DistanciaMaximaSegura_m;
|
||||
|
||||
// ---------- AUTONOMIA EM TEMPO (L/min) ----------
|
||||
|
||||
/// <summary>
|
||||
/// Consumo médio de herbicida por minuto (L/min) durante pulverização.
|
||||
/// </summary>
|
||||
public double LPorMinuto { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Tempo estimado restante pulverizando, em minutos.
|
||||
/// </summary>
|
||||
public double TempoEstimadoMinutosPulverizando { get; private set; }
|
||||
|
||||
// ---------- JANELAS DE MÉDIA MÓVEL ----------
|
||||
public double HerbicidaPorAtuacao_L { get; private set; }
|
||||
|
||||
// Distância: vamos usar uma janela de ~50 m (mesma ideia da bateria)
|
||||
private const double JanelaAutonomia_m = 50.0;
|
||||
|
||||
// Tempo: janela de ~60 s pulverizando
|
||||
private const double JanelaTempo_s = 60.0;
|
||||
|
||||
private readonly Queue<(double deltaDist_m, double deltaVol_L)> _janelaDist = new Queue<(double deltaDist_m, double deltaVol_L)>();
|
||||
private readonly Queue<(double deltaTempo_s, double deltaVol_L)> _janelaTempo = new Queue<(double deltaTempo_s, double deltaVol_L)>();
|
||||
private readonly Queue<(double dist_m, double vol_L)> _janelaDist = new Queue<(double dist_m, double vol_L)>();
|
||||
private readonly Queue<(double tempo_s, double vol_L)> _janelaTempo = new Queue<(double tempo_s, double vol_L)>();
|
||||
|
||||
private double _somaDistanciaJanela_m;
|
||||
private double _somaVolumeDistJanela_L;
|
||||
|
||||
private double _somaTempoJanela_s;
|
||||
private double _somaVolumeTempoJanela_L;
|
||||
|
||||
// Valores anteriores para cálculo de deltas
|
||||
private double _volumeAnterior_L;
|
||||
private double _distanciaTotalAnterior_m;
|
||||
private double _tempoTotalAnterior_s;
|
||||
|
|
@ -148,192 +139,258 @@ namespace AgroBase.Services
|
|||
private bool _inicializado;
|
||||
|
||||
private SensorModel SensorMassaReservatorio => Variaveis.OperacaoEmAndamento.DispAtu?.Dados?.Sensores?.FirstOrDefault(x => x.Componente == S_Code.sMAS && x.ID == "MASRS");
|
||||
public AtuadorBombaModel AgitadorCalda => Variaveis.OperacaoEmAndamento.DispAtu?.Dados?.BombasPressurizadoras?.FirstOrDefault(x => x.ID == "AGTCLD");
|
||||
public bool PulverizadorLiberado { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Atualiza o estado do sistema de herbicida.
|
||||
///
|
||||
/// Chamar periodicamente com:
|
||||
/// - volumeMedido_L: leitura de nível atual do reservatório (L)
|
||||
/// - pulverizando: true se algum bico está ativo
|
||||
/// - distanciaTotalMetrosAtual: distância total acumulada (m)
|
||||
/// - tempoTotalSegundosAtual: tempo total de operação (s)
|
||||
/// </summary>
|
||||
public void AtualizarConsumo(double distanciaTotalMetrosAtual, double tempoTotalSegundosAtual)
|
||||
public AtuadorBombaModel AgitadorCalda => Variaveis.OperacaoEmAndamento.DispAtu?.Dados?.BombasPressurizadoras?.FirstOrDefault(x => x.ID == "AGTCLD");
|
||||
|
||||
public void IniciarOperacao(double distanciaTotalMetrosAtual, double tempoTotalSegundosAtual)
|
||||
{
|
||||
if (!_inicializado)
|
||||
return;
|
||||
|
||||
_volumeInicialOperacao_L = VolumeAtual_L;
|
||||
|
||||
_distanciaTotalAnterior_m = distanciaTotalMetrosAtual;
|
||||
_tempoTotalAnterior_s = tempoTotalSegundosAtual;
|
||||
|
||||
OperacaoAtiva = true;
|
||||
OperacaoFinalizada = false;
|
||||
|
||||
ResetarJanelas();
|
||||
}
|
||||
|
||||
public void FinalizarOperacao()
|
||||
{
|
||||
if (!OperacaoAtiva)
|
||||
return;
|
||||
|
||||
OperacaoAtiva = false;
|
||||
OperacaoFinalizada = true;
|
||||
}
|
||||
|
||||
public void AtualizarConsumo(double distanciaTotalMetrosAtual, double tempoTotalSegundosAtual, double velocidadeAtual_m_s)
|
||||
{
|
||||
Iniciado = SensorMassaReservatorio?.Inicializado ?? false;
|
||||
|
||||
if (!Iniciado)
|
||||
return;
|
||||
|
||||
bool pulverizando = Variaveis.OperacaoEmAndamento.DispAtu?.Dados?.BicosPulverizadores?.Any(x => x.Inicializado && x._EstadoLeitura == Estado.Ligado) ?? false;
|
||||
double massaLida_Kg = SensorMassaReservatorio?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Massa)?.atual?.valor ?? 0;
|
||||
double massaLida_Kg_bruto = SensorMassaReservatorio?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.LeituraBruta)?.atual?.valor ?? 0;
|
||||
LerReservatorio(out double massaLida_Kg, out double massaCalc_Kg, out double volumeMedido_L);
|
||||
|
||||
double.TryParse(SensorMassaReservatorio.Parametros.FirstOrDefault(x => x.Descricao == "Offset")?.Valor ?? "0", out double offset);
|
||||
double massa_calc = (massaLida_Kg_bruto * 1) + offset;
|
||||
MassaAtual_Kg = massaLida_Kg;
|
||||
MassaAtual_Kg_Calc = massaCalc_Kg;
|
||||
VolumeAtual_L = volumeMedido_L;
|
||||
|
||||
double volumeMedido_L = massa_calc / DensidadeProduto;
|
||||
int qtd_atuacoes = Variaveis.OperacaoEmAndamento.Controle?.Bicos?.Sum(x => x.Atuacoes) ?? 0;
|
||||
BicosAtivos = ObterQuantidadeBicosAtivos();
|
||||
Pulverizando = BicosAtivos > 0;
|
||||
|
||||
// Sanitiza volume
|
||||
if (volumeMedido_L < 0) volumeMedido_L = 0;
|
||||
if (volumeMedido_L > CapacidadeLitros) volumeMedido_L = CapacidadeLitros;
|
||||
VazaoFluxoAtual_mLs = ObterVazaoFluxo_mLs();
|
||||
VazaoEstimativaBicos_mLs = BicosAtivos * VazaoPorBicoBase_mLs;
|
||||
VazaoReferencia_mLs = VazaoFluxoAtual_mLs > 0
|
||||
? VazaoFluxoAtual_mLs
|
||||
: VazaoEstimativaBicos_mLs;
|
||||
|
||||
LPorMinutoEstimadoBicos = VazaoEstimativaBicos_mLs * 60.0 / 1000.0;
|
||||
|
||||
PulverizadorLiberado =
|
||||
PercentualAtual >= VariaveisEquipamento.PercentualReservatorioMinCritio;
|
||||
|
||||
// Inicialização
|
||||
if (!_inicializado)
|
||||
{
|
||||
_inicializado = true;
|
||||
_volumeAnterior_L = volumeMedido_L;
|
||||
_distanciaTotalAnterior_m = distanciaTotalMetrosAtual;
|
||||
_tempoTotalAnterior_s = tempoTotalSegundosAtual;
|
||||
|
||||
MassaAtual_Kg = massaLida_Kg;
|
||||
MassaAtual_Kg_Calc = massa_calc;
|
||||
VolumeAtual_L = volumeMedido_L;
|
||||
Inicializar(distanciaTotalMetrosAtual, tempoTotalSegundosAtual);
|
||||
AtualizarAutonomia(velocidadeAtual_m_s);
|
||||
return;
|
||||
}
|
||||
|
||||
MassaAtual_Kg = massaLida_Kg;
|
||||
MassaAtual_Kg_Calc = massa_calc;
|
||||
VolumeAtual_L = volumeMedido_L;
|
||||
double deltaVolumeMassa_L = Math.Max(0, _volumeAnterior_L - VolumeAtual_L);
|
||||
_volumeAnterior_L = VolumeAtual_L;
|
||||
|
||||
PulverizadorLiberado = PercentualAtual >= VariaveisEquipamento.PercentualReservatorioMinCritio;
|
||||
|
||||
// --- Cálculo de deltas básicos ---
|
||||
|
||||
double deltaVolume_L = 0.0;
|
||||
double diffVol = _volumeAnterior_L - volumeMedido_L;
|
||||
|
||||
// Só considera volume consumido (queda de nível) e apenas quando pulverizando
|
||||
if (pulverizando && diffVol > 0)
|
||||
{
|
||||
deltaVolume_L = diffVol;
|
||||
VolumeConsumido_L += deltaVolume_L;
|
||||
}
|
||||
|
||||
if (qtd_atuacoes > 0)
|
||||
{
|
||||
HerbicidaPorAtuacao = VolumeConsumido_L / qtd_atuacoes;
|
||||
}
|
||||
|
||||
_volumeAnterior_L = volumeMedido_L;
|
||||
|
||||
double deltaDist_m = distanciaTotalMetrosAtual - _distanciaTotalAnterior_m;
|
||||
if (deltaDist_m < 0) deltaDist_m = 0;
|
||||
double deltaDist_m = Math.Max(0, distanciaTotalMetrosAtual - _distanciaTotalAnterior_m);
|
||||
_distanciaTotalAnterior_m = distanciaTotalMetrosAtual;
|
||||
|
||||
double deltaTempo_s = tempoTotalSegundosAtual - _tempoTotalAnterior_s;
|
||||
if (deltaTempo_s < 0) deltaTempo_s = 0;
|
||||
double deltaTempo_s = Math.Max(0, tempoTotalSegundosAtual - _tempoTotalAnterior_s);
|
||||
_tempoTotalAnterior_s = tempoTotalSegundosAtual;
|
||||
|
||||
// --- Atualiza janela de distância (L/m) ---
|
||||
AtualizarJanelaDistancia(deltaDist_m, deltaVolume_L, pulverizando);
|
||||
double deltaVolumeFluxo_L = 0;
|
||||
|
||||
// --- Atualiza janela de tempo (L/min) ---
|
||||
AtualizarJanelaTempo(deltaTempo_s, deltaVolume_L, pulverizando);
|
||||
if (Pulverizando && deltaTempo_s > 0 && VazaoReferencia_mLs > 0)
|
||||
deltaVolumeFluxo_L = VazaoReferencia_mLs * deltaTempo_s / 1000.0;
|
||||
|
||||
// --- Atualiza métricas de autonomia ---
|
||||
AtualizarAutonomia();
|
||||
double deltaVolumeParaTaxa_L = EscolherDeltaVolumeParaTaxa(deltaVolumeMassa_L, deltaVolumeFluxo_L);
|
||||
|
||||
if (Pulverizando && deltaVolumeParaTaxa_L > 0)
|
||||
{
|
||||
AtualizarJanelaDistancia(deltaDist_m, deltaVolumeParaTaxa_L);
|
||||
AtualizarJanelaTempo(deltaTempo_s, deltaVolumeParaTaxa_L);
|
||||
}
|
||||
|
||||
AtualizarHerbicidaPorAtuacao();
|
||||
AtualizarAutonomia(velocidadeAtual_m_s);
|
||||
}
|
||||
|
||||
private void AtualizarJanelaDistancia(double deltaDist_m, double deltaVolume_L, bool pulverizando)
|
||||
private double EscolherDeltaVolumeParaTaxa(double deltaMassa_L, double deltaFluxo_L)
|
||||
{
|
||||
// Só faz sentido atualizar se o robô andou e estava pulverizando
|
||||
if (!pulverizando || deltaDist_m <= 0 || deltaVolume_L <= 0)
|
||||
if (deltaFluxo_L > 0)
|
||||
return deltaFluxo_L;
|
||||
|
||||
return deltaMassa_L;
|
||||
}
|
||||
|
||||
private void LerReservatorio(out double massaLida_Kg, out double massaCalc_Kg, out double volumeMedido_L)
|
||||
{
|
||||
massaLida_Kg = SensorMassaReservatorio?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Massa)?.atual?.valor ?? 0;
|
||||
|
||||
double leituraBruta = SensorMassaReservatorio?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.LeituraBruta)?.atual?.valor ?? 0;
|
||||
|
||||
double.TryParse(SensorMassaReservatorio?.Parametros?.FirstOrDefault(x => x.Descricao == "Offset")?.Valor ?? "0", out double offset);
|
||||
|
||||
massaCalc_Kg = leituraBruta + offset;
|
||||
|
||||
volumeMedido_L = DensidadeProduto > 0 ? massaCalc_Kg / DensidadeProduto : 0;
|
||||
|
||||
volumeMedido_L = Clamp(volumeMedido_L, 0, CapacidadeLitros);
|
||||
}
|
||||
|
||||
private double ObterVazaoFluxo_mLs()
|
||||
{
|
||||
var dados = Variaveis.OperacaoEmAndamento.DispAtu?.Dados;
|
||||
|
||||
if (dados == null)
|
||||
return 0;
|
||||
|
||||
double vazao = dados.VazaoFluxoMLpSReferencia;
|
||||
|
||||
if (vazao < 0)
|
||||
return 0;
|
||||
|
||||
return vazao;
|
||||
}
|
||||
|
||||
private int ObterQuantidadeBicosAtivos()
|
||||
{
|
||||
return Variaveis.OperacaoEmAndamento.DispAtu?.Dados?.BicosPulverizadores?.Count(x => x.Inicializado && x.ComandoAtuar) ?? 0;
|
||||
}
|
||||
|
||||
private void Inicializar(double distanciaTotalMetrosAtual, double tempoTotalSegundosAtual)
|
||||
{
|
||||
_inicializado = true;
|
||||
|
||||
_volumeInicialInstancia_L = VolumeAtual_L;
|
||||
_volumeAnterior_L = VolumeAtual_L;
|
||||
|
||||
_distanciaTotalAnterior_m = distanciaTotalMetrosAtual;
|
||||
_tempoTotalAnterior_s = tempoTotalSegundosAtual;
|
||||
}
|
||||
|
||||
private void AtualizarJanelaDistancia(double deltaDist_m, double deltaVolume_L)
|
||||
{
|
||||
if (deltaDist_m <= 0 || deltaVolume_L <= 0)
|
||||
return;
|
||||
|
||||
_janelaDist.Enqueue((deltaDist_m, deltaVolume_L));
|
||||
|
||||
_somaDistanciaJanela_m += deltaDist_m;
|
||||
_somaVolumeDistJanela_L += deltaVolume_L;
|
||||
|
||||
// Mantém a janela limitada a JanelaAutonomia_m
|
||||
while (_somaDistanciaJanela_m > JanelaAutonomia_m && _janelaDist.Count > 0)
|
||||
{
|
||||
var (dOld, vOld) = _janelaDist.Dequeue();
|
||||
_somaDistanciaJanela_m -= dOld;
|
||||
_somaVolumeDistJanela_L -= vOld;
|
||||
var old = _janelaDist.Dequeue();
|
||||
|
||||
_somaDistanciaJanela_m -= old.dist_m;
|
||||
_somaVolumeDistJanela_L -= old.vol_L;
|
||||
}
|
||||
|
||||
if (_somaDistanciaJanela_m > 0 && _somaVolumeDistJanela_L > 0)
|
||||
if (_somaDistanciaJanela_m > 0.5)
|
||||
{
|
||||
LPorMetro = _somaVolumeDistJanela_L / _somaDistanciaJanela_m;
|
||||
|
||||
double alpha = 0.2;
|
||||
if (LPorMetroHistorico <= 0)
|
||||
LPorMetroHistorico = LPorMetro;
|
||||
else
|
||||
LPorMetroHistorico = LPorMetroHistorico * (1 - alpha) + LPorMetro * alpha;
|
||||
const double alpha = 0.2;
|
||||
|
||||
LPorMetroHistorico = LPorMetroHistorico <= 0
|
||||
? LPorMetro
|
||||
: LPorMetroHistorico * (1.0 - alpha) + LPorMetro * alpha;
|
||||
}
|
||||
}
|
||||
|
||||
private void AtualizarJanelaTempo(double deltaTempo_s, double deltaVolume_L, bool pulverizando)
|
||||
private void AtualizarJanelaTempo(double deltaTempo_s, double deltaVolume_L)
|
||||
{
|
||||
// Só faz sentido atualizar se o tempo avançou, estava pulverizando e houve consumo
|
||||
if (!pulverizando || deltaTempo_s <= 0 || deltaVolume_L <= 0)
|
||||
if (deltaTempo_s <= 0 || deltaVolume_L <= 0)
|
||||
return;
|
||||
|
||||
_janelaTempo.Enqueue((deltaTempo_s, deltaVolume_L));
|
||||
|
||||
_somaTempoJanela_s += deltaTempo_s;
|
||||
_somaVolumeTempoJanela_L += deltaVolume_L;
|
||||
|
||||
// Mantém a janela de tempo limitada a JanelaTempo_s
|
||||
while (_somaTempoJanela_s > JanelaTempo_s && _janelaTempo.Count > 0)
|
||||
{
|
||||
var (tOld, vOld) = _janelaTempo.Dequeue();
|
||||
_somaTempoJanela_s -= tOld;
|
||||
_somaVolumeTempoJanela_L -= vOld;
|
||||
var old = _janelaTempo.Dequeue();
|
||||
|
||||
_somaTempoJanela_s -= old.tempo_s;
|
||||
_somaVolumeTempoJanela_L -= old.vol_L;
|
||||
}
|
||||
|
||||
if (_somaTempoJanela_s > 0 && _somaVolumeTempoJanela_L > 0)
|
||||
{
|
||||
// L/s * 60 = L/min
|
||||
if (_somaTempoJanela_s > 1.0)
|
||||
LPorMinuto = (_somaVolumeTempoJanela_L / _somaTempoJanela_s) * 60.0;
|
||||
}
|
||||
}
|
||||
|
||||
private void AtualizarAutonomia()
|
||||
private void AtualizarHerbicidaPorAtuacao()
|
||||
{
|
||||
// ----- Distância máxima pulverizando (m) -----
|
||||
if (VolumeAtual_L > 0 && LPorMetro > 0)
|
||||
{
|
||||
DistanciaMaximaTeorica_m = VolumeAtual_L / LPorMetro;
|
||||
int qtdAtuacoes = Variaveis.OperacaoEmAndamento.Controle?.Bicos?.Sum(x => x.Atuacoes) ?? 0;
|
||||
|
||||
double margem = FuncoesMatematicas.Clamp(MargemSegurancaAutonomia, 0.0, 0.9);
|
||||
DistanciaMaximaSegura_m = DistanciaMaximaTeorica_m * (1.0 - margem);
|
||||
if (DistanciaMaximaSegura_m < 0)
|
||||
DistanciaMaximaSegura_m = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
DistanciaMaximaTeorica_m = 0;
|
||||
DistanciaMaximaSegura_m = 0;
|
||||
}
|
||||
if (qtdAtuacoes > 0)
|
||||
HerbicidaPorAtuacao_L = VolumeConsumidoOperacao_L / qtdAtuacoes;
|
||||
}
|
||||
|
||||
// ----- Tempo máximo pulverizando (min) -----
|
||||
double consumoRef_LPorMetro = LPorMetroReferencia;
|
||||
private void AtualizarAutonomia(double velocidadeAtual_m_s)
|
||||
{
|
||||
double consumoRef_LPorMetro = CalcularLPorMetroReferencia(velocidadeAtual_m_s);
|
||||
|
||||
if (VolumeAtual_L > 0 && consumoRef_LPorMetro > 0)
|
||||
{
|
||||
DistanciaMaximaTeorica_m = VolumeAtual_L / consumoRef_LPorMetro;
|
||||
|
||||
double margem = FuncoesMatematicas.Clamp(MargemSegurancaAutonomia, 0.0, 0.9);
|
||||
double margem = Clamp(MargemSegurancaAutonomia, 0.0, 0.9);
|
||||
DistanciaMaximaSegura_m = DistanciaMaximaTeorica_m * (1.0 - margem);
|
||||
if (DistanciaMaximaSegura_m < 0)
|
||||
DistanciaMaximaSegura_m = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
DistanciaMaximaTeorica_m = 0;
|
||||
DistanciaMaximaSegura_m = 0;
|
||||
}
|
||||
|
||||
double consumoTempoRef_LMin = LPorMinuto > 0
|
||||
? LPorMinuto
|
||||
: LPorMinutoEstimadoBicos;
|
||||
|
||||
if (VolumeAtual_L > 0 && consumoTempoRef_LMin > 0)
|
||||
{
|
||||
double margem = Clamp(MargemSegurancaAutonomia, 0.0, 0.9);
|
||||
|
||||
TempoEstimadoMinutosPulverizando =
|
||||
(VolumeAtual_L / consumoTempoRef_LMin) * (1.0 - margem);
|
||||
}
|
||||
else
|
||||
{
|
||||
TempoEstimadoMinutosPulverizando = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private double CalcularLPorMetroReferencia(double velocidadeAtual_m_s)
|
||||
{
|
||||
if (LPorMetroHistorico > 0)
|
||||
return LPorMetroHistorico;
|
||||
|
||||
if (LPorMetro > 0)
|
||||
return LPorMetro;
|
||||
|
||||
double velocidade_m_min = velocidadeAtual_m_s * 60.0;
|
||||
|
||||
if (velocidade_m_min > 0.1 && LPorMinutoEstimadoBicos > 0)
|
||||
return LPorMinutoEstimadoBicos / velocidade_m_min;
|
||||
|
||||
return LPorMetroBase;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper direto para o Manager/Health:
|
||||
/// indica se o volume atual é suficiente para pulverizar uma rua de certo comprimento (m).
|
||||
/// </summary>
|
||||
public bool ConseguePulverizarRua(double comprimentoRua_m)
|
||||
{
|
||||
if (comprimentoRua_m <= 0)
|
||||
|
|
@ -342,28 +399,80 @@ namespace AgroBase.Services
|
|||
return DistanciaMaximaSegura_m >= comprimentoRua_m;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Permite "forçar" um volume inicial (por exemplo, depois de reabastecer).
|
||||
/// </summary>
|
||||
public void DefinirVolumeAtual(double volume_L)
|
||||
{
|
||||
volume_L = FuncoesMatematicas.Clamp(volume_L, 0, CapacidadeLitros);
|
||||
volume_L = Clamp(volume_L, 0, CapacidadeLitros);
|
||||
|
||||
VolumeAtual_L = volume_L;
|
||||
_volumeAnterior_L = volume_L;
|
||||
VolumeConsumido_L = CapacidadeLitros - VolumeAtual_L;
|
||||
_volumeInicialInstancia_L = volume_L;
|
||||
|
||||
// Zera as janelas (melhor não carregar histórico de antes de reabastecer)
|
||||
ResetarJanelas();
|
||||
}
|
||||
|
||||
private void ResetarTudo()
|
||||
{
|
||||
Iniciado = false;
|
||||
OperacaoAtiva = false;
|
||||
OperacaoFinalizada = false;
|
||||
|
||||
MassaAtual_Kg = 0;
|
||||
MassaAtual_Kg_Calc = 0;
|
||||
VolumeAtual_L = 0;
|
||||
|
||||
_volumeInicialInstancia_L = 0;
|
||||
_volumeInicialOperacao_L = 0;
|
||||
|
||||
BicosAtivos = 0;
|
||||
Pulverizando = false;
|
||||
PulverizadorLiberado = false;
|
||||
|
||||
VazaoFluxoAtual_mLs = 0;
|
||||
VazaoEstimativaBicos_mLs = 0;
|
||||
VazaoReferencia_mLs = 0;
|
||||
|
||||
LPorMetro = 0;
|
||||
LPorMetroHistorico = 0;
|
||||
LPorMetroBase = 0;
|
||||
LPorMinuto = 0;
|
||||
LPorMinutoEstimadoBicos = 0;
|
||||
|
||||
DistanciaMaximaTeorica_m = 0;
|
||||
DistanciaMaximaSegura_m = 0;
|
||||
TempoEstimadoMinutosPulverizando = 0;
|
||||
|
||||
HerbicidaPorAtuacao_L = 0;
|
||||
|
||||
_inicializado = false;
|
||||
_volumeAnterior_L = 0;
|
||||
_distanciaTotalAnterior_m = 0;
|
||||
_tempoTotalAnterior_s = 0;
|
||||
|
||||
ResetarJanelas();
|
||||
}
|
||||
|
||||
private void ResetarJanelas()
|
||||
{
|
||||
_janelaDist.Clear();
|
||||
_janelaTempo.Clear();
|
||||
|
||||
_somaDistanciaJanela_m = 0;
|
||||
_somaVolumeDistJanela_L = 0;
|
||||
|
||||
_somaTempoJanela_s = 0;
|
||||
_somaVolumeTempoJanela_L = 0;
|
||||
|
||||
LPorMetro = 0;
|
||||
LPorMinuto = 0;
|
||||
}
|
||||
|
||||
private static double Clamp(double value, double min, double max)
|
||||
{
|
||||
return FuncoesMatematicas.Clamp(value, min, max);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ---------------- AGITADOR ----------------
|
||||
|
||||
private bool _agitadorIntermitenteLigado = false;
|
||||
private DateTime _agitadorUltimaTroca = DateTime.MinValue;
|
||||
|
|
@ -378,7 +487,6 @@ namespace AgroBase.Services
|
|||
private int AtuAgitadorTempoDesligadoMs = 30000;
|
||||
private int AtuAgitadorBoostRetomadaMs = 15000;
|
||||
|
||||
|
||||
private double PotenciaLimitePorNivel(double nivelPct)
|
||||
{
|
||||
if (nivelPct <= 5) return 0;
|
||||
|
|
@ -402,7 +510,6 @@ namespace AgroBase.Services
|
|||
|
||||
bool operacaoIniciada = Variaveis.OperacaoEmAndamento?.Iniciado ?? false;
|
||||
bool pausado = Variaveis.OperacaoEmAndamento?.Pausa ?? false;
|
||||
|
||||
bool operacaoAtiva = operacaoIniciada && !pausado;
|
||||
|
||||
bool bicosAtuando =
|
||||
|
|
@ -412,7 +519,6 @@ namespace AgroBase.Services
|
|||
double potenciaFinal = 0;
|
||||
DateTime agora = DateTime.Now;
|
||||
|
||||
// Boost ao iniciar/retomar operação
|
||||
if (operacaoAtiva && !_agitadorOperacaoAtivaAnterior)
|
||||
{
|
||||
_agitadorBoostAte = agora.AddMilliseconds(AtuAgitadorBoostRetomadaMs);
|
||||
|
|
@ -438,10 +544,6 @@ namespace AgroBase.Services
|
|||
else
|
||||
potenciaFinal = AtuAgitadorPotenciaManutencao;
|
||||
}
|
||||
else
|
||||
{
|
||||
potenciaFinal = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case ModoAgitadorCalda.Intermitente:
|
||||
|
|
@ -472,18 +574,13 @@ namespace AgroBase.Services
|
|||
: 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
potenciaFinal = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
potenciaFinal = Math.Min(potenciaFinal, PotenciaLimitePorNivel(PercentualAtual));
|
||||
potenciaFinal = FuncoesMatematicas.Clamp(potenciaFinal, 0, 100);
|
||||
potenciaFinal = Clamp(potenciaFinal, 0, 100);
|
||||
|
||||
AgitadorCalda.PotenciaSP = potenciaFinal;
|
||||
_agitadorOperacaoAtivaAnterior = operacaoAtiva;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -104,9 +104,9 @@ namespace AgroBase.Services.Operadores
|
|||
{
|
||||
foreach (var cam in cameras)
|
||||
{
|
||||
var camera_str = RedisService.Get(RedisService.CamKey(cam.Key));
|
||||
var camera_str = RedisService.Get(RedisService.CamKey(cam.Key)) ?? "";
|
||||
var camera = JsonConvert.DeserializeObject<CameraWorkerItemModel>(camera_str);
|
||||
if (camera.mx_id == null) continue;
|
||||
if (camera?.mx_id == null) continue;
|
||||
CamerasConectadas.Add(camera);
|
||||
}
|
||||
}
|
||||
|
|
@ -114,5 +114,19 @@ namespace AgroBase.Services.Operadores
|
|||
return CamerasConectadas;
|
||||
}
|
||||
|
||||
public static OAKCameraModel AtualizarDadosCamera(string mx_id)
|
||||
{
|
||||
var cam = CamerasConectadas.FirstOrDefault(x => x.mx_id == mx_id);
|
||||
if (cam == null) return null;
|
||||
var camera_str = RedisService.Get(RedisService.CamKey(cam.mx_id)) ?? "";
|
||||
var camera = JsonConvert.DeserializeObject<CameraWorkerItemModel>(camera_str);
|
||||
if (camera?.mx_id == null) return null;
|
||||
var imu_str = RedisService.Get(RedisService.CamImuKey(cam.mx_id)) ?? "";
|
||||
var imu = JsonConvert.DeserializeObject<OAKImuModel>(imu_str);
|
||||
camera.imu = imu?.dados;
|
||||
cam = camera;
|
||||
return camera.ToOAK();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -221,12 +221,14 @@ namespace AgroBase.Services.Operadores
|
|||
("path_ia_model_ruas_seg", VersionamentoService.ArquivoModeloSegStreetDetector.CaminhoCompleto),
|
||||
("path_ia_labelmap_ruas_seg", VersionamentoService.ArquivoLabelmapSegStreetDetector.CaminhoCompleto),
|
||||
("path_ia_norm_stats_ruas_seg", VersionamentoService.ArquivoModeloNormstatsStreetDetector.CaminhoCompleto),
|
||||
("ia_backbone_ruas_seg", "nvidia/segformer-b0-finetuned-ade-512-512"),
|
||||
("ia_backbone_ruas_seg", "C:\\AgroBaseModels\\Backbones\\nvidia_mit_b0"),
|
||||
("ia_mode_ruas", "dual_label"),
|
||||
("path_ia_model_ruas_det", VersionamentoService.ArquivoModeloDetStreetDetector.CaminhoCompleto),
|
||||
("path_ia_model_ervas", VersionamentoService.ArquivoModeloWeedDetector.CaminhoCompleto),
|
||||
("path_ia_labelmap_ervas", VersionamentoService.ArquivoModeloLabelmapWeedDetector.CaminhoCompleto),
|
||||
("path_ia_norm_stats_ervas", VersionamentoService.ArquivoModeloNormstatsWeedDetector.CaminhoCompleto),
|
||||
("ia_backbone_ervas", "nvidia/segformer-b1-finetuned-ade-512-512"),
|
||||
("path_ia_module_params_ervas", VersionamentoService.ArquivoModeloModuleParamsWeedDetector.CaminhoCompleto),
|
||||
("ia_backbone_ervas", "C:\\AgroBaseModels\\Backbones\\nvidia_mit_b1"),
|
||||
("angulo_roll_max", VariaveisEquipamento.AnguloInclinacaoRollMax),
|
||||
("angulo_pitch_max", VariaveisEquipamento.AnguloInclinacaoPitchMax)
|
||||
);
|
||||
|
|
@ -313,9 +315,9 @@ namespace AgroBase.Services.Operadores
|
|||
),
|
||||
("Snr", new
|
||||
{
|
||||
percentual_altura_solo = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho.PercentualAlturaSolo,
|
||||
distancia_maxima = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho.DistanciaMaximaVisao,
|
||||
distancia_minima = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho.DistanciaMinimaVisao
|
||||
percentual_altura_solo = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho?.PercentualAlturaSolo ?? 0.1,
|
||||
distancia_maxima = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho?.DistanciaMaximaVisao ?? 5000,
|
||||
distancia_minima = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho?.DistanciaMinimaVisao ?? 300
|
||||
}
|
||||
)
|
||||
);
|
||||
|
|
@ -757,15 +759,76 @@ namespace AgroBase.Services.Operadores
|
|||
);
|
||||
|
||||
var DadosMod = _Sensoriamento.DadosPerformance;
|
||||
RedisService.AtualizarCampos(RedisService.ModKey(Enums.T_Code.Npc),
|
||||
RedisService.AtualizarCampos(
|
||||
RedisService.ModKey(Enums.T_Code.Npc),
|
||||
// Base / sincronismo
|
||||
("timestamp", agora),
|
||||
("timestamp_unix_ms", DadosMod.TimestampUnixMs),
|
||||
("freq_base", 1.0 / Variaveis.OperacaoEmAndamento.tmrLeiturasInterval),
|
||||
("cpu_load", DadosMod.CPU_load ?? 0),
|
||||
("gpu_load", DadosMod.GPU_load ?? 0),
|
||||
("hdd_load", DadosMod.HDD_load ?? 0),
|
||||
("ram_usage", DadosMod.RAM_usage ?? 0),
|
||||
("cpu_temp", DadosMod.CPU_temp ?? 0),
|
||||
("gpu_temp", DadosMod.GPU_temp ?? 0)
|
||||
|
||||
// CPU
|
||||
("cpu_load_percent", DadosMod.CPU_load_percent ?? 0),
|
||||
("cpu_temp_package_c", DadosMod.CPU_temp_package_c ?? 0),
|
||||
("cpu_power_package_w", DadosMod.CPU_power_package_w ?? 0),
|
||||
("cpu_power_cores_w", DadosMod.CPU_power_cores_w ?? 0),
|
||||
("cpu_power_graphics_w", DadosMod.CPU_power_graphics_w ?? 0),
|
||||
("cpu_power_dram_w", DadosMod.CPU_power_dram_w ?? 0),
|
||||
("cpu_clock_avg_mhz", DadosMod.CPU_clock_avg_mhz ?? 0),
|
||||
("cpu_clock_max_mhz", DadosMod.CPU_clock_max_mhz ?? 0),
|
||||
("cpu_bus_speed_mhz", DadosMod.CPU_bus_speed_mhz ?? 0),
|
||||
|
||||
// RAM
|
||||
("ram_usage_percent", DadosMod.RAM_usage_percent ?? 0),
|
||||
("ram_used_gb", DadosMod.RAM_used_gb ?? 0),
|
||||
("ram_available_gb", DadosMod.RAM_available_gb ?? 0),
|
||||
("ram_total_gb", DadosMod.RAM_total_gb ?? 0),
|
||||
|
||||
// GPU loads
|
||||
("gpu_load_percent", DadosMod.GPU_load_percent ?? 0),
|
||||
("gpu_core_load_percent", DadosMod.GPU_core_load_percent ?? 0),
|
||||
("gpu_frame_buffer_load_percent", DadosMod.GPU_frame_buffer_load_percent ?? 0),
|
||||
("gpu_memory_load_percent", DadosMod.GPU_memory_load_percent ?? 0),
|
||||
("gpu_video_engine_load_percent", DadosMod.GPU_video_engine_load_percent ?? 0),
|
||||
("gpu_bus_interface_load_percent", DadosMod.GPU_bus_interface_load_percent ?? 0),
|
||||
|
||||
// GPU térmico / energia / clock
|
||||
("gpu_temp_core_c", DadosMod.GPU_temp_core_c ?? 0),
|
||||
("gpu_power_w", DadosMod.GPU_power_w ?? 0),
|
||||
("gpu_core_clock_mhz", DadosMod.GPU_core_clock_mhz ?? 0),
|
||||
("gpu_memory_clock_mhz", DadosMod.GPU_memory_clock_mhz ?? 0),
|
||||
("gpu_shader_clock_mhz", DadosMod.GPU_shader_clock_mhz ?? 0),
|
||||
|
||||
// GPU fan / PCIe
|
||||
("gpu_fan_percent", DadosMod.GPU_fan_percent ?? 0),
|
||||
("gpu_fan_rpm", DadosMod.GPU_fan_rpm ?? 0),
|
||||
("gpu_pcie_rx", DadosMod.GPU_pcie_rx ?? 0),
|
||||
("gpu_pcie_tx", DadosMod.GPU_pcie_tx ?? 0),
|
||||
|
||||
// VRAM
|
||||
("gpu_vram_total_mb", DadosMod.GPU_vram_total_mb ?? 0),
|
||||
("gpu_vram_used_mb", DadosMod.GPU_vram_used_mb ?? 0),
|
||||
("gpu_vram_free_mb", DadosMod.GPU_vram_free_mb ?? 0),
|
||||
("gpu_vram_used_percent", DadosMod.GPU_vram_used_percent ?? 0),
|
||||
|
||||
// Disco
|
||||
("disk_used_space_percent", DadosMod.Disk_used_space_percent ?? 0),
|
||||
|
||||
// Processo C#
|
||||
("process_thread_count", DadosMod.Process_thread_count),
|
||||
("process_working_set_mb", DadosMod.Process_working_set_mb),
|
||||
("process_private_memory_mb", DadosMod.Process_private_memory_mb),
|
||||
("process_virtual_memory_mb", DadosMod.Process_virtual_memory_mb),
|
||||
("process_cpu_time_total_s", DadosMod.Process_cpu_time_total_s),
|
||||
|
||||
// ThreadPool
|
||||
("threadpool_available_worker_threads", DadosMod.ThreadPool_available_worker_threads),
|
||||
("threadpool_available_completion_port_threads", DadosMod.ThreadPool_available_completion_port_threads),
|
||||
("threadpool_max_worker_threads", DadosMod.ThreadPool_max_worker_threads),
|
||||
("threadpool_max_completion_port_threads", DadosMod.ThreadPool_max_completion_port_threads),
|
||||
("threadpool_used_worker_threads", DadosMod.ThreadPool_used_worker_threads),
|
||||
("threadpool_used_completion_port_threads", DadosMod.ThreadPool_used_completion_port_threads),
|
||||
("threadpool_used_worker_percent", DadosMod.ThreadPool_used_worker_percent),
|
||||
("threadpool_used_completion_port_percent", DadosMod.ThreadPool_used_completion_port_percent)
|
||||
);
|
||||
|
||||
var DadosCan = CanManager.CanService;
|
||||
|
|
|
|||
|
|
@ -31,6 +31,11 @@ namespace AgroBase.Services
|
|||
return CtxKey.DadosCameras + mx_id;
|
||||
}
|
||||
|
||||
public static string CamImuKey(string mx_id)
|
||||
{
|
||||
return CtxKey.DadosCameras + mx_id + "_Imu";
|
||||
}
|
||||
|
||||
public static string Get(string chave)
|
||||
{
|
||||
return _db.StringGet(chave);
|
||||
|
|
|
|||
|
|
@ -92,6 +92,16 @@ namespace AgroBase.Services
|
|||
}
|
||||
}
|
||||
}
|
||||
public static VersaoArquivoModel ArquivoModeloModuleParamsWeedDetector
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_ArquivoLock)
|
||||
{
|
||||
return _ArquivosVersionados.Where(x => x.TipoArquivo == TipoArquivoVersionado.ModeloIA_WeedDetector).Skip(3).FirstOrDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
public static VersaoArquivoModel ArquivoParametros(T_Code Dispositivo)
|
||||
{
|
||||
lock (_ArquivoLock)
|
||||
|
|
|
|||
Loading…
Reference in New Issue