This commit is contained in:
Diego Freitas 2026-05-21 19:48:36 -03:00
parent d42a7d4005
commit 7c8da7e435
21 changed files with 1732 additions and 673 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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
if (pulsos <= 0 || periodo <= 0)
return 0.0;
// Equação do fabricante: F = 8.1*q - 3 (q em L/min)
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.310 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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