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); nudPressaoSP.Value = Convert.ToInt32(Variaveis.OperacaoEmAndamento.Parametros.Controle.AtuPressaoLinha);
txtPressaoVmin.Text = DispAtu.Dados._PressaoVmin.ToString(); txtPressaoVmin.Text = DispAtu.Dados._PressaoVmin.ToString();
txtPressaoVmax.Text = DispAtu.Dados._PressaoVmax.ToString(); txtPressaoVmax.Text = DispAtu.Dados._PressaoVmax.ToString();
txtMLRef.Text = DispAtu.Dados._FluxoMlRef.ToString(); txtMLRef.Text = DispAtu.Dados.VazaoFluxoMLpSReferencia.ToString();
txtPulsosRef.Text = DispAtu.Dados._FluxoPulsoRef.ToString(); //txtPulsosRef.Text = DispAtu.Dados._FluxoPulsoRef.ToString();
txtVolume.Text = DispAtu.Dados.VolumeVazaoAferido.ToString(); txtVolume.Text = DispAtu.Dados.VolumeVazaoAferido.ToString();
grdSensoriamento.Rows.Clear(); grdSensoriamento.Rows.Clear();
@ -207,8 +207,8 @@ namespace AgroBase.Forms.Atuador
Variaveis.OperacaoEmAndamento.Parametros.Controle.AtuPressaoLinha = Convert.ToDouble(nudPressaoSP.Value); Variaveis.OperacaoEmAndamento.Parametros.Controle.AtuPressaoLinha = Convert.ToDouble(nudPressaoSP.Value);
DispAtu.Dados._PressaoVmin = Convert.ToDouble(txtPressaoVmin.Text); DispAtu.Dados._PressaoVmin = Convert.ToDouble(txtPressaoVmin.Text);
DispAtu.Dados._PressaoVmax = Convert.ToDouble(txtPressaoVmax.Text); DispAtu.Dados._PressaoVmax = Convert.ToDouble(txtPressaoVmax.Text);
DispAtu.Dados._FluxoMlRef = Convert.ToDouble(txtMLRef.Text); //DispAtu.Dados._FluxoMlRef = Convert.ToDouble(txtMLRef.Text);
DispAtu.Dados._FluxoPulsoRef = Convert.ToDouble(txtPulsosRef.Text); //DispAtu.Dados._FluxoPulsoRef = Convert.ToDouble(txtPulsosRef.Text);
DispAtu.Dados.VolumeVazaoAferido = Convert.ToDouble(txtVolume.Text); DispAtu.Dados.VolumeVazaoAferido = Convert.ToDouble(txtVolume.Text);
} }

View File

@ -1,9 +1,6 @@
using AgroBase.Models; using AgroBase.Models;
using AgroBase.Models.Components; using AgroBase.Models.Components;
using AgroBase.Models.Operadores;
using AgroBase.Services;
using AgroBase.Services.Operadores; using AgroBase.Services.Operadores;
using Assimp;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data; using System.Data;
@ -264,14 +261,14 @@ namespace AgroBase.Forms.IHM
var cameras = CameraWorkerService.GetListaCameras(); var cameras = CameraWorkerService.GetListaCameras();
ListaCameras = cameras.Select(x => new OAKCameraModel() ListaCameras = cameras.Select(x => new OAKCameraModel()
{ {
Index = 0, Index = cameras.IndexOf(x),
Dispositivo = x.dispositivo, Dispositivo = x.dispositivo,
Version = x.versao, Version = x.versao,
Name = x.modelo, Name = x.modelo,
Id = x.mx_id, Id = x.mx_id,
}).ToList(); }).ToList();
CameraCaminho = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho.Clone(); CameraCaminho = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho?.Clone();
CamerasSolo = new List<OAKCameraModel>(Variaveis.OperacaoEmAndamento.DispSen.Dados.CamerasSolo); CamerasSolo = new List<OAKCameraModel>(Variaveis.OperacaoEmAndamento.DispSen.Dados.CamerasSolo);
for (int i = 0; i < Variaveis.OperacaoEmAndamento.Parametros.QtdCamerasSolo; i++) for (int i = 0; i < Variaveis.OperacaoEmAndamento.Parametros.QtdCamerasSolo; i++)
@ -281,7 +278,7 @@ namespace AgroBase.Forms.IHM
cmbCameraCaminho.Items.Clear(); cmbCameraCaminho.Items.Clear();
cmbCameraCaminho.Items.AddRange(ListaCameras.Select(x => x.Description).ToArray()); 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) if (cameraSelecionada != null)
{ {
cmbCameraCaminho.SelectedIndex = cmbCameraCaminho.Items.IndexOf(cameraSelecionada.Description); cmbCameraCaminho.SelectedIndex = cmbCameraCaminho.Items.IndexOf(cameraSelecionada.Description);
@ -344,7 +341,7 @@ namespace AgroBase.Forms.IHM
CamerasSolo.Add(new OAKCameraModel()); 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) if (cameraSelecionada != null)
{ {
@ -410,11 +407,11 @@ namespace AgroBase.Forms.IHM
{ {
if (idx == -1) if (idx == -1)
{ {
emUso = CamerasSolo.Any(x => x.Id == cam.Id); emUso = CamerasSolo.Any(x => cam.Id != null && x.Id == cam.Id);
} }
else 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.flwCamerasSolo = new System.Windows.Forms.FlowLayoutPanel();
this.chbSonarAtivado = new System.Windows.Forms.CheckBox(); this.chbSonarAtivado = new System.Windows.Forms.CheckBox();
this.lblPressao = new System.Windows.Forms.Label(); this.lblPressao = new System.Windows.Forms.Label();
this.lblStatusCarroMapa = new System.Windows.Forms.Label();
((System.ComponentModel.ISupportInitialize)(this.chartGraficos)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.chartGraficos)).BeginInit();
this.tabControl1.SuspendLayout(); this.tabControl1.SuspendLayout();
this.tabMapa.SuspendLayout(); this.tabMapa.SuspendLayout();
@ -352,6 +353,7 @@
// //
// tabDeteccoes // tabDeteccoes
// //
this.tabDeteccoes.Controls.Add(this.lblStatusCarroMapa);
this.tabDeteccoes.Controls.Add(this.pnlDeteccoesRua); this.tabDeteccoes.Controls.Add(this.pnlDeteccoesRua);
this.tabDeteccoes.Location = new System.Drawing.Point(4, 22); this.tabDeteccoes.Location = new System.Drawing.Point(4, 22);
this.tabDeteccoes.Margin = new System.Windows.Forms.Padding(2); this.tabDeteccoes.Margin = new System.Windows.Forms.Padding(2);
@ -721,6 +723,16 @@
this.lblPressao.TabIndex = 38; this.lblPressao.TabIndex = 38;
this.lblPressao.Text = "80 psi"; 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 // frmOperacaoManual
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@ -763,6 +775,7 @@
this.tabInformacoes.ResumeLayout(false); this.tabInformacoes.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.gridDados)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.gridDados)).EndInit();
this.tabDeteccoes.ResumeLayout(false); this.tabDeteccoes.ResumeLayout(false);
this.tabDeteccoes.PerformLayout();
this.tabPulverizador.ResumeLayout(false); this.tabPulverizador.ResumeLayout(false);
this.tabPulverizador.PerformLayout(); this.tabPulverizador.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.nudPotenciaSP)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.nudPotenciaSP)).EndInit();
@ -835,5 +848,6 @@
private System.Windows.Forms.Label lblPotenciaSP; private System.Windows.Forms.Label lblPotenciaSP;
private System.Windows.Forms.NumericUpDown nudPotenciaSP; private System.Windows.Forms.NumericUpDown nudPotenciaSP;
private System.Windows.Forms.Label lblPressao; 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); //var frameSeg = await VisualWorkerService.GetCameraFrame(CameraFrameType.Segmentacao);
//AtualizarImagemPainel(pnlDeteccoesRua, frameSeg?.image()); //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 finally
{ {

View File

@ -736,65 +736,44 @@ namespace AgroBase.Forms.Operacoes
{ {
new GraficoInterativoSerieModel() new GraficoInterativoSerieModel()
{ {
Titulo = "CPU %", Titulo = "GPU Geral %",
Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.CPU_load ?? 0)).ToList(), Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.GPU_load_percent ?? 0)).ToList(),
Visivel = true, Visivel = true,
MostrarValor = true MostrarValor = true
}, },
new GraficoInterativoSerieModel() new GraficoInterativoSerieModel()
{ {
Titulo = "GPU %", Titulo = "GPU Core %",
Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.GPU_load ?? 0)).ToList(), Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.GPU_core_load_percent ?? 0)).ToList(),
Visivel = true, Visivel = true,
MostrarValor = true MostrarValor = true
}, },
new GraficoInterativoSerieModel() new GraficoInterativoSerieModel()
{ {
Titulo = "HDD %", Titulo = "GPU Memory %",
Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.HDD_load ?? 0)).ToList(), Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.GPU_memory_load_percent ?? 0)).ToList(),
Visivel = true, Visivel = true,
MostrarValor = true MostrarValor = true
}, },
new GraficoInterativoSerieModel() new GraficoInterativoSerieModel()
{ {
Titulo = "RAM %", Titulo = "GPU Frame Buffer %",
Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.RAM_usage ?? 0)).ToList(), Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.GPU_frame_buffer_load_percent ?? 0)).ToList(),
Visivel = true, Visivel = true,
MostrarValor = true MostrarValor = true
}, },
new GraficoInterativoSerieModel() new GraficoInterativoSerieModel()
{ {
Titulo = "CPU Temp", Titulo = "GPU Video Engine %",
Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.CPU_temp ?? 0)).ToList(), Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.GPU_video_engine_load_percent ?? 0)).ToList(),
Visivel = true, Visivel = false,
MostrarValor = true MostrarValor = true
}, },
new GraficoInterativoSerieModel() new GraficoInterativoSerieModel()
{ {
Titulo = "GPU Temp", Titulo = "GPU Bus Interface %",
Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.GPU_temp ?? 0)).ToList(), Valores = LogsOperacao.Select(x => (double)(x?.DadosPerformance.GPU_bus_interface_load_percent ?? 0)).ToList(),
Visivel = true, Visivel = false,
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,
MostrarValor = true MostrarValor = true
}, },
}); });
@ -1148,11 +1127,6 @@ namespace AgroBase.Forms.Operacoes
var Log = LogsOperacao[idxMomentoAtual]; var Log = LogsOperacao[idxMomentoAtual];
var LogAtu = LogsAtuador[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")}%"; lblPercentualBateria.Text = $"Bateria {Log.Bateria.PercentualBateria.ToString("0.00")}%";
FuncoesGlobais.PreencheValorProgressBar(pgbPercentualBateria, Log.Bateria.PercentualBateria); FuncoesGlobais.PreencheValorProgressBar(pgbPercentualBateria, Log.Bateria.PercentualBateria);
@ -1162,13 +1136,13 @@ namespace AgroBase.Forms.Operacoes
lblPercentualReservatorio.Text = $"Reservatório {LogAtu.PercentualReservatorio.ToString("0.00")}%"; lblPercentualReservatorio.Text = $"Reservatório {LogAtu.PercentualReservatorio.ToString("0.00")}%";
FuncoesGlobais.PreencheValorProgressBar(pgbPercentualReservatorio, LogAtu.PercentualReservatorio); FuncoesGlobais.PreencheValorProgressBar(pgbPercentualReservatorio, LogAtu.PercentualReservatorio);
lblHerbicidaConsumido.Text = $"Consumido {herbicidaConsumido.ToString("0.00")} ml"; lblHerbicidaConsumido.Text = $"Consumido {LogAtu.PercentualHerbicidaConsumidoOperacao.ToString("0.00")} ml";
FuncoesGlobais.PreencheValorProgressBar(pgbHerbicidaConsumido, percentualHerbicidaConsumido); FuncoesGlobais.PreencheValorProgressBar(pgbHerbicidaConsumido, LogAtu.PercentualHerbicidaConsumidoOperacao);
txtTempoMovimento.Text = FuncoesGlobais.ConverterSegundosParaHHmmss((int)Log.Movimentacao.TempoMovimentoSegs); txtTempoMovimento.Text = FuncoesGlobais.ConverterSegundosParaHHmmss((int)Log.Movimentacao.TempoMovimentoSegs);
txtStatusOperacao.Text = Log.StatusOperacao.ToString(); txtStatusOperacao.Text = Log.StatusOperacao.ToString();
txtStatusCarro.Text = $"{Log.Trajetoria.StatusCarro}"; 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"; 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 + ")"; 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") + "%)"; 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)"; 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)"; 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"; 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"; 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"; 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.cmbAlgoritmo = new System.Windows.Forms.ComboBox();
this.lblAlgoritmo = new System.Windows.Forms.Label(); this.lblAlgoritmo = new System.Windows.Forms.Label();
this.btnSalvarAlgoritmo = new System.Windows.Forms.Button(); 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.gridDados)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.picBussola)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.picBussola)).BeginInit();
this.SuspendLayout(); this.SuspendLayout();
@ -218,12 +220,34 @@
this.btnSalvarAlgoritmo.UseVisualStyleBackColor = true; this.btnSalvarAlgoritmo.UseVisualStyleBackColor = true;
this.btnSalvarAlgoritmo.Click += new System.EventHandler(this.btnSalvarAlgoritmo_Click); 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 // frmWT901C
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.White; this.BackColor = System.Drawing.Color.White;
this.ClientSize = new System.Drawing.Size(1088, 660); 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.btnSalvarAlgoritmo);
this.Controls.Add(this.lblAlgoritmo); this.Controls.Add(this.lblAlgoritmo);
this.Controls.Add(this.cmbAlgoritmo); this.Controls.Add(this.cmbAlgoritmo);
@ -270,5 +294,7 @@
private System.Windows.Forms.ComboBox cmbAlgoritmo; private System.Windows.Forms.ComboBox cmbAlgoritmo;
private System.Windows.Forms.Label lblAlgoritmo; private System.Windows.Forms.Label lblAlgoritmo;
private System.Windows.Forms.Button btnSalvarAlgoritmo; 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.Drawing.Drawing2D;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Linq; using System.Linq;
using AgroBase.Services.Operadores;
using System.Collections.Generic;
using AgroBase.Models.Operadores;
namespace AgroBase.Forms namespace AgroBase.Forms
{ {
@ -17,6 +20,7 @@ namespace AgroBase.Forms
double AnguloZ = 0; double AnguloZ = 0;
private Visualizador3DService visualizador3D; private Visualizador3DService visualizador3D;
AsyncTaskTimerModel tmrLeitura; AsyncTaskTimerModel tmrLeitura;
List<CameraWorkerItemModel> ListaCameras = new List<CameraWorkerItemModel>();
//WT901C485 WT901C = Variaveis.WT901C; //WT901C485 WT901C = Variaveis.WT901C;
public frmWT901C() public frmWT901C()
@ -50,6 +54,8 @@ namespace AgroBase.Forms
cmbAlgoritmo.Items.Clear(); cmbAlgoritmo.Items.Clear();
cmbAlgoritmo.Items.AddRange(new string[] { "6 Eixos", "9 Eixos" }); cmbAlgoritmo.Items.AddRange(new string[] { "6 Eixos", "9 Eixos" });
AtualizarListaCameras();
} }
private void frmWT901C_FormClosing(object sender, FormClosingEventArgs e) private void frmWT901C_FormClosing(object sender, FormClosingEventArgs e)
@ -59,7 +65,24 @@ namespace AgroBase.Forms
private async Task tmrLeitura_Tick() 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; AnguloX = Imu.InclinacaoFrontal;
AnguloY = Imu.InclinacaoLateral; AnguloY = Imu.InclinacaoLateral;
AnguloZ = Imu.Rotacao; AnguloZ = Imu.Rotacao;
@ -68,6 +91,13 @@ namespace AgroBase.Forms
AtualizarDadosTela(); AtualizarDadosTela();
} }
private void AtualizarListaCameras()
{
ListaCameras = CameraWorkerService.GetListaCameras();
cmbDispositivo.Items.Clear();
cmbDispositivo.Items.AddRange(ListaCameras.Select(x => x.modelo).ToArray());
}
private void PopularDadosGrid() private void PopularDadosGrid()
{ {
gridDados.Rows.Clear(); gridDados.Rows.Clear();
@ -371,6 +401,5 @@ namespace AgroBase.Forms
{ {
await WT901CService.AlterarAlgoritmo(cmbAlgoritmo.SelectedIndex == 1); await WT901CService.AlterarAlgoritmo(cmbAlgoritmo.SelectedIndex == 1);
} }
} }
} }

View File

@ -86,133 +86,143 @@ namespace AgroBase.Models.Modules
public HerbicideCounterService ContadorCarga = new HerbicideCounterService(VariaveisEquipamento.CapacidadeReservatorio, VariaveisEquipamento.DensidadeHerbicida); public HerbicideCounterService ContadorCarga = new HerbicideCounterService(VariaveisEquipamento.CapacidadeReservatorio, VariaveisEquipamento.DensidadeHerbicida);
#region VAZAO #region VAZAO
private SensorModel SensorFluxoLinha => Sensores.FirstOrDefault(x => x.Componente == S_Code.sFLX && x.ID == "FLXLN"); private SensorModel SensorFluxoLinha => Sensores.FirstOrDefault(x => x.Componente == S_Code.sFLX && x.ID == "FLXLN");
public double VolumeVazaoAferido { get; set; } = 0; 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 VazaoFluxoMLpSInstantanea => SensorFluxoLinha?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Fluxo)?.atual?.valor ?? 0;
public double VazaoFluxoMLpSInstantaneaCalc public double VazaoFluxoMLpSInstantaneaCalc
{ {
get get
{ {
int pulsos = (int)(SensorFluxoLinha?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.QtdPulsos)?.atual?.valor ?? 0.0); 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); 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; 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 < 0)
if (q_L_min > 10.0) q_L_min = 10.0; // opcional: clamp no máximo q_L_min = 0;
// Converte para mL/s
double q_mL_s = q_L_min * (1000.0 / 60.0); if (q_L_min > VazaoMaximaSensor_LMin)
return q_mL_s; 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 VazaoMediaMLs { get; set; }
public double VolumeVazadoML { get; set; } public double VolumeVazadoML { get; set; }
public double TempoAtuado { get; set; } public double TempoAtuado { get; set; }
private List<AtuadorBicoModel> bicosAtivosAnterior;
private List<AtuadorBicoModel> bicosAtivosAnterior = new List<AtuadorBicoModel>();
public void AtualizaTempoAtuadoGeral() public void AtualizaTempoAtuadoGeral()
{ {
DateTime agora = DateTime.Now; DateTime agora = DateTime.Now;
// Quem está ativo AGORA var bicosAtivos = BicosPulverizadores.Where(x => x.Inicializado && x.ComandoAtuar).ToList();
var bicosAtivos = BicosPulverizadores.Where(x => x.Inicializado && x._EstadoLeitura == Estado.Ligado).ToList();
bool algumBicoAtivo = bicosAtivos.Count > 0; bool algumBicoAtivo = bicosAtivos.Count > 0;
bool algumBicoAtivoAnterior = bicosAtivosAnterior?.Any() ?? false; bool algumBicoAtivoAnterior = bicosAtivosAnterior?.Any() ?? false;
// Início de uma "sessão" (transição OFF -> ON)
if (algumBicoAtivo && !algumBicoAtivoAnterior) if (algumBicoAtivo && !algumBicoAtivoAnterior)
{ _ultimoRegistroVazao = agora;
_ultimoRegistroVazao = agora; // inicia integração a partir daqui
// (opcional) se você quer métricas por sessão, zere volumes/médias aqui
// foreach (var b in BicosPulverizadores) { b.VolumeVazadoML = 0; b.VazaoMediaMLs = 0; }
// _tempoAtuadoBicoSeg.Clear();
}
// Fim de sessão (transição ON -> OFF)
if (!algumBicoAtivo && algumBicoAtivoAnterior) if (!algumBicoAtivo && algumBicoAtivoAnterior)
{ {
AtualizaVazaoEVolume(bicosAtivosAnterior, agora); AtualizaVazaoEVolume(bicosAtivosAnterior, agora);
_ultimoRegistroVazao = DateTime.MinValue; _ultimoRegistroVazao = DateTime.MinValue;
VazaoMediaMLs = TempoAtuado > 0 ? (VolumeVazadoML / TempoAtuado) : 0;
// zera instantânea quando não tem bico ativo
foreach (var b in BicosPulverizadores) foreach (var b in BicosPulverizadores)
b.VazaoInstantaneaMLs = 0; b.VazaoInstantaneaMLs = 0;
} }
// Integra vazão/volume enquanto tiver bico ativo if (algumBicoAtivo)
AtualizaVazaoEVolume(bicosAtivos, agora); AtualizaVazaoEVolume(bicosAtivos, agora);
// Atualiza indicadores VazaoMediaMLs = TempoAtuado > 0 ? VolumeVazadoML / TempoAtuado : 0;
AtualizaPercentualErvas(); AtualizaPercentualErvas();
bicosAtivosAnterior = new List<AtuadorBicoModel>(bicosAtivos); bicosAtivosAnterior = new List<AtuadorBicoModel>(bicosAtivos);
} }
private void AtualizaVazaoEVolume(List<AtuadorBicoModel> bicosAtivos, DateTime agora) private void AtualizaVazaoEVolume(List<AtuadorBicoModel> bicosAtivos, DateTime agora)
{ {
// Só integra se houver bicos ativos
if (bicosAtivos == null || bicosAtivos.Count == 0) if (bicosAtivos == null || bicosAtivos.Count == 0)
return; return;
// Captura vazão total instantânea (ml/s) if (_ultimoRegistroVazao == DateTime.MinValue)
double vazaoTotalInst = VazaoFluxoMLpSInstantanea; {
_ultimoRegistroVazao = agora;
if (_ultimoRegistroVazao == default || _ultimoRegistroVazao == DateTime.MinValue)
return; return;
}
// dt em segundos
double dt = (agora - _ultimoRegistroVazao).TotalSeconds; double dt = (agora - _ultimoRegistroVazao).TotalSeconds;
_ultimoRegistroVazao = agora; _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; VolumeVazadoML += vazaoTotalInst * dt;
TempoAtuado += dt; TempoAtuado += dt;
VazaoMediaMLs = TempoAtuado > 0 ? (VolumeVazadoML / TempoAtuado) : 0;
// ======== POR BICO (divide por ativos) ========
double vazaoPorBicoInst = vazaoTotalInst / bicosAtivos.Count; double vazaoPorBicoInst = vazaoTotalInst / bicosAtivos.Count;
foreach (var bico in bicosAtivos) foreach (var bico in bicosAtivos)
{ {
// Instantânea por bico
bico.VazaoInstantaneaMLs = vazaoPorBicoInst; bico.VazaoInstantaneaMLs = vazaoPorBicoInst;
// Volume por bico (ml) = (ml/s) * s
bico.VolumeVazadoML += vazaoPorBicoInst * dt; bico.VolumeVazadoML += vazaoPorBicoInst * dt;
bico.TempoAtuado += 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() private void AtualizaPercentualErvas()
{ {
//double tempoTotalOperacao = Variaveis.OperacaoEmAndamento.Sensoriamento.TempoDecorridoSeg * 1000.0; double tempoTotalOperacao = Variaveis.OperacaoEmAndamento.Sensoriamento?.Movimentacao?.TempoMovimentoSegs ?? 0;
double tempoTotalOperacao = (Variaveis.OperacaoEmAndamento.Sensoriamento?.Movimentacao?.TempoMovimentoSegs ?? 0) * 1000.0; PercentualErvasTerreno = tempoTotalOperacao > 0 ? Math.Round((TempoAtuado / tempoTotalOperacao) * 100.0, 2) : 0;
if (tempoTotalOperacao > 0)
{
var percentual = Math.Round((TempoAtuado / tempoTotalOperacao) * 100.0, 2);
PercentualErvasTerreno = percentual;
} }
else
{
PercentualErvasTerreno = 0;
}
}
#endregion #endregion

View File

@ -9,6 +9,7 @@ using System.Data;
using static AgroBase.Services.LoRaEspService; using static AgroBase.Services.LoRaEspService;
using AgroBase.Services.Operadores; using AgroBase.Services.Operadores;
using System.Diagnostics; using System.Diagnostics;
using AgroBase.Models.Operadores;
namespace AgroBase.Models.Modules namespace AgroBase.Models.Modules
{ {
@ -86,7 +87,7 @@ namespace AgroBase.Models.Modules
_TaxaAmostragem = 1000, _TaxaAmostragem = 1000,
RequisitarDados = true, RequisitarDados = true,
CameraCaminho = new OAKCameraModel(), CameraCaminho = new OAKCameraModel(),
CamerasSolo = new List<OAKCameraModel>(), CamerasSolo = new List<OAKCameraModel>(Variaveis.OperacaoEmAndamento.Parametros.QtdCamerasSolo ?? VariaveisEquipamento.QuantidadeCamerasSolo),
// 21 ~ 23 // 21 ~ 23
Sinaleiros = new List<SensorSinaleiroModel>() 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; return obj;
} }
@ -2408,6 +2404,24 @@ namespace AgroBase.Models.Modules
Sinaleiros.First(x => x.ID == "LEDOP").Comportamento = VariaveisEquipamento.ComportamentoLedPorStatus(StatusLED.Piscando, status_operacao: _statusOperacao); 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 public class SensorModel

View File

@ -32,6 +32,8 @@ namespace AgroBase.Models
public double fx { get; set; } public double fx { get; set; }
public double baseline { get; set; } public double baseline { get; set; }
public CameraWorkerItemModel cam { get; set; }
public double DistanciaMaximaVisao { get; set; } = 5000; public double DistanciaMaximaVisao { get; set; } = 5000;
public double DistanciaMinimaVisao { get; set; } = 500; public double DistanciaMinimaVisao { get; set; } = 500;
public double PercentualAlturaSolo { get; set; } = 30; public double PercentualAlturaSolo { get; set; } = 30;
@ -100,6 +102,7 @@ namespace AgroBase.Models
Version = Version, Version = Version,
fx = fx, fx = fx,
baseline = baseline, baseline = baseline,
cam = cam,
}; };
} }
} }
@ -167,6 +170,12 @@ namespace AgroBase.Models
} }
public class OAKImuModel public class OAKImuModel
{
public OAKImuDataModel dados { get; set; }
public ManagerWorkerMessageResponseModulosPendentesModel saude { get; set; }
}
public class OAKImuDataModel
{ {
public double timestamp { get; set; } public double timestamp { get; set; }
public double roll { get; set; } public double roll { get; set; }

View File

@ -1197,7 +1197,12 @@ namespace AgroBase.Models
Controle.Reiniciar(); Controle.Reiniciar();
ControleAnterior.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>(); GPSTrajetoria = new List<GPSModel>();
@ -1234,6 +1239,7 @@ namespace AgroBase.Models
Variaveis.OperacaoEmAndamento.Finalizando = false; Variaveis.OperacaoEmAndamento.Finalizando = false;
Variaveis.OperacaoEmAndamento.Trajetoria?.AutonomiaCorredor?.Parar(); Variaveis.OperacaoEmAndamento.Trajetoria?.AutonomiaCorredor?.Parar();
Variaveis.OperacaoEmAndamento.DispSen?.Dados?.ContadorCarga?.FinalizarOperacao(); Variaveis.OperacaoEmAndamento.DispSen?.Dados?.ContadorCarga?.FinalizarOperacao();
Variaveis.OperacaoEmAndamento.DispAtu?.Dados?.ContadorCarga?.FinalizarOperacao();
if (Variaveis.OperacaoEmAndamento.Parametros.Modo == ModoOperacao.RetornoBase) if (Variaveis.OperacaoEmAndamento.Parametros.Modo == ModoOperacao.RetornoBase)
{ {
@ -2026,6 +2032,9 @@ namespace AgroBase.Models
MassaReservatorio = Variaveis.OperacaoEmAndamento.DispAtu.Dados.ContadorCarga.MassaAtual_Kg, MassaReservatorio = Variaveis.OperacaoEmAndamento.DispAtu.Dados.ContadorCarga.MassaAtual_Kg,
PercentualReservatorio = Variaveis.OperacaoEmAndamento.DispAtu.Dados.ContadorCarga.PercentualAtual, PercentualReservatorio = Variaveis.OperacaoEmAndamento.DispAtu.Dados.ContadorCarga.PercentualAtual,
VolumeReservatorio = Variaveis.OperacaoEmAndamento.DispAtu.Dados.ContadorCarga.VolumeAtual_L, 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_SP = Variaveis.OperacaoEmAndamento.Parametros.Controle.AtuPressaoLinha,
PressaoLinha = Variaveis.OperacaoEmAndamento.DispAtu.Dados.PressaoLinha, PressaoLinha = Variaveis.OperacaoEmAndamento.DispAtu.Dados.PressaoLinha,
PotenciaBomba = Variaveis.OperacaoEmAndamento.DispAtu.Dados.BombasPressurizadoras.FirstOrDefault()?._Potencia ?? 0, 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); double tmp_max = Math.Max(Variaveis.OperacaoEmAndamento.DadosPerformance?.GPU_temp ?? 0, Variaveis.OperacaoEmAndamento.DadosPerformance?.CPU_temp ?? 0);
_DispMvd?.Dados?.AtualizarDadosFreio(); _DispMvd?.Dados?.AtualizarDadosFreio();
_DispSen?.Dados?.AtualizarStatusSinaleiros(Variaveis.OperacaoEmAndamento.Parametros?.Modo ?? ModoOperacao.NaoDefinido, Variaveis.OperacaoEmAndamento.StatusAtual); _DispSen?.Dados?.AtualizarStatusSinaleiros(Variaveis.OperacaoEmAndamento.Parametros?.Modo ?? ModoOperacao.NaoDefinido, Variaveis.OperacaoEmAndamento.StatusAtual);
_DispSen?.Dados?.AtualizarDadosCameras();
_DispAtu?.Dados?.AtualizaTempoAtuadoGeral(); _DispAtu?.Dados?.AtualizaTempoAtuadoGeral();
_Cooler?.Atualizar(tmp_max, DateTime.Now); _Cooler?.Atualizar(tmp_max, DateTime.Now);
_Bateria?.AtualizarConsumo(_DispMvd?.Dados?.DistanciaPercorridaTotal ?? 0); _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); _Reservatorio?.AtualizarAgitadorCalda(pControle?.AtuAgitadorModo ?? ModoAgitadorCalda.SemAgitacao);
_Trajetoria?.AtualizarDadosAutonomiaCorredor(); _Trajetoria?.AtualizarDadosAutonomiaCorredor();
//var sIMU = LivoxManagerProcess.DadosLeitura.imu; //var sIMU = LivoxManagerProcess.DadosLeitura.imu;
string imu = RedisService.Get(RedisService.ModKey(T_Code.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; bool imu_iniciado = sIMU?.timestamp > 0 && HealthWorkerService.ModulosSaude.FirstOrDefault(x => x.modulo == T_Code.Imu)?.status != StatusModulo.Desconectado;
var dadosIMU = sIMU != null ? new OperacaoSensoriamentoLogImuModel() var dadosIMU = sIMU != null ? new OperacaoSensoriamentoLogImuModel()
{ {
@ -2719,9 +2729,12 @@ namespace AgroBase.Models
{ {
QtdCamerasSolo = _DispSen.Dados.CamerasSolo.Count, QtdCamerasSolo = _DispSen.Dados.CamerasSolo.Count,
CapacidadeReservatorio = VariaveisEquipamento.CapacidadeReservatorio, 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, PercentualErvasTerreno = _DispAtu.Dados.PercentualErvasTerreno,
HerbicidaPorErva = _Reservatorio.HerbicidaPorAtuacao, HerbicidaPorErva = _Reservatorio.HerbicidaPorAtuacao_L,
ErvasNoRadar = WeedWorkerService.DadosLeitura?.Analise?.ervas_no_radar ?? false, ErvasNoRadar = WeedWorkerService.DadosLeitura?.Analise?.ervas_no_radar ?? false,
PercentualErvasNoRadar = WeedWorkerService.DadosLeitura?.Analise?.estatisticas?.erva?.ema_global ?? 0, PercentualErvasNoRadar = WeedWorkerService.DadosLeitura?.Analise?.estatisticas?.erva?.ema_global ?? 0,
PercentualReservatorio = _Reservatorio.PercentualAtual, PercentualReservatorio = _Reservatorio.PercentualAtual,
@ -3029,6 +3042,9 @@ namespace AgroBase.Models
public int QtdCamerasSolo { get; set; } public int QtdCamerasSolo { get; set; }
public double CapacidadeReservatorio { get; set; } public double CapacidadeReservatorio { get; set; }
public double HerbicidaConsumido { 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 PercentualErvasTerreno { get; set; }
public double HerbicidaPorErva { get; set; } public double HerbicidaPorErva { get; set; }
public bool ErvasNoRadar { get; set; } public bool ErvasNoRadar { get; set; }
@ -3066,6 +3082,9 @@ namespace AgroBase.Models
ErvasNoRadar = ErvasNoRadar, ErvasNoRadar = ErvasNoRadar,
PercentualErvasNoRadar = PercentualErvasNoRadar, PercentualErvasNoRadar = PercentualErvasNoRadar,
HerbicidaConsumido = HerbicidaConsumido, HerbicidaConsumido = HerbicidaConsumido,
HerbicidaConsumidoOperacao = HerbicidaConsumidoOperacao,
PercentualHerbicidaConsumido = PercentualHerbicidaConsumido,
PercentualHerbicidaConsumidoOperacao = PercentualHerbicidaConsumidoOperacao,
HerbicidaPorErva = HerbicidaPorErva, HerbicidaPorErva = HerbicidaPorErva,
PercentualErvasTerreno = PercentualErvasTerreno, PercentualErvasTerreno = PercentualErvasTerreno,
PercentualReservatorio = PercentualReservatorio, PercentualReservatorio = PercentualReservatorio,
@ -3352,6 +3371,9 @@ namespace AgroBase.Models
public double PressaoLinha { get; set; } public double PressaoLinha { get; set; }
public double VolumeReservatorio { get; set; } public double VolumeReservatorio { get; set; }
public double PercentualReservatorio { 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 double PotenciaBomba { get; set; }
public bool BombaLigada { get; set; } public bool BombaLigada { get; set; }
public double VazaoFluxoMLpSInstantanea { get; set; } public double VazaoFluxoMLpSInstantanea { get; set; }

View File

@ -52,6 +52,19 @@ namespace AgroBase.Models.Operadores
public SaudeWorkerModel saude { get; set; } public SaudeWorkerModel saude { get; set; }
public CameraWorkerItemPerformanceModel performance { 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 public class CameraWorkerItemPerformanceModel

View File

@ -592,10 +592,15 @@ namespace AgroBase.Models.Operadores
public class VisualWorkerMessageSegmentacaoSemanticaDebugCorredorModel public class VisualWorkerMessageSegmentacaoSemanticaDebugCorredorModel
{ {
public double nav_global { get; set; } public string origem_status { get; set; }
public double nav_near { get; set; } public StatusCarroMapa status_modelo { get; set; }
public double nav_mid { get; set; } public string status_modelo_nome { get; set; }
public double nav_far { 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 public class VisualWorkerMessageMatrizConfiancaModel

View File

@ -1,176 +1,778 @@
using OpenHardwareMonitor.Hardware; using OpenHardwareMonitor.Hardware;
using System.Diagnostics;
using System.Threading;
using System; using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
namespace AgroBase.Models 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 public class PerformanceModel
{ {
private static readonly object ComputerLock = new object();
private static Computer computer; private static Computer computer;
private DateTime _ultimaLeituraPerformance = DateTime.MinValue;
public PerformanceModel() 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() computer = new Computer()
{ {
CPUEnabled = true, CPUEnabled = true,
GPUEnabled = true, GPUEnabled = true,
RAMEnabled = true, RAMEnabled = true,
HDDEnabled = true, HDDEnabled = true,
MainboardEnabled = false,
FanControllerEnabled = false,
}; };
try try
{ {
computer.Open(); computer.Open();
} }
catch (ArgumentOutOfRangeException ex) catch
{
}
catch (Exception ex)
{ {
computer = null;
} }
} }
} }
public float? CPU_load { get; set; } // ============================================================
public float? GPU_load { get; set; } // Atualização principal
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;
public void AtualizarDadosPerformance() 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) if (computer == null || computer.Hardware == null)
{ {
InicializarComputer();
if (computer == null || computer.Hardware == null)
return; return;
} }
if (DateTime.Now > UltimaLeituraPerformance.AddSeconds(1)) // Variáveis locais, para só atualizar propriedades no final.
{
UltimaLeituraPerformance = DateTime.Now;
float? cpuLoad = null; float? cpuLoad = null;
float? gpuLoad = null; float? cpuTempPackage = null;
float? hddLoad = null; float? cpuPowerPackage = null;
float? ramUsage = null; float? cpuPowerCores = null;
float? cpuTemp = null; float? cpuPowerGraphics = null;
float? gpuTemp = 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
{
lock (ComputerLock)
{
foreach (var hardwareItem in computer.Hardware) foreach (var hardwareItem in computer.Hardware)
{ {
hardwareItem.Update(); hardwareItem.Update();
if (hardwareItem.HardwareType == HardwareType.CPU) switch (hardwareItem.HardwareType)
{ {
case HardwareType.CPU:
LerCpu(hardwareItem,
ref cpuLoad,
ref cpuTempPackage,
ref cpuPowerPackage,
ref cpuPowerCores,
ref cpuPowerGraphics,
ref cpuPowerDram,
ref cpuClockAvg,
ref cpuClockMax,
ref cpuBusSpeed);
break;
case HardwareType.RAM:
LerRam(hardwareItem,
ref ramUsage,
ref ramUsedGb,
ref ramAvailableGb);
break;
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;
}
}
}
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;
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) foreach (var sensor in hardwareItem.Sensors)
{ {
if (sensor.SensorType == SensorType.Load && sensor.Name == "CPU Total") if (!sensor.Value.HasValue)
{ continue;
string name = sensor.Name ?? "";
if (sensor.SensorType == SensorType.Load && name == "CPU Total")
cpuLoad = sensor.Value; cpuLoad = sensor.Value;
}
if (sensor.SensorType == SensorType.Temperature && sensor.Name == "CPU Package") 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"))
{ {
cpuTemp = sensor.Value; float v = sensor.Value.Value;
} clockSum += v;
} clockCount++;
if (!clockMax.HasValue || v > clockMax.Value)
clockMax = v;
} }
if (hardwareItem.HardwareType == HardwareType.GpuNvidia || hardwareItem.HardwareType == HardwareType.GpuAti) 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) foreach (var sensor in hardwareItem.Sensors)
{ {
if (sensor.SensorType == SensorType.Load && sensor.Name == "GPU Core") if (!sensor.Value.HasValue)
{ continue;
gpuLoad = sensor.Value;
}
if (sensor.SensorType == SensorType.Temperature && sensor.Name == "GPU Core")
{
gpuTemp = sensor.Value;
}
}
}
if (hardwareItem.HardwareType == HardwareType.RAM) string name = sensor.Name ?? "";
{
foreach (var sensor in hardwareItem.Sensors) if (sensor.SensorType == SensorType.Load && name == "Memory")
{
if (sensor.SensorType == SensorType.Load && sensor.Name == "Memory")
{
ramUsage = sensor.Value; 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;
} }
} }
if (hardwareItem.HardwareType == HardwareType.HDD) 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) foreach (var sensor in hardwareItem.Sensors)
{ {
if (sensor.SensorType == SensorType.Load && sensor.Name == "Used Space") 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)
{ {
hddLoad = sensor.Value; 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;
} }
} }
int activeThreads = Process.GetCurrentProcess().Threads.Count; // ============================================================
ThreadPool.GetAvailableThreads(out int workerThreads, out int completionPortThreads); // Processo / ThreadPool
ThreadPool.GetMaxThreads(out int maxWorkerThreads, out int maxCompletionPortThreads); // ============================================================
CPU_load = cpuLoad; private void AtualizarDadosProcesso()
GPU_load = gpuLoad; {
HDD_load = hddLoad; try
RAM_usage = ramUsage; {
CPU_temp = cpuTemp; using (var proc = Process.GetCurrentProcess())
GPU_temp = gpuTemp; {
ActiveThreads = activeThreads; Process_thread_count = proc.Threads.Count;
WorkerThreads = workerThreads; Process_working_set_mb = BytesToMb(proc.WorkingSet64);
MaxWorkerThreads = maxWorkerThreads; Process_private_memory_mb = BytesToMb(proc.PrivateMemorySize64);
CompletionPortThreads = completionPortThreads; Process_virtual_memory_mb = BytesToMb(proc.VirtualMemorySize64);
MaxCompletionPortThreads = maxCompletionPortThreads; 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() public PerformanceModel Clone()
{ {
return new PerformanceModel() return new PerformanceModel()
{ {
ActiveThreads = ActiveThreads, Timestamp = this.Timestamp,
CompletionPortThreads = CompletionPortThreads, TimestampUnixMs = this.TimestampUnixMs,
MaxWorkerThreads = MaxWorkerThreads,
MaxCompletionPortThreads = MaxCompletionPortThreads, CPU_load_percent = this.CPU_load_percent,
CPU_load = CPU_load, CPU_temp_package_c = this.CPU_temp_package_c,
GPU_load = GPU_load, CPU_power_package_w = this.CPU_power_package_w,
RAM_usage = RAM_usage, CPU_power_cores_w = this.CPU_power_cores_w,
CPU_temp = CPU_temp, CPU_power_graphics_w = this.CPU_power_graphics_w,
GPU_temp = GPU_temp, CPU_power_dram_w = this.CPU_power_dram_w,
HDD_load = HDD_load, CPU_clock_avg_mhz = this.CPU_clock_avg_mhz,
WorkerThreads = WorkerThreads 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 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 CapacidadeMaxima_Ah = max_Ah;
WhPorMetroBase = w_m_base; CargaMaxima_C = max_Ah * 3600.0;
WhPorMetroBase = wh_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;
MargemSegurancaAutonomia = 0.30; MargemSegurancaAutonomia = 0.30;
ResetarHistoricosAutonomia(); ResetarTudo();
} }
public bool Iniciado { get; private set; } public bool Iniciado { get; private set; }
public bool BmsLigado { 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 bool _estadoInicializado;
private DateTime? _ultimaLeituraIntegrada; private DateTime? _ultimaLeituraIntegrada;
// Capacidade e estado absoluto do pack public double CapacidadeMaxima_Ah { get; private set; }
private double CargaMaxima_C { get; set; } // Coulombs private double CargaMaxima_C { get; set; }
private double CargaAtual_C { get; set; } // Coulombs
// Snapshot inicial da instância public double CargaAtual_C { get; private set; }
private double _socInicialInstancia { get; set; } public double CargaAtualAmp => CargaAtual_C / 3600.0;
private double _cargaInicialInstancia_C { get; set; }
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 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 public double PercentualConsumidoTotal
{ {
get get
{ {
if (CargaMaxima_C <= 0) return 0; 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 public double PercentualConsumidoOperacao
{ {
get get
{ {
if (CargaMaxima_C <= 0) if (!OperacaoAtiva && !OperacaoFinalizada)
return 0; return 0;
double calc = (ConsumidoOperacao_C / CargaMaxima_C) * 100.0; if (CargaMaxima_C <= 0) return 0;
return FuncoesMatematicas.Clamp(calc, 0, 100);
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 get
{ {
if (_cargaInicioOperacao_C <= 0) return 0; if (_socInicialOperacao <= 0) return 0;
double calc = (ConsumidoOperacao_C / _cargaInicioOperacao_C) * 100.0;
return FuncoesMatematicas.Clamp(calc, 0, 100); 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 public double EnergiaConsumidaOperacao_Wh
{ {
get get
@ -110,32 +168,16 @@ namespace AgroBase.Services
if (!OperacaoAtiva && !OperacaoFinalizada) if (!OperacaoAtiva && !OperacaoFinalizada)
return 0; return 0;
double referenciaFim = OperacaoFinalizada double fim = OperacaoFinalizada
? _energiaTotalNoFimOperacao_Wh ? _energiaConsumidaFimOperacao_Wh
: EnergiaConsumidaTotal_Wh; : EnergiaConsumidaTotal_Wh;
return Math.Max(0, referenciaFim - _energiaTotalNoInicioOperacao_Wh); return Math.Max(0, fim - _energiaConsumidaInicioOperacao_Wh);
} }
} }
// Estado atual public double EnergiaConsumidaTotal_kWh => EnergiaConsumidaTotal_Wh / 1000.0;
public double PercentualAtual public double EnergiaConsumidaOperacao_kWh => EnergiaConsumidaOperacao_Wh / 1000.0;
{
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 WhRestante public double WhRestante
{ {
@ -149,12 +191,14 @@ namespace AgroBase.Services
} }
} }
// Histórico para suavização de corrente public double kWhRestante => WhRestante / 1000.0;
private const int BufferSize = 30;
private readonly Queue<double> _historicoCorrente = new Queue<double>(); 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 WhPorMetro { get; private set; }
public double kWhPorMetro => WhPorMetro / 1000.0;
public double WhPorMetroBase { get; set; } public double WhPorMetroBase { get; set; }
public double WhPorMetroHistorico { get; private set; } public double WhPorMetroHistorico { get; private set; }
@ -181,18 +225,17 @@ namespace AgroBase.Services
private double _distanciaTotalMetrosAnterior; private double _distanciaTotalMetrosAnterior;
private double _energiaConsumidaAnterior_Wh_Total; private double _energiaConsumidaAnterior_Wh_Total;
public void IniciarOperacao() public void IniciarOperacao(double distanciaTotalMetrosAtual = 0)
{ {
if (!_estadoInicializado) if (!_estadoInicializado)
return; return;
_socInicialOperacao = PercentualBateria; _socInicialOperacao = PercentualBateria;
_cargaInicioOperacao_C = CargaAtual_C; _distanciaInicioOperacao_m = distanciaTotalMetrosAtual;
_consumidoTotalNoInicioOperacao_C = ConsumidoTotal_C;
_energiaTotalNoInicioOperacao_Wh = EnergiaConsumidaTotal_Wh;
_consumidoTotalNoFimOperacao_C = 0; _consumidoIntegradoOperacao_C = 0;
_energiaTotalNoFimOperacao_Wh = 0; _energiaConsumidaInicioOperacao_Wh = EnergiaConsumidaTotal_Wh;
_energiaConsumidaFimOperacao_Wh = 0;
OperacaoAtiva = true; OperacaoAtiva = true;
OperacaoFinalizada = false; OperacaoFinalizada = false;
@ -203,8 +246,7 @@ namespace AgroBase.Services
if (!OperacaoAtiva) if (!OperacaoAtiva)
return; return;
_consumidoTotalNoFimOperacao_C = ConsumidoTotal_C; _energiaConsumidaFimOperacao_Wh = EnergiaConsumidaTotal_Wh;
_energiaTotalNoFimOperacao_Wh = EnergiaConsumidaTotal_Wh;
OperacaoAtiva = false; OperacaoAtiva = false;
OperacaoFinalizada = true; OperacaoFinalizada = true;
@ -212,63 +254,22 @@ namespace AgroBase.Services
public void AtualizarConsumo(double distanciaTotalMetrosAtual) public void AtualizarConsumo(double distanciaTotalMetrosAtual)
{ {
var dalyBms = DalyBMSService.DadosLeitura; LerFontes();
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;
if (!Iniciado) if (!Iniciado)
return; return;
DateTime? leituraAtual = BmsLigado ? bms_ultima_leitura : sen_ultima_leitura; DateTime? leituraAtual = ObterDataLeituraAtual();
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;
if (!leituraAtual.HasValue || leituraAtual.Value == DateTime.MinValue) if (!leituraAtual.HasValue || leituraAtual.Value == DateTime.MinValue)
return; return;
// Primeira leitura válida da instância
if (!_estadoInicializado) if (!_estadoInicializado)
{ {
_socInicialInstancia = PercentualBateria; InicializarEstado(leituraAtual.Value, distanciaTotalMetrosAtual);
_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);
return; return;
} }
// Só integra se chegou leitura nova
if (_ultimaLeituraIntegrada.HasValue && leituraAtual.Value <= _ultimaLeituraIntegrada.Value) if (_ultimaLeituraIntegrada.HasValue && leituraAtual.Value <= _ultimaLeituraIntegrada.Value)
{ {
_dt = 0; _dt = 0;
@ -282,45 +283,160 @@ namespace AgroBase.Services
if (_dt <= 0 || _dt > 10) if (_dt <= 0 || _dt > 10)
{ {
Console.WriteLine($"[COULOMB COUNTER] dt inválido: {_dt:F3}s"); Console.WriteLine($"[COULOMB COUNTER] dt inválido: {_dt:F3}s");
AtualizarCargaAtualPeloSocOuIntegrador();
AtualizarAutonomia(distanciaTotalMetrosAtual);
return; return;
} }
// Assumindo descarga positiva. Se no Daly a descarga vier negativa, inverter aqui. CorrenteDescarga_A = NormalizarCorrenteDescarga(CorrenteInstantanea);
double correnteDescarga_A = Math.Max(0, 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) if (OperacaoAtiva && !OperacaoFinalizada)
{ _consumidoIntegradoOperacao_C = Clamp(_consumidoIntegradoOperacao_C + deltaCoulombs, 0, CargaMaxima_C);
ConsumidoOperacao_C += deltaCoulombs;
ConsumidoOperacao_C = FuncoesMatematicas.Clamp(ConsumidoOperacao_C, 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) if (deltaEnergia_Wh > 0)
EnergiaConsumidaTotal_Wh += deltaEnergia_Wh; EnergiaConsumidaTotal_Wh += deltaEnergia_Wh;
_historicoCorrente.Enqueue(correnteDescarga_A); AtualizarCargaAtualPeloSocOuIntegrador();
if (_historicoCorrente.Count > BufferSize) AtualizarHistoricos();
_historicoCorrente.Dequeue(); AtualizarTempoRestante();
AtualizarAutonomia(distanciaTotalMetrosAtual);
}
double correnteMedia = _historicoCorrente.Count > 0 private void LerFontes()
? _historicoCorrente.Average() {
: 0; var dalyBms = DalyBMSService.DadosLeitura;
if (correnteMedia > 0 && CargaAtualAmp > 0) bool bms_iniciado = dalyBms?.Iniciado ?? false;
TempoEstimadoMinutos = (CargaAtualAmp / correnteMedia) * 60.0; DateTime? bms_ultima_leitura = dalyBms?.UltimoComandoRecebido;
else double bms_tensao = dalyBms?.Pack?.TensaoTotal_V ?? 0;
TempoEstimadoMinutos = 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); 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) private void AtualizarAutonomia(double distanciaTotalMetrosAtual)
{ {
if (!_estadoInicializado) if (!_estadoInicializado)
@ -337,6 +453,7 @@ namespace AgroBase.Services
{ {
_historicoDeltaDist_m.Enqueue(deltaDist_m); _historicoDeltaDist_m.Enqueue(deltaDist_m);
_historicoDeltaWh.Enqueue(deltaWh); _historicoDeltaWh.Enqueue(deltaWh);
_somaDistanciaJanela_m += deltaDist_m; _somaDistanciaJanela_m += deltaDist_m;
_somaEnergiaJanela_Wh += deltaWh; _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) public void AtualizarValorConsumidoTotal(double consumoTotal_Ah)
{ {
double coulombsConsumidos = consumoTotal_Ah * 3600.0; double coulombsConsumidos = consumoTotal_Ah * 3600.0;
ConsumidoTotal_C = FuncoesMatematicas.Clamp(coulombsConsumidos, 0, CargaMaxima_C); _consumidoIntegradoTotal_C = Clamp(coulombsConsumidos, 0, CargaMaxima_C);
if (_estadoInicializado) AtualizarCargaAtualPeloSocOuIntegrador();
{
double cargaAtualCalculada = _cargaInicialInstancia_C - ConsumidoTotal_C;
CargaAtual_C = FuncoesMatematicas.Clamp(cargaAtualCalculada, 0, CargaMaxima_C);
}
} }
public bool ConseguePercorrer(double distanciaRequerida_m) public bool ConseguePercorrer(double distanciaRequerida_m)
@ -408,5 +499,65 @@ namespace AgroBase.Services
return DistanciaMaximaSegura_m >= distanciaRequerida_m; 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 = { string[] comandos = {
// Bauds // Bauds
$"config com1 115200\r\n", $"config com1 115200\r\n",
$"config {porta_usb} 115200\r\n", $"config com2 115200\r\n",
$"config {porta_entrada} 115200\r\n", $"config com3 115200\r\n",
// limpa logs das portas // limpa logs das portas
$"unlog com1\r\n", $"unlog com1\r\n",
@ -158,8 +158,9 @@ namespace AgroBase.Services
string distancia_min = "0"; string distancia_min = "0";
string[] comandos = { string[] comandos = {
// Bauds // Bauds
$"config {porta_usb} 115200\r\n", $"config com1 115200\r\n",
$"config {porta_saida} 115200\r\n", $"config com2 115200\r\n",
$"config com3 115200\r\n",
// limpa logs das portas // limpa logs das portas
$"unlog com1\r\n", $"unlog com1\r\n",

View File

@ -9,138 +9,129 @@ namespace AgroBase.Services
{ {
public class HerbicideCounterService 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; CapacidadeLitros = capacidadeLitros;
VolumeAtual_L = 0;
VolumeConsumido_L = 0;
DensidadeProduto = densidadeProduto; 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 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; } public double CapacidadeLitros { get; }
/// <summary>
/// Densidade do produto.
/// </summary>
public double DensidadeProduto { get; } public double DensidadeProduto { get; }
/// <summary> public int QuantidadeBicos { get; }
/// Massa atual lida no reservatório (Kg).
/// </summary> 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 { get; private set; }
public double MassaAtual_Kg_Calc { 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; } public double VolumeAtual_L { get; private set; }
/// <summary> private double _volumeInicialInstancia_L;
/// Volume total consumido desde o início (L). private double _volumeInicialOperacao_L;
/// </summary>
public double VolumeConsumido_L { get; private set; } 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 public double PercentualAtual
{ {
get get
{ {
if (CapacidadeLitros <= 0) return 0; if (CapacidadeLitros <= 0) return 0;
var p = (VolumeAtual_L / CapacidadeLitros) * 100.0; return Clamp((VolumeAtual_L / CapacidadeLitros) * 100.0, 0, 100);
return FuncoesMatematicas.Clamp(p, 0, 100);
} }
} }
public double PercentualConsumido public double PercentualConsumidoTotal
{ {
get 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; } 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; } 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; } public double DistanciaMaximaSegura_m { get; private set; }
/// <summary>
/// Alias mais descritivo para uso direto pelo Manager.
/// </summary>
public double DistanciaEstimadaRestantePulverizando_m => DistanciaMaximaSegura_m; 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; } 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; private const double JanelaAutonomia_m = 50.0;
// Tempo: janela de ~60 s pulverizando
private const double JanelaTempo_s = 60.0; 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 dist_m, double vol_L)> _janelaDist = new Queue<(double dist_m, double vol_L)>();
private readonly Queue<(double deltaTempo_s, double deltaVol_L)> _janelaTempo = new Queue<(double deltaTempo_s, double deltaVol_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 _somaDistanciaJanela_m;
private double _somaVolumeDistJanela_L; private double _somaVolumeDistJanela_L;
private double _somaTempoJanela_s; private double _somaTempoJanela_s;
private double _somaVolumeTempoJanela_L; private double _somaVolumeTempoJanela_L;
// Valores anteriores para cálculo de deltas
private double _volumeAnterior_L; private double _volumeAnterior_L;
private double _distanciaTotalAnterior_m; private double _distanciaTotalAnterior_m;
private double _tempoTotalAnterior_s; private double _tempoTotalAnterior_s;
@ -148,192 +139,258 @@ namespace AgroBase.Services
private bool _inicializado; private bool _inicializado;
private SensorModel SensorMassaReservatorio => Variaveis.OperacaoEmAndamento.DispAtu?.Dados?.Sensores?.FirstOrDefault(x => x.Componente == S_Code.sMAS && x.ID == "MASRS"); 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> public AtuadorBombaModel AgitadorCalda => Variaveis.OperacaoEmAndamento.DispAtu?.Dados?.BombasPressurizadoras?.FirstOrDefault(x => x.ID == "AGTCLD");
/// Atualiza o estado do sistema de herbicida.
/// public void IniciarOperacao(double distanciaTotalMetrosAtual, double tempoTotalSegundosAtual)
/// Chamar periodicamente com: {
/// - volumeMedido_L: leitura de nível atual do reservatório (L) if (!_inicializado)
/// - pulverizando: true se algum bico está ativo return;
/// - distanciaTotalMetrosAtual: distância total acumulada (m)
/// - tempoTotalSegundosAtual: tempo total de operação (s) _volumeInicialOperacao_L = VolumeAtual_L;
/// </summary>
public void AtualizarConsumo(double distanciaTotalMetrosAtual, double tempoTotalSegundosAtual) _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; Iniciado = SensorMassaReservatorio?.Inicializado ?? false;
if (!Iniciado) if (!Iniciado)
return; return;
bool pulverizando = Variaveis.OperacaoEmAndamento.DispAtu?.Dados?.BicosPulverizadores?.Any(x => x.Inicializado && x._EstadoLeitura == Estado.Ligado) ?? false; LerReservatorio(out double massaLida_Kg, out double massaCalc_Kg, out double volumeMedido_L);
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;
double.TryParse(SensorMassaReservatorio.Parametros.FirstOrDefault(x => x.Descricao == "Offset")?.Valor ?? "0", out double offset);
double massa_calc = (massaLida_Kg_bruto * 1) + offset;
double volumeMedido_L = massa_calc / DensidadeProduto;
int qtd_atuacoes = Variaveis.OperacaoEmAndamento.Controle?.Bicos?.Sum(x => x.Atuacoes) ?? 0;
// Sanitiza volume
if (volumeMedido_L < 0) volumeMedido_L = 0;
if (volumeMedido_L > CapacidadeLitros) volumeMedido_L = CapacidadeLitros;
// Inicialização
if (!_inicializado)
{
_inicializado = true;
_volumeAnterior_L = volumeMedido_L;
_distanciaTotalAnterior_m = distanciaTotalMetrosAtual;
_tempoTotalAnterior_s = tempoTotalSegundosAtual;
MassaAtual_Kg = massaLida_Kg; MassaAtual_Kg = massaLida_Kg;
MassaAtual_Kg_Calc = massa_calc; MassaAtual_Kg_Calc = massaCalc_Kg;
VolumeAtual_L = volumeMedido_L; VolumeAtual_L = volumeMedido_L;
BicosAtivos = ObterQuantidadeBicosAtivos();
Pulverizando = BicosAtivos > 0;
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;
if (!_inicializado)
{
Inicializar(distanciaTotalMetrosAtual, tempoTotalSegundosAtual);
AtualizarAutonomia(velocidadeAtual_m_s);
return; return;
} }
MassaAtual_Kg = massaLida_Kg; double deltaVolumeMassa_L = Math.Max(0, _volumeAnterior_L - VolumeAtual_L);
MassaAtual_Kg_Calc = massa_calc; _volumeAnterior_L = VolumeAtual_L;
VolumeAtual_L = volumeMedido_L;
PulverizadorLiberado = PercentualAtual >= VariaveisEquipamento.PercentualReservatorioMinCritio; double deltaDist_m = Math.Max(0, distanciaTotalMetrosAtual - _distanciaTotalAnterior_m);
// --- 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;
_distanciaTotalAnterior_m = distanciaTotalMetrosAtual; _distanciaTotalAnterior_m = distanciaTotalMetrosAtual;
double deltaTempo_s = tempoTotalSegundosAtual - _tempoTotalAnterior_s; double deltaTempo_s = Math.Max(0, tempoTotalSegundosAtual - _tempoTotalAnterior_s);
if (deltaTempo_s < 0) deltaTempo_s = 0;
_tempoTotalAnterior_s = tempoTotalSegundosAtual; _tempoTotalAnterior_s = tempoTotalSegundosAtual;
// --- Atualiza janela de distância (L/m) --- double deltaVolumeFluxo_L = 0;
AtualizarJanelaDistancia(deltaDist_m, deltaVolume_L, pulverizando);
// --- Atualiza janela de tempo (L/min) --- if (Pulverizando && deltaTempo_s > 0 && VazaoReferencia_mLs > 0)
AtualizarJanelaTempo(deltaTempo_s, deltaVolume_L, pulverizando); deltaVolumeFluxo_L = VazaoReferencia_mLs * deltaTempo_s / 1000.0;
// --- Atualiza métricas de autonomia --- double deltaVolumeParaTaxa_L = EscolherDeltaVolumeParaTaxa(deltaVolumeMassa_L, deltaVolumeFluxo_L);
AtualizarAutonomia();
if (Pulverizando && deltaVolumeParaTaxa_L > 0)
{
AtualizarJanelaDistancia(deltaDist_m, deltaVolumeParaTaxa_L);
AtualizarJanelaTempo(deltaTempo_s, deltaVolumeParaTaxa_L);
} }
private void AtualizarJanelaDistancia(double deltaDist_m, double deltaVolume_L, bool pulverizando) AtualizarHerbicidaPorAtuacao();
AtualizarAutonomia(velocidadeAtual_m_s);
}
private double EscolherDeltaVolumeParaTaxa(double deltaMassa_L, double deltaFluxo_L)
{ {
// Só faz sentido atualizar se o robô andou e estava pulverizando if (deltaFluxo_L > 0)
if (!pulverizando || deltaDist_m <= 0 || deltaVolume_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; return;
_janelaDist.Enqueue((deltaDist_m, deltaVolume_L)); _janelaDist.Enqueue((deltaDist_m, deltaVolume_L));
_somaDistanciaJanela_m += deltaDist_m; _somaDistanciaJanela_m += deltaDist_m;
_somaVolumeDistJanela_L += deltaVolume_L; _somaVolumeDistJanela_L += deltaVolume_L;
// Mantém a janela limitada a JanelaAutonomia_m
while (_somaDistanciaJanela_m > JanelaAutonomia_m && _janelaDist.Count > 0) while (_somaDistanciaJanela_m > JanelaAutonomia_m && _janelaDist.Count > 0)
{ {
var (dOld, vOld) = _janelaDist.Dequeue(); var old = _janelaDist.Dequeue();
_somaDistanciaJanela_m -= dOld;
_somaVolumeDistJanela_L -= vOld; _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; LPorMetro = _somaVolumeDistJanela_L / _somaDistanciaJanela_m;
double alpha = 0.2; const double alpha = 0.2;
if (LPorMetroHistorico <= 0)
LPorMetroHistorico = LPorMetro; LPorMetroHistorico = LPorMetroHistorico <= 0
else ? LPorMetro
LPorMetroHistorico = LPorMetroHistorico * (1 - alpha) + LPorMetro * alpha; : 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 (deltaTempo_s <= 0 || deltaVolume_L <= 0)
if (!pulverizando || deltaTempo_s <= 0 || deltaVolume_L <= 0)
return; return;
_janelaTempo.Enqueue((deltaTempo_s, deltaVolume_L)); _janelaTempo.Enqueue((deltaTempo_s, deltaVolume_L));
_somaTempoJanela_s += deltaTempo_s; _somaTempoJanela_s += deltaTempo_s;
_somaVolumeTempoJanela_L += deltaVolume_L; _somaVolumeTempoJanela_L += deltaVolume_L;
// Mantém a janela de tempo limitada a JanelaTempo_s
while (_somaTempoJanela_s > JanelaTempo_s && _janelaTempo.Count > 0) while (_somaTempoJanela_s > JanelaTempo_s && _janelaTempo.Count > 0)
{ {
var (tOld, vOld) = _janelaTempo.Dequeue(); var old = _janelaTempo.Dequeue();
_somaTempoJanela_s -= tOld;
_somaVolumeTempoJanela_L -= vOld; _somaTempoJanela_s -= old.tempo_s;
_somaVolumeTempoJanela_L -= old.vol_L;
} }
if (_somaTempoJanela_s > 0 && _somaVolumeTempoJanela_L > 0) if (_somaTempoJanela_s > 1.0)
{
// L/s * 60 = L/min
LPorMinuto = (_somaVolumeTempoJanela_L / _somaTempoJanela_s) * 60.0; LPorMinuto = (_somaVolumeTempoJanela_L / _somaTempoJanela_s) * 60.0;
} }
private void AtualizarHerbicidaPorAtuacao()
{
int qtdAtuacoes = Variaveis.OperacaoEmAndamento.Controle?.Bicos?.Sum(x => x.Atuacoes) ?? 0;
if (qtdAtuacoes > 0)
HerbicidaPorAtuacao_L = VolumeConsumidoOperacao_L / qtdAtuacoes;
} }
private void AtualizarAutonomia() private void AtualizarAutonomia(double velocidadeAtual_m_s)
{ {
// ----- Distância máxima pulverizando (m) ----- double consumoRef_LPorMetro = CalcularLPorMetroReferencia(velocidadeAtual_m_s);
if (VolumeAtual_L > 0 && LPorMetro > 0)
{
DistanciaMaximaTeorica_m = VolumeAtual_L / LPorMetro;
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;
}
// ----- Tempo máximo pulverizando (min) -----
double consumoRef_LPorMetro = LPorMetroReferencia;
if (VolumeAtual_L > 0 && consumoRef_LPorMetro > 0) if (VolumeAtual_L > 0 && consumoRef_LPorMetro > 0)
{ {
DistanciaMaximaTeorica_m = VolumeAtual_L / consumoRef_LPorMetro; 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); DistanciaMaximaSegura_m = DistanciaMaximaTeorica_m * (1.0 - margem);
if (DistanciaMaximaSegura_m < 0)
DistanciaMaximaSegura_m = 0;
} }
else else
{ {
DistanciaMaximaTeorica_m = 0; DistanciaMaximaTeorica_m = 0;
DistanciaMaximaSegura_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) public bool ConseguePulverizarRua(double comprimentoRua_m)
{ {
if (comprimentoRua_m <= 0) if (comprimentoRua_m <= 0)
@ -342,28 +399,80 @@ namespace AgroBase.Services
return DistanciaMaximaSegura_m >= comprimentoRua_m; return DistanciaMaximaSegura_m >= comprimentoRua_m;
} }
/// <summary>
/// Permite "forçar" um volume inicial (por exemplo, depois de reabastecer).
/// </summary>
public void DefinirVolumeAtual(double volume_L) 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; VolumeAtual_L = volume_L;
_volumeAnterior_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(); _janelaDist.Clear();
_janelaTempo.Clear(); _janelaTempo.Clear();
_somaDistanciaJanela_m = 0; _somaDistanciaJanela_m = 0;
_somaVolumeDistJanela_L = 0; _somaVolumeDistJanela_L = 0;
_somaTempoJanela_s = 0; _somaTempoJanela_s = 0;
_somaVolumeTempoJanela_L = 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 bool _agitadorIntermitenteLigado = false;
private DateTime _agitadorUltimaTroca = DateTime.MinValue; private DateTime _agitadorUltimaTroca = DateTime.MinValue;
@ -378,7 +487,6 @@ namespace AgroBase.Services
private int AtuAgitadorTempoDesligadoMs = 30000; private int AtuAgitadorTempoDesligadoMs = 30000;
private int AtuAgitadorBoostRetomadaMs = 15000; private int AtuAgitadorBoostRetomadaMs = 15000;
private double PotenciaLimitePorNivel(double nivelPct) private double PotenciaLimitePorNivel(double nivelPct)
{ {
if (nivelPct <= 5) return 0; if (nivelPct <= 5) return 0;
@ -402,7 +510,6 @@ namespace AgroBase.Services
bool operacaoIniciada = Variaveis.OperacaoEmAndamento?.Iniciado ?? false; bool operacaoIniciada = Variaveis.OperacaoEmAndamento?.Iniciado ?? false;
bool pausado = Variaveis.OperacaoEmAndamento?.Pausa ?? false; bool pausado = Variaveis.OperacaoEmAndamento?.Pausa ?? false;
bool operacaoAtiva = operacaoIniciada && !pausado; bool operacaoAtiva = operacaoIniciada && !pausado;
bool bicosAtuando = bool bicosAtuando =
@ -412,7 +519,6 @@ namespace AgroBase.Services
double potenciaFinal = 0; double potenciaFinal = 0;
DateTime agora = DateTime.Now; DateTime agora = DateTime.Now;
// Boost ao iniciar/retomar operação
if (operacaoAtiva && !_agitadorOperacaoAtivaAnterior) if (operacaoAtiva && !_agitadorOperacaoAtivaAnterior)
{ {
_agitadorBoostAte = agora.AddMilliseconds(AtuAgitadorBoostRetomadaMs); _agitadorBoostAte = agora.AddMilliseconds(AtuAgitadorBoostRetomadaMs);
@ -438,10 +544,6 @@ namespace AgroBase.Services
else else
potenciaFinal = AtuAgitadorPotenciaManutencao; potenciaFinal = AtuAgitadorPotenciaManutencao;
} }
else
{
potenciaFinal = 0;
}
break; break;
case ModoAgitadorCalda.Intermitente: case ModoAgitadorCalda.Intermitente:
@ -472,18 +574,13 @@ namespace AgroBase.Services
: 0; : 0;
} }
break; break;
default:
potenciaFinal = 0;
break;
} }
potenciaFinal = Math.Min(potenciaFinal, PotenciaLimitePorNivel(PercentualAtual)); potenciaFinal = Math.Min(potenciaFinal, PotenciaLimitePorNivel(PercentualAtual));
potenciaFinal = FuncoesMatematicas.Clamp(potenciaFinal, 0, 100); potenciaFinal = Clamp(potenciaFinal, 0, 100);
AgitadorCalda.PotenciaSP = potenciaFinal; AgitadorCalda.PotenciaSP = potenciaFinal;
_agitadorOperacaoAtivaAnterior = operacaoAtiva; _agitadorOperacaoAtivaAnterior = operacaoAtiva;
} }
} }
} }

View File

@ -104,9 +104,9 @@ namespace AgroBase.Services.Operadores
{ {
foreach (var cam in cameras) 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); var camera = JsonConvert.DeserializeObject<CameraWorkerItemModel>(camera_str);
if (camera.mx_id == null) continue; if (camera?.mx_id == null) continue;
CamerasConectadas.Add(camera); CamerasConectadas.Add(camera);
} }
} }
@ -114,5 +114,19 @@ namespace AgroBase.Services.Operadores
return CamerasConectadas; 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_model_ruas_seg", VersionamentoService.ArquivoModeloSegStreetDetector.CaminhoCompleto),
("path_ia_labelmap_ruas_seg", VersionamentoService.ArquivoLabelmapSegStreetDetector.CaminhoCompleto), ("path_ia_labelmap_ruas_seg", VersionamentoService.ArquivoLabelmapSegStreetDetector.CaminhoCompleto),
("path_ia_norm_stats_ruas_seg", VersionamentoService.ArquivoModeloNormstatsStreetDetector.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_ruas_det", VersionamentoService.ArquivoModeloDetStreetDetector.CaminhoCompleto),
("path_ia_model_ervas", VersionamentoService.ArquivoModeloWeedDetector.CaminhoCompleto), ("path_ia_model_ervas", VersionamentoService.ArquivoModeloWeedDetector.CaminhoCompleto),
("path_ia_labelmap_ervas", VersionamentoService.ArquivoModeloLabelmapWeedDetector.CaminhoCompleto), ("path_ia_labelmap_ervas", VersionamentoService.ArquivoModeloLabelmapWeedDetector.CaminhoCompleto),
("path_ia_norm_stats_ervas", VersionamentoService.ArquivoModeloNormstatsWeedDetector.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_roll_max", VariaveisEquipamento.AnguloInclinacaoRollMax),
("angulo_pitch_max", VariaveisEquipamento.AnguloInclinacaoPitchMax) ("angulo_pitch_max", VariaveisEquipamento.AnguloInclinacaoPitchMax)
); );
@ -313,9 +315,9 @@ namespace AgroBase.Services.Operadores
), ),
("Snr", new ("Snr", new
{ {
percentual_altura_solo = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho.PercentualAlturaSolo, percentual_altura_solo = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho?.PercentualAlturaSolo ?? 0.1,
distancia_maxima = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho.DistanciaMaximaVisao, distancia_maxima = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho?.DistanciaMaximaVisao ?? 5000,
distancia_minima = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho.DistanciaMinimaVisao distancia_minima = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho?.DistanciaMinimaVisao ?? 300
} }
) )
); );
@ -757,15 +759,76 @@ namespace AgroBase.Services.Operadores
); );
var DadosMod = _Sensoriamento.DadosPerformance; 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", agora),
("timestamp_unix_ms", DadosMod.TimestampUnixMs),
("freq_base", 1.0 / Variaveis.OperacaoEmAndamento.tmrLeiturasInterval), ("freq_base", 1.0 / Variaveis.OperacaoEmAndamento.tmrLeiturasInterval),
("cpu_load", DadosMod.CPU_load ?? 0),
("gpu_load", DadosMod.GPU_load ?? 0), // CPU
("hdd_load", DadosMod.HDD_load ?? 0), ("cpu_load_percent", DadosMod.CPU_load_percent ?? 0),
("ram_usage", DadosMod.RAM_usage ?? 0), ("cpu_temp_package_c", DadosMod.CPU_temp_package_c ?? 0),
("cpu_temp", DadosMod.CPU_temp ?? 0), ("cpu_power_package_w", DadosMod.CPU_power_package_w ?? 0),
("gpu_temp", DadosMod.GPU_temp ?? 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; var DadosCan = CanManager.CanService;

View File

@ -31,6 +31,11 @@ namespace AgroBase.Services
return CtxKey.DadosCameras + mx_id; return CtxKey.DadosCameras + mx_id;
} }
public static string CamImuKey(string mx_id)
{
return CtxKey.DadosCameras + mx_id + "_Imu";
}
public static string Get(string chave) public static string Get(string chave)
{ {
return _db.StringGet(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) public static VersaoArquivoModel ArquivoParametros(T_Code Dispositivo)
{ {
lock (_ArquivoLock) lock (_ArquivoLock)