Ajustes de estrutura de dados

This commit is contained in:
Diego Freitas 2025-11-24 13:05:50 -03:00
parent c5e90f7b44
commit 909b7261d6
1939 changed files with 43891 additions and 13378 deletions

View File

@ -652,96 +652,6 @@
<None Include="Imagens\salvar.png" />
<Content Include="Imagens\transferidor.png" />
<None Include="Imagens\voltar.png" />
<Content Include="Python\Models\deeplabv3plus\backbone\hrnetv2.py">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\deeplabv3plus\backbone\mobilenetv2.py">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\deeplabv3plus\backbone\resnet.py">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\deeplabv3plus\backbone\xception.py">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\deeplabv3plus\backbone\__init__.py">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\deeplabv3plus\modeling.py">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\deeplabv3plus\utils.py">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\deeplabv3plus\_deeplab.py">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\deeplabv3plus\__init__.py">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\yolov7\models\common.py">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\yolov7\models\experimental.py">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\yolov7\models\yolo.py">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\yolov7\models\__init__.py">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\yolov7\utils\activations.py">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\yolov7\utils\add_nms.py">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\yolov7\utils\autoanchor.py">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\yolov7\utils\aws\resume.py">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\yolov7\utils\aws\__init__.py">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\yolov7\utils\datasets.py">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\yolov7\utils\general.py">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\yolov7\utils\google_app_engine\additional_requirements.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\yolov7\utils\google_utils.py">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\yolov7\utils\loss.py">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\yolov7\utils\metrics.py">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\yolov7\utils\plots.py">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\yolov7\utils\torch_utils.py">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\yolov7\utils\wandb_logging\log_dataset.py">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\yolov7\utils\wandb_logging\wandb_utils.py">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\yolov7\utils\wandb_logging\__init__.py">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\yolov7\utils\__init__.py">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Python\Output\folium\images\position_marker.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@ -933,69 +843,6 @@
</Compile>
<None Include="Imagens\esp32-s3.jpg" />
<None Include="Imagens\esp32-wrover.jpg" />
<Content Include="Python\Models\yolo\coco.names">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\yolo\yolov3.cfg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\yolo\yolov3.weights">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\yolo\coco-tiny.names">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\yolo\yolov3-tiny.cfg">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\yolo\yolov3-tiny.weights">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\yolo\yolov3-weed.weights">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\yolo\crop_weed_detection.weights">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<None Include="Python\Models\deeplabv3plus\backbone\__pycache__\hrnetv2.cpython-311.pyc">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="Python\Models\deeplabv3plus\backbone\__pycache__\mobilenetv2.cpython-311.pyc">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="Python\Models\deeplabv3plus\backbone\__pycache__\resnet.cpython-311.pyc">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="Python\Models\deeplabv3plus\backbone\__pycache__\xception.cpython-311.pyc">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="Python\Models\deeplabv3plus\backbone\__pycache__\__init__.cpython-311.pyc">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="Python\Models\deeplabv3plus\__pycache__\modeling.cpython-311.pyc">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="Python\Models\deeplabv3plus\__pycache__\utils.cpython-311.pyc">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="Python\Models\deeplabv3plus\__pycache__\_deeplab.cpython-311.pyc">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="Python\Models\deeplabv3plus\__pycache__\__init__.cpython-311.pyc">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<Content Include="Python\Models\yolov7\utils\aws\mime.sh">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\yolov7\utils\aws\userdata.sh">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\yolov7\utils\google_app_engine\app.yaml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Python\Models\yolov7\utils\google_app_engine\Dockerfile">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<None Include="Python\Output\fonts\glyphicons-halflings-regular.ttf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
@ -1024,7 +871,7 @@
<Content Include="Python\Scripts\map_load.py" />
</ItemGroup>
<ItemGroup>
<Folder Include="Python\Models\yolov7\utils\wandb_logging\__pycache__\" />
<Folder Include="Python\Models\" />
</ItemGroup>
<ItemGroup>
<None Update="runtimes\win-x64\native\*.dll">

View File

@ -27,7 +27,7 @@ namespace AgroBase.Forms.Atuador
{
PopularBicos();
nudPressaoSP.Value = Convert.ToInt32(Variaveis.OperacaoEmAndamento.Controle.PressaoLinha);
nudPressaoSP.Value = Convert.ToInt32(Variaveis.OperacaoEmAndamento.Parametros.Controle.AtuPressaoLinha);
txtMMassaRef.Text = DispAtu.Dados._MassaRef.ToString();
txtMLeituraRef.Text = DispAtu.Dados._MassaLeituraRef.ToString();
txtPressaoVmin.Text = DispAtu.Dados._PressaoVmin.ToString();
@ -63,7 +63,7 @@ namespace AgroBase.Forms.Atuador
private void PopularBicos()
{
for (int i = 0; i < DispAtu.Dados.QuantidadeBicos; i++)
for (int i = 0; i < Variaveis.OperacaoEmAndamento.Parametros.QtdBicos; i++)
{
string ID = DispAtu.Dados.BicosPulverizadores[i].ID;
Label lblBico = new Label()
@ -153,7 +153,7 @@ namespace AgroBase.Forms.Atuador
private void nudPressaoSP_ValueChanged(object sender, EventArgs e)
{
var Bomba = Variaveis.OperacaoEmAndamento.DispAtu.Dados.BombasPressurizadoras.FirstOrDefault();
Variaveis.OperacaoEmAndamento.Controle.PressaoLinha = Convert.ToInt32(((NumericUpDown)sender).Value);
Variaveis.OperacaoEmAndamento.Parametros.Controle.AtuPressaoLinha = Convert.ToInt32(((NumericUpDown)sender).Value);
GeneralJoystick.EnviarComandoAtuador(S_Code.sBMB, Bomba.ComandoAtuar, Bomba.ID);
}
@ -206,7 +206,7 @@ namespace AgroBase.Forms.Atuador
private void btnSalvar_Click(object sender, EventArgs e)
{
Variaveis.OperacaoEmAndamento.Controle.PressaoLinha = Convert.ToDouble(nudPressaoSP.Value);
Variaveis.OperacaoEmAndamento.Parametros.Controle.AtuPressaoLinha = Convert.ToDouble(nudPressaoSP.Value);
DispAtu.Dados._MassaRef = Convert.ToDouble(txtMMassaRef.Text);
DispAtu.Dados._MassaLeituraRef = Convert.ToDouble(txtMLeituraRef.Text);
DispAtu.Dados._PressaoVmin = Convert.ToDouble(txtPressaoVmin.Text);

View File

@ -27,9 +27,9 @@ namespace AgroBase.Forms.Atuador
}
chbBicosAtuacao.Checked = Disp.Dados.BicosPulverizadores.Any(x => x.AtuacaoNivelAlto);
nudBicosQtd.Value = Disp.Dados.QuantidadeBicos;
nudBicosQtd.Value = Variaveis.OperacaoEmAndamento.Parametros.QtdBicos;
txtDensidade.Text = Disp.Dados.DensidadeHerbicida.ToString("0.00");
nudCapMax.Value = Convert.ToInt32(Variaveis.OperacaoEmAndamento.CapacidadeReservatorio);
nudCapMax.Value = Convert.ToInt32(Variaveis.OperacaoEmAndamento.Parametros.QtdCamerasSolo);
}
private void frmAtuConfig_FormClosing(object sender, FormClosingEventArgs e)
@ -41,9 +41,9 @@ namespace AgroBase.Forms.Atuador
private void btnSalvar_Click(object sender, EventArgs e)
{
Disp.Dados.BicosPulverizadores.ForEach(x => x.AtuacaoNivelAlto = chbBicosAtuacao.Checked);
Disp.Dados.QuantidadeBicos = Convert.ToInt32(nudBicosQtd.Value);
Variaveis.OperacaoEmAndamento.Parametros.QtdBicos = Convert.ToInt32(nudBicosQtd.Value);
Disp.Dados.DensidadeHerbicida = Convert.ToDouble(txtDensidade.Text.Replace(".", ","));
Variaveis.OperacaoEmAndamento.CapacidadeReservatorio = Convert.ToDouble(nudCapMax.Value);
Variaveis.OperacaoEmAndamento.Parametros.CapacidadeReservatorio = Convert.ToDouble(nudCapMax.Value);
Disp.SalvarParametros(Disp.Dados);
}

View File

@ -123,7 +123,7 @@ namespace AgroBase.Forms.IHM
chbSonarAtivado.Enabled = KinectService.Iniciado;
if (KinectService.Iniciado)
{
chbSonarAtivado.Checked = Variaveis.OperacaoEmAndamento.Controle.SonarAtivado;
chbSonarAtivado.Checked = Variaveis.OperacaoEmAndamento.Parametros.Controle.SonarAtivado;
}
}
@ -259,7 +259,7 @@ namespace AgroBase.Forms.IHM
CameraCaminho = Variaveis.OperacaoEmAndamento.DispSen.Dados.CameraCaminho.Clone();
CamerasSolo = new List<OAKCameraModel>(Variaveis.OperacaoEmAndamento.DispSen.Dados.CamerasSolo);
for (int i = 0; i < Variaveis.OperacaoEmAndamento.QuantidadeCamerasSolo; i++)
for (int i = 0; i < Variaveis.OperacaoEmAndamento.Parametros.QtdCamerasSolo; i++)
{
GerarCameraSolo(i);
}

View File

@ -526,7 +526,7 @@ namespace AgroBase.Forms.IHM
private async Task EnviarComandoBomba(bool Ligar, double Pressao, int Timeout, AtuadorModel disp = null)
{
var Bomba = Variaveis.OperacaoEmAndamento.DispAtu.Dados.BombasPressurizadoras.FirstOrDefault();
Variaveis.OperacaoEmAndamento.Controle.PressaoLinha = Pressao + 10;
Variaveis.OperacaoEmAndamento.Parametros.Controle.AtuPressaoLinha = Pressao + 10;
GeneralJoystick.EnviarComandoAtuador(S_Code.sBMB, Ligar, Bomba.ID);
DateTime inicio = DateTime.Now;
@ -941,7 +941,7 @@ namespace AgroBase.Forms.IHM
TipoMovimentoDirecional _oldTipoMovimento = Variaveis.OperacaoEmAndamento.Controle.TipoMovimento;
double _oldAngulo = Variaveis.OperacaoEmAndamento.Controle.Angulo;
double _oldVelocidadeMP = Variaveis.OperacaoEmAndamento.Controle.VelocidadeMP;
double _oldVelocidadeMP = Variaveis.OperacaoEmAndamento.Parametros.Controle.DirVelocidadeMovimento;
DispositivosService<MovimentacaoUnificadaModel> Dispositivo = (DispositivosService<MovimentacaoUnificadaModel>)Variaveis.DispositivosConectados.FirstOrDefault(x => x.Dispositivo == Enums.T_Code.Mvd);
@ -952,7 +952,7 @@ namespace AgroBase.Forms.IHM
Variaveis.OperacaoEmAndamento.Controle.TipoMovimento = TipoMovimentoDirecional.Diagnostico;
Variaveis.OperacaoEmAndamento.Controle.Angulo = 25;
Variaveis.OperacaoEmAndamento.Controle.VelocidadeMP = 30;
Variaveis.OperacaoEmAndamento.Parametros.Controle.DirVelocidadeMovimento = 30;
bool SenConectado = SerialService.DispositivosMapeados.Any(x => x.Dispositivo == T_Code.Sen);
idx = PreencheDadosLinha(grid, Testes, idx, SenConectado ? 1 : 0);
@ -1001,7 +1001,7 @@ namespace AgroBase.Forms.IHM
Variaveis.OperacaoEmAndamento.Controle.TipoMovimento = _oldTipoMovimento;
Variaveis.OperacaoEmAndamento.Controle.Angulo = _oldAngulo;
Variaveis.OperacaoEmAndamento.Controle.VelocidadeMP = _oldVelocidadeMP;
Variaveis.OperacaoEmAndamento.Parametros.Controle.DirVelocidadeMovimento = _oldVelocidadeMP;
return true;
}
@ -1227,7 +1227,7 @@ namespace AgroBase.Forms.IHM
bool PzmConectado = SerialService.DispositivosMapeados.Any(x => x.Dispositivo == Enums.T_Code.Pzm);
idx = PreencheDadosLinha(grid, Testes, idx, PzmConectado ? 1 : 0);
var S36V = Variaveis.OperacaoEmAndamento.Sensoriamento.Bateria;
var S36V = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Bateria;
bool S36VInicializado = S36V.Iniciado;
idx = PreencheDadosLinha(grid, Testes, idx, S36VInicializado ? 1 : 0);
@ -1264,7 +1264,7 @@ namespace AgroBase.Forms.IHM
double Corrente12V = S12V.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.Corrente).atual.valor;
idx = PreencheDadosLinha(grid, Testes, idx, Corrente12V);
var SImu = Variaveis.OperacaoEmAndamento.Sensoriamento.IMU;
var SImu = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.IMU;
double Orientacao = SImu.Iniciado ? SImu.Rotacao : -1;
idx = PreencheDadosLinha(grid, Testes, idx, Orientacao);
@ -1274,13 +1274,13 @@ namespace AgroBase.Forms.IHM
bool GpsInicializado = GPSService.Iniciado;
idx = PreencheDadosLinha(grid, Testes, idx, GpsInicializado ? 1 : 0);
double Precisao = GpsInicializado ? (int)Variaveis.OperacaoEmAndamento.Sensoriamento.Gps.QualidadeFix : -1;
double Precisao = GpsInicializado ? (int)Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps.QualidadeFix : -1;
idx = PreencheDadosLinha(grid, Testes, idx, Precisao);
double Satelites = GpsInicializado ? Variaveis.OperacaoEmAndamento.Sensoriamento.Gps.NumeroSatelites : -1;
double Satelites = GpsInicializado ? Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps.NumeroSatelites : -1;
idx = PreencheDadosLinha(grid, Testes, idx, Satelites);
double OrientacaoGPS = GpsInicializado ? Variaveis.OperacaoEmAndamento.Sensoriamento.Gps.OrientacaoReal : -1;
double OrientacaoGPS = GpsInicializado ? Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps.OrientacaoReal : -1;
idx = PreencheDadosLinha(grid, Testes, idx, OrientacaoGPS);
bool A05Conectado = SerialService.DispositivosMapeados.Any(x => x.Dispositivo == Enums.T_Code.A05);

View File

@ -136,7 +136,7 @@ namespace AgroBase.Forms.IHM
public void AtualizarMapaDinamico()
{
var _Sensoriamento = Variaveis.OperacaoEmAndamento.Sensoriamento;
var _Sensoriamento = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura;
var _Trajetoria = Variaveis.OperacaoEmAndamento.Trajetoria;
if (_Trajetoria != null && _Trajetoria.CorredorAtual != null)
@ -160,10 +160,10 @@ namespace AgroBase.Forms.IHM
pnlOrientacao.Invalidate();
pnlInclinacao.Invalidate();
var _Sensoriamento = Variaveis.OperacaoEmAndamento.Sensoriamento;
var _Sensoriamento = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura;
lblUltimaLeituraSolo.Text = "Última Leitura Solo: " + Variaveis.OperacaoEmAndamento.Sensoriamento.OperadorErvas.UltimaMensagem.ToString("HH:mm:ss.fff");
lblUltimaLeituraCaminho.Text = "Última Leitura Caminho: " + Variaveis.OperacaoEmAndamento.Sensoriamento.OperadorVisual.UltimaMensagem.ToString("HH:mm:ss.fff");
lblUltimaLeituraSolo.Text = "Última Leitura Solo: " + _Sensoriamento.OperadorErvas.UltimaMensagem.ToString("HH:mm:ss.fff");
lblUltimaLeituraCaminho.Text = "Última Leitura Caminho: " + _Sensoriamento.OperadorVisual.UltimaMensagem.ToString("HH:mm:ss.fff");
lblPerformance.Text = _Sensoriamento.DadosPerformance.PerformanceStr;
lblMapaCarregado.Text = "Operação: " + Variaveis.OperacaoEmAndamento.Descricao;
@ -210,7 +210,7 @@ namespace AgroBase.Forms.IHM
tkbVelocidade.Value = Convert.ToInt32(_Sensoriamento.Controle.PercentualVelocidadeSP);
tkbAnguloDirecional.Minimum = 0;
tkbAnguloDirecional.Maximum = Convert.ToInt32(_Sensoriamento.Controle.Angulo_Max);
tkbAnguloDirecional.Maximum = Convert.ToInt32(Variaveis.OperacaoEmAndamento.Parametros.Controle.DirAnguloMaximo);
tkbAnguloDirecional.Value = Math.Abs(Convert.ToInt32(_Sensoriamento.Controle.Angulo));
}
@ -294,8 +294,8 @@ namespace AgroBase.Forms.IHM
{
try
{
double angulo = Variaveis.OperacaoEmAndamento.Sensoriamento.Gps.AnguloCarroDefinido;
FuncoesGlobais.DesenharInclinacao((Panel)sender, e, (float)angulo, 90, (float)Variaveis.OperacaoEmAndamento.Sensoriamento.Trajetoria.AnguloCaminho);
double angulo = Variaveis.OperacaoEmAndamento.Parametros?.DadosLeitura?.Gps?.AnguloCarroDefinido ?? 0;
FuncoesGlobais.DesenharInclinacao((Panel)sender, e, (float)angulo, 90, (float)(Variaveis.OperacaoEmAndamento.Parametros?.DadosLeitura?.Trajetoria?.AnguloCaminho ?? 0));
}
catch { }
}
@ -333,15 +333,16 @@ namespace AgroBase.Forms.IHM
pnlJoystick.Visible = false;
tabControl1.TabPages.Remove(tabControle);
var pControle = Variaveis.OperacaoEmAndamento.Parametros.Controle;
var _Controle = Variaveis.OperacaoEmAndamento.Controle;
cmbModoControle.SelectedIndex = (int)_Controle.TipoMovimento;
chbSonarAtivado.Checked = _Controle.SonarAtivado;
chbFrenagemAutomatica.Checked = _Controle.FrenagemAutomatica;
nudVelSemErvas.Value = (int)_Controle.PercentualVelocidadeMax;
nudVelComErvas.Value = (int)_Controle.PercentualVelocidadeMin;
chbPulverizadorAutomatico.Checked = _Controle.PulverizadorAutomatico;
nudPercentualAtuacaoBico.Value = (int)(_Controle.PercentualInicioPulverizacao * 100.0);
nudPressaoLinha.Value = (int)_Controle.PressaoLinha;
chbSonarAtivado.Checked = pControle.SonarAtivado;
chbFrenagemAutomatica.Checked = pControle.FrenagemAutomatica;
nudVelSemErvas.Value = (int)pControle.MovVelocidadeSErvasPercent;
nudVelComErvas.Value = (int)pControle.MovVelocidadeCErvasPercent;
chbPulverizadorAutomatico.Checked = pControle.PulverizadorAutomatico;
nudPercentualAtuacaoBico.Value = (int)pControle.AtuPercentualInicioPulverizacao;
nudPressaoLinha.Value = (int)pControle.AtuPressaoLinha;
FuncoesGlobais.PreencheValorTrackBar(tkbAnguloDirecional, _Controle.Angulo);
FuncoesGlobais.PreencheValorTrackBar(tkbVelocidade, _Controle.PercentualVelocidadeSP);
@ -670,7 +671,7 @@ namespace AgroBase.Forms.IHM
try
{
// 1) Pega o estado atual do seu sistema
var src = Variaveis.OperacaoEmAndamento.ModulosMandatorios;
var src = Variaveis.OperacaoEmAndamento.Parametros.ModulosMandatorios;
var saude = HealthWorkerService.ModulosSaude;
// 2) Constrói snapshot
@ -802,7 +803,7 @@ namespace AgroBase.Forms.IHM
// escreve de volta na fonte oficial
var disp = _modulosUI[idx].Disp;
var alvo = Variaveis.OperacaoEmAndamento.ModulosMandatorios.FirstOrDefault(m => m.Dispositivo.Equals(disp));
var alvo = Variaveis.OperacaoEmAndamento.Parametros.ModulosMandatorios.FirstOrDefault(m => m.Dispositivo.Equals(disp));
if (alvo != null)
{
if (alvo.Utilizar && alvo.Mandatorio && !novoUtilizar)
@ -866,16 +867,16 @@ namespace AgroBase.Forms.IHM
{ ("Não", DialogResult.No), () => { } },
}
);
var _Controle = Variaveis.OperacaoEmAndamento.Controle;
var pControle = Variaveis.OperacaoEmAndamento.Parametros.Controle;
if (res == DialogResult.Yes)
{
_Controle.SonarAtivado = chbSonarAtivado.Checked;
_Controle.FrenagemAutomatica = chbFrenagemAutomatica.Checked;
_Controle.RPM_Max = (int)FuncoesMatematicas.CalculaRPMVelocidade(FuncoesMatematicas.CalculaVelocidadeMsPercentual((int)nudVelSemErvas.Value));
_Controle.RPM_Min = (int)FuncoesMatematicas.CalculaRPMVelocidade(FuncoesMatematicas.CalculaVelocidadeMsPercentual((int)nudVelComErvas.Value));
_Controle.PulverizadorAutomatico = chbPulverizadorAutomatico.Checked;
_Controle.PercentualInicioPulverizacao = ((double)nudPercentualAtuacaoBico.Value / 100.0);
_Controle.PressaoLinha = (double)nudPressaoLinha.Value;
pControle.SonarAtivado = chbSonarAtivado.Checked;
pControle.FrenagemAutomatica = chbFrenagemAutomatica.Checked;
pControle.MovVelocidadeSErvasPercent = (int)FuncoesMatematicas.CalculaRPMVelocidade(FuncoesMatematicas.CalculaVelocidadeMsPercentual((int)nudVelSemErvas.Value));
pControle.MovVelocidadeCErvasPercent = (int)FuncoesMatematicas.CalculaRPMVelocidade(FuncoesMatematicas.CalculaVelocidadeMsPercentual((int)nudVelComErvas.Value));
pControle.PulverizadorAutomatico = chbPulverizadorAutomatico.Checked;
pControle.AtuPercentualInicioPulverizacao = ((double)nudPercentualAtuacaoBico.Value / 100.0);
pControle.AtuPressaoLinha = (double)nudPressaoLinha.Value;
RedisService.AtualizarCampos(
CtxKey.DadosPesosMPC,
@ -893,13 +894,13 @@ namespace AgroBase.Forms.IHM
}
else
{
chbSonarAtivado.Checked = _Controle.SonarAtivado;
chbFrenagemAutomatica.Checked = _Controle.FrenagemAutomatica;
nudVelSemErvas.Value = (int)_Controle.PercentualVelocidadeMax;
nudVelComErvas.Value = (int)_Controle.PercentualVelocidadeMin;
chbPulverizadorAutomatico.Checked = _Controle.PulverizadorAutomatico;
nudPercentualAtuacaoBico.Value = (int)(_Controle.PercentualInicioPulverizacao * 100.0);
nudPressaoLinha.Value = (int)_Controle.PressaoLinha;
chbSonarAtivado.Checked = pControle.SonarAtivado;
chbFrenagemAutomatica.Checked = pControle.FrenagemAutomatica;
nudVelSemErvas.Value = (int)pControle.MovVelocidadeSErvasPercent;
nudVelComErvas.Value = (int)pControle.MovVelocidadeCErvasPercent;
chbPulverizadorAutomatico.Checked = pControle.PulverizadorAutomatico;
nudPercentualAtuacaoBico.Value = (int)pControle.AtuPercentualInicioPulverizacao;
nudPressaoLinha.Value = (int)pControle.AtuPressaoLinha;
string pesosMpcStr = RedisService.Get(CtxKey.DadosPesosMPC);
var pesos = JsonConvert.DeserializeObject<MPCPesosModel>(pesosMpcStr);
txtPesoPosicao.Text = pesos.posicao.ToString();

View File

@ -227,7 +227,7 @@ namespace AgroBase.Forms.Operacoes
{
string disp = chb.Name.Replace("chb", "");
T_Code Dispositivo = (T_Code)Enum.Parse(typeof(T_Code), disp);
chb.Checked = Variaveis.OperacaoEmAndamento.ModulosMandatorios.Any(x => x.Dispositivo == Dispositivo && x.Mandatorio);
chb.Checked = Variaveis.OperacaoEmAndamento.Parametros.ModulosMandatorios.Any(x => x.Dispositivo == Dispositivo && x.Mandatorio);
}
txtModoOperacao.Text = Variaveis.OperacaoEmAndamento.Modo.ToString();

View File

@ -60,8 +60,8 @@ namespace AgroBase.Forms.Operacoes
flwCamerasSolo.Controls.Add(pnlCam);
}
chbPulverizador.Checked = Variaveis.OperacaoEmAndamento.Controle.PulverizadorAutomatico;
chbSonarAtivado.Checked = Variaveis.OperacaoEmAndamento.Controle.SonarAtivado;
chbPulverizador.Checked = Variaveis.OperacaoEmAndamento.Parametros.Controle.PulverizadorAutomatico;
chbSonarAtivado.Checked = Variaveis.OperacaoEmAndamento.Parametros.Controle.SonarAtivado;
InicializarComandosDirecional();
PopularInformacoesGerais();
@ -151,7 +151,7 @@ namespace AgroBase.Forms.Operacoes
AtualizarInformacoesGerais();
var _Sensoriamento = Variaveis.OperacaoEmAndamento.Sensoriamento;
var _Sensoriamento = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura;
lblDistanciaEsquerda.Text = "Distancia Esq: " + _Sensoriamento.Trajetoria.DistanciaEsquerda.ToString("0.00") + " cm";
lblDistanciaDireita.Text = "Distancia Dir: " + _Sensoriamento.Trajetoria.DistanciaDireita.ToString("0.00") + " cm";
@ -173,7 +173,7 @@ namespace AgroBase.Forms.Operacoes
chbPulverizador.Checked = false;
}
bool sonarAtivado = Variaveis.OperacaoEmAndamento.Sensoriamento.OperadorVisual.Status == StatusModulo.Operante;
bool sonarAtivado = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.OperadorVisual.Status == StatusModulo.Operante;
chbSonarAtivado.Enabled = sonarAtivado;
if (!sonarAtivado)
{
@ -424,8 +424,8 @@ namespace AgroBase.Forms.Operacoes
{
try
{
double angulo = Variaveis.OperacaoEmAndamento.Sensoriamento.Gps.OrientacaoReal;
double angulo2 = Variaveis.OperacaoEmAndamento.Sensoriamento.Gps.AnguloCarroDefinido;
double angulo = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps.OrientacaoReal;
double angulo2 = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps.AnguloCarroDefinido;
FuncoesGlobais.DesenharInclinacao((Panel)sender, e, (float)angulo, -90, (float)angulo2);
}
catch { }
@ -433,7 +433,7 @@ namespace AgroBase.Forms.Operacoes
private void pnlAnguloMagnetometro_Paint(object sender, PaintEventArgs e)
{
var imu = Variaveis.OperacaoEmAndamento.Sensoriamento.IMU;
var imu = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.IMU;
try
{
double angulo = imu.Rotacao;
@ -512,7 +512,7 @@ namespace AgroBase.Forms.Operacoes
var AB12V = _SensoresCorrente.FirstOrDefault(x => x.ID == "AB12V");
var AB19V = _SensoresCorrente.FirstOrDefault(x => x.ID == "AB19V");
var AB24V = _SensoresCorrente.FirstOrDefault(x => x.ID == "AB24V");
var _Sensoriamento = Variaveis.OperacaoEmAndamento.Sensoriamento;
var _Sensoriamento = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura;
gridDados.Rows[0].Cells[1].Value = _Sensoriamento.TempoDecorrido.ToString("HH:mm:ss");
gridDados.Rows[1].Cells[1].Value = _Sensoriamento.Movimentacao.TempoMovimento.ToString("HH:mm:ss");
@ -570,15 +570,15 @@ namespace AgroBase.Forms.Operacoes
private void PopularBicos()
{
var Atuador = Variaveis.OperacaoEmAndamento.DispAtu;
nudPressaoSP.Value = Convert.ToInt32(Variaveis.OperacaoEmAndamento.Controle.PressaoLinha);
nudPressaoSP.Value = Convert.ToInt32(Variaveis.OperacaoEmAndamento.Parametros.Controle.AtuPressaoLinha);
int panelWidth = pnlAtuadores.Width;
int circleDiameter = 40; // Diâmetro dos círculos grandes
int spaceBetweenCircles = (panelWidth - (circleDiameter * Atuador.Dados.QuantidadeBicos)) / (Atuador.Dados.QuantidadeBicos + 1);
int spaceBetweenCircles = (panelWidth - (circleDiameter * Variaveis.OperacaoEmAndamento.Parametros.QtdBicos)) / (Variaveis.OperacaoEmAndamento.Parametros.QtdBicos + 1);
int yPosition = (pnlAtuadores.Height - circleDiameter) / 3; // Centralizado verticalmente
for (int i = 0; i < Atuador.Dados.QuantidadeBicos; i++)
for (int i = 0; i < Variaveis.OperacaoEmAndamento.Parametros.QtdBicos; i++)
{
// Calcula a posição x do círculo
int xPosition = spaceBetweenCircles + (i * (circleDiameter + spaceBetweenCircles));
@ -637,7 +637,7 @@ namespace AgroBase.Forms.Operacoes
private void nudPressaoSP_ValueChanged(object sender, EventArgs e)
{
var Bomba = Variaveis.OperacaoEmAndamento.DispAtu.Dados.BombasPressurizadoras.FirstOrDefault();
Variaveis.OperacaoEmAndamento.Controle.PressaoLinha = Convert.ToInt32(((NumericUpDown)sender).Value);
Variaveis.OperacaoEmAndamento.Parametros.Controle.AtuPressaoLinha = Convert.ToInt32(((NumericUpDown)sender).Value);
GeneralJoystick.EnviarComandoAtuador(S_Code.sBMB, Bomba.ComandoAtuar, Bomba.ID);
}
@ -678,12 +678,12 @@ namespace AgroBase.Forms.Operacoes
private void chbPulverizador_CheckedChanged(object sender, EventArgs e)
{
Variaveis.OperacaoEmAndamento.Controle.PulverizadorAutomatico = ((CheckBox)sender).Checked;
Variaveis.OperacaoEmAndamento.Parametros.Controle.PulverizadorAutomatico = ((CheckBox)sender).Checked;
}
private void chbSonarAtivado_CheckedChanged(object sender, EventArgs e)
{
Variaveis.OperacaoEmAndamento.Controle.SonarAtivado = ((CheckBox)sender).Checked;
Variaveis.OperacaoEmAndamento.Parametros.Controle.SonarAtivado = ((CheckBox)sender).Checked;
}
private void chbSonarDesvioAutomatico_CheckedChanged(object sender, EventArgs e)

View File

@ -68,7 +68,7 @@ namespace AgroBase.Forms.Operacoes
pnlCaminho.Invalidate();
pnlAnguloCamera.Invalidate();
var _Sensoriamento = Variaveis.OperacaoEmAndamento.Sensoriamento;
var _Sensoriamento = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura;
/*var ultimaLeitura = Variaveis.OperacaoEmAndamento.CamerasSolo.OrderByDescending(x => x.Leitura.timestamp).FirstOrDefault();
if (ultimaLeitura != null)
@ -282,7 +282,7 @@ namespace AgroBase.Forms.Operacoes
{
try
{
double angulo = Variaveis.OperacaoEmAndamento.Sensoriamento.Gps.AnguloCarroDefinido;
double angulo = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps.AnguloCarroDefinido;
FuncoesGlobais.DesenharInclinacao((Panel)sender, e, (float)angulo, -90);
}
catch { }

View File

@ -27,7 +27,8 @@ namespace AgroBase.Forms.Operacoes
void CarregarParametros()
{
ModulosMandatorios = Variaveis.OperacaoEmAndamento.ModulosMandatorios.ToList();
var _Parametros = Variaveis.OperacaoEmAndamento.Parametros;
ModulosMandatorios = _Parametros.ModulosMandatorios.ToList();
cmbOperacao.Items.Clear();
cmbOperacao.Items.AddRange(Enum.GetNames(typeof(ModoOperacao)));
@ -52,24 +53,24 @@ namespace AgroBase.Forms.Operacoes
});
nudVelocidadeComErvas.Minimum = 0;
nudVelocidadeComErvas.Maximum = Convert.ToInt32(VariaveisEquipamento.RPM_Max_Roda);
nudVelocidadeComErvas.Value = Convert.ToInt32(Variaveis.OperacaoEmAndamento.Controle.RPM_Min);
nudVelocidadeComErvas.Maximum = 100;
nudVelocidadeComErvas.Value = Convert.ToInt32(_Parametros.Controle.MovVelocidadeCErvasPercent);
nudVelocidadeSemErvas.Minimum = 0;
nudVelocidadeSemErvas.Maximum = Convert.ToInt32(VariaveisEquipamento.RPM_Max_Roda);
nudVelocidadeSemErvas.Value = Convert.ToInt32(Variaveis.OperacaoEmAndamento.Controle.RPM_Max);
nudVelocidadeSemErvas.Maximum = 100;
nudVelocidadeSemErvas.Value = Convert.ToInt32(_Parametros.Controle.MovVelocidadeSErvasPercent);
lblKmhCErvas.Text = FuncoesMatematicas.CalculaVelocidadeRPM(Variaveis.OperacaoEmAndamento.Controle.RPM_Min).ToString("0.00") + " Km/h";
lblKmhSErvas.Text = FuncoesMatematicas.CalculaVelocidadeRPM(Variaveis.OperacaoEmAndamento.Controle.RPM_Max).ToString("0.00") + " Km/h";
nudAnguloMaximo.Value = Convert.ToInt32(Variaveis.OperacaoEmAndamento.Controle.Angulo_Max);
nudAnguloMinimo.Value = Convert.ToInt32(Variaveis.OperacaoEmAndamento.Controle.Angulo_Min);
nudVelocidadeMP.Value = Convert.ToInt32(Variaveis.OperacaoEmAndamento.Controle.VelocidadeMP);
lblKmhCErvas.Text = FuncoesMatematicas.ConverteMsParaKmh(FuncoesMatematicas.CalculaVelocidadeMsPercentual(_Parametros.Controle.MovVelocidadeCErvasPercent)).ToString("0.00") + " Km/h";
lblKmhSErvas.Text = FuncoesMatematicas.ConverteMsParaKmh(FuncoesMatematicas.CalculaVelocidadeMsPercentual(_Parametros.Controle.MovVelocidadeSErvasPercent)).ToString("0.00") + " Km/h";
nudAnguloMaximo.Value = Convert.ToInt32(_Parametros.Controle.DirAnguloMaximo);
nudAnguloMinimo.Value = Convert.ToInt32(-_Parametros.Controle.DirAnguloMaximo);
nudVelocidadeMP.Value = Convert.ToInt32(_Parametros.Controle.DirVelocidadeMovimento);
nudTemposalvarlog.Value = (decimal)Variaveis.OperacaoEmAndamento.tmrLogsInterval / 1000;
nudQtdBicos.Value = Variaveis.OperacaoEmAndamento.DispAtu.Dados.QuantidadeBicos;
nudQtdCameras.Value = Variaveis.OperacaoEmAndamento.QuantidadeCamerasSolo;
nudCapacidadereservatorio.Value = Convert.ToInt32(Variaveis.OperacaoEmAndamento.CapacidadeReservatorio);
nudQtdBicos.Value = _Parametros.QtdBicos;
nudQtdCameras.Value = _Parametros.QtdCamerasSolo;
nudCapacidadereservatorio.Value = Convert.ToInt32(_Parametros.CapacidadeReservatorio);
txtDensidadeherbicida.Text = Variaveis.OperacaoEmAndamento.DispAtu.Dados.DensidadeHerbicida.ToString("0.00");
nudAtuarem.Value = Convert.ToInt32(Variaveis.OperacaoEmAndamento.Controle.PercentualInicioPulverizacao * 100);
nudAtuarem.Value = Convert.ToInt32(_Parametros.Controle.AtuPercentualInicioPulverizacao);
cmbScriptErvas.SelectedIndex = cmbScriptErvas.Items.IndexOf(Variaveis.OperacaoEmAndamento.DispAtu.Dados.ScriptDeteccaoErvas.Replace(".py", ""));
}
@ -125,19 +126,18 @@ namespace AgroBase.Forms.Operacoes
void SalvarOperacao()
{
Variaveis.OperacaoEmAndamento.ModulosMandatorios = ModulosMandatorios.Where(x => x.Utilizar).ToList();
Variaveis.OperacaoEmAndamento.Controle.RPM_Max = (int)(nudVelocidadeSemErvas.Value);
Variaveis.OperacaoEmAndamento.Controle.RPM_Min = (int)(nudVelocidadeComErvas.Value);
Variaveis.OperacaoEmAndamento.Controle.Angulo_Max = (int)(nudAnguloMaximo.Value);
Variaveis.OperacaoEmAndamento.Controle.Angulo_Min = (int)(nudAnguloMinimo.Value);
Variaveis.OperacaoEmAndamento.Controle.VelocidadeMP = (int)(nudVelocidadeMP.Value);
Variaveis.OperacaoEmAndamento.Parametros.ModulosMandatorios = ModulosMandatorios.Where(x => x.Utilizar).ToList();
Variaveis.OperacaoEmAndamento.Parametros.Controle.MovVelocidadeSErvasPercent = (int)(nudVelocidadeSemErvas.Value);
Variaveis.OperacaoEmAndamento.Parametros.Controle.MovVelocidadeCErvasPercent = (int)(nudVelocidadeComErvas.Value);
Variaveis.OperacaoEmAndamento.Parametros.Controle.DirAnguloMaximo = (int)(nudAnguloMaximo.Value);
Variaveis.OperacaoEmAndamento.Parametros.Controle.DirVelocidadeMovimento = (int)(nudVelocidadeMP.Value);
Variaveis.OperacaoEmAndamento.tmrLogsInterval = (double)(nudTemposalvarlog.Value * 1000);
Variaveis.OperacaoEmAndamento.DispAtu.Dados.QuantidadeBicos = (int)nudQtdBicos.Value;
Variaveis.OperacaoEmAndamento.QuantidadeCamerasSolo = (int)nudQtdCameras.Value;
Variaveis.OperacaoEmAndamento.CapacidadeReservatorio = (double)nudCapacidadereservatorio.Value;
Variaveis.OperacaoEmAndamento.Parametros.QtdBicos = (int)nudQtdBicos.Value;
Variaveis.OperacaoEmAndamento.Parametros.QtdCamerasSolo = (int)nudQtdCameras.Value;
Variaveis.OperacaoEmAndamento.Parametros.CapacidadeReservatorio = (double)nudCapacidadereservatorio.Value;
Variaveis.OperacaoEmAndamento.DispAtu.Dados.DensidadeHerbicida = Convert.ToDouble(txtDensidadeherbicida.Text.Replace(".", ","));
Variaveis.OperacaoEmAndamento.Controle.PercentualInicioPulverizacao = (double)(nudAtuarem.Value / 100);
Variaveis.OperacaoEmAndamento.DispAtu.Dados.ScriptDeteccaoErvas = cmbScriptErvas.Text + ".py";
Variaveis.OperacaoEmAndamento.Parametros.Controle.AtuPercentualInicioPulverizacao = (double)(nudAtuarem.Value / 100);
//Variaveis.OperacaoEmAndamento.Parametros.DispAtu.Dados.ScriptDeteccaoErvas = cmbScriptErvas.Text + ".py";
if (chbSalvar.Checked)
{

View File

@ -49,7 +49,7 @@ namespace AgroBase.Forms
{
cmbTipoControleDirecional.Items.Clear();
cmbTipoControleDirecional.Items.AddRange(Enum.GetNames(typeof(Enums.TiposControladorDirecional)));
cmbTipoControleDirecional.SelectedIndex = (int)Variaveis.OperacaoEmAndamento.Controle.TipoControleDirecional;
cmbTipoControleDirecional.SelectedIndex = (int)Variaveis.OperacaoEmAndamento.Parametros.Controle.DirTipoMovimento;
cmbStatusCorredor.Items.Clear();
cmbStatusCorredor.Items.AddRange(Enum.GetNames(typeof(Enums.StatusCarroMapa)));
@ -116,9 +116,15 @@ namespace AgroBase.Forms
return;
AtualizandoTela = true;
var _Sensoriamento = Variaveis.OperacaoEmAndamento.Sensoriamento;
var _Sensoriamento = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura;
var _Trajetoria = Variaveis.OperacaoEmAndamento.Trajetoria;
if (_Trajetoria == null)
{
AtualizandoTela = false;
return;
}
lblStatusOperacao.Text = "Operação: " + Enum.GetName(typeof(StatusOperacao), _Sensoriamento.StatusOperacao);
lblTipoMovimento.Text = _Sensoriamento.Controle.TipoMovimento.ToString();
@ -257,12 +263,12 @@ namespace AgroBase.Forms
// Obtém os parâmetros
double anguloAtual = double.Parse(txtAnguloGPS.Text);
var _Gps = Variaveis.OperacaoEmAndamento.Sensoriamento.Gps;
var _Gps = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps;
double anguloControle = 0.0;
TipoMovimentoDirecional tipoMovimento = Variaveis.OperacaoEmAndamento.Controle.TipoMovimento;
var tipoControle = Variaveis.OperacaoEmAndamento.Controle.TipoControleDirecional;
var tipoControle = Variaveis.OperacaoEmAndamento.Parametros.Controle.DirTipoMovimento;
if (passosOperacao.Count > 0 && Variaveis.OperacaoEmAndamento.Simulando)
{
@ -319,7 +325,7 @@ namespace AgroBase.Forms
AtualizarPosicaoGPS();
Variaveis.OperacaoEmAndamento.Sensoriamento.AtualizarDados();
Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.AtualizarDados();
if (!chbAutomatico.Checked)
{
@ -434,8 +440,8 @@ namespace AgroBase.Forms
{
//double angulo = Variaveis.OperacaoEmAndamento.Trajetoria.AnguloCaminho;
//double anguloCorredor = Variaveis.OperacaoEmAndamento.Trajetoria.AnguloMedioCorredor;
double angulo = Variaveis.OperacaoEmAndamento.Trajetoria.ProximoPonto?.Orientacao ?? 0;
double anguloCorredor = Variaveis.OperacaoEmAndamento.Trajetoria.AnguloCaminho;
double angulo = Variaveis.OperacaoEmAndamento.Trajetoria?.ProximoPonto?.Orientacao ?? 0;
double anguloCorredor = Variaveis.OperacaoEmAndamento.Trajetoria?.AnguloCaminho ?? 0;
FuncoesGlobais.DesenharInclinacao((Panel)sender, e, (float)angulo, 90, (float)anguloCorredor);
}
catch { }
@ -445,7 +451,7 @@ namespace AgroBase.Forms
{
try
{
double angulo = Variaveis.OperacaoEmAndamento.Sensoriamento.Gps?.AnguloCarroDefinido ?? 0;
double angulo = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura?.Gps?.AnguloCarroDefinido ?? 0;
FuncoesGlobais.DesenharInclinacao((Panel)sender, e, (float)angulo, 90);
}
catch { }
@ -456,7 +462,7 @@ namespace AgroBase.Forms
try
{
double angulo = Variaveis.OperacaoEmAndamento.SimulacaoAnguloControle;
double dif = Variaveis.OperacaoEmAndamento.Sensoriamento.Trajetoria?.ErroOrientacaoAngularProximoPonto ?? 0;
double dif = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura?.Trajetoria?.ErroOrientacaoAngularProximoPonto ?? 0;
FuncoesGlobais.DesenharInclinacao((Panel)sender, e, (float)angulo, 90, (float)dif);
}
catch { }
@ -500,7 +506,7 @@ namespace AgroBase.Forms
private void cmbTipoControleDirecional_SelectedIndexChanged(object sender, EventArgs e)
{
Variaveis.OperacaoEmAndamento.Controle.TipoControleDirecional = (TiposControladorDirecional)cmbTipoControleDirecional.SelectedIndex;
Variaveis.OperacaoEmAndamento.Parametros.Controle.DirTipoMovimento = (TiposControladorDirecional)cmbTipoControleDirecional.SelectedIndex;
RedisService.AtualizarCampos(CtxKey.DadosOperacao, ("configurado", false));
}

View File

@ -69,7 +69,7 @@ namespace AgroBase.Forms.Simuladores
Task.Run(async () =>
{
OAKCameraFrameModel frame = await VisualWorkerService.GetCameraFrame(CameraFrameType.Segmentacao);
var dadosSeg = Variaveis.OperacaoEmAndamento.Sensoriamento.OperadorVisual.Analises.segmentacao;
var dadosSeg = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.OperadorVisual.Analises.segmentacao;
DesenharCorredor(frame?.image(), dadosSeg.centros_corredor, dadosSeg.width, dadosSeg.height, 80);
this.Invoke((MethodInvoker)(() =>

View File

@ -214,7 +214,7 @@ namespace AgroBase.Forms
{
try
{
double angulo = Variaveis.OperacaoEmAndamento.Sensoriamento.Gps.AnguloCarroDefinido;
double angulo = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps.AnguloCarroDefinido;
FuncoesGlobais.DesenharInclinacao((Panel)sender, e, (float)angulo, 90);
}
catch { }
@ -476,7 +476,7 @@ namespace AgroBase.Forms
{
Latitude = GPSService.UltimaLeitura.Latitude,
Longitude = GPSService.UltimaLeitura.Longitude,
Orientation = Variaveis.OperacaoEmAndamento.Sensoriamento.Gps.AnguloCarroDefinido
Orientation = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps.AnguloCarroDefinido
});
_robotState.UpdateCurrentRobotState();

View File

@ -69,9 +69,9 @@ namespace AgroBase.Forms
AtualizarDadosSensorCorrente("AB36V", lblB36V);
}
lblMagnetometro.ForeColor = Variaveis.OperacaoEmAndamento.Sensoriamento.IMU.Iniciado ? Color.Green : Color.Red;
lblMagnetometro.ForeColor = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.IMU.Iniciado ? Color.Green : Color.Red;
var Gps = Variaveis.OperacaoEmAndamento.Sensoriamento.Gps;
var Gps = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps;
lblGPS.ForeColor = Gps.Inicializado ? Color.Green : Color.Red;
if (Gps.Inicializado)
{
@ -395,7 +395,7 @@ namespace AgroBase.Forms
private void pnlOrientacaoGPS_Paint(object sender, PaintEventArgs e)
{
var _Sensoriamento = Variaveis.OperacaoEmAndamento.Sensoriamento;
var _Sensoriamento = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura;
double Angulo = _Sensoriamento.Gps.OrientacaoReal;
double AnguloMovimento = _Sensoriamento.Gps.OrientacaoMovimento;
FuncoesGlobais.DesenharInclinacao((Panel)sender, e, (float)Angulo, -90, (float)AnguloMovimento);
@ -403,7 +403,7 @@ namespace AgroBase.Forms
private void pnlOrientacaoMagnetometro_Paint(object sender, PaintEventArgs e)
{
var _Sensoriamento = Variaveis.OperacaoEmAndamento.Sensoriamento;
var _Sensoriamento = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura;
double Angulo = _Sensoriamento.IMU.Rotacao;
double AnguloCorrigido = _Sensoriamento.IMU.RotacaoCorrigida;
FuncoesGlobais.DesenharInclinacao((Panel)sender, e, (float)Angulo, -90, (float)AnguloCorrigido);

View File

@ -41,7 +41,7 @@ namespace AgroBase.Forms
private async Task tmrLeitura_Tick()
{
var Gps = Variaveis.OperacaoEmAndamento.Sensoriamento.Gps;
var Gps = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps;
lblAltitude.Text = "Altitude: " + Gps.Altitude.ToString("0.0") + " m";
lblDatahora.Text = "Ultima Leitura: " + Gps.DataHora.ToString("HH:mm:ss");

View File

@ -62,7 +62,7 @@ namespace AgroBase.Forms
private void btnRegistrarPontos_Click(object sender, EventArgs e)
{
GPSModel P1 = Variaveis.OperacaoEmAndamento.Sensoriamento.Gps.Clone();
GPSModel P1 = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps.Clone();
if (Pontos[idxRua].Count == 0)
{
@ -127,8 +127,8 @@ namespace AgroBase.Forms
{
try
{
double angulo = Variaveis.OperacaoEmAndamento.Sensoriamento.Gps.AnguloCarroDefinido;
double anguloCorredor = Variaveis.OperacaoEmAndamento.Sensoriamento.Gps.OrientacaoMovimento;
double angulo = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps.AnguloCarroDefinido;
double anguloCorredor = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps.OrientacaoMovimento;
FuncoesGlobais.DesenharInclinacao((Panel)sender, e, (float)angulo, 90, (float)anguloCorredor);
}
catch { }
@ -180,7 +180,7 @@ namespace AgroBase.Forms
ultimoPonto = Pontos[Pontos.Count - 2][Pontos[Pontos.Count - 2].Count - 1];
}
var Gps = Variaveis.OperacaoEmAndamento.Sensoriamento.Gps;
var Gps = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps;
pnlOrientacaoGps.Invalidate();
lblStatusGPS.Text = $"GPS - Precisão: {Gps.PrecisaoCm} cm, " +

View File

@ -172,7 +172,7 @@ namespace AgroBase
tkbVelocidade.Minimum = 0;
tkbVelocidade.Maximum = 100;
FuncoesGlobais.PreencheValorTrackBar(tkbVelocidade, Variaveis.OperacaoEmAndamento.Controle.VelocidadeMP);
FuncoesGlobais.PreencheValorTrackBar(tkbVelocidade, Variaveis.OperacaoEmAndamento.Parametros.Controle.DirVelocidadeMovimento);
tkbAngulo.Minimum = 0;
tkbAngulo.Maximum = 90;
@ -181,7 +181,7 @@ namespace AgroBase
trkKmh.Minimum = 0;
trkKmh.Maximum = 100;
trkRPM.Minimum = Variaveis.OperacaoEmAndamento.Controle.RPM_Min;
trkRPM.Minimum = Variaveis.OperacaoEmAndamento.Parametros.Controle.MovVelocidadeCErvasPercent;
trkRPM.Maximum = VariaveisEquipamento.RPM_Max_Roda;
AtualizaRPM((int)Variaveis.OperacaoEmAndamento.Controle.PercentualVelocidadeSP);
@ -267,8 +267,8 @@ namespace AgroBase
private void tkbVelocidadeMP_ValueChanged(object sender, EventArgs e)
{
Variaveis.OperacaoEmAndamento.Controle.VelocidadeMP = tkbVelocidade.Value;
lblVelocidade.Text = "Velocidade: " + Variaveis.OperacaoEmAndamento.Controle.VelocidadeMP + "%";
Variaveis.OperacaoEmAndamento.Parametros.Controle.DirVelocidadeMovimento = tkbVelocidade.Value;
lblVelocidade.Text = "Velocidade: " + Variaveis.OperacaoEmAndamento.Parametros.Controle.DirVelocidadeMovimento + "%";
}
private void tkbAngulo_ValueChanged(object sender, EventArgs e)

View File

@ -59,7 +59,7 @@ namespace AgroBase.Forms
private async Task tmrLeitura_Tick()
{
var Imu = Variaveis.OperacaoEmAndamento.Sensoriamento.IMU;
var Imu = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.IMU;
AnguloX = Imu.InclinacaoFrontal;
AnguloY = Imu.InclinacaoLateral;
AnguloZ = Imu.Rotacao;

View File

@ -181,7 +181,8 @@
Aguardando = 3,
EmAndamento = 4,
Parado = 5,
Concluido = 6
Concluido = 6,
Erro = 7
}
public enum StatusCarroMapa

View File

@ -66,6 +66,8 @@ namespace AgroBase.Models
public DateTime UltimoComandoRespondido { get; set; }
public double AnguloCarroDefinido { get; set; }
public int Heartbeat { get; set; } = 0;
public double LeverArmLateral { get; set; } = 0;
public double LeverArmFrontal { get; set; } = 0;
public GPSModel Clone()
{
@ -105,6 +107,10 @@ namespace AgroBase.Models
PDOP = PDOP,
VDOP = VDOP,
BaseID = BaseID,
LeverArmFrontal = LeverArmFrontal,
LeverArmLateral = LeverArmLateral,
X = X,
Y = Y
};
}
}

View File

@ -826,7 +826,7 @@ namespace AgroBase
private static bool VerificaComandoValidoSonar(Keys Comando)
{
List<Keys> ComandosImpedidos = new List<Keys>();
var Sonar = Variaveis.OperacaoEmAndamento.Sensoriamento.OperadorVisual;
var Sonar = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.OperadorVisual;
Sonar?.Resumo?.AtualizarStatusBloqueio(false);
var DeveParar = Sonar?.Resumo?.DeveParar ?? false;
if (DeveParar)

View File

@ -64,7 +64,7 @@ public class MPCController
public async Task EnviarDadosTrajetoria(List<PontoTrajetoriaModel> _trajetoria)
{
var _Controle = Variaveis.OperacaoEmAndamento.Controle;
var pControle = Variaveis.OperacaoEmAndamento.Parametros.Controle;
var trajetoria = new
{
@ -78,10 +78,10 @@ public class MPCController
})
.ToList(),
horizonte = Horizonte,
angulo_max_graus = _Controle.Angulo_Max,
angulo_max_graus = pControle.DirAnguloMaximo,
distancia_entre_eixos = (VariaveisEquipamento.DistanciaEntreEixos / 100.0),
velocidade_min = FuncoesMatematicas.CalculaVelocidadeMsPercentual(_Controle.PercentualVelocidadeMin),
velocidade_max = FuncoesMatematicas.CalculaVelocidadeMsPercentual(_Controle.PercentualVelocidadeMax)
velocidade_min = FuncoesMatematicas.CalculaVelocidadeMsPercentual(pControle.MovVelocidadeCErvasPercent),
velocidade_max = FuncoesMatematicas.CalculaVelocidadeMsPercentual(pControle.MovVelocidadeSErvasPercent)
};
await Variaveis.MqttServiceLocal.PublishAsync(
@ -101,7 +101,7 @@ public class MPCController
_dt = (EnviadoEm - _ultimaAtualizacao).TotalSeconds;
double dtCalc = Math.Max(tempoMinimo, Math.Min(tempoMaximo, _dt));
var _Sensoriamento = Variaveis.OperacaoEmAndamento.Sensoriamento;
var _Sensoriamento = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura;
var dadosEnvio = new
{

View File

@ -24,10 +24,10 @@ public class MPCControllerAprimorado
public MPCControllerAprimorado()
{
this.maxAnguloDirecao = Variaveis.OperacaoEmAndamento?.Controle?.Angulo_Max ?? 30.0;
this.maxAnguloDirecao = Variaveis.OperacaoEmAndamento.Parametros?.Controle?.DirAnguloMaximo ?? 30.0;
this.maxAngulo4Rodas = this.maxAnguloDirecao * 0.8;
this.velocidadeMin = Variaveis.OperacaoEmAndamento?.Controle?.PercentualVelocidadeMin ?? 20.0;
this.velocidadeMax = Variaveis.OperacaoEmAndamento?.Controle?.PercentualVelocidadeMax ?? 100.0;
this.velocidadeMin = Variaveis.OperacaoEmAndamento.Parametros?.Controle?.MovVelocidadeCErvasPercent ?? 20.0;
this.velocidadeMax = Variaveis.OperacaoEmAndamento.Parametros?.Controle?.MovVelocidadeSErvasPercent ?? 100.0;
}
public (double anguloControle, Enums.TipoMovimentoDirecional modo) CalcularControle(GPSModel posicalAtual, double velocidadeAtual, List<GPSModel> proximaTrajetoria, Enums.TipoMovimentoDirecional[] modosPermitidos)

View File

@ -28,10 +28,10 @@ public class MPCControllerSimple
{
// Definições baseadas em variáveis globais
this.horizon = Convert.ToInt32(distancePredict / TrajetoriaMapaOperacaoModel.DistanciaEntrePontos);
this.maxSteeringAngle = Variaveis.OperacaoEmAndamento?.Controle?.Angulo_Max ?? 30.0;
this.maxSteeringAngle = Variaveis.OperacaoEmAndamento.Parametros.Controle?.DirAnguloMaximo ?? 30.0;
this.maxSteeringAngleFourWheels = this.maxSteeringAngle * 1.0;
this.minVelocity = Variaveis.OperacaoEmAndamento?.Controle?.PercentualVelocidadeMin ?? 20.0;
this.maxVelocity = Variaveis.OperacaoEmAndamento?.Controle?.PercentualVelocidadeMax ?? 100.0;
this.minVelocity = Variaveis.OperacaoEmAndamento.Parametros.Controle?.MovVelocidadeCErvasPercent ?? 20.0;
this.maxVelocity = Variaveis.OperacaoEmAndamento.Parametros.Controle?.MovVelocidadeSErvasPercent ?? 100.0;
this.accelerationLimit = 1.5; // Limita aceleração a valores realistas
}
@ -52,7 +52,7 @@ public class MPCControllerSimple
List<(double steering, Enums.TipoMovimentoDirecional mode)> candidates = GenerateControlCandidates();
double bestCost = double.MaxValue;
(double steeringAngle, Enums.TipoMovimentoDirecional mode) bestControl = (0, Enums.TipoMovimentoDirecional.RodasDianteiras);
bool insideStreet = Variaveis.OperacaoEmAndamento.Sensoriamento.Trajetoria.CorredorAtual.Dentro;
bool insideStreet = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Trajetoria.CorredorAtual.Dentro;
double velocity = FuncoesMatematicas.CalculaVelocidadeMsPercentual(currentVelocity);
double distanciaPasso = dt * velocity;

View File

@ -666,7 +666,7 @@ namespace AgroBase.Models
private void DrawObstacle(Graphics g, float xRobot, float yRobot, Color pointColor, Color borderColor, float angle, Obstaculo obstaculo, float PxToCm)
{
GPSModel posicaoRobo = Variaveis.OperacaoEmAndamento.Sensoriamento.Gps;
GPSModel posicaoRobo = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps;
GPSModel posicaoObstaculo = GPSUtils.GerarPontoDeslocado(posicaoRobo, angle, obstaculo.DistanciaMedia_mm / 1000);
float x = xRobot + (float)((posicaoObstaculo.Longitude - posicaoRobo.Longitude) * _zoom);

View File

@ -157,66 +157,66 @@ namespace AgroBase.Models
}
}
public void PopularTrajetoriaMapa()
public void PopularTrajetoriaMapa(MapaFeatureCollectionModel dados = null)
{
if (mapaService.DadosMapa != null)
if (dados != null) mapaService.DadosMapa = dados;
if (mapaService.DadosMapa == null) return;
double OrientacaoRuas = -999;
//DistanciaTotal = 0;
/*if (!RuasPercorrer.Any())
{
double OrientacaoRuas = -999;
//DistanciaTotal = 0;
/*if (!RuasPercorrer.Any())
{
RuasPercorrer = mapaService.DadosMapa.features.Select(x => x.geometry.id).ToList();
}*/
TrajetoriaMapa = new List<List<GPSModel>>();
RuasPercorrer = mapaService.DadosMapa.features.Select(x => x.geometry.id).ToList();
}*/
TrajetoriaMapa = new List<List<GPSModel>>();
foreach (var ID in RuasPercorrer)
foreach (var ID in RuasPercorrer)
{
var rua = mapaService.DadosMapa.features.FirstOrDefault(x => ID == x.geometry.id);
if (rua != null)
{
var rua = mapaService.DadosMapa.features.FirstOrDefault(x => ID == x.geometry.id);
if (rua != null)
TrajetoriaMapa.Add(new List<GPSModel>());
foreach (var ponto in rua.geometry.coordinates)
{
TrajetoriaMapa.Add(new List<GPSModel>());
foreach (var ponto in rua.geometry.coordinates)
/*if (rua.geometry.coordinates.IndexOf(ponto) == 0 || rua.geometry.coordinates.IndexOf(ponto) == rua.geometry.coordinates.Count - 1)
{
/*if (rua.geometry.coordinates.IndexOf(ponto) == 0 || rua.geometry.coordinates.IndexOf(ponto) == rua.geometry.coordinates.Count - 1)
{
continue;
}*/
continue;
}*/
GPSModel item = new GPSModel()
{
Longitude = ponto[0],
Latitude = ponto[1],
};
TrajetoriaMapa[TrajetoriaMapa.Count - 1].Add(item);
/*if (Trajetoria[Trajetoria.Count - 1].Count > 1)
{
DistanciaTotal += GPSService.DistanciaEntrePontos(Trajetoria[Trajetoria.Count - 1][Trajetoria[Trajetoria.Count - 1].Count - 2], item);
}*/
}
GPSModel item = new GPSModel()
{
Longitude = ponto[0],
Latitude = ponto[1],
};
TrajetoriaMapa[TrajetoriaMapa.Count - 1].Add(item);
/*if (Trajetoria[Trajetoria.Count - 1].Count > 1)
{
DistanciaTotal += GPSService.DistanciaEntrePontos(Trajetoria[Trajetoria.Count - 1][Trajetoria[Trajetoria.Count - 1].Count - 2], item);
}*/
}
var Rua = TrajetoriaMapa[TrajetoriaMapa.Count - 1];
if (OrientacaoRuas == -999)
var Rua = TrajetoriaMapa[TrajetoriaMapa.Count - 1];
if (OrientacaoRuas == -999)
{
OrientacaoRuas = GPSUtils.CalcularOrientacao(Rua[Rua.Count - 1], Rua[Rua.Count - 2]);
}
else
{
double MargemErroAngulo = 45;
double orientacaoRua = GPSUtils.CalcularOrientacao(Rua[Rua.Count - 1], Rua[Rua.Count - 2]);
double anguloOposto = (orientacaoRua + 180) % 360;
if ((anguloOposto + MargemErroAngulo) >= OrientacaoRuas && (anguloOposto - MargemErroAngulo) <= OrientacaoRuas)
{
OrientacaoRuas = GPSUtils.CalcularOrientacao(Rua[Rua.Count - 1], Rua[Rua.Count - 2]);
}
else
{
double MargemErroAngulo = 45;
double orientacaoRua = GPSUtils.CalcularOrientacao(Rua[Rua.Count - 1], Rua[Rua.Count - 2]);
double anguloOposto = (orientacaoRua + 180) % 360;
if ((anguloOposto + MargemErroAngulo) >= OrientacaoRuas && (anguloOposto - MargemErroAngulo) <= OrientacaoRuas)
{
Rua.Reverse();
}
Rua.Reverse();
}
}
}
}
if (TrajetoriaMapa.Any())
{
Variaveis.OperacaoEmAndamento.Trajetoria = new TrajetoriaMapaOperacaoModel(TrajetoriaMapa);
Variaveis.OperacaoEmAndamento.Trajetoria.ProjetarTrajetoriaFixa();
}
if (TrajetoriaMapa.Any())
{
Variaveis.OperacaoEmAndamento.Trajetoria = new TrajetoriaMapaOperacaoModel(TrajetoriaMapa);
Variaveis.OperacaoEmAndamento.Trajetoria.ProjetarTrajetoriaFixa();
}
}

View File

@ -55,7 +55,7 @@ namespace AgroBase.Models.Modules
FuncoesPinout.SDA,
FuncoesPinout.SCL,
};
public int QuantidadeBicos { get; set; } = 4;
//public int QuantidadeBicos { get; set; } = 4;
public double DensidadeHerbicida { get; set; } = 1.0;
public List<AtuadorBicoModel> BicosPulverizadores { get; set; } = new List<AtuadorBicoModel>();
public List<AtuadorBombaModel> BombasPressurizadoras { get; set; } = new List<AtuadorBombaModel>();
@ -90,7 +90,7 @@ namespace AgroBase.Models.Modules
{
get
{
return VolumeReservatorio / Variaveis.OperacaoEmAndamento.CapacidadeReservatorio * 100.0;
return VolumeReservatorio / Variaveis.OperacaoEmAndamento.Parametros.CapacidadeReservatorio * 100.0;
}
}
#endregion
@ -140,7 +140,7 @@ namespace AgroBase.Models.Modules
}
public void AtualizaPercentualErvas()
{
double tempoTotalOperacao = Variaveis.OperacaoEmAndamento.Sensoriamento.TempoDecorridoSeg * 1000.0;
double tempoTotalOperacao = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.TempoDecorridoSeg * 1000.0;
if (tempoTotalOperacao > 0)
{
@ -225,7 +225,6 @@ namespace AgroBase.Models.Modules
_EnderecoCAN_Rx = 0x12,
_TaxaAmostragem = 1000,
RequisitarDados = true,
QuantidadeBicos = 4,
BicosPulverizadores = new List<AtuadorBicoModel>(),
BombasPressurizadoras = new List<AtuadorBombaModel>()
{
@ -422,7 +421,7 @@ namespace AgroBase.Models.Modules
},
},
};
for (int i = 0; i < Atuador.QuantidadeBicos; i++)
for (int i = 0; i < Variaveis.OperacaoEmAndamento.Parametros.QtdBicos; i++)
{
int posicao = (i + 1);
Atuador.BicosPulverizadores.Add(new AtuadorBicoModel()
@ -779,7 +778,7 @@ namespace AgroBase.Models.Modules
bomba.ComandoAtuar = false;
}
// Religa a bomba caso esteja desligada, o nivel de herbicida esta estavel e o pulverizador automatico esta ligado
else if (PercentualReservatorio >= VariaveisEquipamento.PercentualReservatorioMin && leituraEstado == false && Variaveis.OperacaoEmAndamento.Controle.PulverizadorAutomatico)
else if (PercentualReservatorio >= VariaveisEquipamento.PercentualReservatorioMin && leituraEstado == false && Variaveis.OperacaoEmAndamento.Parametros.Controle.PulverizadorAutomatico)
{
bomba.ComandoAtuar = true;
}
@ -1077,7 +1076,7 @@ namespace AgroBase.Models.Modules
{
(byte)Componente,
(byte)(conectar ? 1 : 0),
(byte)Variaveis.OperacaoEmAndamento.Controle.PressaoLinha,
(byte)Variaveis.OperacaoEmAndamento.Parametros.Controle.AtuPressaoLinha,
(byte)(pinout.Pinos.FirstOrDefault(x => x.ComponenteID == ID && x.Funcao == FuncoesPinout.ENA)?.Pino ?? PinoutUtils.PINO_INVALIDO),
(byte)(pinout.Pinos.FirstOrDefault(x => x.Funcao == FuncoesPinout.CS)?.Pino ?? PinoutUtils.PINO_INVALIDO),
};
@ -1105,12 +1104,12 @@ namespace AgroBase.Models.Modules
new byte[]
{
(byte)(ComandoAtuar ? Estado.Ligado : Estado.Desligado),
(byte)(Variaveis.OperacaoEmAndamento.Controle.PressaoLinha)
(byte)(Variaveis.OperacaoEmAndamento.Parametros.Controle.AtuPressaoLinha)
}
);
}
public bool AtingiuPressao() => Variaveis.OperacaoEmAndamento.DispAtu.Dados.PressaoLinha >= Variaveis.OperacaoEmAndamento.Controle.PressaoLinha;
public bool AtingiuPressao() => Variaveis.OperacaoEmAndamento.DispAtu.Dados.PressaoLinha >= Variaveis.OperacaoEmAndamento.Parametros.Controle.AtuPressaoLinha;
}

View File

@ -29,7 +29,7 @@ namespace AgroBase.Models.Modules
{
get
{
return Convert.ToInt32(((Variaveis.OperacaoEmAndamento.Controle?.VelocidadeMP ?? 0) / 100.0) * Velocidade_Max);
return Convert.ToInt32(((Variaveis.OperacaoEmAndamento.Parametros?.Controle?.DirVelocidadeMovimento ?? 0) / 100.0) * Velocidade_Max);
}
}

View File

@ -489,7 +489,7 @@ namespace AgroBase.Models.Modules
}
private double VelocidadeAtual =>
FuncoesMatematicas.CalculaVelocidadePercentualMs(Variaveis.OperacaoEmAndamento.Sensoriamento.Movimentacao?.VelocidadeMedia ?? 0);
FuncoesMatematicas.CalculaVelocidadePercentualMs(Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura?.Movimentacao?.VelocidadeMedia ?? 0);
private bool StatusControleEmFreio =>
(Variaveis.OperacaoEmAndamento.Controle?.TiposControle?

View File

@ -7,7 +7,6 @@ using static AgroBase.Models.Enums;
using System.Globalization;
using System.Data;
using static AgroBase.Services.LoRaEspService;
using System.Windows.Forms;
using AgroBase.Services.Operadores;
using AgroBase.Models.Operadores;
using System.Diagnostics;
@ -1689,7 +1688,7 @@ namespace AgroBase.Models.Modules
},
};
for (int i = 0; i < Variaveis.OperacaoEmAndamento.QuantidadeCamerasSolo; i++)
for (int i = 0; i < Variaveis.OperacaoEmAndamento.Parametros.QtdCamerasSolo; i++)
{
obj.CamerasSolo.Add(new OAKCameraModel());
}
@ -2025,7 +2024,7 @@ namespace AgroBase.Models.Modules
GeneralJoystick.EnviarComandoSensoriamento(S_Code.sLED, ledOP.ID, comportamento);
}
var statusLedAt = Variaveis.OperacaoEmAndamento.Controle.MovimentoAutomatico ? StatusLED.Aceso : StatusLED.Apagado;
var statusLedAt = Variaveis.OperacaoEmAndamento.Parametros.Controle.MovimentoAutomatico ? StatusLED.Aceso : StatusLED.Apagado;
var valAt = (int?)(ledAT?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.StatusLEDComando)?.atual?.valor) ?? 0;
if (ledAT != null && (!ledAT.Comportamento.statusLED.Equals(statusLedAt) || (valAt != (int)statusLedAt)))
{
@ -2931,7 +2930,7 @@ namespace AgroBase.Models.Modules
{
case DadosLoRaParse.ComandoControle:
{
Keys tecla = (Keys)data[2];
BotoesJoystick tecla = (BotoesJoystick)data[2];
int percentualVelocidadeSp = data[3];
TipoMovimentoDirecional tipoMovimentoDirecional = (TipoMovimentoDirecional)data[4];
int anguloMp = data[5];
@ -2939,15 +2938,17 @@ namespace AgroBase.Models.Modules
T_Code dispositivo = (T_Code)data[6];
bool emergencia = data[7] == 1;
OperacaoControleBaseModel Controle = new OperacaoControleBaseModel()
OperacaoComandoBaseModel Controle = new OperacaoComandoBaseModel()
{
Momento = DateTime.Now,
Tecla = tecla,
AnguloMP = anguloMp,
Controle = new OperacaoComandoBaseControleModel()
{
AnguloSP = anguloMp,
PercentualVelocidadeSP = percentualVelocidadeSp,
TipoMovimentoDirecional = tipoMovimentoDirecional,
},
Emergencia = emergencia,
PercentualVelocidadeSP = percentualVelocidadeSp,
TipoMovimento = tipoMovimentoDirecional,
//VelocidadeMP = velocidadeMp,
Dispositivo = dispositivo
};
Variaveis.OperacaoEmAndamento.ExecutaComandoDaBase(Controle);

File diff suppressed because it is too large Load Diff

View File

@ -5,25 +5,55 @@ namespace AgroBase.Models.Operacoes
{
public class OperacaoParametrosModel
{
public string RoverId { get; set; }
public bool Alive { get; set; }
public bool Configurado { get; set; }
public ModoOperacao Modo { get; set; }
public string Descricao { get; set; }
public int QtdCamerasSolo { get; set; }
public int QtdBicos { get; set; }
public double CapacidadeReservatorio { get; set; }
public List<OperacaoModulosMandatoriosModel> ModulosMandatorios { get; set; }
public List<OperacaoParametrosMandatoriosModel> ParametrosMandatorios { get; set; }
public int MovVelocidadeSErvasPercent { get; set; }
public int MovVelocidadeCErvasPercent { get; set; }
public int DirAnguloMaximo { get; set; }
public int DirVelocidadeMovimento { get; set; }
public TiposControladorDirecional DirTipoMovimento { get; set; }
public int AtuPercentualDeteccaoVertical { get; set; }
public double AtuCapacidadeReservatorio { get; set; }
public double AtuPressaoLinha { get; set; }
public int AtuDuracaoAtuacao { get; set; }
public MapasModel Mapa { get; set; }
public UltrasonicA05Configuracoes ConfiguracaoUltrassom { get; set; }
public OperacaoParametrosControleModel Controle { get; set; }
public MapaFeatureCollectionModel Mapa { get; set; }
public List<string> RuasPercorrer { get; set; }
public OperacaoSensoriamentoLogModel DadosLeitura { get; set; }
}
public class OperacaoParametrosControleModel
{
public bool SonarAtivado { get; set; }
public int QtdCamerasSolo { get; set; }
public bool MovimentoAutomatico { get; set; }
public bool PulverizadorAutomatico { get; set; }
public bool FrenagemAtuomatica { get; set; }
public bool FrenagemAutomatica { get; set; }
public int MovVelocidadeSErvasPercent { get; set; }
public int MovRpmMax
{
get
{
return System.Convert.ToInt32(VariaveisEquipamento.RPM_Max_Roda * (MovVelocidadeSErvasPercent / 100.0));
}
}
public int MovVelocidadeCErvasPercent { get; set; }
public int MovRpmMin
{
get
{
return System.Convert.ToInt32(VariaveisEquipamento.RPM_Max_Roda * (MovVelocidadeCErvasPercent / 100.0));
}
}
public int DirAnguloMaximo { get; set; }
public double DirVelocidadeMovimento { get; set; }
public TiposControladorDirecional DirTipoMovimento { get; set; }
public double AtuPressaoLinha { get; set; }
public int AtuDuracaoAtuacao { get; set; }
public double AtuPercentualInicioPulverizacao { get; set; }
public double AtuAlturaAreaPulverizacao { get; set; }
public double AtuPercentualErvasBicoOn { get; set; }
public double AtuPercentualErvasBicoOff { get; set; }
}
}

View File

@ -61,10 +61,10 @@ namespace AgroBase.Models.Operadores
public void AtualizarStatusBloqueio(bool consideraEmMovimento)
{
var Sonar = Variaveis.OperacaoEmAndamento.Sensoriamento.OperadorVisual;
var Sonar = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.OperadorVisual;
ObstaculoDetectado = (Sonar.Analises?.matriz_confianca?.block?.decision?.parar ?? false);
if (!Variaveis.OperacaoEmAndamento.Controle.SonarAtivado)
if (!Variaveis.OperacaoEmAndamento.Parametros.Controle.SonarAtivado)
{
_comandoParadaEnviado = false;
DeveParar = false;

View File

@ -176,7 +176,7 @@ namespace AgroBase.Models
public void DetectarObstaculos(OAKDLiteSubdivisoesModel modelo)
{
Subdivisoes = service.ConverterSubdivisoes(modelo);
Obstaculos = service.IdentificarObstaculos(Subdivisoes, Variaveis.OperacaoEmAndamento.Controle.SonarAtivado);
Obstaculos = service.IdentificarObstaculos(Subdivisoes, Variaveis.OperacaoEmAndamento.Parametros.Controle.SonarAtivado);
AtualizarDadosObstaculos(modelo?.x_max ?? 640, modelo?.y_max ?? 480);
}

View File

@ -601,7 +601,7 @@ namespace AgroBase.Models
{
get
{
return DistanciaMedia / FuncoesMatematicas.ConverteKmhParaMs(Variaveis.OperacaoEmAndamento.Sensoriamento.Movimentacao.VelocidadeMedia);
return DistanciaMedia / FuncoesMatematicas.ConverteKmhParaMs(Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Movimentacao.VelocidadeMedia);
}
}
public double DeslocamentoNecessarioDesvio
@ -769,18 +769,18 @@ namespace AgroBase.Models
{
get
{
double anguloAbsolutoObstaculo = (Variaveis.OperacaoEmAndamento.Sensoriamento.Gps.AnguloCarroDefinido + AnguloInicial + AnguloFinal) / 2.0;
double anguloAbsolutoObstaculo = (Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps.AnguloCarroDefinido + AnguloInicial + AnguloFinal) / 2.0;
double anguloRad = anguloAbsolutoObstaculo * (Math.PI / 180.0);
// Supondo que a distância seja em metros e utilizando uma aproximação simples da Terra como esfera
// para converter distância e ângulo em mudança de latitude/longitude.
double deltaLatitude = (DistanciaMedia * Math.Cos(anguloRad)) / 111111; // Dividindo por 111111 para converter metros em graus
double deltaLongitude = (DistanciaMedia * Math.Sin(anguloRad)) / (111111 * Math.Cos(Variaveis.OperacaoEmAndamento.Sensoriamento.Gps.Latitude * (Math.PI / 180.0)));
double deltaLongitude = (DistanciaMedia * Math.Sin(anguloRad)) / (111111 * Math.Cos(Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps.Latitude * (Math.PI / 180.0)));
return new GPSModel
{
Latitude = Variaveis.OperacaoEmAndamento.Sensoriamento.Gps.Latitude + deltaLatitude,
Longitude = Variaveis.OperacaoEmAndamento.Sensoriamento.Gps.Longitude + deltaLongitude
Latitude = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps.Latitude + deltaLatitude,
Longitude = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps.Longitude + deltaLongitude
};
}
}

View File

@ -36,9 +36,9 @@ namespace AgroBase.Models
public double TempoEntreLeituras { get; private set; }
private void AtualizarTempoEntreLeituras()
{
double dt = Math.Min((1.0 / GPSService.TaxaAmostragemHz), (UltimaAtualizacaoDados - Variaveis.OperacaoEmAndamento.Sensoriamento.Gps.Momento).TotalSeconds);
double dt = Math.Min((1.0 / GPSService.TaxaAmostragemHz), (UltimaAtualizacaoDados - Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps.Momento).TotalSeconds);
TempoEntreLeituras = dt;
UltimaAtualizacaoDados = Variaveis.OperacaoEmAndamento.Sensoriamento.Gps.Momento;
UltimaAtualizacaoDados = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps.Momento;
}
public List<List<GPSModel>> RuasPlantacao { get; set; }
@ -81,8 +81,8 @@ namespace AgroBase.Models
{
get
{
double distPP = GPSUtils.DistanciaEntrePontos(Variaveis.OperacaoEmAndamento.Sensoriamento.Gps, PrimeiroPontoRuaMapa);
double distUP = GPSUtils.DistanciaEntrePontos(Variaveis.OperacaoEmAndamento.Sensoriamento.Gps, UltimoPontoRuaMapa);
double distPP = GPSUtils.DistanciaEntrePontos(Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps, PrimeiroPontoRuaMapa);
double distUP = GPSUtils.DistanciaEntrePontos(Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps, UltimoPontoRuaMapa);
// 0 para mais próximo do primeiro ponto da rua (ENTRANDO)
// 1 para mais próximo do último ponto da rua (SAINDO)
@ -122,7 +122,7 @@ namespace AgroBase.Models
{
new PontoTrajetoriaModel(TipoPontoRua.PosicaoRobo)
{
Posicao = Variaveis.OperacaoEmAndamento.Sensoriamento.Gps,
Posicao = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps,
LarguraCorredor = 1.0,
idxCorredor = CorredorAtual?.Idx ?? 0,
Visitado = true
@ -215,7 +215,7 @@ namespace AgroBase.Models
private void AtualizarAnguloCaminho()
{
PontoTrajetoriaModel pontoComparar = PontoAtual.Aproximando ? PontoAtual : ProximoPonto != null ? ProximoPonto : PontoAtual;
AnguloCaminho = GPSUtils.CalcularOrientacao(Variaveis.OperacaoEmAndamento.Sensoriamento.Gps, pontoComparar.Posicao);
AnguloCaminho = GPSUtils.CalcularOrientacao(Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps, pontoComparar.Posicao);
}
[JsonProperty]
public double DistanciaEsquerda { get; private set; }
@ -223,8 +223,8 @@ namespace AgroBase.Models
public double DistanciaDireita { get; private set; }
private void AtualizarDistanciasLaterais()
{
DistanciaEsquerda = CalcularDistanciaLateral(true, Variaveis.OperacaoEmAndamento.Sensoriamento.Gps, CorredorAtual?.idxRuaEsquerda ?? 0, PontoAtual?.Direcao ?? DirecaoCarroRua.Ida);
DistanciaDireita = CalcularDistanciaLateral(false, Variaveis.OperacaoEmAndamento.Sensoriamento.Gps, CorredorAtual?.idxRuaDireita ?? 0, PontoAtual?.Direcao ?? DirecaoCarroRua.Ida);
DistanciaEsquerda = CalcularDistanciaLateral(true, Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps, CorredorAtual?.idxRuaEsquerda ?? 0, PontoAtual?.Direcao ?? DirecaoCarroRua.Ida);
DistanciaDireita = CalcularDistanciaLateral(false, Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps, CorredorAtual?.idxRuaDireita ?? 0, PontoAtual?.Direcao ?? DirecaoCarroRua.Ida);
}
public double CalcularDistanciaLateral(bool ladoEsquerdo, GPSModel posicaoAtual, int idxRua, DirecaoCarroRua direcaoAtual)
@ -472,11 +472,11 @@ namespace AgroBase.Models
{
if (!velocidadeSemErvasMs.HasValue)
{
velocidadeSemErvasMs = FuncoesMatematicas.CalculaVelocidadeMsPercentual(Variaveis.OperacaoEmAndamento.Controle.PercentualVelocidadeMax) * 0.8;
velocidadeSemErvasMs = FuncoesMatematicas.CalculaVelocidadeMsPercentual(Variaveis.OperacaoEmAndamento.Parametros.Controle.MovVelocidadeSErvasPercent) * 0.8;
}
if (!velocidadeComErvasMs.HasValue)
{
velocidadeComErvasMs = FuncoesMatematicas.CalculaVelocidadeMsPercentual(Variaveis.OperacaoEmAndamento.Controle.PercentualVelocidadeMin);
velocidadeComErvasMs = FuncoesMatematicas.CalculaVelocidadeMsPercentual(Variaveis.OperacaoEmAndamento.Parametros.Controle.MovVelocidadeCErvasPercent);
}
// Supondo que metade do percurso tem ervas e a outra metade não tem
@ -527,12 +527,12 @@ namespace AgroBase.Models
if (CorredorAtual.Idx > 0) return;
if (!CorredorAtual.Dentro) return;
GPSModel posicaoAtual = Variaveis.OperacaoEmAndamento.Sensoriamento.Gps.Clone();
GPSModel posicaoAtual = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps.Clone();
if (PrimeiroPontoDentroMapa == null) PrimeiroPontoDentroMapa = posicaoAtual;
var OpVisual = Variaveis.OperacaoEmAndamento.Sensoriamento?.OperadorVisual ?? new VisualWorkerModel();
StatusModulo OpVisualStatus = Variaveis.OperacaoEmAndamento.Sensoriamento.ModulosSaude.FirstOrDefault(x => x.modulo == T_Code.Snr)?.status ?? StatusModulo.Desconectado;
var OpVisual = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura?.OperadorVisual ?? new VisualWorkerModel();
StatusModulo OpVisualStatus = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.ModulosSaude.FirstOrDefault(x => x.modulo == T_Code.Snr)?.status ?? StatusModulo.Desconectado;
if (OpVisualStatus != StatusModulo.Operante) return;
@ -558,7 +558,7 @@ namespace AgroBase.Models
private void AtualizarErroCombinado()
{
var _Sensoriamento = Variaveis.OperacaoEmAndamento.Sensoriamento;
var _Sensoriamento = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura;
//double anguloCamera = _Sensoriamento.OperadorVisual.Leitura.obj?.segmentacao?.angulo_rua ?? 0;
double anguloCorredor = AnguloMedioCorredor;
@ -575,7 +575,7 @@ namespace AgroBase.Models
double curvaDaRua = GPSUtils.CalcularDiferencaAngulo(anguloProximoPonto, anguloCorredor);
// Peso do desalinhamento atual (prioriza alinhar o robô ao corredor)
double pesoAlinhamento = Math.Min(Math.Abs(desalinhamentoComRua) / Variaveis.OperacaoEmAndamento.Controle.Angulo_Max, 1.0); // Normaliza até 30°
double pesoAlinhamento = Math.Min(Math.Abs(desalinhamentoComRua) / Variaveis.OperacaoEmAndamento.Parametros.Controle.DirAnguloMaximo, 1.0); // Normaliza até 30°
// Peso do centro (prioriza ir pro ponto central do corredor)
double pesoCentro = 1.0 - pesoAlinhamento;
@ -736,9 +736,9 @@ namespace AgroBase.Models
double limiarDistanciaMargem = DistanciaErroMapaPlantacao > -1 ? DistanciaErroMapaPlantacao : 5.0;
double distanciaCorredor = CorredorAtual.DistanciaTotal;
double distanciaRestanteCorredor = CorredorAtual.DistanciaRestante;
double distanciaUltimoPontoCorredor = GPSUtils.DistanciaEntrePontos(Variaveis.OperacaoEmAndamento.Sensoriamento.Gps, CorredorAtual.Pontos.LastOrDefault().Posicao);
var OpVisual = Variaveis.OperacaoEmAndamento.Sensoriamento?.OperadorVisual ?? new VisualWorkerModel();
StatusModulo OpVisualStatus = Variaveis.OperacaoEmAndamento.Sensoriamento.ModulosSaude.FirstOrDefault(x => x.modulo == T_Code.Snr)?.status ?? StatusModulo.Desconectado;
double distanciaUltimoPontoCorredor = GPSUtils.DistanciaEntrePontos(Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps, CorredorAtual.Pontos.LastOrDefault().Posicao);
var OpVisual = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura?.OperadorVisual ?? new VisualWorkerModel();
StatusModulo OpVisualStatus = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.ModulosSaude.FirstOrDefault(x => x.modulo == T_Code.Snr)?.status ?? StatusModulo.Desconectado;
var DadosSegmentacao = OpVisual.Analises?.segmentacao ?? new VisualWorkerMessageSegmentacaoSemanticaModel();
if (OpVisualStatus == StatusModulo.Operante || Variaveis.OperacaoEmAndamento.Simulando) //OpVisual.Iniciado &&
@ -782,7 +782,7 @@ namespace AgroBase.Models
double anguloControle = Variaveis.OperacaoEmAndamento.Controle.Angulo;
if (abrirCurva && !CorredorAtual.Ultimo)
{
anguloControle = CorredorAtual.idxRuaDireita > CorredorAtual.idxRuaEsquerda ? Variaveis.OperacaoEmAndamento.Controle.Angulo_Min : Variaveis.OperacaoEmAndamento.Controle.Angulo_Max;
anguloControle = CorredorAtual.idxRuaDireita > CorredorAtual.idxRuaEsquerda ? -Variaveis.OperacaoEmAndamento.Parametros.Controle.DirAnguloMaximo : Variaveis.OperacaoEmAndamento.Parametros.Controle.DirAnguloMaximo;
}
int pontosMarcar = 0;
@ -812,7 +812,7 @@ namespace AgroBase.Models
{
Console.WriteLine($"Angulo de controle definido de {Variaveis.OperacaoEmAndamento.Controle.Angulo} para {anguloControle}");
Variaveis.OperacaoEmAndamento.Controle.Angulo = anguloControle;
Variaveis.OperacaoEmAndamento.Controle.PercentualVelocidadeSP = Variaveis.OperacaoEmAndamento.Controle.PercentualVelocidadeMin;
Variaveis.OperacaoEmAndamento.Controle.PercentualVelocidadeSP = Variaveis.OperacaoEmAndamento.Parametros.Controle.MovVelocidadeCErvasPercent;
Variaveis.OperacaoEmAndamento.Controle.TipoMovimento = TipoMovimentoDirecional.MovimentoArco;
Variaveis.OperacaoEmAndamento.Controle.TiposControle.FirstOrDefault(x => x.Tipo == T_Code.Dir).DelayEnvioComandoExtra = 1500;
Variaveis.OperacaoEmAndamento.Controle.TiposControle.FirstOrDefault(x => x.Tipo == T_Code.Mov).DelayEnvioComandoExtra = 2000;
@ -933,7 +933,7 @@ namespace AgroBase.Models
Console.WriteLine("Muito tempo sem receber novo comando do Manager Worker! Reduzindo Velocidade!");
RedisService.AtualizarCampos(
CtxKey.DadosControle,
("velocidade_sp", _Controle.PercentualVelocidadeMin)
("velocidade_sp", Variaveis.OperacaoEmAndamento.Parametros.Controle.MovVelocidadeCErvasPercent)
);
}
}
@ -1179,7 +1179,7 @@ namespace AgroBase.Models
idxCorredor = 0,
idxPonto = 0,
idxPontoCorredor = 0,
Posicao = posicaoRobo ?? Variaveis.OperacaoEmAndamento.Sensoriamento.Gps,
Posicao = posicaoRobo ?? Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps,
Orientacao = 0,
Direcao = direcaoAtual,
Visitado = true,
@ -1478,7 +1478,7 @@ namespace AgroBase.Models
public void AjustarTrajetoriaParaDesvio(Obstaculo obstaculo)
{
GPSModel posicaoAtual = Variaveis.OperacaoEmAndamento.Sensoriamento.Gps;
GPSModel posicaoAtual = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps;
double distanciaObstaculo = ((double)obstaculo.DistanciaMedia_mm / 1000);
double larguraObstaculo = ((double)obstaculo.Largura_mm / 1000);
@ -1726,7 +1726,7 @@ namespace AgroBase.Models
private void AtualizarOrientacaoAtual()
{
OrientacaoAtual = GPSUtils.CalcularOrientacao(Variaveis.OperacaoEmAndamento.Sensoriamento.Gps, Posicao);
OrientacaoAtual = GPSUtils.CalcularOrientacao(Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps, Posicao);
}
private void AtualizarOrientacaoAnterior()
@ -1780,7 +1780,7 @@ namespace AgroBase.Models
private void AtualizarDistanciaAtual()
{
DistanciaAtual = GPSUtils.DistanciaEntrePontos(Variaveis.OperacaoEmAndamento.Sensoriamento.Gps, Posicao);
DistanciaAtual = GPSUtils.DistanciaEntrePontos(Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Gps, Posicao);
}
private void AtualizarDistanciaAnterior()

View File

@ -55,7 +55,7 @@ namespace AgroBase.Models
public static string CaminhoParametros { get; } = "Parametros/";
public static string CaminhoModelos { get; } = "C:\\AgroBaseModels\\";
public static List<IDispositivosService> DispositivosConectados { get; set; } = new List<IDispositivosService>();
public static OperacaoModel OperacaoEmAndamento { get; set; } = new OperacaoModel(ModoOperacao.Manual);
public static OperacaoModel OperacaoEmAndamento { get; set; } = new OperacaoModel(ModoOperacao.MapaGPS);
public static MqttService MqttServiceLocal { get; set; }
public static MqttService MqttServiceBase { get; set; }
public static LoRaEspService LoraService
@ -109,7 +109,7 @@ namespace AgroBase.Models
MqttServiceBase.Topicos.Clear();
}
MqttServiceLocal = new MqttService("localhost", 1883, IsAgroMonitor ? "base" : VariaveisEquipamento.Parametros.serial_number, true, msg => Console.WriteLine($"[MQTT localhost:{1883}] - {msg}"));
MqttServiceLocal = new MqttService("localhost", 1883, VariaveisEquipamento.Parametros.serial_number, true, msg => Console.WriteLine($"[MQTT localhost:{1883}] - {msg}"));
await MqttServiceLocal.AdicionarNovoTopico(MapasVariaveisModel.TopicoCoordenadasGPS);
await MqttServiceLocal.AdicionarNovoTopico(MapasVariaveisModel.TopicoTrajetoriaDinamica);
await MqttServiceLocal.AdicionarNovoTopico(MapasVariaveisModel.TopicoSelecaoRuasMapa, true, 1, async (message) =>
@ -120,14 +120,19 @@ namespace AgroBase.Models
MqttServiceBase = new MqttService(VariaveisEquipamento.Parametros.base_ip, 1883, VariaveisEquipamento.Parametros.serial_number, false, msg => Console.WriteLine($"[MQTT {VariaveisEquipamento.Parametros.base_ip}:{1883}] - {msg}"));
await MqttServiceBase.AdicionarNovoTopico(VariaveisMonitoramento.TopicoMqttDispositivos);
await MqttServiceBase.AdicionarNovoTopico(VariaveisEquipamento.TopicoMqttTelemetria.Replace("<id>", VariaveisEquipamento.Parametros.serial_number));
await MqttServiceBase.AdicionarNovoTopico(VariaveisEquipamento.TopicoMqttParametros.Replace("<id>", VariaveisEquipamento.Parametros.serial_number));
await MqttServiceBase.AdicionarNovoTopico(VariaveisEquipamento.TopicoMqttHeartbeat.Replace("<id>", VariaveisEquipamento.Parametros.serial_number), true, 1, async (message) =>
{
if (string.IsNullOrEmpty(message.Mensagem)) return;
VariaveisOperacao.PosicaoBase.UltimoComandoRespondido = DateTime.Now;
});
await MqttServiceBase.AdicionarNovoTopico(VariaveisEquipamento.TopicoMqttComandos.Replace("<id>", VariaveisEquipamento.Parametros.serial_number), true, 1, async (message) =>
{
if (string.IsNullOrEmpty(message.Mensagem))
return;
if (string.IsNullOrEmpty(message.Mensagem)) return;
try
{
string json = message.Mensagem;
var cmd = JsonConvert.DeserializeObject<OperacaoControleBaseModel>(json);
var cmd = JsonConvert.DeserializeObject<OperacaoComandoBaseModel>(json);
OperacaoEmAndamento.ExecutaComandoDaBase(cmd);
}
catch (Exception ex)
@ -160,6 +165,7 @@ namespace AgroBase.Models
{
string json = message.Mensagem;
var posicao = JsonConvert.DeserializeObject<GPSModel>(json);
posicao.Momento = DateTime.Now;
VariaveisOperacao.PosicaoBase = posicao;
}
catch (Exception ex)
@ -197,15 +203,17 @@ namespace AgroBase.Models
_parametros = value;
}
}
public static string TopicoMqttHeartbeat { get; } = $"agrobot/v1/rover/<id>/heartbeat";
public static string TopicoMqttComandos { get; } = $"agrobot/v1/rover/<id>/cmd";
public static string TopicoMqttTelemetria { get; } = $"agrobot/v1/rover/<id>/telemetry";
public static string TopicoMqttParametros { get; } = $"agrobot/v1/rover/<id>/parameters";
public static double LarguraEsquerda { get; } = 44.0; // 62
public static double LarguraDireita { get; } = 44.0; // 22
public static double ComprimentoFrente { get; } = 7.0; // 7
public static double ComprimentoTras { get; } = 107.0; // 107
public static double LeverArmFrontal { get; } = 1.0;
public static double LeverArmLateral { get; } = 0.0;
public static double DistanciaEntreEixos { get; } = 92.0;
public static double LeverArmFrontal { get; set; } = 100.0; // cm
public static double LeverArmLateral { get; set; } = 0.0; // cm
public static double LarguraEquipamentoMm
{
get
@ -219,6 +227,9 @@ namespace AgroBase.Models
public static double PercentualTensaoBateriaMin { get; set; } = 25.0;
public static double PercentualReservatorioMin { get; set; } = 8.0;
public static double PercentualToleranciaPressaoLinha { get; set; } = 0.15;
public static int QuantidadeCamerasSolo { get; set; } = 1;
public static int QuantidadeBicosPulverizadores { get; set; } = 4;
public static double CapacidadeReservatorio { get; set; } = 30;
public static double ReducaoDirecional { get; set; } = 20.0;
public static int RPM_Min_Roda { get; set; } = 15;
public static int RPM_Max_Roda
@ -554,6 +565,8 @@ namespace AgroBase.Models
public bool Carregado { get; set; }
public string serial_number { get; set; }
public string base_ip { get; set; }
public int base_porta_caminho { get; set; }
public int base_porta_ervas { get; set; }
public void AtualizarParametros()
{
@ -568,6 +581,8 @@ namespace AgroBase.Models
serial_number = par.serial_number;
base_ip = par.base_ip;
base_porta_caminho = par.base_porta_caminho;
base_porta_ervas = par.base_porta_ervas;
Carregado = true;
}
@ -590,7 +605,7 @@ namespace AgroBase.Models
{
if (!Variaveis.IsAgroMonitor && Variaveis.OperacaoEmAndamento.DispAtu != null)
{
return Variaveis.OperacaoEmAndamento.Sensoriamento.Atuador.PercentualErvasTerreno / 100.0;
return Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Atuador.PercentualErvasTerreno / 100.0;
}
return 0.3;
}
@ -601,7 +616,7 @@ namespace AgroBase.Models
{
if (!Variaveis.IsAgroMonitor && Variaveis.OperacaoEmAndamento.DispAtu != null)
{
return (100.0 - Variaveis.OperacaoEmAndamento.Sensoriamento.Atuador.PercentualErvasTerreno) / 100.0;
return (100.0 - Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Atuador.PercentualErvasTerreno) / 100.0;
}
return 0.7;
}

View File

@ -217,7 +217,7 @@ namespace AgroMonitor
idxTick++;
}
public static async void EnviarDadosControle(string rover_id, OperacaoControleBaseModel controle)
public static async void EnviarDadosControle(string rover_id, OperacaoComandoBaseModel controle)
{
var topico = Variaveis.MqttServiceLocal.Topicos.FirstOrDefault(x => x.Topico == VariaveisEquipamento.TopicoMqttComandos.Replace("<id>", rover_id));
if (topico != null)

View File

@ -66,7 +66,7 @@ namespace AgroBase.Services
public void AtualizarConsumo()
{
var Bateria = Variaveis.OperacaoEmAndamento.Sensoriamento.Bateria;
var Bateria = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.Bateria;
if (!Bateria.Iniciado)
{

View File

@ -943,9 +943,13 @@ namespace AgroBase.Services
{
PenultimaLeitura.Ntrip_ativado = UltimaLeitura.Ntrip_ativado;
PenultimaLeitura.Heartbeat = UltimaLeitura.Heartbeat;
PenultimaLeitura.LeverArmFrontal = UltimaLeitura.LeverArmFrontal;
PenultimaLeitura.LeverArmLateral = UltimaLeitura.LeverArmLateral;
UltimaLeitura.Ntrip_ativado = CorrecaoRTK_Ntrip;
UltimaLeitura.Heartbeat = (UltimaLeitura.Heartbeat + 1) % 10;
UltimaLeitura.LeverArmFrontal = VariaveisEquipamento.LeverArmFrontal;
UltimaLeitura.LeverArmLateral = VariaveisEquipamento.LeverArmLateral;
if (Variaveis.IsAgroMonitor)
{
@ -1142,7 +1146,7 @@ namespace AgroBase.Services
{
double anguloFinal = 0.0;
bool imuIniciado = Variaveis.OperacaoEmAndamento.Sensoriamento.IMU?.Iniciado ?? false;
bool imuIniciado = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura?.IMU?.Iniciado ?? false;
bool gpsIniciado = Iniciado;
if (imuIniciado)
@ -1162,7 +1166,7 @@ namespace AgroBase.Services
double heading = UltimaLeitura.OrientacaoReal;
double angMov = UltimaLeitura.OrientacaoMovimento;
double distJan = UltimaLeitura.Distancia;
double velPercent = Variaveis.OperacaoEmAndamento.Simulando ? Variaveis.OperacaoEmAndamento.Controle.RPM_SP : Variaveis.OperacaoEmAndamento.Sensoriamento.Movimentacao?.RPMMedio ?? 0;
double velPercent = Variaveis.OperacaoEmAndamento.Simulando ? Variaveis.OperacaoEmAndamento.Controle.RPM_SP : Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura?.Movimentacao?.RPMMedio ?? 0;
bool rtkFix = UltimaLeitura.QualidadeFix == TiposCorrecaoGPS.RTKFixo;
double angAnterior = UltimaLeitura.AnguloCarroDefinido;
@ -1173,7 +1177,7 @@ namespace AgroBase.Services
else if (imuIniciado)
{
// Apenas o WT901C está disponível
anguloFinal = Variaveis.OperacaoEmAndamento.Sensoriamento.IMU.RotacaoCorrigida;
anguloFinal = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura.IMU.RotacaoCorrigida;
}
else
{
@ -1330,10 +1334,10 @@ namespace AgroBase.Services
public class GeoLeverArm
{
public GeoLeverArm(double _xb = 0, double _yb = 0, bool _invH = false, bool _mirrL = false)
public GeoLeverArm(double _xbCm = 0, double _ybCm = 0, bool _invH = false, bool _mirrL = false)
{
xB = _xb;
yB = _yb;
xB = _xbCm / 100.0;
yB = _ybCm / 100.0;
invertHeading = _invH;
mirrorLateral = _mirrL;
}

View File

@ -624,7 +624,7 @@ namespace AgroBase.Services
public static Bitmap ExibirObstaculos(Bitmap bitmap, List<Subdivisao> subdivisoes, List<Obstaculo> obstaculos, bool ExibirTexto = false)
{
if (bitmap == null || (!Variaveis.OperacaoEmAndamento.Controle.SonarAtivado && Variaveis.OperacaoEmAndamento.Iniciado))
if (bitmap == null || (!Variaveis.OperacaoEmAndamento.Parametros.Controle.SonarAtivado && Variaveis.OperacaoEmAndamento.Iniciado))
{
return bitmap;
}
@ -968,7 +968,7 @@ namespace AgroBase.Services
private static List<Obstaculo> IdentificarObstaculos()
{
if (!Variaveis.OperacaoEmAndamento.Controle.SonarAtivado || Parametros.Subdivisoes == null)
if (!Variaveis.OperacaoEmAndamento.Parametros.Controle.SonarAtivado || Parametros.Subdivisoes == null)
{
return new List<Obstaculo>();
}

View File

@ -682,7 +682,7 @@ namespace AgroBase.Services
}
}
public static void EnviarDadosComandoControle(OperacaoControleBaseModel Controle, byte EnderecoDestinatario)
public static void EnviarDadosComandoControle(OperacaoComandoBaseModel Controle, byte EnderecoDestinatario)
{
if (Iniciado)
{

View File

@ -137,7 +137,7 @@ namespace AgroBase.Services
if (ageRxMs > beaconPeriodoMs + 2000) return;
// --- ENVIO (ideal: agregue em 1-2 frames) ---
var s = Variaveis.OperacaoEmAndamento.Sensoriamento;
var s = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura;
foreach (var dado in LoRaSerializer.SerializeGPS(s.Gps))
Variaveis.LoraService?.EnviarDadosLoRaViaCAN(dado);

View File

@ -160,7 +160,7 @@ namespace AgroBase.Services
return (Endereco, model);
}
public static byte[] SerializeControleModel(OperacaoControleBaseModel model)
public static byte[] SerializeControleModel(OperacaoComandoBaseModel model)
{
List<byte> bytes = new List<byte>();
@ -174,26 +174,26 @@ namespace AgroBase.Services
bytes.AddRange(BitConverter.GetBytes((int)model.Dispositivo));
// Serializar RPM
bytes.AddRange(BitConverter.GetBytes(model.PercentualVelocidadeSP));
bytes.AddRange(BitConverter.GetBytes(model.Controle.PercentualVelocidadeSP));
// Serializar AnguloMP
bytes.AddRange(BitConverter.GetBytes(model.AnguloMP));
bytes.AddRange(BitConverter.GetBytes(model.Controle.AnguloSP));
// Serializar VelocidadeMP
bytes.AddRange(BitConverter.GetBytes(model.VelocidadeMP));
bytes.AddRange(BitConverter.GetBytes(model.Controle.VelocidadeMP));
// Serializar Emergencia
bytes.AddRange(BitConverter.GetBytes(model.Emergencia));
// Serializar TipoMovimento (int)
bytes.AddRange(BitConverter.GetBytes((int)model.TipoMovimento));
bytes.AddRange(BitConverter.GetBytes((int)model.Controle.TipoMovimentoDirecional));
return bytes.ToArray();
}
public static OperacaoControleBaseModel DeserializeControleModel(byte[] bytes)
public static OperacaoComandoBaseModel DeserializeControleModel(byte[] bytes)
{
OperacaoControleBaseModel model = new OperacaoControleBaseModel();
OperacaoComandoBaseModel model = new OperacaoComandoBaseModel();
int index = 0;
// Desserializar Momento (DateTime)
@ -201,7 +201,7 @@ namespace AgroBase.Services
index += sizeof(long);
// Desserializar Tecla (int)
model.Tecla = (Keys)BitConverter.ToInt32(bytes, index);
model.Tecla = (BotoesJoystick)BitConverter.ToInt32(bytes, index);
index += sizeof(int);
// Desserializar Dispositivo (int)
@ -209,15 +209,15 @@ namespace AgroBase.Services
index += sizeof(int);
// Desserializar RPM
model.PercentualVelocidadeSP = BitConverter.ToDouble(bytes, index);
model.Controle.PercentualVelocidadeSP = BitConverter.ToDouble(bytes, index);
index += sizeof(double);
// Desserializar AnguloMP
model.AnguloMP = BitConverter.ToDouble(bytes, index);
model.Controle.AnguloSP = BitConverter.ToDouble(bytes, index);
index += sizeof(double);
// Desserializar VelocidadeMP
model.VelocidadeMP = BitConverter.ToDouble(bytes, index);
model.Controle.VelocidadeMP = BitConverter.ToDouble(bytes, index);
index += sizeof(double);
// Desserializar Emergencia
@ -225,7 +225,7 @@ namespace AgroBase.Services
index += sizeof(bool);
// Desserializar TipoMovimento (int)
model.TipoMovimento = (TipoMovimentoDirecional)BitConverter.ToInt32(bytes, index);
model.Controle.TipoMovimentoDirecional = (TipoMovimentoDirecional)BitConverter.ToInt32(bytes, index);
index += sizeof(int);
return model;
@ -274,14 +274,14 @@ namespace AgroBase.Services
};
}
public static byte[] SerializeComandoControle(OperacaoControleBaseModel Controle)
public static byte[] SerializeComandoControle(OperacaoComandoBaseModel Controle)
{
List<byte> dados = new List<byte>();
dados.AddRange(CanPrefix(DadosLoRaParse.ComandoControle));
dados.Add((byte)Controle.Tecla); // 1 byte
dados.Add((byte)Controle.PercentualVelocidadeSP); // 1 byte
dados.Add((byte)Controle.TipoMovimento); // 1 byte
dados.Add((byte)Controle.AnguloMP); // 1 byte
dados.Add((byte)Controle.Controle.PercentualVelocidadeSP); // 1 byte
dados.Add((byte)Controle.Controle.TipoMovimentoDirecional); // 1 byte
dados.Add((byte)Controle.Controle.AnguloSP); // 1 byte
//dados.Add((byte)Controle.VelocidadeMP); // 1 byte
dados.Add((byte)Controle.Dispositivo); // 1 byte
dados.Add((byte)(Controle.Emergencia ? 1 : 0)); // 1 byte
@ -296,7 +296,8 @@ namespace AgroBase.Services
dados.Add((byte)Controle.PercentualVelocidadeSP); // 1 byte
dados.Add((byte)Controle.TipoMovimento); // 1 byte
dados.Add((byte)Controle.Angulo); // 1 byte
dados.Add((byte)Controle.VelocidadeMP); // 1 byte
//dados.Add((byte)Controle.VelocidadeMP); // 1 byte
dados.Add((byte)0); // 1 byte
return dados.ToArray();
}

View File

@ -108,7 +108,7 @@ namespace AgroBase.Services.Operadores
AtualizarDadosModulos();
AtualizarDadosControleOperacao();
var _Sensoriamento = Variaveis.OperacaoEmAndamento.Sensoriamento;
var _Sensoriamento = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura;
if (_Sensoriamento == null)
{
@ -165,6 +165,9 @@ namespace AgroBase.Services.Operadores
{
RedisService.AtualizarCampos(
CtxKey.DadosEquipamento,
("base_ip", VariaveisEquipamento.Parametros.base_ip),
("base_porta_caminho", VariaveisEquipamento.Parametros.base_porta_caminho),
("base_porta_ervas", VariaveisEquipamento.Parametros.base_porta_ervas),
("largura", VariaveisEquipamento.LarguraEquipamentoMm / 1000.0),
("distancia_entre_eixos", VariaveisEquipamento.DistanciaEntreEixos / 100.0),
("percentual_reservatorio_min", VariaveisEquipamento.PercentualReservatorioMin),
@ -195,6 +198,8 @@ namespace AgroBase.Services.Operadores
return;
}
var _Parametros = Variaveis.OperacaoEmAndamento.Parametros;
var pControle = _Parametros.Controle;
var _Controle = Variaveis.OperacaoEmAndamento.Controle;
RedisService.AtualizarCampos(
@ -202,20 +207,20 @@ namespace AgroBase.Services.Operadores
("configurado", true),
("modo", Variaveis.OperacaoEmAndamento.Modo),
("tempo_aguardar_inicio_operacao", Variaveis.OperacaoEmAndamento.TempoIniciarOperacao),
("modulos_mandatorios", Variaveis.OperacaoEmAndamento.ModulosMandatorios.Where(x => x.Mandatorio && x.Utilizar).Select(x => (int)x.Dispositivo).ToArray()),
("modulos_opcionais", Variaveis.OperacaoEmAndamento.ModulosMandatorios.Where(x => !x.Mandatorio && x.Utilizar).Select(x => (int)x.Dispositivo).ToArray()),
("parametros_mandatorios", Variaveis.OperacaoEmAndamento.ParametrosMandatorios.Where(x => x.Mandatorio && x.Utilizar).Select(x => (int)x.Parametro).ToArray()),
("modulos_mandatorios", _Parametros.ModulosMandatorios.Where(x => x.Mandatorio && x.Utilizar).Select(x => (int)x.Dispositivo).ToArray()),
("modulos_opcionais", _Parametros.ModulosMandatorios.Where(x => !x.Mandatorio && x.Utilizar).Select(x => (int)x.Dispositivo).ToArray()),
("parametros_mandatorios", _Parametros.ParametrosMandatorios.Where(x => x.Mandatorio && x.Utilizar).Select(x => (int)x.Parametro).ToArray()),
("Mov", new
{
percent_vel_max = _Controle.PercentualVelocidadeMax,
percent_vel_min = _Controle.PercentualVelocidadeMin,
percent_vel_max = pControle.MovVelocidadeSErvasPercent,
percent_vel_min = pControle.MovVelocidadeCErvasPercent,
}
),
("Dir", new
{
angulo_max = _Controle.Angulo_Max,
vel_movimento = _Controle.VelocidadeMP,
tipo_controle = (int)_Controle.TipoControleDirecional,
angulo_max = pControle.DirAnguloMaximo,
vel_movimento = pControle.DirVelocidadeMovimento,
tipo_controle = (int)pControle.DirTipoMovimento,
mpc = new
{
pontos = Variaveis.OperacaoEmAndamento.Trajetoria?._TrajetoriaFixa?
@ -228,9 +233,9 @@ namespace AgroBase.Services.Operadores
})
.ToList(),
horizonte = 2.5,
angulo_max_graus = _Controle.Angulo_Max,
velocidade_min = FuncoesMatematicas.CalculaVelocidadeMsPercentual(_Controle.PercentualVelocidadeMin),
velocidade_max = FuncoesMatematicas.CalculaVelocidadeMsPercentual(_Controle.PercentualVelocidadeMax),
angulo_max_graus = pControle.DirAnguloMaximo,
velocidade_min = FuncoesMatematicas.CalculaVelocidadeMsPercentual(pControle.MovVelocidadeCErvasPercent),
velocidade_max = FuncoesMatematicas.CalculaVelocidadeMsPercentual(pControle.MovVelocidadeSErvasPercent),
tempo_entre_comandos = (Variaveis.OperacaoEmAndamento.Controle.TiposControle.FirstOrDefault(x => x.Tipo == Enums.T_Code.Dir)?.DelayEnvioComando ?? 500) / 1000.0,
passos_atraso = 1
}
@ -238,11 +243,14 @@ namespace AgroBase.Services.Operadores
),
("Atu", new
{
qtd_bicos = Variaveis.OperacaoEmAndamento.DispAtu.Dados.QuantidadeBicos,
tempo_atuacao = _Controle.TempoAtuacao,
capacidade_reservatorio = Variaveis.OperacaoEmAndamento.CapacidadeReservatorio,
pressao_linha = _Controle.PressaoLinha,
percent_vertical_deteccao = _Controle.PercentualInicioPulverizacao,
qtd_bicos = _Parametros.QtdBicos,
tempo_atuacao = pControle.AtuDuracaoAtuacao,
capacidade_reservatorio = _Parametros.CapacidadeReservatorio,
pressao_linha = pControle.AtuPressaoLinha,
percent_vertical_deteccao = pControle.AtuPercentualInicioPulverizacao,
height_area_deteccao = pControle.AtuAlturaAreaPulverizacao,
pct_erva_bico_on = pControle.AtuPercentualErvasBicoOn,
pct_erva_bico_off = pControle.AtuPercentualErvasBicoOff
}
),
("Snr", new
@ -268,12 +276,13 @@ namespace AgroBase.Services.Operadores
public static void AtualizarDadosControleOperacao()
{
var pControle = Variaveis.OperacaoEmAndamento.Parametros.Controle;
RedisService.AtualizarCampos(
CtxKey.DadosControle,
("pulverizador_automatico", Variaveis.OperacaoEmAndamento.Controle.PulverizadorAutomatico),
("movimento_automatico", Variaveis.OperacaoEmAndamento.Controle.MovimentoAutomatico),
("frenagem_automatica", Variaveis.OperacaoEmAndamento.Controle.FrenagemAutomatica),
("sonar_ativado", Variaveis.OperacaoEmAndamento.Controle.SonarAtivado)
("pulverizador_automatico", pControle.PulverizadorAutomatico),
("movimento_automatico", pControle.MovimentoAutomatico),
("frenagem_automatica", pControle.FrenagemAutomatica),
("sonar_ativado", pControle.SonarAtivado)
);
}
@ -281,7 +290,7 @@ namespace AgroBase.Services.Operadores
{
if (Variaveis.OperacaoEmAndamento.DispMvd == null) return;
var _Sensoriamento = Variaveis.OperacaoEmAndamento.Sensoriamento;
var _Sensoriamento = Variaveis.OperacaoEmAndamento.Parametros.DadosLeitura;
var agora = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
//Console.WriteLine(RedisService.Get(RedisService.ModKey(Enums.T_Code.Gps)));

View File

@ -104,7 +104,7 @@ namespace AgroBase.Services.Operadores
break;
case ManagerWorkerCommandType.EnviarDadosControle:
if (Variaveis.OperacaoEmAndamento.Controle.MovimentoAutomatico)
if (Variaveis.OperacaoEmAndamento.Parametros.Controle.MovimentoAutomatico)
{
AtualizarControle(comando.@params);
}

View File

@ -79,7 +79,7 @@ namespace AgroBase.Services.Operadores
if (!Conectado)
{
TempoDesconectado++;
if (Variaveis.OperacaoEmAndamento.Iniciado && Variaveis.OperacaoEmAndamento.Controle.MovimentoAutomatico)
if (Variaveis.OperacaoEmAndamento.Iniciado && Variaveis.OperacaoEmAndamento.Parametros.Controle.MovimentoAutomatico)
{
RedisService.AtualizarCampos(
CtxKey.DadosOperacao,

View File

@ -101,7 +101,7 @@ namespace AgroBase.Services.Operadores
break;
case WeedWorkerCommandType.EnviarDadosControle:
if (Variaveis.OperacaoEmAndamento.Controle.PulverizadorAutomatico)
if (Variaveis.OperacaoEmAndamento.Parametros.Controle.PulverizadorAutomatico)
{
AtualizarControle(comando.@params);
}

View File

@ -371,7 +371,7 @@ namespace AgroBase.Services
});
if (PrimeiraExecucao)
{
OperacaoModel.CarregarParametrosOperacaoPadrao(ModoOperacao.Manual);
OperacaoModel.CarregarParametrosOperacaoPadrao(ModoOperacao.MapaGPS);
}
}

View File

@ -164,7 +164,7 @@ namespace AgroBase.Services
public static Bitmap ExibirObstaculos(Bitmap bitmap, SonarCamModel leitura, bool ExibirTexto = false)
{
if (bitmap == null || (!Variaveis.OperacaoEmAndamento.Controle.SonarAtivado && Variaveis.OperacaoEmAndamento.Iniciado))
if (bitmap == null || (!Variaveis.OperacaoEmAndamento.Parametros.Controle.SonarAtivado && Variaveis.OperacaoEmAndamento.Iniciado))
{
return bitmap;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -6,12 +6,23 @@ from health_worker.modulos.imu import IMUCamera
from shared.enums import StatusModulo, T_Code
from shared.contexto_global_redis import ContextoGlobalRedis, CtxKey
import subprocess
import cv2
GST_LAUNCH = r"C:\Program Files\gstreamer\1.0\msvc_x86_64\bin\gst-launch-1.0.exe"
class CameraOak:
def __init__(self, mostrar_log, mx_id, modelo_ia_seg=None, modelo_ia_det=None):
self.mostrar_log = mostrar_log
self.modelo_ia_seg = modelo_ia_seg
self.modelo_ia_det = modelo_ia_det
self.gst_proc = None
self.gst_WIDTH = 640
self.gst_HEIGHT = 360
self.gst_FPS = 10
self.gst_BIT_RATE = 500
self._ultimo_envio_gst = 0.0
self.dispositivo = T_Code.Vzo
self.modelo = "Desconhecido"
self.ultima_saude = {}
@ -72,6 +83,39 @@ class CameraOak:
_camera["tem_depht"] = self.tem_depth
_camera["tem_imu"] = self.tem_imu
# Criar processo para transmissao de video
try:
_cfg = ContextoGlobalRedis.get_equipamento() or {}
_ip = _cfg.get("base_ip")
_porta = _cfg.get("base_porta_caminho") if self.dispositivo == T_Code.Snr else _cfg.get("base_porta_ervas")
if _ip is not None and _porta is not None:
self.mostrar_log(f"Iniciando GStreamer para {_ip}:{_porta}...")
gst_cmd = [
GST_LAUNCH,
"fdsrc", "fd=0",
"!", "videoparse",
f"width={self.gst_WIDTH}", f"height={self.gst_HEIGHT}",
"format=bgr",
f"framerate={self.gst_FPS}/1",
"!", "videoconvert",
"!", "videoscale",
"!", f"video/x-raw,width={self.gst_WIDTH},height={self.gst_HEIGHT}",
"!", "x264enc", "tune=zerolatency", "speed-preset=ultrafast",
f"bitrate={self.gst_BIT_RATE}", "key-int-max=20",
"!", "rtph264pay", "config-interval=-1", "pt=96",
#"!", "h264parse", "!", "mpegtsmux",
"!", "udpsink",
f"host={_ip}", f"port={_porta}",
"sync=false", "async=false",
]
self.gst_proc = subprocess.Popen(
gst_cmd,
stdin=subprocess.PIPE,
)
except Exception as e:
self.gst_proc = None
self.mostrar_log(f"Erro ao criar script de transmissao de video: {e}")
# Fase 2: criar pipeline e instanciar normalmente
try:
self.pipeline = self._criar_pipeline()
@ -350,6 +394,32 @@ class CameraOak:
#self.timestamp_ultimo_frame_rgb = time.time()
dur = time.time() - start
_stream_on = (ContextoGlobalRedis.get_camera(self.mx_id) or {}).get("streaming", False)
if self.gst_proc is not None and _stream_on:
# --- CONTROLE DE FPS PARA STREAMING ---
enviar_para_gst = True
if getattr(self, "gst_FPS", None) and self.gst_FPS > 0:
intervalo_min = 1.0 / float(self.gst_FPS)
agora = time.time()
if (agora - self._ultimo_envio_gst) < intervalo_min:
enviar_para_gst = False
else:
self._ultimo_envio_gst = agora
if frame is not None and frame.size > 0 and enviar_para_gst:
# --- RESIZE SÓ PARA O STREAM ---
if frame.shape[1] != self.gst_WIDTH or frame.shape[0] != self.gst_HEIGHT:
frame_stream = cv2.resize(
frame,
(self.gst_WIDTH, self.gst_HEIGHT),
interpolation=cv2.INTER_AREA
)
else:
frame_stream = frame
try:
self.gst_proc.stdin.write(frame_stream.tobytes())
except BrokenPipeError:
self.mostrar_log("GStreamer fechou o pipe. Encerrando.")
resultado = {
"erro": None,
"duracao": dur,

View File

@ -58,7 +58,6 @@ def load_seg_config(force_reload=False):
# "frames_histerese": 2,
# "min_area_px": 400,
# "max_area_frac": 0.2,
# "area_atuacao_bicos": 0.1,
# "ia_roi_begin": 0.0,
# "ia_roi_size": 1.0,
# "ia_resolution": [512,288],
@ -79,7 +78,6 @@ def load_seg_config(force_reload=False):
"frames_histerese": 2,
"min_area_px": 400,
"max_area_frac": 0.2,
"area_atuacao_bicos": 0.1,
"ia_roi_begin": 0.0,
"ia_roi_size": 1.0,
"ia_resolution": [512,288],
@ -97,8 +95,6 @@ def load_seg_config(force_reload=False):
"det_every_n": 0,
"usar_radar_global_gate": True,
"min_frac_erva_por_bico_on": 0.02,
"min_frac_erva_por_bico_off": 0.01,
"max_frac_cana_por_bico": 0.009,
"ema_frac_bico": 0.35,
"on_frames_required": 3,
@ -115,7 +111,10 @@ def load_seg_config(force_reload=False):
_CONFIG_CACHE["ia_model_path"] = ContextoGlobalRedis.get_equipamento().get("path_ia_model_ervas", "C:/AgroBaseModels/Ervas/model-2_1.blob")
_CONFIG_CACHE["ia_labelmap_path"] = ContextoGlobalRedis.get_equipamento().get("path_ia_labelmap_ervas", "C:/AgroBaseModels/Ervas/model-2_1.txt")
_CONFIG_CACHE["faixa_atuacao_bicos"] = dadosAtu.get("percent_vertical_deteccao", 0.3)
_CONFIG_CACHE["faixa_atuacao_bicos"] = dadosAtu.get("percent_vertical_deteccao", 0.7)
_CONFIG_CACHE["area_atuacao_bicos"] = dadosAtu.get("height_area_deteccao", 0.1)
_CONFIG_CACHE["min_frac_erva_por_bico_on"] = dadosAtu.get("pct_erva_bico_on", 0.02)
_CONFIG_CACHE["min_frac_erva_por_bico_off"] = dadosAtu.get("pct_erva_bico_off", 0.01)
return _CONFIG_CACHE
def reload_seg_config():

View File

@ -269,7 +269,7 @@ namespace AgroMonitor.Forms
Keys[] TeclasDir = { Keys.A, Keys.D };
Keys[] TeclasMov = { Keys.W, Keys.S, Keys.Space };
OperacaoControleBaseModel Controle = new OperacaoControleBaseModel()
OperacaoComandoBaseModel Controle = new OperacaoComandoBaseModel()
{
Momento = DateTime.Now,
Tecla = DeParaTeclas[Tecla],

View File

@ -1,5 +1,6 @@
using OperationControl.Models;
using System.Windows;
using Application = System.Windows.Application;
namespace OperationControl
{

View File

@ -19,6 +19,7 @@
</LinearGradientBrush>
<conv:MultiplyConverter x:Key="MultiplyConverter"/>
<conv:LateralErrorToOffsetConverter x:Key="LateralErrorToOffsetConverter"/>
</UserControl.Resources>
<!-- MOLDURA -->
@ -30,6 +31,13 @@
BorderBrush="#2ECC71">
<Grid>
<Grid.RowDefinitions>
<!-- parte de cima: horizonte / attitude -->
<RowDefinition/>
<!-- parte de baixo: barra de erro lateral -->
<RowDefinition Height="24"/>
</Grid.RowDefinitions>
<!-- VIEWPORT: corta o conteúdo dentro do quadro -->
<Grid x:Name="Viewport" ClipToBounds="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
@ -101,6 +109,37 @@
</Grid>
</Grid>
<!-- BARRA DE ERRO LATERAL (linha 1) -->
<Grid Grid.Row="1" Margin="2,6,2,0">
<Border x:Name="LateralTrack" CornerRadius="4" Background="#222" BorderBrush="#555" BorderThickness="1">
<Grid>
<!-- linha de referência (meio da rua) -->
<Rectangle Width="2" Fill="#666" HorizontalAlignment="Center" RadiusX="1" RadiusY="1"/>
<!-- barrinha que se move com o erro -->
<Rectangle Width="32" Height="6" RadiusX="3" RadiusY="3" Fill="#F1C40F" Stroke="#222" StrokeThickness="0.5">
<Rectangle.RenderTransform>
<TranslateTransform>
<TranslateTransform.X>
<MultiBinding Converter="{StaticResource LateralErrorToOffsetConverter}">
<!-- Largura do trilho -->
<Binding ElementName="LateralTrack" Path="ActualWidth"/>
<!-- Erro normalizado (-1 a +1) -->
<Binding Path="LateralNormalized" RelativeSource="{RelativeSource AncestorType=UserControl}"/>
</MultiBinding>
</TranslateTransform.X>
</TranslateTransform>
</Rectangle.RenderTransform>
</Rectangle>
<!-- valor numérico opcional (no canto direito) -->
<TextBlock Text="{Binding LateralError, RelativeSource={RelativeSource AncestorType=UserControl}, StringFormat={}{0:0.00} cm}" Foreground="#AAA" FontSize="10" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0,0,4,0"/>
</Grid>
</Border>
</Grid>
</Grid>
</Border>

View File

@ -1,7 +1,10 @@
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using UserControl = System.Windows.Controls.UserControl;
using Color = System.Windows.Media.Color;
using System.Globalization;
using System.Windows.Data;
namespace OperationControl.Controls
{
@ -81,6 +84,54 @@ namespace OperationControl.Controls
set => SetValue(CriticalLimitProperty, value);
}
// === LATERAL ERROR ===
public static readonly DependencyProperty LateralErrorProperty =
DependencyProperty.Register(
nameof(LateralError),
typeof(double),
typeof(AttitudeIndicator),
new PropertyMetadata(0.0, OnLateralChanged));
public static readonly DependencyProperty LateralMaxAbsProperty =
DependencyProperty.Register(
nameof(LateralMaxAbs),
typeof(double),
typeof(AttitudeIndicator),
new PropertyMetadata(50.0, OnLateralChanged)); // 0,5 m por padrão
private static readonly DependencyPropertyKey LateralNormalizedPropertyKey =
DependencyProperty.RegisterReadOnly(
nameof(LateralNormalized),
typeof(double),
typeof(AttitudeIndicator),
new PropertyMetadata(0.0));
public static readonly DependencyProperty LateralNormalizedProperty =
LateralNormalizedPropertyKey.DependencyProperty;
public double LateralError
{
get => (double)GetValue(LateralErrorProperty);
set => SetValue(LateralErrorProperty, value);
}
public double LateralMaxAbs
{
get => (double)GetValue(LateralMaxAbsProperty);
set => SetValue(LateralMaxAbsProperty, value);
}
/// <summary>
/// Erro lateral normalizado em [-1, 1]
/// -1 = limite à esquerda, 0 = centro, +1 = limite à direita
/// </summary>
public double LateralNormalized
{
get => (double)GetValue(LateralNormalizedProperty);
private set => SetValue(LateralNormalizedPropertyKey, value);
}
// Derivados
public double MaxAbsAngle => Math.Max(Math.Abs(RollDeg), Math.Abs(PitchDeg));
@ -108,5 +159,29 @@ namespace OperationControl.Controls
else
Chrome.BorderBrush = new SolidColorBrush(Color.FromRgb(0x2E, 0xCC, 0x71)); // verde
}
static void OnLateralChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var c = (AttitudeIndicator)d;
c.UpdateLateral();
c.Raise(nameof(LateralNormalized));
}
void UpdateLateral()
{
var max = Math.Max(0.0001, LateralMaxAbs);
// normaliza para [-1, 1] e faz clamp
var n = LateralError / max;
if (n > 1) n = 1;
if (n < -1) n = -1;
LateralNormalized = n;
}
}
}

View File

@ -1,7 +1,7 @@
using OpenTK.Wpf;
using OpenTK.Graphics.OpenGL;
using System.Windows.Controls;
using System.Windows.Input;
using UserControl = System.Windows.Controls.UserControl;
namespace OperationControl.Controls
{
@ -244,7 +244,7 @@ namespace OperationControl.Controls
if (e.ChangedButton == MouseButton.Middle) dragMid = false;
if (!dragLeft && !dragMid) Mouse.Capture(null);
}
void OnMouseMove(object s, MouseEventArgs e)
void OnMouseMove(object s, System.Windows.Input.MouseEventArgs e)
{
var p = e.GetPosition(GLHost);
if (dragLeft)

View File

@ -0,0 +1,15 @@
<UserControl x:Class="OperationControl.Controls.GstVideoView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:OperationControl.Controls"
mc:Ignorable="d"
xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
xmlns:wfi="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"
xmlns:ffme="clr-namespace:Unosquare.FFME;assembly=ffme.win"
Height="247" Width="420">
<Grid Background="Black">
<ffme:MediaElement x:Name="Media" Background="Gray" LoadedBehavior="Play" UnloadedBehavior="Manual" />
</Grid>
</UserControl>

View File

@ -0,0 +1,226 @@
using System.Windows;
using Gst;
using GstVideo;
using Unosquare.FFME;
using Task = System.Threading.Tasks.Task;
using UserControl = System.Windows.Controls.UserControl;
namespace OperationControl.Controls
{
/// <summary>
/// Interaction logic for GstVideoView.xaml
/// </summary>
public partial class GstVideoView : UserControl
{
private Pipeline? _pipeline;
private Element? _videoSink;
private Bus? _bus;
#region DP: Host e Port
public string Host
{
get => (string)GetValue(HostProperty);
set => SetValue(HostProperty, value);
}
public static readonly DependencyProperty HostProperty =
DependencyProperty.Register(
nameof(Host),
typeof(string),
typeof(GstVideoView),
new PropertyMetadata("0.0.0.0", OnEndpointChanged));
public int Port
{
get => (int)GetValue(PortProperty);
set => SetValue(PortProperty, value);
}
public static readonly DependencyProperty PortProperty =
DependencyProperty.Register(
nameof(Port),
typeof(int),
typeof(GstVideoView),
new PropertyMetadata(5000, OnEndpointChanged));
private static void OnEndpointChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var view = (GstVideoView)d;
// Se já estiver carregado, reinicia o pipeline com IP/porta novos
if (view.IsLoaded)
{
//view.RestartPipeline();
}
}
#endregion
public string SourceUrl { get; set; } = "udp://0.0.0.0:5000";
public GstVideoView()
{
InitializeComponent();
InitGStreamer();
Loaded += (_, _) =>
{
//if (VideoPanel.IsHandleCreated == false)
// VideoPanel.CreateControl();
};
Unloaded += (_, _) => Stop();
}
private void InitGStreamer()
{
//Gst.Application.Init();
}
public void StartPipeline()
{
if (_pipeline != null)
return;
// pipeline simples só pra testar: videotestsrc → videoconvert → autovideosink
_pipeline = new Pipeline();
var src = ElementFactory.Make("videotestsrc", "src");
var conv = ElementFactory.Make("videoconvert", "conv");
var sink = ElementFactory.Make("autovideosink", "sink");
if (src is null || conv is null || sink is null)
throw new Exception("Falha ao criar algum elemento do pipeline.");
_pipeline.Add(src);
_pipeline.Add(conv);
_pipeline.Add(sink);
if (!src.Link(conv) || !conv.Link(sink))
throw new Exception("Falha ao linkar o pipeline.");
// >>> AQUI entra a correção do Bus (ver seção 2) <<<
_pipeline.SetState(State.Playing);
}
public void Start2()
{
if (_pipeline != null)
return;
//if (!VideoPanel.IsHandleCreated)
// VideoPanel.CreateControl();
// Monta o pipeline de recepção (ajuste caps se precisar)
string pipeDesc =
$"udpsrc port={Port} " +
"caps = application/x-rtp, media=video, encoding-name=H264, payload=96 " +
"! rtph264depay ! h264parse ! avdec_h264 ! videoconvert " +
"! d3d11videosink name=vsink sync=false";
// Cria pipeline a partir da string
_pipeline = new Pipeline(new Gst.Internal.PipelineHandle(1, false));
if (_pipeline is null)
throw new InvalidOperationException("Falha ao criar pipeline GStreamer.");
// Pega o sink pelo nome
_videoSink = _pipeline.GetChildByName("vsink") as Element;
if (_videoSink is null)
throw new InvalidOperationException("Não foi possível encontrar o elemento 'vsink' no pipeline.");
// Faz o cast para VideoOverlay
var overlay = _videoSink as VideoOverlay;
if (overlay is null)
throw new InvalidOperationException("O sink não implementa VideoOverlay.");
// Passa o handle da janela do Panel para o sink
//var hwnd = VideoPanel.Handle;
//overlay.SetWindowHandle((nuint)hwnd);
// (Opcional) configurar bus para logar erros
_bus = _pipeline.GetBus();
_bus.AddSignalWatch();
_bus.OnMessage += OnBusMessage;
// Play!
_pipeline.SetState(State.Playing);
}
public void Stop2()
{
if (_pipeline == null)
return;
_pipeline.SetState(State.Null);
if (_bus != null)
{
_bus.OnMessage -= OnBusMessage;
_bus.Dispose();
_bus = null;
}
_pipeline.Dispose();
_pipeline = null;
_videoSink = null;
}
private void OnBusMessage(object? sender, Bus.MessageSignalArgs e)
{
switch (e.Message.Type)
{
case MessageType.Error:
//e.Message.ParseError(out var err, out var debug);
//Console.WriteLine($"[GST ERROR] {err}: {debug}");
Console.WriteLine($"[GST ERROR] {e.Message}");
break;
case MessageType.Eos:
Console.WriteLine("[GST] End of stream");
// Se quiser, reinicia ou dá Stop();
break;
}
}
public async Task Start()
{
try
{
if (Media.IsOpen)
return;
// Abre o stream (udp, rtsp, http…)
await Media.Open(new System.Uri(SourceUrl));
await Media.Play();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"[FFME] Erro ao iniciar vídeo: {ex}");
}
}
public async void Stop()
{
try
{
if (Media.IsOpen)
{
await Media.Stop();
await Media.Close();
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"[FFME] Erro ao parar vídeo: {ex}");
}
}
}
}

View File

@ -1,7 +1,8 @@
using System.Windows;
using System.Windows.Controls;
using System.ComponentModel;
using System.Windows.Media;
using UserControl = System.Windows.Controls.UserControl;
using Color = System.Windows.Media.Color;
namespace OperationControl.Controls
{
@ -101,7 +102,7 @@ namespace OperationControl.Controls
if (Chrome == null) return;
bool no_course = double.IsNaN(CourseHeading);
var a = no_course ? 0 : DifHeading;
var a = no_course ? 0 : Math.Abs(DifHeading);
var cor = new SolidColorBrush(Color.FromRgb(0x2E, 0xCC, 0x71)); // verde
if (a >= 10)
cor = new SolidColorBrush(Color.FromRgb(0xE7, 0x4C, 0x3C)); // vermelho

View File

@ -1,6 +1,9 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using UserControl = System.Windows.Controls.UserControl;
using Brush = System.Windows.Media.Brush;
using Brushes = System.Windows.Media.Brushes;
using Color = System.Windows.Media.Color;
namespace OperationControl.Controls
{

View File

@ -1,6 +1,7 @@
<UserControl x:Class="OperationControl.Controls.ManualControlPad"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:OperationControl.Controls"
x:Name="Root" Focusable="True" MinWidth="382">
<Border CornerRadius="8" Background="#111" BorderBrush="Black" BorderThickness="1" Width="382" MinHeight="66">
@ -49,24 +50,72 @@
<!-- Botões + Modo Manual à direita -->
<Canvas Grid.Column="1" Margin="0,0,-184,0">
<!-- Emergência (ícone MDL2) -->
<Button Content="" FontFamily="Segoe MDL2 Assets" ToolTip="Parada de Emergência" Background="#E74C3C" Foreground="White" Width="70" Height="20" Click="OnEmergencyClick" HorizontalAlignment="Center" VerticalAlignment="Top" Canvas.Top="1"/>
<!-- Iniciar | Pausar -->
<ToggleButton x:Name="BtnRun" Width="108" Height="20" Checked="OnRunToggle" Unchecked="OnRunToggle" Canvas.Left="75" Canvas.Top="1" HorizontalAlignment="Left" VerticalAlignment="Top">
<ToggleButton.Style>
<Style TargetType="ToggleButton">
<Setter Property="Content" Value="Iniciar"/>
<Button x:Name="btnEmergencia" FontFamily="Segoe UI Emoji" Width="70" Height="20" Click="OnEmergencyClick" HorizontalAlignment="Center" VerticalAlignment="Top" Canvas.Top="1">
<Button.Style>
<Style TargetType="Button">
<!-- estado normal (desativado) -->
<Setter Property="Content" Value="🚨"/>
<Setter Property="Background" Value="#E74C3C"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="ToolTip" Value="Ativar Parada de Emergência"/>
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content" Value="Pausar"/>
</Trigger>
<!-- quando a emergência estiver ATIVA -->
<DataTrigger Value="True" Binding="{Binding EmergencyActivated, RelativeSource={RelativeSource AncestorType=local:ManualControlPad}}">
<Setter Property="Background" Value="White"/>
<Setter Property="Foreground" Value="#E74C3C"/>
<Setter Property="Content" Value="⛔"/>
<Setter Property="ToolTip" Value="Desativar Parada de Emergência"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
<!-- Referenciar -->
<Button Content="Referenciar" Width="70" Height="20" Click="OnRefClick" Canvas.Top="23" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<!-- Modo Manual (abre/fecha painel) -->
</Button.Style>
</Button>
<Button x:Name="BtnPausa" Width="70" Height="20" Click="OnPauseClick" Canvas.Top="23" HorizontalAlignment="Left" VerticalAlignment="Center">
<Button.Style>
<Style TargetType="Button">
<!-- estado normal (desativado) -->
<Setter Property="Content" Value="⏸️"/>
<Setter Property="Background" Value="Yellow"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="ToolTip" Value="Colocar Operação em Espera"/>
<Style.Triggers>
<!-- quando a emergência estiver ATIVA -->
<DataTrigger Value="True" Binding="{Binding PauseActivated, RelativeSource={RelativeSource AncestorType=local:ManualControlPad}}">
<Setter Property="Content" Value="▶️"/>
<Setter Property="Background" Value="#27AE60"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="ToolTip" Value="Retomar Operação"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
<Button x:Name="BtnReferenciar" Width="108" Height="20" Click="OnRefClick" HorizontalAlignment="Center" VerticalAlignment="Top" Canvas.Left="75" Canvas.Top="1">
<Button.Style>
<Style TargetType="Button">
<Setter Property="IsEnabled" Value="True"/>
<Setter Property="Content" Value="⚙️ Recalibrar"/>
<Setter Property="Background" Value="White"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="ToolTip" Value="Realizar processo de calibragem do equipamento"/>
<Style.Triggers>
<DataTrigger Value="True" Binding="{Binding RefActivated, RelativeSource={RelativeSource AncestorType=local:ManualControlPad}}">
<Setter Property="IsEnabled" Value="False"/>
<Setter Property="Content" Value="🔄 Calibrando"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="ToolTip" Value="Calibragem em andamento"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
<ToggleButton x:Name="TgManual" Width="108" Height="20" Checked="OnManualToggle" Unchecked="OnManualToggle" Canvas.Left="75" Canvas.Top="23" HorizontalAlignment="Left" VerticalAlignment="Top">
<ToggleButton.Style>
<Style TargetType="ToggleButton">

View File

@ -1,10 +1,16 @@
using System.Collections.ObjectModel;
using OperationControl.Models;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media.Animation;
using UserControl = System.Windows.Controls.UserControl;
using KeyEventArgs = System.Windows.Input.KeyEventArgs;
using Binding = System.Windows.Data.Binding;
using Application = System.Windows.Application;
using Point = System.Windows.Point;
using Size = System.Windows.Size;
using Mapsui;
namespace OperationControl.Controls
{
@ -26,21 +32,38 @@ namespace OperationControl.Controls
InitializeComponent();
MoveModes.Clear();
MoveModes.Add("RodasDianteiras");
MoveModes.Add("RodasTraseiras");
MoveModes.Add("RotacionarNoEixo");
MoveModes.Add("MovimentoArco");
MoveModes.Add("MovimentoLateral");
MoveModes.Add("MovimentoDiagonal");
MoveModes.Add("Diagnostico");
foreach (var t in Enum.GetNames(typeof(AgroBase.Models.Enums.TipoMovimentoDirecional)))
{
MoveModes.Add(t);
}
SelectedMoveMode = MoveModes[0];
Loaded += (_, __) => UpdateThumb();
SizeChanged += (_, __) => { if (ManualContainer.Height > 0) AnimateManual(true, instant: true); };
EmergencyClicked += ManualControlPad_EmergencyClicked;
PauseClicked += ManualControlPad_PauseClicked;
ReferenceClicked += ManualControlPad_ReferenceClicked;
ModeChanged += ManualControlPad_ModeChanged;
CommandChanged += ManualControlPad_CommandChanged;
}
// ======= Header displays (bind do app) =======
public bool EmergencyActivated { get => (bool)GetValue(EmergencyActivatedProperty); set => SetValue(EmergencyActivatedProperty, value); }
public static readonly DependencyProperty EmergencyActivatedProperty = DependencyProperty.Register(nameof(EmergencyActivated), typeof(bool), typeof(ManualControlPad), new PropertyMetadata(false));
public bool PauseActivated { get => (bool)GetValue(PauseActivatedProperty); set => SetValue(PauseActivatedProperty, value); }
public static readonly DependencyProperty PauseActivatedProperty = DependencyProperty.Register(nameof(PauseActivated), typeof(bool), typeof(ManualControlPad), new PropertyMetadata(false));
public bool RefActivated { get => (bool)GetValue(RefActivatedProperty); set => SetValue(RefActivatedProperty, value); }
public static readonly DependencyProperty RefActivatedProperty = DependencyProperty.Register(nameof(RefActivated), typeof(bool), typeof(ManualControlPad), new PropertyMetadata(false));
public double SpeedSpKmh { get => (double)GetValue(SpeedSpKmhProperty); set => SetValue(SpeedSpKmhProperty, value); }
public static readonly DependencyProperty SpeedSpKmhProperty = DependencyProperty.Register(nameof(SpeedSpKmh), typeof(double), typeof(ManualControlPad), new PropertyMetadata(0d));
public double SpeedCurKmh { get => (double)GetValue(SpeedCurKmhProperty); set => SetValue(SpeedCurKmhProperty, value); }
@ -51,8 +74,8 @@ namespace OperationControl.Controls
public double AngleCurDeg { get => (double)GetValue(AngleCurDegProperty); set => SetValue(AngleCurDegProperty, value); }
public static readonly DependencyProperty AngleCurDegProperty = DependencyProperty.Register(nameof(AngleCurDeg), typeof(double), typeof(ManualControlPad), new PropertyMetadata(0d));
public string MoveType { get => (string)GetValue(MoveTypeProperty); set => SetValue(MoveTypeProperty, value); }
public static readonly DependencyProperty MoveTypeProperty = DependencyProperty.Register(nameof(MoveType), typeof(string), typeof(ManualControlPad), new PropertyMetadata("—"));
public AgroBase.Models.Enums.TipoMovimentoDirecional MoveType { get => (AgroBase.Models.Enums.TipoMovimentoDirecional)GetValue(MoveTypeProperty); set => SetValue(MoveTypeProperty, value); }
public static readonly DependencyProperty MoveTypeProperty = DependencyProperty.Register(nameof(MoveType), typeof(AgroBase.Models.Enums.TipoMovimentoDirecional), typeof(ManualControlPad), new PropertyMetadata(AgroBase.Models.Enums.TipoMovimentoDirecional.RodasDianteiras));
// ======= Ajustes (painel manual) =======
public double SpeedPercent { get => (double)GetValue(SpeedPercentProperty); set => SetValue(SpeedPercentProperty, value); }
@ -69,7 +92,7 @@ namespace OperationControl.Controls
// ===== Eventos públicos =====
public event PropertyChangedEventHandler PropertyChanged; void Raise(string n) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(n));
public event EventHandler EmergencyClicked;
public event EventHandler RunToggled; // BtnRun.IsChecked
public event EventHandler PauseClicked;
public event EventHandler ReferenceClicked;
public event EventHandler ModeChanged;
public event EventHandler CommandChanged;
@ -77,7 +100,7 @@ namespace OperationControl.Controls
// Botões
void OnEmergencyClick(object s, RoutedEventArgs e) => EmergencyClicked?.Invoke(this, EventArgs.Empty);
void OnRefClick(object s, RoutedEventArgs e) => ReferenceClicked?.Invoke(this, EventArgs.Empty);
void OnRunToggle(object s, RoutedEventArgs e) => RunToggled?.Invoke(this, EventArgs.Empty);
void OnPauseClick(object s, RoutedEventArgs e) => PauseClicked?.Invoke(this, EventArgs.Empty);
// Modo Manual → anima painel
void OnManualToggle(object s, RoutedEventArgs e)
@ -201,8 +224,73 @@ namespace OperationControl.Controls
ThumbTT.Y = -ThrottleCmd * r; // cima +
}
// Helpers
public bool IsRunning => BtnRun.IsChecked == true;
public void AtualizarDadosControle(double? angMax = null, double? angSp = null, double? angCur = null, AgroBase.Models.Enums.TipoMovimentoDirecional? tipoMov = null, double? velPct = null, double? velSp = null, double? velKmh = null, bool? emg = null, bool? pause = null, bool? refing = null)
{
if (angMax != null) MaxSteerDeg = (double)angMax;
if (angSp != null) AngleSpDeg = (double)angSp;
if (angCur != null) AngleCurDeg = (double)angCur;
if (tipoMov != null) MoveType = (AgroBase.Models.Enums.TipoMovimentoDirecional)tipoMov;
if (velPct != null) SpeedPercent = (double)velPct;
if (velSp != null) SpeedSpKmh = (double)velSp;
if (velKmh != null) SpeedCurKmh = (double)velKmh;
if (emg != null) EmergencyActivated = (bool)emg;
if (pause != null) PauseActivated = (bool)pause;
if (refing != null) RefActivated = (bool)refing;
}
private void ManualControlPad_EmergencyClicked(object? sender, EventArgs e)
{
EmergencyActivated = !EmergencyActivated;
VariaveisControleOperacao.EnviarComandoParada(emergencia: EmergencyActivated);
}
private void ManualControlPad_PauseClicked(object? sender, EventArgs e)
{
if (VariaveisControleOperacao.RoverEmFoco.DadosLeitura?.OperacaoIniciada ?? false)
{
//PauseActivated = !PauseActivated;
//VariaveisControleOperacao.EnviarComandoParada(pausa: PauseActivated);
if (System.Windows.MessageBox.Show("Deseja finalizar a operação em andamento?", "Finalizar Operação", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
{
VariaveisControleOperacao.EnviarComandoIniciarOperacao(false);
}
}
else
{
if (!(TgManual.IsChecked ?? false) && !(((App)Application.Current).Shell.Main?.MAP?.RuasMapaCarregado?.Any(x => x.Selected) ?? false))
{
System.Windows.MessageBox.Show("Para iniciar a operação automática, é necessário carregar um mapa e selecionar as ruas onde o equipamento irá operar!", "Parametrização", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
if (System.Windows.MessageBox.Show("Deseja iniciar a operação com os parâmetros atuais?", "Iniciar Operação", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
{
VariaveisControleOperacao.EnviarComandoIniciarOperacao(true, true);
}
}
}
private void ManualControlPad_ReferenceClicked(object? sender, EventArgs e)
{
RefActivated = !RefActivated;
VariaveisControleOperacao.EnviarComandoReferenciamento();
}
private void ManualControlPad_CommandChanged(object? sender, EventArgs e)
{
throw new NotImplementedException();
}
private void ManualControlPad_ModeChanged(object? sender, EventArgs e)
{
throw new NotImplementedException();
}
}
// ===== visuais
@ -213,4 +301,5 @@ namespace OperationControl.Controls
public object Convert(object v, Type t, object p, System.Globalization.CultureInfo c) => (v is bool b && b) ? EnabledOpacity : DisabledOpacity;
public object ConvertBack(object v, Type t, object p, System.Globalization.CultureInfo c) => Binding.DoNothing;
}
}

View File

@ -1,11 +1,9 @@
using System.IO;
using System.Windows;
using System.Windows.Controls;
using BruTile;
using BruTile.MbTiles;
using BruTile.Predefined;
using SQLite;
using Microsoft.Win32;
using NetTopologySuite.IO;
using NetTopologySuite.Features;
@ -21,11 +19,18 @@ using Mapsui.Nts;
using Mapsui.UI.Wpf;
// Aliases para evitar conflito com NetTopologySuite.* (NTS)
using UserControl = System.Windows.Controls.UserControl;
using OpenFileDialog = Microsoft.Win32.OpenFileDialog;
using MIFeature = Mapsui.IFeature;
using Brush = Mapsui.Styles.Brush;
using Pen = Mapsui.Styles.Pen;
using Color = Mapsui.Styles.Color;
using Font = Mapsui.Styles.Font;
using NFeature = NetTopologySuite.Features.Feature;
using Mapsui.Manipulations;
using Mapsui.Extensions;
using OperationControl.Models;
using static AgroBase.Models.Enums;
namespace OperationControl.Controls
@ -67,6 +72,8 @@ namespace OperationControl.Controls
public event EventHandler<MapMarkerManager.MarkerClickedEventArgs>? MarkerClicked;
protected virtual void OnMarkerClicked(string markerId)
{
if (markerId == null) markers?.ClearMarkerFocused();
else markers?.SetMarkerFocused(markerId, true);
MarkerClicked?.Invoke(this, new MapMarkerManager.MarkerClickedEventArgs(markerId));
}
@ -78,7 +85,7 @@ namespace OperationControl.Controls
#region RUAS PLANTACAO
private Layer MapaPlantacao_Layer;
private List<StreetMapDictionaryModel> RuasMapaCarregado;
public List<StreetMapDictionaryModel> RuasMapaCarregado;
public event EventHandler<StreetMapClickedEventArgs>? StreetMapClicked;
protected virtual void OnStreetMapClicked(string streetId)
@ -461,24 +468,18 @@ namespace OperationControl.Controls
var info = Mapa.GetMapInfo(sp, Mapa.Map.Layers /*, 18*/);
var feat = info?.Feature;
if (info?.Layer == markers.Layer)
if (info?.Layer == markers.Layer && feat != null && markers != null && markers.TryGetIdFromFeature(feat, out var id))
{
if (feat != null && markers != null && markers.TryGetIdFromFeature(feat, out var id))
{
markers.SetMarkerFocused(id, true);
Mapa.Cursor = System.Windows.Input.Cursors.Hand;
OnMarkerClicked(id);
}
else
{
markers?.ClearMarkerFocused();
OnMarkerClicked(null);
}
OnMarkerClicked(id);
}
else if (info?.Layer == MapaPlantacao_Layer && feat is MIFeature roadFeature)
{
HighlightRoad(roadFeature);
}
else
{
OnMarkerClicked(null);
}
};
@ -492,7 +493,9 @@ namespace OperationControl.Controls
var info = Mapa.GetMapInfo(sp, Mapa.Map.Layers /*, 18*/);
var feat = info?.Feature;
if ((feat != null && markers != null && markers.TryGetIdFromFeature(feat, out _)) || feat != null)
if (feat != null && markers != null && markers.TryGetIdFromFeature(feat, out _))
Mapa.Cursor = System.Windows.Input.Cursors.Hand;
else if (feat != null && info?.Layer == MapaPlantacao_Layer && feat is MIFeature roadFeature)
Mapa.Cursor = System.Windows.Input.Cursors.Hand;
else
Mapa.Cursor = System.Windows.Input.Cursors.Arrow;
@ -777,6 +780,52 @@ namespace OperationControl.Controls
return dict.TryGetValue(fieldName, out var v) ? v : null;
}
public AgroBase.Models.MapaFeatureCollectionModel CriarDadosMapa()
{
AgroBase.Models.MapaFeatureCollectionModel _mapa = new AgroBase.Models.MapaFeatureCollectionModel() { type = "FeatureCollection", features = new List<AgroBase.Models.MapaFeatureModel>() };
foreach (var x in RuasMapaCarregado.Where(x => x.Selected))
{
string id = ((dynamic)x.Feature).Id.ToString();
string type = ((dynamic)x.Feature).Geometry.GeometryType;
string s = ((dynamic)x.Feature).Geometry.CoordinateSequence.ToString();
s = s.Trim().TrimStart('(').TrimEnd(')');
var pairs = s.Split("),", StringSplitOptions.RemoveEmptyEntries);
var coordinates = new List<List<double>>();
foreach (var p in pairs)
{
var clean = p.Replace("(", "").Replace(")", "").Trim();
var parts = clean.Split(',', StringSplitOptions.RemoveEmptyEntries);
if (parts.Length == 2 && double.TryParse(parts[0], System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out double lon) && double.TryParse(parts[1], System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out double lat))
{
coordinates.Add(new List<double> { lon, lat });
}
}
AgroBase.Models.MapaFeatureGeometryModel geometry = new AgroBase.Models.MapaFeatureGeometryModel()
{
id = GetAttr(x.Feature, "Id"),
type = type,
coordinates = coordinates
};
_mapa.features.Add(new AgroBase.Models.MapaFeatureModel()
{
type = "Feature",
geometry = geometry,
properties = new AgroBase.Models.MapaFeaturePropertiesModel()
{
Id = GetAttr(x.Feature, "Id"),
Dist1 = double.Parse(GetAttr(x.Feature, "Dist1")),
Dist2 = double.Parse(GetAttr(x.Feature, "Dist2")),
Length = double.Parse(GetAttr(x.Feature, "Length")),
Name = GetAttr(x.Feature, "Name")
}
});
};
return _mapa;
}
}
public class MapMarkerManager
@ -805,6 +854,14 @@ namespace OperationControl.Controls
private readonly Layer _layer;
public Layer Layer { get { return _layer; } }
public enum MarkerStatus
{
Normal,
Warning,
Error,
Offline
}
public bool Added(string id)
@ -826,6 +883,7 @@ namespace OperationControl.Controls
public void SetMarkerFocused(string id, bool focused)
{
ClearMarkerFocused();
var f = _features.FirstOrDefault(x => x.Id == id);
if (f != null) f.Focused = focused;
}
@ -856,7 +914,7 @@ namespace OperationControl.Controls
}
}
public void AddMarker(string id, double lat, double lon, double headingDeg, System.Windows.Media.Color color, string? label = null, bool center = false)
public void AddMarker(string id, bool isBase, double? lat = null, double? lon = null, double? heading = null, System.Windows.Media.Color? color = null, string? label = null, StatusOperacao? status = null, bool? pulv = null, bool center = false)
{
if (string.IsNullOrWhiteSpace(id)) throw new ArgumentException("id inválido", nameof(id));
@ -865,7 +923,7 @@ namespace OperationControl.Controls
var marker = _features.FirstOrDefault(x => x.Id == id);
if (marker != null)
{
marker.UpdateData(lat, lon, headingDeg, label, color);
marker.UpdateData(lat: lat, lon: lon, heading: heading, label: label, color: color, status: status, pulverizando: pulv);
}
else
{
@ -873,15 +931,18 @@ namespace OperationControl.Controls
{
Id = id,
Features = new List<MIFeature>(),
Color = color,
Heading = headingDeg,
Lat = lat,
Lon = lon,
Color = color ?? GetColorForMarker(id, isBase),
Heading = heading ?? 0,
Lat = lat ?? 0,
Lon = lon ?? 0,
Label = lbl,
Seta = new List<GeometryFeature>(),
Status = status ?? StatusOperacao.NaoIniciado,
Pulverizando = pulv ?? false,
Focused = false
};
marker.CreateTrajectory(_map);
marker.UpdateData(lat, lon, headingDeg);
marker.UpdateData();
_features.Add(marker);
}
@ -891,12 +952,26 @@ namespace OperationControl.Controls
_map.Map?.Navigator?.CenterOn(marker.Point.Point);
}
public void UpdateMarkerPosition(string id, double lat, double lon, double headingDeg, bool pulv = false)
public void UpdateMarkerPosition(string id, double? lat = null, double? lon = null, double? heading = null, List<double[]>? predict = null)
{
if (string.IsNullOrWhiteSpace(id)) throw new ArgumentException("id inválido", nameof(id));
var marker = _features.FirstOrDefault(x => x.Id == id);
if (marker == null) return;
marker.UpdateData(lat, lon, headingDeg, pulverizando: pulv);
marker.UpdateData(lat: lat, lon: lon, heading: heading, predict: predict);
UpdateFeatures();
}
public void UpdateMarkerInfo(string id, StatusOperacao? status = null, bool? pulv = null)
{
if (string.IsNullOrWhiteSpace(id)) throw new ArgumentException("id inválido", nameof(id));
var marker = _features.FirstOrDefault(x => x.Id == id);
if (marker == null) return;
marker.UpdateData(status: status, pulverizando: pulv);
UpdateFeatures();
}
@ -922,10 +997,19 @@ namespace OperationControl.Controls
Style = null
};
_map.Map!.Layers.Add(_trajLayer);
_predProvider = new MemoryProvider(_predFeatures);
_predLayer = new Layer
{
Name = $"pred_{Id}",
DataSource = _predProvider,
Style = null
};
_map.Map!.Layers.Add(_predLayer);
}
public string Id { get; set; }
public bool Focused { get; set; }
public bool Pulverizando { get; set; }
public PointFeature Point { get; set; }
public List<MIFeature> Features { get; set; }
public double Lat { get; set; }
@ -933,18 +1017,23 @@ namespace OperationControl.Controls
public double Heading { get; set; }
public string Label { get; set; }
public System.Windows.Media.Color Color { get; set; }
public StatusOperacao Status { get; set; }
public List<GeometryFeature> Seta { get; set; }
public Coordinate Position { get; set; }
public List<double[]> Predict { get; set; }
public void UpdateData(double lat, double lon, double heading, string? label = null, System.Windows.Media.Color? color = null, bool pulverizando = false)
public void UpdateData(double? lat = null, double? lon = null, double? heading = null, string? label = null, System.Windows.Media.Color? color = null, bool? pulverizando = null, StatusOperacao? status = null, List<double[]>? predict = null)
{
Features.Clear();
Lat = lat;
Lon = lon;
Heading = heading;
if (lat != null) Lat = (double)lat;
if (lon != null) Lon = (double)lon;
if (heading != null) Heading = (double)heading;
if (label != null) Label = label;
if (color != null) Color = (System.Windows.Media.Color)color;
if (status != null) Status = (StatusOperacao)status;
if (pulverizando != null) Pulverizando = (bool)pulverizando;
if (predict != null) Predict = predict;
var (x, y) = Mapsui.Projections.SphericalMercator.FromLonLat(Lon, Lat);
var newPoint = new MPoint(x, y);
@ -957,7 +1046,10 @@ namespace OperationControl.Controls
Features.Add(Point);
Seta.ForEach(f => Features.Add(f));
UpdateRoverPosition(pulverizando);
if (lat != null || lon != null)
UpdateRoverPosition();
if (predict != null)
UpdatePredictTrajectory();
}
private void UpsertHeadingFeature(MPoint centerWorld, bool withArrowHead = true)
@ -1024,55 +1116,129 @@ namespace OperationControl.Controls
});
}
private void SetStyles()
private void SetStyles(double _pulseFactor = 1.0)
{
if (Point.Styles == null) Point.Styles = new List<IStyle>();
else Point.Styles.Clear();
// cor base
var c = new Mapsui.Styles.Color(Color.R, Color.G, Color.B, Color.A);
// Pega o “visual” conforme o Status
var (baseColor, statusGlyph, labelBackColor) = GetStatusVisual();
// 1) Ponto central minúsculo (precisão)
Point.Styles.Add(new SymbolStyle
{
SymbolScale = 0.22, // ponto bem pequeno
Fill = new Brush(c),
SymbolScale = 0.22,
Fill = new Brush(baseColor),
Outline = null
});
// 2) “Aura” simulando gradiente (3 círculos com alpha/escala crescentes)
Point.Styles.Add(new SymbolStyle
{
SymbolScale = 0.55,
Fill = new Brush(new Mapsui.Styles.Color(c.R, c.G, c.B, 120)),
SymbolScale = _pulseFactor * 0.55,
Fill = new Brush(new Color(baseColor.R, baseColor.G, baseColor.B, 120)),
Outline = null
});
Point.Styles.Add(new SymbolStyle
{
SymbolScale = 0.95,
Fill = new Brush(new Mapsui.Styles.Color(c.R, c.G, c.B, 70)),
SymbolScale = _pulseFactor * 0.95,
Fill = new Brush(new Color(baseColor.R, baseColor.G, baseColor.B, 70)),
Outline = null
});
Point.Styles.Add(new SymbolStyle
{
SymbolScale = 1.4,
Fill = new Brush(new Mapsui.Styles.Color(c.R, c.G, c.B, 30)),
SymbolScale = _pulseFactor * 1.4,
Fill = new Brush(new Color(baseColor.R, baseColor.G, baseColor.B, 30)),
Outline = null
});
// 3) Rótulo do id (pequeno, acima do ponto)
if (!string.IsNullOrWhiteSpace(Label))
{
// texto: se tiver glyph, coloca na frente
var texto = string.IsNullOrEmpty(statusGlyph)
? Label
: $"{Label} {statusGlyph}";
var backColor = labelBackColor ?? new Color(0, 0, 0, 140);
Point.Styles.Add(new LabelStyle
{
Text = Label,
Text = texto,
ForeColor = Mapsui.Styles.Color.White,
BackColor = new Brush(new Mapsui.Styles.Color(0, 0, 0, 140)),
Offset = new Offset(0, -30)
BackColor = new Brush(backColor),
Offset = new Offset(0, -30),
Font = new Font { FontFamily = "Segoe UI Emoji", Size = 18 }
});
}
}
private (Mapsui.Styles.Color baseColor, string statusGlyph, Mapsui.Styles.Color? labelBackColor) GetStatusVisual()
{
string glyph = "";
Mapsui.Styles.Color? back = null;
// Base default = cor do robô (personalizada)
var baseColor = new Mapsui.Styles.Color(Color.R, Color.G, Color.B, Color.A);
switch (Status)
{
case StatusOperacao.NaoIniciado:
glyph = "⏳";
baseColor = new Mapsui.Styles.Color(150, 150, 150, 255); // cinza médio
back = new Mapsui.Styles.Color(60, 60, 60, 160); // cinza escuro translúcido
break;
case StatusOperacao.Parametrizando:
glyph = "🔧";
baseColor = new Mapsui.Styles.Color(40, 120, 255, 255); // azul forte
back = new Mapsui.Styles.Color(100, 160, 255, 140); // azul claro translúcido
break;
case StatusOperacao.Calibrando:
glyph = "🎯";
baseColor = new Mapsui.Styles.Color(160, 70, 255, 255); // roxo vibrante
back = new Mapsui.Styles.Color(180, 120, 255, 140); // roxo suave
break;
case StatusOperacao.Aguardando:
glyph = "💤";
baseColor = new Mapsui.Styles.Color(0, 110, 140, 255); // azul petróleo
back = new Mapsui.Styles.Color(0, 150, 180, 140); // turquesa suave
break;
case StatusOperacao.EmAndamento:
glyph = "▶";
baseColor = new Mapsui.Styles.Color(0, 220, 40, 255); // verde limão
back = new Mapsui.Styles.Color(0, 200, 30, 140); // verde limão translúcido
break;
case StatusOperacao.Parado:
glyph = "⏸";
baseColor = new Mapsui.Styles.Color(255, 180, 0, 255); // amarelo dourado
back = new Mapsui.Styles.Color(255, 210, 80, 140); // amarelo claro suaaave
break;
case StatusOperacao.Concluido:
glyph = "✔";
baseColor = new Mapsui.Styles.Color(0, 150, 60, 255); // verde escuro
back = new Mapsui.Styles.Color(0, 130, 50, 140); // verde escuro suave
break;
case StatusOperacao.Erro:
glyph = "⛔";
baseColor = new Mapsui.Styles.Color(220, 40, 40, 255);
back = new Mapsui.Styles.Color(120, 0, 0, 190);
break;
default:
glyph = "";
break;
}
return (baseColor, glyph, back);
}
#region TRAJETORIA
@ -1080,9 +1246,9 @@ namespace OperationControl.Controls
private Layer _trajLayer;
private List<MIFeature> _trajFeatures { get; set; } = new List<MIFeature>();
private VectorStyle CreateTrajectoryStyle(string roverId, bool pulverizando)
private VectorStyle CreateTrajectoryStyle()
{
if (pulverizando)
if (Pulverizando)
{
return new VectorStyle
{
@ -1098,7 +1264,7 @@ namespace OperationControl.Controls
}
}
public void UpdateRoverPosition(bool pulverizando)
public void UpdateRoverPosition()
{
var (x, y) = Mapsui.Projections.SphericalMercator.FromLonLat(Lon, Lat);
var newCoord = new Coordinate(x, y);
@ -1109,8 +1275,8 @@ namespace OperationControl.Controls
Geometry = line
};
gf["RoverId"] = Id;
gf["Pulverizando"] = pulverizando ? "1" : "0";
gf.Styles.Add(CreateTrajectoryStyle(Id, pulverizando));
gf["Pulverizando"] = Pulverizando ? "1" : "0";
gf.Styles.Add(CreateTrajectoryStyle());
_trajFeatures.Add(gf);
_trajLayer.DataSource = new MemoryProvider(_trajFeatures);
_trajLayer.DataHasChanged();
@ -1118,6 +1284,67 @@ namespace OperationControl.Controls
}
#endregion
#region SIMULACAO
private MemoryProvider _predProvider;
private Layer _predLayer;
private List<MIFeature> _predFeatures { get; set; } = new List<MIFeature>();
public void UpdatePredictTrajectory()
{
if (_predLayer == null || Predict == null || Predict.Count < 2)
return;
_predFeatures.Clear();
// Converte lista (lon, lat) -> coordenadas em SphericalMercator
var coords = new List<Coordinate>();
foreach (var lon_lat in Predict)
{
double lon = lon_lat[0];
double lat = lon_lat[1];
var (x, y) = Mapsui.Projections.SphericalMercator.FromLonLat(lon, lat);
coords.Add(new Coordinate(x, y));
}
// Garante que tem pelo menos 2 pontos
if (coords.Count < 2)
return;
var line = new LineString(coords.ToArray());
var gf = new GeometryFeature
{
Geometry = line
};
gf["RoverId"] = Id;
gf["Tipo"] = "Predict";
gf.Styles.Add(CreatePredictStyle());
_predFeatures.Add(gf);
_predLayer.DataSource = new MemoryProvider(_predFeatures);
_predLayer.DataHasChanged();
}
private IStyle CreatePredictStyle()
{
return new VectorStyle
{
Line = new Pen
{
Color = Mapsui.Styles.Color.Lime, // verde-limão
Width = 2,
PenStyle = PenStyle.Dash // linha tracejada
}
};
}
#endregion
}
public class MarkerClickedEventArgs : EventArgs

View File

@ -1,7 +1,9 @@
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Media;
using UserControl = System.Windows.Controls.UserControl;
using Brush = System.Windows.Media.Brush;
using Brushes = System.Windows.Media.Brushes;
using Color = System.Windows.Media.Color;
namespace OperationControl.Controls
{

View File

@ -1,6 +1,5 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using UserControl = System.Windows.Controls.UserControl;
namespace OperationControl.Controls
{

View File

@ -1,7 +1,8 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Animation;
using System.Windows.Media;
using UserControl = System.Windows.Controls.UserControl;
using Color = System.Windows.Media.Color;
namespace OperationControl.Controls
{

View File

@ -1,6 +1,11 @@
using System.Globalization;
using System.Windows.Data;
using System.Windows.Media;
using Color = System.Windows.Media.Color;
using ColorConverter = System.Windows.Media.ColorConverter;
using Brushes = System.Windows.Media.Brushes;
using Brush = System.Windows.Media.Brush;
using Binding = System.Windows.Data.Binding;
namespace OperationControl.Converters
{
@ -96,4 +101,27 @@ namespace OperationControl.Converters
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
=> Binding.DoNothing;
}
public class LateralErrorToOffsetConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType,
object parameter, CultureInfo culture)
{
if (values.Length < 2) return 0;
double width = System.Convert.ToDouble(values[0], culture);
double errorN = System.Convert.ToDouble(values[1], culture);
// limite visual: 40% da meia largura
double maxFactor = 0.4;
return errorN * (width * 0.5 * maxFactor);
}
public object[] ConvertBack(object value, Type[] targetTypes,
object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
}

View File

@ -16,13 +16,13 @@ namespace OperationControl.Models
public void Inicializar()
{
Show();
APIService.IniciarRotinas();
Variaveis.IniciarMQTT();
tmrComunicacao.Elapsed += (_, __) => tmrComunicacao_Elapsed();
tmrComunicacao.Start();
Show();
}
private void Show()
@ -36,13 +36,20 @@ namespace OperationControl.Models
{
if (tmrComunicacaoTicking) return;
tmrComunicacaoTicking = true;
if (tmrComunicacaoTicks % VariaveisEquipamento.TempoEntrePingsConexao == 0 && Variaveis.GpsService != null)
try
{
VariaveisControleOperacao.EnviarDadosPosicao(Variaveis.GpsService.UltimaLeitura);
if (tmrComunicacaoTicks % (VariaveisEquipamento.TempoEntrePingsConexao / 1000) == 0 && Variaveis.GpsService != null)
{
VariaveisControleOperacao.EnviarDadosPosicao(Variaveis.GpsService.UltimaLeitura);
}
VariaveisControleOperacao.EnviarDadosHeartbeat();
VariaveisControleOperacao.AtualizarListaRoversNaRede();
}
finally
{
tmrComunicacaoTicks++;
tmrComunicacaoTicking = false;
}
VariaveisControleOperacao.AtualizarListaRoversNaRede();
tmrComunicacaoTicks++;
tmrComunicacaoTicking = false;
}
}

View File

@ -1,8 +1,11 @@
using AgroBase.Models;
using Newtonsoft.Json;
using System.Diagnostics;
using System.Windows;
using OperationControl.Services;
using AgroMonitor;
using Application = System.Windows.Application;
using AgroBase.Models.Operacoes;
using Mapsui;
namespace OperationControl.Models
{
@ -29,8 +32,9 @@ namespace OperationControl.Models
MqttService = new MqttService("localhost", 1883, "base", true, msg => MostrarLog($"[MQTT localhost:1883] - {msg}"));
await MqttService.AdicionarNovoTopico(VariaveisControleOperacao.TopicoMqttRTCM);
await MqttService.AdicionarNovoTopico(VariaveisControleOperacao.TopicoMqttDispositivos, true, 1, async (message) =>
await MqttService.AdicionarNovoTopico(VariaveisMonitoramento.TopicoMqttPosicao);
await MqttService.AdicionarNovoTopico(VariaveisMonitoramento.TopicoMqttRTCM);
await MqttService.AdicionarNovoTopico(VariaveisMonitoramento.TopicoMqttDispositivos, true, 1, async (message) =>
{
try
{
@ -50,108 +54,159 @@ namespace OperationControl.Models
public class VariaveisControleOperacao
{
public static double LeverArmFrontal { get; } = 0.0;
public static double LeverArmLateral { get; } = 0.0;
public static double LeverArmFrontal { get; } = 0.0; // cm
public static double LeverArmLateral { get; } = 0.0; // cm
public static readonly string BaseMarkerID = "BASE";
public static string TopicoMqttDispositivos { get; } = $"agrobot/v1/base/devices";
public static string TopicoMqttPosicao { get; } = $"agrobot/v1/base/position";
public static string TopicoMqttRTCM { get; } = $"agrobot/v1/base/rtcm";
private static readonly object _RoversLock = new object();
public static Dictionary<string, OperacaoSensoriamentoLogModel> RoversNaRede { get; set; } = new Dictionary<string, OperacaoSensoriamentoLogModel>();
private static double TempoRoverVivo = 5.0;
private static bool AdicionandoNovoRover = false;
private static bool AtualizandoListaRovers = false;
public static List<OperacaoParametrosModel> RoversNaRede { get; set; } = new List<OperacaoParametrosModel>();
public static string SelectedRoverId { get; set; } = BaseMarkerID;
public static OperacaoParametrosModel? RoverEmFoco => RoversNaRede.FirstOrDefault(x => x.RoverId == SelectedRoverId);
public static bool BaseEmFoco => SelectedRoverId == BaseMarkerID;
public static async void AdicionarNovoRoverNaRede(string device_id)
{
if (string.IsNullOrEmpty(device_id))
return;
if (AdicionandoNovoRover) return;
AdicionandoNovoRover = true;
bool rover_ja_adicionado = false;
lock (_RoversLock)
try
{
rover_ja_adicionado = RoversNaRede.ContainsKey(device_id);
}
if (string.IsNullOrEmpty(device_id))
return;
if (!rover_ja_adicionado)
{
bool rover_ja_adicionado = false;
lock (_RoversLock)
{
RoversNaRede.Add(device_id, new OperacaoSensoriamentoLogModel() { Momento = DateTime.Now });
rover_ja_adicionado = RoversNaRede.Any(x => x.RoverId == device_id);
}
await Variaveis.MqttService.AdicionarNovoTopico(VariaveisEquipamento.TopicoMqttComandos.Replace("<id>", device_id));
await Variaveis.MqttService.AdicionarNovoTopico(VariaveisEquipamento.TopicoMqttTelemetria.Replace("<id>", device_id), true, 1, async (message) =>
if (!rover_ja_adicionado)
{
try
lock (_RoversLock)
{
string json = message.Mensagem;
var obj = JsonConvert.DeserializeObject<OperacaoSensoriamentoLogModel>(json);
lock (_RoversLock)
RoversNaRede.Add(new OperacaoParametrosModel()
{
RoversNaRede[device_id] = obj;
RoverId = device_id,
Configurado = false,
Alive = true,
DadosLeitura = new OperacaoSensoriamentoLogModel()
{
Momento = DateTime.Now
}
});
}
((App)Application.Current).Shell.Main.AtualizarDadosTela_Telemetria(device_id);
}
}
catch (Exception ex)
{
Variaveis.MostrarLog($"Erro ao deserializar dados de telemetria do rover {device_id}: {ex.Message}");
}
});
bool t_hbt_added = Variaveis.MqttService.Topicos.Any(x => x.Topico == VariaveisEquipamento.TopicoMqttHeartbeat.Replace("<id>", device_id));
if (!t_hbt_added)
await Variaveis.MqttService.AdicionarNovoTopico(VariaveisEquipamento.TopicoMqttHeartbeat.Replace("<id>", device_id));
bool t_cmd_added = Variaveis.MqttService.Topicos.Any(x => x.Topico == VariaveisEquipamento.TopicoMqttComandos.Replace("<id>", device_id));
if (!t_cmd_added)
await Variaveis.MqttService.AdicionarNovoTopico(VariaveisEquipamento.TopicoMqttComandos.Replace("<id>", device_id));
bool t_tel_added = Variaveis.MqttService.Topicos.Any(x => x.Topico == VariaveisEquipamento.TopicoMqttTelemetria.Replace("<id>", device_id));
if (!t_tel_added)
await Variaveis.MqttService.AdicionarNovoTopico(VariaveisEquipamento.TopicoMqttTelemetria.Replace("<id>", device_id), true, 1, async (message) =>
{
try
{
string json = message.Mensagem;
if (string.IsNullOrEmpty(json)) return;
var obj = JsonConvert.DeserializeObject<OperacaoSensoriamentoLogModel>(json);
lock (_RoversLock)
{
var rover = RoversNaRede.FirstOrDefault(x => x.RoverId == device_id);
if (rover != null)
{
obj.Momento = DateTime.Now;
rover.DadosLeitura = obj;
}
}
((App)Application.Current).Shell.Main?.AtualizarDadosTela_Telemetria(device_id);
}
catch (Exception ex)
{
Variaveis.MostrarLog($"Erro ao deserializar dados de telemetria do rover {device_id}: {ex.Message}");
}
});
bool t_par_added = Variaveis.MqttService.Topicos.Any(x => x.Topico == VariaveisEquipamento.TopicoMqttParametros.Replace("<id>", device_id));
if (!t_par_added)
await Variaveis.MqttService.AdicionarNovoTopico(VariaveisEquipamento.TopicoMqttParametros.Replace("<id>", device_id), true, 1, async (message) =>
{
try
{
string json = message.Mensagem;
if (string.IsNullOrEmpty(json)) return;
var obj = JsonConvert.DeserializeObject<OperacaoParametrosModel>(json);
lock (_RoversLock)
{
var rover = RoversNaRede.FirstOrDefault(x => x.RoverId == device_id);
if (rover != null)
{
rover = obj;
}
}
((App)Application.Current).Shell.Main?.AtualizarDadosTela_Telemetria(device_id);
}
catch (Exception ex)
{
Variaveis.MostrarLog($"Erro ao deserializar dados de parametros do rover {device_id}: {ex.Message}");
}
});
await Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
List<string> dispositivos_ids = new List<string>() { "BASE" };
lock (_RoversLock)
{
List<string> dispositivos_ids = new List<string>() { "BASE" };
dispositivos_ids.Union(RoversNaRede.Select(x => x.Key).ToList());
((App)Application.Current).Shell.Main.AtualizarListaDispositivos(dispositivos_ids);
dispositivos_ids = dispositivos_ids.Union(RoversNaRede.Select(x => x.RoverId).ToList()).ToList();
}
catch (Exception exUi)
{
Variaveis.MostrarLog($"Erro ao atualizar UI lista dispositivos: {exUi.Message}");
}
}));
((App)Application.Current).Shell.Main?.AtualizarListaDispositivos(dispositivos_ids);
}
}
finally
{
AdicionandoNovoRover = false;
}
}
public static async void AtualizarListaRoversNaRede()
{
List<string> rovers_desconectados = new List<string>();
var rovers_atual = new Dictionary<string, OperacaoSensoriamentoLogModel>();
lock (_RoversLock)
{
rovers_atual = new Dictionary<string, OperacaoSensoriamentoLogModel>(RoversNaRede);
}
foreach (var rover in rovers_atual)
{
double tempo_sem_resposta = (DateTime.Now - rover.Value.Momento).TotalSeconds;
if (tempo_sem_resposta > 5.0)
{
rovers_desconectados.Add(rover.Key);
}
}
foreach (var device_id in rovers_desconectados)
if (AtualizandoListaRovers) return;
AtualizandoListaRovers = true;
try
{
var rovers_atual = new List<OperacaoParametrosModel>();
lock (_RoversLock)
{
RoversNaRede.Remove(device_id);
if (SelectedRoverId == device_id)
rovers_atual = new List<OperacaoParametrosModel>(RoversNaRede);
}
foreach (var rover in rovers_atual)
{
rover.Alive = (DateTime.Now - rover.DadosLeitura.Momento).TotalSeconds < TempoRoverVivo;
if (!rover.Alive)
{
((App)Application.Current).Shell.Main.LimparDadosTela_Telemetria();
((App)Application.Current).Shell.Main?.MAP?.markers?.UpdateMarkerInfo(rover.RoverId, status: AgroBase.Models.Enums.StatusOperacao.Erro);
}
}
var topicos_rover = Variaveis.MqttService.Topicos.Where(x => x.Topico.Contains(device_id)).ToList();
foreach (var topico in topicos_rover)
{
await Variaveis.MqttService.UnsubscribeAsync(topico);
Variaveis.MqttService.Topicos.Remove(topico);
}
}
finally
{
AtualizandoListaRovers = false;
}
}
public static async void EnviarDadosControle(string rover_id, OperacaoControleBaseModel controle)
public static async void EnviarDadosHeartbeat()
{
var topicos = Variaveis.MqttService.Topicos.Where(x => x.Topico.Contains(VariaveisEquipamento.TopicoMqttHeartbeat.Split("/")[VariaveisEquipamento.TopicoMqttHeartbeat.Split("/").Length - 1]));
foreach (var topico in topicos)
{
await Variaveis.MqttService.PublishAsync(topico, "0");
}
}
private static async void EnviarDadosControle(string rover_id, OperacaoComandoBaseModel controle)
{
var topico = Variaveis.MqttService.Topicos.FirstOrDefault(x => x.Topico == VariaveisEquipamento.TopicoMqttComandos.Replace("<id>", rover_id));
if (topico != null)
@ -163,7 +218,7 @@ namespace OperationControl.Models
public static async void EnviarDadosPosicao(GPSModel posicao)
{
var topico = Variaveis.MqttService.Topicos.FirstOrDefault(x => x.Topico == TopicoMqttPosicao);
var topico = Variaveis.MqttService.Topicos.FirstOrDefault(x => x.Topico == VariaveisMonitoramento.TopicoMqttPosicao);
if (topico != null)
{
string json = JsonConvert.SerializeObject(posicao);
@ -173,12 +228,74 @@ namespace OperationControl.Models
public static async void EnviarDadosCorrecaoRTCM(byte[] correcao)
{
var topico = Variaveis.MqttService.Topicos.FirstOrDefault(x => x.Topico == TopicoMqttRTCM);
var topico = Variaveis.MqttService.Topicos.FirstOrDefault(x => x.Topico == VariaveisMonitoramento.TopicoMqttRTCM);
if (topico != null)
{
await Variaveis.MqttService.PublishAsync(topico, correcao);
}
}
#region Controle
public static void EnviarComandoIniciarOperacao(bool iniciar, bool simulador = false)
{
EnviarDadosControle(SelectedRoverId, new OperacaoComandoBaseModel()
{
Momento = DateTime.Now,
Dispositivo = AgroBase.Models.Enums.T_Code.Mod,
Tecla = simulador ? AgroBase.Models.Enums.BotoesJoystick.Share : iniciar ? AgroBase.Models.Enums.BotoesJoystick.PS : AgroBase.Models.Enums.BotoesJoystick.Vazio
});
}
public static void EnviarComandoTransmissaoVideo(AgroBase.Models.Enums.T_Code disp, bool ligar)
{
EnviarDadosControle(SelectedRoverId, new OperacaoComandoBaseModel()
{
Momento = DateTime.Now,
Dispositivo = disp,
Tecla = ligar ? AgroBase.Models.Enums.BotoesJoystick.L1 : AgroBase.Models.Enums.BotoesJoystick.Vazio
});
}
public static void EnviarComandoParada(bool? emergencia = null, bool? pausa = null)
{
var cmd = new OperacaoComandoBaseModel() { Momento = DateTime.Now };
if (emergencia != null) cmd.Emergencia = (bool)emergencia;
if (pausa != null) cmd.Pausa = (bool)pausa;
if (emergencia != null || pausa != null)
EnviarDadosControle(SelectedRoverId, cmd);
}
public static void EnviarComandoReferenciamento()
{
EnviarDadosControle(SelectedRoverId, new OperacaoComandoBaseModel()
{
Momento = DateTime.Now,
Tecla = AgroBase.Models.Enums.BotoesJoystick.R3
});
}
public static void EnviarComandoLeverArm(double valorCm)
{
EnviarDadosControle(SelectedRoverId, new OperacaoComandoBaseModel()
{
Momento = DateTime.Now,
Dispositivo = AgroBase.Models.Enums.T_Code.Gps,
LeverArmLateral = Math.Round(valorCm, 0),
});
}
public static void EnviarParametrosOperacao(OperacaoParametrosModel parametros)
{
EnviarDadosControle(SelectedRoverId, new OperacaoComandoBaseModel()
{
Momento = DateTime.Now,
Parametros = parametros,
Tecla = (!(RoverEmFoco.DadosLeitura?.OperacaoIniciada ?? false) ? AgroBase.Models.Enums.BotoesJoystick.Options : AgroBase.Models.Enums.BotoesJoystick.Vazio)
});
}
#endregion
}
}

View File

@ -6,6 +6,7 @@
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>true</UseWPF>
<UseWindowsForms>True</UseWindowsForms>
</PropertyGroup>
<ItemGroup>
@ -21,6 +22,12 @@
<ItemGroup>
<PackageReference Include="BruTile" Version="6.0.0" />
<PackageReference Include="BruTile.MbTiles" Version="6.0.0" />
<PackageReference Include="Extended.Wpf.Toolkit" Version="5.0.0" />
<PackageReference Include="FFME.Windows" Version="7.0.361-beta.1" />
<PackageReference Include="GirCore.Gst-1.0" Version="0.7.0-preview.3" />
<PackageReference Include="GirCore.GstVideo-1.0" Version="0.7.0-preview.3" />
<PackageReference Include="LibVLCSharp" Version="3.9.4" />
<PackageReference Include="LibVLCSharp.WPF" Version="3.9.4" />
<PackageReference Include="Mapsui" Version="5.0.0" />
<PackageReference Include="Mapsui.Extensions" Version="5.0.0" />
<PackageReference Include="Mapsui.Wpf" Version="5.0.0" />
@ -31,6 +38,7 @@
<PackageReference Include="OpenTK" Version="4.9.4" />
<PackageReference Include="ScottPlot.WPF" Version="5.1.57" />
<PackageReference Include="System.IO.Ports" Version="10.0.0" />
<PackageReference Include="VideoLAN.LibVLC.Windows" Version="3.0.21" />
</ItemGroup>
<ItemGroup>

View File

@ -13,6 +13,9 @@
<Compile Update="Controls\Bbox3DViewer.xaml.cs">
<SubType>Code</SubType>
</Compile>
<Compile Update="Controls\GstVideoView.xaml.cs">
<SubType>Code</SubType>
</Compile>
<Compile Update="Controls\HeadingIndicator.xaml.cs">
<SubType>Code</SubType>
</Compile>
@ -42,6 +45,9 @@
<Page Update="Controls\Bbox3DViewer.xaml">
<SubType>Designer</SubType>
</Page>
<Page Update="Controls\GstVideoView.xaml">
<SubType>Designer</SubType>
</Page>
<Page Update="Controls\HeadingIndicator.xaml">
<SubType>Designer</SubType>
</Page>

View File

@ -9,6 +9,7 @@ using AgroBase.Models;
using static AgroBase.Models.Enums;
using OperationControl.Models;
using System.Windows;
using Application = System.Windows.Application;
namespace OperationControl.Services
{
@ -1199,6 +1200,7 @@ namespace OperationControl.Services
{
Models.Variaveis.MostrarLog("Poucas amostras de RTK FIX coletadas. Tente aumentar o tempo ou verificar sinais.");
CorrecaoAbsoluta = false;
FixLiberado = false;
return CorrecaoAbsoluta;
}
@ -1211,6 +1213,7 @@ namespace OperationControl.Services
Models.Variaveis.MostrarLog($"[BASE/FIX] Coordenadas aplicadas (n={nAmostras}):");
Models.Variaveis.MostrarLog($" lat = {lat:0.000000000}, lon = {lon:0.000000000}, h = {h:0.000}");
CorrecaoAbsoluta = true;
FixLiberado = false;
return CorrecaoAbsoluta;
}
finally

View File

@ -4,6 +4,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:scott="clr-namespace:ScottPlot.WPF;assembly=ScottPlot.WPF"
xmlns:vlc="clr-namespace:LibVLCSharp.WPF;assembly=LibVLCSharp.WPF"
xmlns:controls="clr-namespace:OperationControl.Controls"
mc:Ignorable="d"
Title="Controle da Opearação Agrobot" Height="1025" Width="1920" WindowStartupLocation="CenterScreen" WindowState="Maximized">
@ -26,30 +27,30 @@
<Canvas>
<Label Content="Resumo Operacional" FontWeight="Bold" FontSize="10" HorizontalAlignment="Left" Canvas.Top="-4" VerticalAlignment="Center" Canvas.Left="-2"/>
<Label Content="Rua Atual" FontSize="10" HorizontalAlignment="Center" Canvas.Top="12" VerticalAlignment="Top" RenderTransformOrigin="0.756,0.502"/>
<controls:ProgressBarText Height="10" Canvas.Left="57" Canvas.Top="19" Width="92" HorizontalAlignment="Left" VerticalAlignment="Center" Value="63"/>
<Label Content="74,17 m / 135,84 m (1)" FontSize="10" Canvas.Top="12" HorizontalAlignment="Center" VerticalAlignment="Center" Canvas.Left="154"/>
<controls:ProgressBarText x:Name="pgbResumo_RuaAtual" Height="10" Canvas.Left="57" Canvas.Top="19" Width="92" HorizontalAlignment="Left" VerticalAlignment="Center" Value="63"/>
<Label x:Name="lblResumo_RuaAtual" Content="74,17 m / 135,84 m (1)" FontSize="10" Canvas.Top="12" HorizontalAlignment="Center" VerticalAlignment="Center" Canvas.Left="154"/>
<Label Content="Área Total" FontSize="10" HorizontalAlignment="Center" Canvas.Top="28" VerticalAlignment="Top"/>
<controls:ProgressBarText Height="10" Canvas.Left="57" Canvas.Top="34" Width="92" HorizontalAlignment="Left" VerticalAlignment="Top" Value="78"/>
<Label Content="365,32 m / 1.366,10 m" FontSize="10" Canvas.Top="28" HorizontalAlignment="Center" VerticalAlignment="Top" Canvas.Left="154"/>
<controls:ProgressBarText x:Name="pgbResumo_AreaTotal" Height="10" Canvas.Left="57" Canvas.Top="34" Width="92" HorizontalAlignment="Left" VerticalAlignment="Top" Value="78"/>
<Label x:Name="lblResumo_AreaTotal" Content="365,32 m / 1.366,10 m" FontSize="10" Canvas.Top="28" HorizontalAlignment="Center" VerticalAlignment="Top" Canvas.Left="154"/>
<Label Content="Bateria" FontSize="10" HorizontalAlignment="Center" Canvas.Top="44" VerticalAlignment="Top"/>
<controls:ProgressBarText Height="10" Canvas.Left="57" Canvas.Top="51" Width="92" HorizontalAlignment="Left" VerticalAlignment="Top" Value="84"/>
<Label Content="40,85 V (01:36:45)" FontSize="9" HorizontalAlignment="Center" Canvas.Top="44" VerticalAlignment="Center" Canvas.Left="154"/>
<controls:ProgressBarText x:Name="pgbResumo_Bateria" Height="10" Canvas.Left="57" Canvas.Top="51" Width="92" HorizontalAlignment="Left" VerticalAlignment="Top" Value="84"/>
<Label x:Name="lblResumo_Bateria" Content="40,85 V (01:36:45)" FontSize="9" HorizontalAlignment="Center" Canvas.Top="44" VerticalAlignment="Center" Canvas.Left="154"/>
<Label Content="Herbicida" FontSize="10" HorizontalAlignment="Center" Canvas.Top="60" VerticalAlignment="Top"/>
<controls:ProgressBarText Height="10" Canvas.Left="57" Canvas.Top="67" Width="92" HorizontalAlignment="Left" VerticalAlignment="Top" Value="73"/>
<Label Content="21,90 L (584,32 m)" FontSize="9" HorizontalAlignment="Left" Canvas.Top="60" VerticalAlignment="Center" Canvas.Left="154"/>
<controls:ProgressBarText x:Name="pgbResumo_Herbicida" Height="10" Canvas.Left="57" Canvas.Top="67" Width="92" HorizontalAlignment="Left" VerticalAlignment="Top" Value="73"/>
<Label x:Name="lblResumo_Herbicida" Content="21,90 L (584,32 m)" FontSize="9" HorizontalAlignment="Left" Canvas.Top="60" VerticalAlignment="Center" Canvas.Left="154"/>
<Label Content="Infestação" FontSize="10" Canvas.Top="76" HorizontalAlignment="Center" VerticalAlignment="Top"/>
<controls:ProgressBarText Height="10" Canvas.Left="57" Canvas.Top="83" Width="92" HorizontalAlignment="Center" VerticalAlignment="Top" Value="23"/>
<Label Content="234,51 mL/erva" FontSize="9" HorizontalAlignment="Center" Canvas.Top="76" VerticalAlignment="Top" Canvas.Left="154"/>
<controls:ProgressBarText x:Name="pgbResumo_Infestacao" Height="10" Canvas.Left="57" Canvas.Top="83" Width="92" HorizontalAlignment="Center" VerticalAlignment="Top" Value="23"/>
<Label x:Name="lblResumo_Infestacao" Content="234,51 mL/erva" FontSize="9" HorizontalAlignment="Center" Canvas.Top="76" VerticalAlignment="Top" Canvas.Left="154"/>
<Label Content="Conexão" FontSize="10" Canvas.Top="92" HorizontalAlignment="Center" VerticalAlignment="Top"/>
<controls:ProgressBarText Height="10" Canvas.Left="57" Canvas.Top="99" Width="92" HorizontalAlignment="Center" VerticalAlignment="Top" Value="97"/>
<Label Content="4,9 dBi (574,65 m)" FontSize="9" HorizontalAlignment="Center" Canvas.Top="92" VerticalAlignment="Top" Canvas.Left="154"/>
<controls:ProgressBarText x:Name="pgbResumo_Conexao" Height="10" Canvas.Left="57" Canvas.Top="99" Width="92" HorizontalAlignment="Center" VerticalAlignment="Top" Value="97"/>
<Label x:Name="lblResumo_Conexao" Content="4,9 dBi (574,65 m)" FontSize="9" HorizontalAlignment="Center" Canvas.Top="92" VerticalAlignment="Top" Canvas.Left="154"/>
<Label Content="Operação Liberado" FontSize="10" Canvas.Top="12" HorizontalAlignment="Left" VerticalAlignment="Center" Canvas.Left="286"/>
<Label Content="Modo Automático" FontSize="10" Canvas.Top="28" HorizontalAlignment="Left" VerticalAlignment="Center" Canvas.Left="286"/>
<Label Content="Status EmAndamento" FontSize="10" Canvas.Top="44" HorizontalAlignment="Left" VerticalAlignment="Center" Canvas.Left="286"/>
<Label Content="Carro CaminhandoRua" FontSize="10" Canvas.Top="60" HorizontalAlignment="Left" VerticalAlignment="Center" Canvas.Left="286"/>
<Label Content="Temperatura 45,32°C" FontSize="10" Canvas.Top="76" HorizontalAlignment="Left" VerticalAlignment="Center" Canvas.Left="286"/>
<Label Content="Duração 00:23:15 / 00:54:15" FontSize="10" Canvas.Top="92" HorizontalAlignment="Left" VerticalAlignment="Center" Canvas.Left="286"/>
<Label x:Name="lblResumo_OperacaoLiberada" Content="Operação Liberado" FontFamily="Segoe UI Emoji" FontSize="10" Canvas.Top="12" HorizontalAlignment="Left" VerticalAlignment="Center" Canvas.Left="286"/>
<Label x:Name="lblResumo_OperacaoModo" Content="Modo Automático" FontSize="10" Canvas.Top="28" HorizontalAlignment="Left" VerticalAlignment="Center" Canvas.Left="286"/>
<Label x:Name="lblResumo_OperacaoStatus" Content="Status EmAndamento" FontSize="10" Canvas.Top="44" HorizontalAlignment="Left" VerticalAlignment="Center" Canvas.Left="286"/>
<Label x:Name="lblResumo_StatusCarro" Content="Carro CaminhandoRua" FontSize="10" Canvas.Top="60" HorizontalAlignment="Left" VerticalAlignment="Center" Canvas.Left="286"/>
<Label x:Name="lblResumo_TemperaturaGeral" Content="Temperatura 45,32°C" FontSize="10" Canvas.Top="76" HorizontalAlignment="Left" VerticalAlignment="Center" Canvas.Left="286"/>
<Label x:Name="lblResumo_OperacaoDuracao" Content="Duração 00:23:15 / 00:54:15" FontSize="10" Canvas.Top="92" HorizontalAlignment="Left" VerticalAlignment="Center" Canvas.Left="286"/>
</Canvas>
@ -143,8 +144,13 @@
<Label x:Name="lblGNSS_Correcao" Content="Correção RTKFixo B 1,3 s" HorizontalAlignment="Center" VerticalAlignment="Top" Canvas.Top="16" FontSize="9"/>
<Label x:Name="lblGNSS_Satelites" Content="Satélites 29 (0,60 cm)" HorizontalAlignment="Center" VerticalAlignment="Top" Canvas.Top="29" FontSize="9"/>
<Label x:Name="lblGNSS_Altitude" Content="Altitude 634,21 m" HorizontalAlignment="Left" VerticalAlignment="Top" Canvas.Left="-1" Canvas.Top="42" FontSize="9"/>
<Button x:Name="btnGNSS_FixarBase" Content="Fixar" Canvas.Left="127" Canvas.Top="17" Click="btnGNSS_FixarBase_Click" HorizontalAlignment="Left" VerticalAlignment="Center" Width="50"/>
<Label x:Name="lblGNSS_Progresso" Content="0,00%" HorizontalAlignment="Right" VerticalAlignment="Center" Canvas.Left="143" Canvas.Top="42" FontSize="9"/>
<Slider x:Name="sldGNSS_LeverArm" Canvas.Left="67" Canvas.Top="1" Width="116" HorizontalAlignment="Center" Height="18" VerticalAlignment="Center" Maximum="5" Minimum="-5" TickFrequency="1" Value="0" ValueChanged="sldGNSS_LeverArm_ValueChanged"/>
<Label x:Name="lblGNSS_Progresso" Content="0,00%" HorizontalAlignment="Center" VerticalAlignment="Top" Canvas.Left="143" Canvas.Top="16" FontSize="9"/>
<Button x:Name="btnGNSS_FixarBase" Content="Fixar" Canvas.Left="127" Canvas.Top="42" Click="btnGNSS_FixarBase_Click" HorizontalAlignment="Center" VerticalAlignment="Center" Width="50"/>
</Canvas>
</Border>
@ -154,25 +160,28 @@
<Canvas Height="64" VerticalAlignment="Bottom">
<Label Content="Parâmetros da Operação" FontWeight="Bold" FontSize="11" Canvas.Top="-3" HorizontalAlignment="Center" VerticalAlignment="Top"/>
<Label Content="Vel. com Ervas" FontSize="9" Canvas.Top="15" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Label Content="Vel. sem Ervas" FontSize="9" Canvas.Top="30" HorizontalAlignment="Center" VerticalAlignment="Top" Canvas.Left="1"/>
<Label Content="Angulo Máximo" FontSize="9" Canvas.Top="45" HorizontalAlignment="Center" VerticalAlignment="Top" Canvas.Left="1"/>
<TextBox Canvas.Left="73" TextWrapping="Wrap" Text="1,5" Canvas.Top="19" Width="30" FontSize="9" HorizontalAlignment="Left" VerticalAlignment="Center" TextAlignment="Center" ToolTip="Velocidade que o equipamento se move quando há presença de ervas no radar, em km/h"/>
<TextBox Canvas.Left="73" TextWrapping="Wrap" Text="3,5" Canvas.Top="34" Width="30" FontSize="9" HorizontalAlignment="Left" VerticalAlignment="Center" TextAlignment="Center" ToolTip="Velocidade que o equipamento se move quando não há presença de ervas no radar, em km/h"/>
<TextBox Canvas.Left="73" TextWrapping="Wrap" Text="30" Canvas.Top="49" Width="30" FontSize="9" HorizontalAlignment="Left" VerticalAlignment="Center" TextAlignment="Center" ToolTip="Angulo máximo de controle direcional, em graus"/>
<Label Content="km/h" FontSize="9" Canvas.Top="15" HorizontalAlignment="Left" VerticalAlignment="Center" Canvas.Left="100"/>
<Label Content="km/h" FontSize="9" Canvas.Top="30" HorizontalAlignment="Left" VerticalAlignment="Center" Canvas.Left="100"/>
<Label Content="°" FontSize="9" Canvas.Top="45" HorizontalAlignment="Left" VerticalAlignment="Center" Canvas.Left="100"/>
<Label Content="Ervas % ROI" FontSize="9" Canvas.Top="15" HorizontalAlignment="Left" VerticalAlignment="Center" Canvas.Left="130"/>
<Label Content="Ervas % Area" FontSize="9" Canvas.Top="30" HorizontalAlignment="Left" VerticalAlignment="Center" Canvas.Left="130"/>
<Label Content="Pressão Linha" FontSize="9" Canvas.Top="45" HorizontalAlignment="Left" VerticalAlignment="Center" Canvas.Left="130"/>
<TextBox Canvas.Left="194" TextWrapping="Wrap" Text="70" Canvas.Top="19" Width="30" FontSize="9" HorizontalAlignment="Left" VerticalAlignment="Center" TextAlignment="Center" ToolTip="Percentual da imagem onde a erva detectada envia o comando para atuação dos bicos pulverizadores, onde 100% em cima e 0% em baixo"/>
<TextBox Canvas.Left="194" TextWrapping="Wrap" Text="10" Canvas.Top="34" Width="30" FontSize="9" HorizontalAlignment="Left" VerticalAlignment="Center" TextAlignment="Center" ToolTip="Percentual de ervas detectada sobre a região de um bico para ligar e desligar o bico pulverizador"/>
<TextBox Canvas.Left="194" TextWrapping="Wrap" Text="85" Canvas.Top="49" Width="30" FontSize="9" HorizontalAlignment="Left" VerticalAlignment="Center" TextAlignment="Center" ToolTip="Pressão da linha, em psi"/>
<Label Content="psi" FontSize="9" Canvas.Top="45" HorizontalAlignment="Left" VerticalAlignment="Center" Canvas.Left="224"/>
<CheckBox Content="Modo Manual" Canvas.Left="249" Canvas.Top="2" FontSize="9" VerticalAlignment="Top" ToolTip="Ativa controle manual do equipamento selecionado" HorizontalAlignment="Left"/>
<CheckBox Content="Pulverizador Automático" Canvas.Left="249" Canvas.Top="18" FontSize="10" HorizontalAlignment="Center" VerticalAlignment="Top" ToolTip="Atuação automática do pulverizador ao detectar ervas no radar sobre a área de um bico"/>
<CheckBox Content="Frenagem Automática" Canvas.Left="249" Canvas.Top="33" FontSize="10" HorizontalAlignment="Left" VerticalAlignment="Center" ToolTip="Acionamento automático dos freios ao detectar obstáculos próximos"/>
<CheckBox Content="Sonar Ativado" Canvas.Left="249" Canvas.Top="48" FontSize="10" HorizontalAlignment="Left" VerticalAlignment="Center" ToolTip="Utilizar dados do sonar na tomada de decisão de controle direcional automático"/>
<Label Content="Vel. sem Ervas" FontSize="9" Canvas.Top="30" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<Label Content="Angulo Máx" FontSize="9" Canvas.Top="45" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<TextBox x:Name="txtParametros_VelCErvas" Canvas.Left="64" TextWrapping="Wrap" Text="1,5" Canvas.Top="19" Width="25" FontSize="9" HorizontalAlignment="Left" VerticalAlignment="Center" TextAlignment="Center" ToolTip="Velocidade que o equipamento se move quando há presença de ervas no radar, em km/h"/>
<TextBox x:Name="txtParametros_VelSErvas" Canvas.Left="64" TextWrapping="Wrap" Text="3,5" Canvas.Top="34" Width="25" FontSize="9" HorizontalAlignment="Left" VerticalAlignment="Center" TextAlignment="Center" ToolTip="Velocidade que o equipamento se move quando não há presença de ervas no radar, em km/h"/>
<TextBox x:Name="txtParametros_AngMax" Canvas.Left="64" TextWrapping="Wrap" Text="30" Canvas.Top="49" Width="25" FontSize="9" HorizontalAlignment="Left" VerticalAlignment="Center" TextAlignment="Center" ToolTip="Angulo máximo de controle direcional, em graus"/>
<Label Content="Início Atuação" FontSize="9" Canvas.Top="15" HorizontalAlignment="Left" VerticalAlignment="Center" Canvas.Left="93"/>
<Label Content="Area Atuação" FontSize="9" Canvas.Top="30" HorizontalAlignment="Left" VerticalAlignment="Center" Canvas.Left="93"/>
<Label Content="Pressão Linha" FontSize="9" Canvas.Top="45" HorizontalAlignment="Left" VerticalAlignment="Center" Canvas.Left="93"/>
<TextBox x:Name="txtParametros_RoiAtuacao" Canvas.Left="156" TextWrapping="Wrap" Text="70" Canvas.Top="19" Width="25" FontSize="9" HorizontalAlignment="Left" VerticalAlignment="Center" TextAlignment="Center" ToolTip="Percentual da imagem onde a erva detectada envia o comando para atuação dos bicos pulverizadores, onde 100% em cima e 0% em baixo"/>
<TextBox x:Name="txtParametros_AreaAtuacao" Canvas.Left="156" TextWrapping="Wrap" Text="10" Canvas.Top="34" Width="25" FontSize="9" HorizontalAlignment="Left" VerticalAlignment="Center" TextAlignment="Center" ToolTip="Percentual de altura da imagem para atuação dos bicos quando as ervas entrarem nessa região"/>
<TextBox x:Name="txtParametros_PressaoLiha" Canvas.Left="156" TextWrapping="Wrap" Text="85" Canvas.Top="49" Width="25" FontSize="9" HorizontalAlignment="Left" VerticalAlignment="Center" TextAlignment="Center" ToolTip="Pressão da linha, em psi"/>
<Label Content="Erva % On" FontSize="9" Canvas.Top="15" HorizontalAlignment="Left" VerticalAlignment="Center" Canvas.Left="185"/>
<Label Content="Erva % Off" FontSize="9" Canvas.Top="30" HorizontalAlignment="Left" VerticalAlignment="Center" Canvas.Left="185"/>
<Label Content="Tempo On" FontSize="9" Canvas.Top="45" HorizontalAlignment="Left" VerticalAlignment="Center" Canvas.Left="185"/>
<TextBox x:Name="txtParametros_PctErvaOn" Canvas.Left="234" TextWrapping="Wrap" Text="2" Canvas.Top="19" Width="25" FontSize="9" HorizontalAlignment="Left" VerticalAlignment="Center" TextAlignment="Center" ToolTip="Percentual de ervas detectado na região de um bico para ligar o bico pulverizador"/>
<TextBox x:Name="txtParametros_PctErvaOff" Canvas.Left="234" TextWrapping="Wrap" Text="1" Canvas.Top="34" Width="25" FontSize="9" HorizontalAlignment="Left" VerticalAlignment="Center" TextAlignment="Center" ToolTip="Percentual de ervas detectado na região de um bico para desligar o bico pulverizador"/>
<TextBox x:Name="txtParametros_TempoOn" Canvas.Left="234" TextWrapping="Wrap" Text="200" Canvas.Top="49" Width="25" FontSize="9" HorizontalAlignment="Left" VerticalAlignment="Center" TextAlignment="Center" ToolTip="Tempo em que o bico pulverizador fica atuado após detectar a erva, em milissegundos"/>
<CheckBox x:Name="chbParametros_Sonar" Content="Sonar Ativado" Canvas.Left="265" Canvas.Top="18" FontSize="10" HorizontalAlignment="Center" VerticalAlignment="Top" ToolTip="Utilizar dados do sonar na tomada de decisão de controle direcional automático"/>
<CheckBox x:Name="chbParametros_Frenagem" Content="Frenagem Automática" Canvas.Left="265" Canvas.Top="33" FontSize="10" HorizontalAlignment="Center" VerticalAlignment="Top" ToolTip="Acionamento automático dos freios ao detectar obstáculos próximos"/>
<CheckBox x:Name="chbParametros_Pulverizador" Content="Pulverizador Automático" Canvas.Left="265" Canvas.Top="48" FontSize="10" HorizontalAlignment="Center" VerticalAlignment="Top" ToolTip="Atuação automática do pulverizador ao detectar ervas no radar sobre a área de um bico"/>
<Button x:Name="btnParametros_Salvar" Content="💾" FontSize="10" Canvas.Left="372" Canvas.Top="3" Click="btnParametros_Salvar_Click" HorizontalAlignment="Left" VerticalAlignment="Center" ToolTip="Salva os ajustes realizados nos parâmetros da operação, e envia para o equipamento em foco"/>
<Button x:Name="btnParametros_Atualizar" Content="🔄" FontSize="10" Canvas.Left="351" Canvas.Top="3" Click="btnParametros_Atualizar_Click" HorizontalAlignment="Left" VerticalAlignment="Center" ToolTip="Atualiza os dados de parâmetros da operação do equipaento em foco"/>
</Canvas>
</Border>
@ -186,27 +195,27 @@
<Border x:Name="brdControle" Margin="659,0,877,943">
<Canvas>
<controls:ManualControlPad x:Name="PadCtl" MaxSteerDeg="90" SpeedSpKmh="3.2" SpeedCurKmh="3.31" AngleSpDeg="2.92" AngleCurDeg="2.4" MoveType="MovimentoDiagonal"/>
<controls:ManualControlPad x:Name="CTRL"/>
</Canvas>
</Border>
<Border Name="brdMapaInfo" BorderBrush="Black" BorderThickness="1" Height="26" Width="980" Canvas.Top="878" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="465,951,0,0">
<Canvas>
<Label Content="Próximo Ponto: 15 | Aproximando | Distância próximo ponto: 1,32 m | Distância ponto anterior: 0,74 m | Corredor: Dentro | Margem: Não | Disância Esquerda: 34 cm | Distância Direita: 36 cm | Status: CaminhandoRua" FontSize="9" HorizontalAlignment="Center" VerticalAlignment="Top" Canvas.Top="1"/>
<Label x:Name="lblMapaInfo_Debug" Content="Próximo Ponto: 15 | Aproximando | Distância próximo ponto: 1,32 m | Distância ponto anterior: 0,74 m | Corredor: Dentro | Margem: Não | Disância Esquerda: 34 cm | Distância Direita: 36 cm | Status: CaminhandoRua" FontSize="9" HorizontalAlignment="Center" VerticalAlignment="Top" Canvas.Top="1"/>
</Canvas>
</Border>
<Border x:Name="brdCameraFrontal" BorderBrush="Black" BorderThickness="1" CornerRadius="8" Margin="1453,0,7,735">
<Canvas>
<Label Content="Câmera frontal | 12 fps | 230 kbps | 0,00% cana | 43 cm - 27 cm | 12,95° | CaminhandoRua" FontSize="10" HorizontalAlignment="Center" VerticalAlignment="Top" Canvas.Top="-3"/>
<Image HorizontalAlignment="Center" Height="243" VerticalAlignment="Top" Width="438" Source="/Resources/caminho.jpeg" Stretch="UniformToFill" Canvas.Top="21" Canvas.Left="10"/>
<vlc:VideoView x:Name="VideoFront" Background="Black" Height="237" Width="438" HorizontalAlignment="Center" Canvas.Top="25" VerticalAlignment="Top" Canvas.Left="10"/>
</Canvas>
</Border>
<Border x:Name="brdCameraTraseira" BorderBrush="Black" BorderThickness="1" CornerRadius="8" Margin="1453,281,7,491">
<Canvas>
<Label Content="Câmera traseira | 10 fps | 193 kbps | 5,41% erva | 0,00% cana" FontSize="10" HorizontalAlignment="Center" VerticalAlignment="Top" Canvas.Top="-3"/>
<Image HorizontalAlignment="Left" Height="201" VerticalAlignment="Center" Width="438" Source="/Resources/solo.jpeg" Stretch="UniformToFill" Canvas.Top="21" Canvas.Left="10"/>
<vlc:VideoView x:Name="VideoWeed" Background="Black" Height="200" Width="438" HorizontalAlignment="Center" Canvas.Top="25" VerticalAlignment="Top" Canvas.Left="10"/>
</Canvas>
</Border>

View File

@ -14,6 +14,14 @@ using OperationControl.Services;
using System.Windows.Controls;
using System.Runtime.CompilerServices;
using System.Windows.Media;
using DotSpatial.Projections.Transforms;
using System;
using LibVLCSharp.Shared;
using MediaPlayer = LibVLCSharp.Shared.MediaPlayer;
using System.IO;
using ComboBox = System.Windows.Controls.ComboBox;
using Application = System.Windows.Application;
using MessageBox = System.Windows.MessageBox;
namespace OperationControl.Windows
{
@ -36,6 +44,11 @@ namespace OperationControl.Windows
DispatcherTimer _clock = new DispatcherTimer();
Random _rand = new Random();
private LibVLC _libVLC;
private MediaPlayer _playerFront;
private MediaPlayer _playerWeed;
private Media _mediaFront;
private Media _mediaWeed;
public MainWindow()
{
@ -71,6 +84,36 @@ namespace OperationControl.Windows
// new AgroBase.Models.LivoxBboxModel{ cx=3.0, cy=-0.7, cz=0.6, d=0.8, w=0.5, h=1.2 },
//});
// Opções focadas em baixa latência
_libVLC = new LibVLC(
"--network-caching=1000", // ms (ajusta depois)
"--clock-jitter=0",
"--clock-synchro=0"
);
// Player da câmera frontal
_playerFront = new MediaPlayer(_libVLC);
VideoFront.MediaPlayer = _playerFront;
_playerWeed = new MediaPlayer(_libVLC);
VideoWeed.MediaPlayer = _playerWeed;
Loaded += MainWindow_Loaded;
Closed += MainWindow_Closed;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
}
private void MainWindow_Closed(object? sender, EventArgs e)
{
PararStreamCameraFrontal(true);
PararStreamCameraErvas(true);
_libVLC?.Dispose();
}
private void PushSample(bool initial = false)
@ -151,101 +194,404 @@ namespace OperationControl.Windows
public void AtualizarListaDispositivos(List<string> dispositivos)
{
cmbDispositivo.Items.Clear();
foreach (var d in dispositivos)
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
cmbDispositivo.Items.Add(d);
if (!MAP.markers.Added(d))
try
{
if (d == VariaveisControleOperacao.BaseMarkerID)
cmbDispositivo.Items.Clear();
foreach (var d in dispositivos)
{
MAP.markers.AddMarker(
d,
Variaveis.GpsService?.UltimaLeitura?.Latitude ?? 0,
Variaveis.GpsService?.UltimaLeitura?.Longitude ?? 0,
Variaveis.GpsService?.UltimaLeitura?.OrientacaoReal ?? 0,
MAP.markers.GetColorForMarker(d, isBase: true),
"Base"
);
}
else
{
var rover = VariaveisControleOperacao.RoversNaRede.FirstOrDefault(x => x.Key == d);
if (rover.Value != null)
cmbDispositivo.Items.Add(d);
if (!MAP.markers.Added(d))
{
MAP.markers.AddMarker(
d,
rover.Value.Gps?.Latitude ?? 0,
rover.Value.Gps?.Longitude ?? 0,
rover.Value.Gps?.AnguloCarroDefinido ?? 0,
MAP.markers.GetColorForMarker(d, isBase: false),
rover.Key
);
if (d == VariaveisControleOperacao.BaseMarkerID)
{
MAP.markers.AddMarker(
d,
true,
lat: Variaveis.GpsService?.UltimaLeitura?.Latitude ?? 0,
lon: Variaveis.GpsService?.UltimaLeitura?.Longitude ?? 0,
heading: Variaveis.GpsService?.UltimaLeitura?.OrientacaoReal ?? 0,
label: "Base"
);
}
else
{
var rover = VariaveisControleOperacao.RoversNaRede.FirstOrDefault(x => x.RoverId == d);
if (rover != null)
{
MAP.markers.AddMarker(
d,
false,
lat: rover.DadosLeitura?.Gps?.Latitude ?? 0,
lon: rover.DadosLeitura?.Gps?.Longitude ?? 0,
heading: rover.DadosLeitura?.Gps?.AnguloCarroDefinido ?? 0
);
}
}
}
}
int idx_selected = dispositivos.IndexOf(VariaveisControleOperacao.SelectedRoverId);
if (idx_selected > -1)
cmbDispositivo.SelectedIndex = idx_selected;
}
}
int idx_selected = dispositivos.IndexOf(VariaveisControleOperacao.SelectedRoverId);
if (idx_selected > -1)
cmbDispositivo.SelectedIndex = idx_selected;
catch (Exception exUi)
{
Variaveis.MostrarLog($"Erro ao atualizar UI lista dispositivos: {exUi.Message}");
}
}));
}
private void cmbDispositivo_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
AtualizarDadosTela_Telemetria(((ComboBox)sender).SelectedValue.ToString());
var selecionado = ((ComboBox)sender).SelectedItem;
if (selecionado == null) return;
bool dados_base = selecionado == VariaveisControleOperacao.BaseMarkerID;
if (dados_base && !VariaveisControleOperacao.BaseEmFoco)
{
PararStreamCameraFrontal();
PararStreamCameraErvas();
}
VariaveisControleOperacao.SelectedRoverId = selecionado.ToString();
MAP.markers.SetMarkerFocused(selecionado.ToString(), true);
AtualizarDadosTela_Telemetria(selecionado.ToString());
brdResumo.IsEnabled = !dados_base;
brdDiagnostico.IsEnabled = !dados_base;
brdControle.IsEnabled = !dados_base;
brdAjustesOperacao.IsEnabled = !dados_base;
if (!dados_base)
{
sldGNSS_LeverArm.Value = VariaveisControleOperacao.RoverEmFoco.DadosLeitura?.Gps?.LeverArmLateral ?? 0;
btnParametros_Atualizar_Click(sender, e);
IniciarStreamCameraFrontal();
IniciarStreamCameraErvas();
}
}
public void LimparDadosTela_Telemetria()
public void LimparDadosTela_Telemetria(string rover_id)
{
VariaveisControleOperacao.SelectedRoverId = "";
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
if (!string.IsNullOrEmpty(rover_id))
{
//MAP.markers.RemoveMarker(rover_id);
//cmbDispositivo.Items.Remove(rover_id);
}
else
{
//cmbDispositivo.SelectedIndex = 0;
}
}
catch (Exception exUi)
{
Variaveis.MostrarLog($"Erro ao atualizar UI telemetria (clear): {exUi.Message}");
}
}));
}
public void AtualizarDadosTela_Telemetria(string rover_id)
{
bool dados_base = rover_id == VariaveisControleOperacao.BaseMarkerID;
var rover = VariaveisControleOperacao.RoversNaRede.FirstOrDefault(x => x.RoverId == rover_id)?.DadosLeitura;
if (dados_base)
{
MAP.markers.UpdateMarkerPosition(rover_id, lat: Variaveis.GpsService?.UltimaLeitura?.Latitude, lon: Variaveis.GpsService?.UltimaLeitura?.Longitude, heading: Variaveis.GpsService?.UltimaLeitura?.OrientacaoReal);
}
else if (rover != null)
{
var simulacao = rover.Controle?.SimulacaoMPC?.Select(x => new double[] { x.longitude, x.latitude })?.ToList();
MAP.markers.UpdateMarkerPosition(rover_id, lat: rover?.Gps?.Latitude, lon: rover?.Gps?.Longitude, heading: rover?.Gps?.OrientacaoReal, predict: simulacao);
MAP.markers.UpdateMarkerInfo(rover_id, status: rover.StatusOperacao);
}
if (rover_id != VariaveisControleOperacao.SelectedRoverId) return;
if (rover_id == VariaveisControleOperacao.BaseMarkerID)
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
Variaveis.MostrarLog($"Atualizando dados da tela para a base");
try
{
if (rover_id == VariaveisControleOperacao.BaseMarkerID)
{
Variaveis.MostrarLog($"Atualizando dados da tela para a base");
AtualizarDadosTela_GNSS(Variaveis.GpsService?.UltimaLeitura ?? new AgroBase.Models.GPSModel());
AtualizarDadosTela_Heading(Variaveis.GpsService?.UltimaLeitura?.AnguloCarroDefinido ?? 0);
AtualizarDadosTela_GNSS(Variaveis.GpsService?.UltimaLeitura ?? new AgroBase.Models.GPSModel(), marker_id: VariaveisControleOperacao.BaseMarkerID);
AtualizarDadosTela_Heading(Variaveis.GpsService?.UltimaLeitura?.AnguloCarroDefinido ?? 0);
}
else
{
if (rover == null) return;
Variaveis.MostrarLog($"Atualizando dados da tela para o dispositivo {rover_id}");
if (rover.Trajetoria != null)
AtualizarDadosTela_Resumo(rover);
if (rover.Gps != null)
AtualizarDadosTela_GNSS(rover.Gps, marker_id: rover_id);
if (rover.Controle != null)
AtualizarDadosTela_Controle(rover.Controle, rover.Movimentacao.AnguloMedio, rover.Movimentacao.VelocidadeMedia, rover.Emergencia, !rover.OperacaoIniciada, rover.StatusOperacao == AgroBase.Models.Enums.StatusOperacao.Calibrando);
//if (rover.Value.Controle != null)
// AtualizarDadosTela_ParametrosOperacao(rover.Value.Controle);
if (rover.Trajetoria != null)
AtualizarDadosTela_Mapa(rover.Trajetoria);
if (rover.Gps != null)
AtualizarDadosTela_Heading(rover.Gps.AnguloCarroDefinido, rover.Modo == AgroBase.Models.Enums.ModoOperacao.Manual ? double.NaN : rover.Trajetoria.AnguloCaminho);
if (rover.IMU != null)
AtualizarDadosTela_IMU(rover.IMU.InclinacaoLateral, rover.IMU.InclinacaoFrontal);
if (rover.LivoxLidar != null)
AtualizarDadostela_LIDAR(rover.LivoxLidar.bboxes);
}
}
catch (Exception exUi)
{
Variaveis.MostrarLog($"Erro ao atualizar UI telemetria (set): {exUi.Message}");
}
}));
}
#endregion
#region RESUMO OPERACIONAL
public void AtualizarDadosTela_Resumo(AgroBase.Models.OperacaoSensoriamentoLogModel dados)
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
pgbResumo_RuaAtual.Value = dados.Trajetoria.PercentualRuaAtual;
lblResumo_RuaAtual.Content = $"{dados.Trajetoria.CorredorAtual.DistanciaPercorridaCorredor.ToString("0.00")} / {dados.Trajetoria.CorredorAtual.DistanciaTotal.ToString("0.00")}";
pgbResumo_AreaTotal.Value = dados.Trajetoria.PercentualOperacao;
lblResumo_AreaTotal.Content = $"{dados.Trajetoria.DistanciaPercorrida.ToString("0.00")} / {dados.Trajetoria.DistanciaTotal.ToString("0.00")}";
pgbResumo_Bateria.Value = dados.Bateria.PorcentagemBateria;
lblResumo_Bateria.Content = $"{dados.Bateria.TensaoInstantanea.ToString("0.00")} V ({dados.Bateria.TempoEstimadoRestanteMinutos})";
pgbResumo_Herbicida.Value = dados.Atuador.PercentualReservatorio;
lblResumo_Herbicida.Content = $"{dados.Atuador.VolumeReservatorio.ToString("0.00")} L ({0.ToString("0.00")})";
pgbResumo_Infestacao.Value = dados.Atuador.PercentualErvasTerreno;
lblResumo_Infestacao.Content = $"{dados.Atuador.VazaoMedia.ToString("0.00")}";
pgbResumo_Conexao.Value = 0;
lblResumo_Conexao.Content = $"0,0 dBi (0,00 m)";
lblResumo_OperacaoLiberada.Content = $"Operação " + (dados.OperacaoLiberada ? "🔓 Liberada" : "🔒 Bloqueada");
lblResumo_OperacaoModo.Content = $"Modo {dados.Modo}";
lblResumo_OperacaoStatus.Content = $"Status {dados.StatusOperacao}" + (dados.StatusOperacao == AgroBase.Models.Enums.StatusOperacao.Aguardando ? $" ({dados.TempoAguardandoSeg.ToString("0")})" : "");
lblResumo_StatusCarro.Content = $"Carro {dados.Trajetoria.StatusCarro}";
lblResumo_TemperaturaGeral.Content = $"Temperatura {(dados.DadosPerformance.CPU_temp ?? 0).ToString("0.00")} °C";
lblResumo_OperacaoDuracao.Content = $"Duração {dados.TempoDecorrido.ToString("HH:mm:ss")} / {dados.Trajetoria.TempoEstimadoOperacao}";
}
catch (Exception exUi)
{
Variaveis.MostrarLog($"Erro ao atualizar UI Resumo: {exUi.Message}");
}
}));
}
#endregion
#region POSICAO
public void AtualizarDadosTela_GNSS(AgroBase.Models.GPSModel dados, string? marker_id = null, double progresso = double.NaN)
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
bool dados_base = marker_id == VariaveisControleOperacao.BaseMarkerID;
lblGNSS_Posicao.Foreground = new SolidColorBrush(dados.Inicializado ? System.Windows.Media.Colors.Green : System.Windows.Media.Colors.Red);
lblGNSS_Correcao.Content = $"Correção {dados.QualidadeFix} " +
(dados.QualidadeFix == AgroBase.Models.Enums.TiposCorrecaoGPS.BaseFix ?
(dados.OrientacaoReal.ToString("0.00") + "°") :
((dados.Ntrip_ativado ? "N" : "B") + $" {dados.IdadeCorrecao.ToString("0.0")} s"));
lblGNSS_Satelites.Content = $"Satélites {dados.NumeroSatelites} ({dados.PrecisaoCm.ToString("0.00")} cm)";
lblGNSS_Altitude.Content = $"Altitude {dados.Altitude.ToString("0.00")} m";
if (dados_base)
{
sldGNSS_LeverArm.Visibility = Visibility.Hidden;
if (double.IsNaN(progresso))
{
lblGNSS_Progresso.Visibility = Visibility.Hidden;
}
else
{
lblGNSS_Progresso.Visibility = Visibility.Visible;
lblGNSS_Progresso.Content = $"{progresso.ToString("0.00")}%";
}
bool gnss_fix_preciso = new List<AgroBase.Models.Enums.TiposCorrecaoGPS>() { AgroBase.Models.Enums.TiposCorrecaoGPS.RTKFixo, AgroBase.Models.Enums.TiposCorrecaoGPS.RTKFlutuante }.Contains(Variaveis.GpsService?.UltimaLeitura?.QualidadeFix ?? AgroBase.Models.Enums.TiposCorrecaoGPS.SemCorrecao);
bool gnss_fixado = Variaveis.GpsService?.BaseFix?.CorrecaoAbsoluta ?? false;
bool gnss_fixando = btnGNSS_FixarBase.Content.ToString() == "Parar";
btnGNSS_FixarBase.IsEnabled = (gnss_fix_preciso && !gnss_fixado) || gnss_fixando || gnss_fixado;
btnGNSS_FixarBase.Content = gnss_fixado || !gnss_fixando ? "Fixar" : "Parar";
}
else
{
btnGNSS_FixarBase.IsEnabled = true;
sldGNSS_LeverArm.Visibility = Visibility.Visible;
lblGNSS_Progresso.Visibility = Visibility.Visible;
lblGNSS_Progresso.Content = $"{(sldGNSS_LeverArm.Value * 10.0).ToString("0")} cm";
lblGNSS_Progresso.Foreground = new SolidColorBrush(Math.Round(sldGNSS_LeverArm.Value * 10.0, 0) == Math.Round(dados.LeverArmLateral, 0) ? System.Windows.Media.Colors.Black : System.Windows.Media.Colors.Red);
btnGNSS_FixarBase.Content = "Aplicar";
}
}
catch (Exception exUi)
{
Variaveis.MostrarLog($"Erro ao atualizar UI GNSS: {exUi.Message}");
}
}));
}
private void btnGNSS_FixarBase_Click(object sender, RoutedEventArgs e)
{
if (VariaveisControleOperacao.BaseEmFoco)
{
if (!Variaveis.GpsService.BaseFix.FixLiberado)
{
if (Variaveis.GpsService.BaseFix.CorrecaoAbsoluta)
{
var res = MessageBox.Show("Mudar posição da base?", "Tem certeza que deseja fixar a posição da base novamente?", MessageBoxButton.YesNo, MessageBoxImage.Question);
if (res == MessageBoxResult.Yes)
{
btnGNSS_FixarBase.Content = "Parar";
Variaveis.GpsService.BaseFix.FixLiberado = true;
Task.Run(async () => await Variaveis.GpsService.ConfigurarModulo());
}
}
else
{
btnGNSS_FixarBase.Content = "Parar";
Variaveis.GpsService.BaseFix.FixLiberado = true;
}
}
else
{
btnGNSS_FixarBase.Content = "Fixar";
Variaveis.GpsService.BaseFix.FixLiberado = false;
}
}
else
{
var rover = VariaveisControleOperacao.RoversNaRede.FirstOrDefault(x => x.Key == rover_id);
if (rover.Value == null) return;
Variaveis.MostrarLog($"Atualizando dados da tela para o dispositivo {rover_id}");
AtualizarDadosTela_GNSS(rover.Value.Gps);
AtualizarDadosTela_Heading(rover.Value.Gps.AnguloCarroDefinido, rover.Value.Modo == AgroBase.Models.Enums.ModoOperacao.Manual ? double.NaN : rover.Value.Trajetoria.AnguloCaminho);
AtualizarDadosTela_IMU(rover.Value.IMU.InclinacaoLateral, rover.Value.IMU.InclinacaoFrontal);
AtualizarDadostela_LIDAR(rover.Value.LivoxLidar.bboxes);
VariaveisControleOperacao.EnviarComandoLeverArm(sldGNSS_LeverArm.Value * 10.0);
}
}
#endregion
#region IMU
public void AtualizarDadosTela_IMU(double roll, double pitch)
private void sldGNSS_LeverArm_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
IMU.RollDeg = roll;
IMU.PitchDeg = pitch;
lblGNSS_Progresso.Content = $"{(sldGNSS_LeverArm.Value * 10.0).ToString("0")} cm";
}
#endregion
#region HEADING
#region CONTROLE
public void AtualizarDadosTela_Heading(double headingRover, double headingCourse = double.NaN)
public void AtualizarDadosTela_Controle(AgroBase.Models.OperacaoControleModel controle, double angulo, double velocidade, bool emergencia, bool pausa, bool refing)
{
HDG.Heading = headingRover;
HDG.CourseHeading = headingCourse;
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
CTRL.AtualizarDadosControle(
angSp: controle.Angulo,
angCur: angulo,
tipoMov: controle.TipoMovimento,
velPct: controle.PercentualVelocidadeSP,
velSp: controle.PercentualVelocidadeSPKmh,
velKmh: velocidade,
emg: emergencia,
pause: pausa,
refing: refing
);
}
catch (Exception exUi)
{
Variaveis.MostrarLog($"Erro ao atualizar UI Controle: {exUi.Message}");
}
}));
}
#endregion
#region PARAMETROS DA OPERACAO
public void AtualizarDadosTela_ParametrosOperacao(AgroBase.Models.Operacoes.OperacaoParametrosControleModel? controle)
{
if (controle == null) return;
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
txtParametros_VelCErvas.Text = controle.MovVelocidadeCErvasPercent.ToString();
txtParametros_VelSErvas.Text = controle.MovVelocidadeSErvasPercent.ToString();
txtParametros_AngMax.Text = controle.DirAnguloMaximo.ToString();
txtParametros_RoiAtuacao.Text = controle.AtuPercentualInicioPulverizacao.ToString();
txtParametros_AreaAtuacao.Text = controle.AtuAlturaAreaPulverizacao.ToString();
txtParametros_PressaoLiha.Text = controle.AtuPressaoLinha.ToString();
txtParametros_PctErvaOn.Text = controle.AtuPercentualErvasBicoOn.ToString();
txtParametros_PctErvaOff.Text = controle.AtuPercentualErvasBicoOff.ToString();
txtParametros_TempoOn.Text = controle.AtuDuracaoAtuacao.ToString();
chbParametros_Pulverizador.IsChecked = controle.PulverizadorAutomatico;
chbParametros_Frenagem.IsChecked = controle.FrenagemAutomatica;
chbParametros_Sonar.IsChecked = controle.SonarAtivado;
}
catch (Exception exUi)
{
Variaveis.MostrarLog($"Erro ao atualizar UI Parametros da Operacao: {exUi.Message}");
}
}));
}
private void btnParametros_Salvar_Click(object sender, RoutedEventArgs e)
{
var modo = (CTRL.TgManual.IsChecked ?? false) ? AgroBase.Models.Enums.ModoOperacao.Manual : AgroBase.Models.Enums.ModoOperacao.MapaGPS;
VariaveisControleOperacao.EnviarParametrosOperacao(new AgroBase.Models.Operacoes.OperacaoParametrosModel()
{
Modo = modo,
Descricao = "Operacao da base",
QtdCamerasSolo = 1,
QtdBicos = 3,
CapacidadeReservatorio = 45,
Controle = new AgroBase.Models.Operacoes.OperacaoParametrosControleModel()
{
MovimentoAutomatico = modo != AgroBase.Models.Enums.ModoOperacao.Manual,
SonarAtivado = chbParametros_Sonar.IsChecked ?? false,
FrenagemAutomatica = chbParametros_Frenagem.IsChecked ?? false,
MovVelocidadeCErvasPercent = int.Parse(txtParametros_VelCErvas.Text),
MovVelocidadeSErvasPercent = int.Parse(txtParametros_VelSErvas.Text),
DirAnguloMaximo = int.Parse(txtParametros_AngMax.Text),
DirTipoMovimento = AgroBase.Models.Enums.TiposControladorDirecional.MPC,
DirVelocidadeMovimento = 50,
PulverizadorAutomatico = chbParametros_Pulverizador.IsChecked ?? false,
AtuPercentualErvasBicoOn = double.Parse(txtParametros_PctErvaOn.Text),
AtuPercentualErvasBicoOff = double.Parse(txtParametros_PctErvaOff.Text),
AtuDuracaoAtuacao = int.Parse(txtParametros_TempoOn.Text),
AtuAlturaAreaPulverizacao = double.Parse(txtParametros_AreaAtuacao.Text),
AtuPercentualInicioPulverizacao = double.Parse(txtParametros_RoiAtuacao.Text),
AtuPressaoLinha = double.Parse(txtParametros_PressaoLiha.Text),
},
ModulosMandatorios = new List<AgroBase.Models.OperacaoModulosMandatoriosModel>(),
ParametrosMandatorios = new List<AgroBase.Models.OperacaoParametrosMandatoriosModel>(),
RuasPercorrer = MAP.RuasMapaCarregado.Where(x => x.Selected).Select(x => x.Id).ToList(),
Mapa = MAP.CriarDadosMapa()
});
}
private void btnParametros_Atualizar_Click(object sender, RoutedEventArgs e)
{
AtualizarDadosTela_ParametrosOperacao(VariaveisControleOperacao.RoverEmFoco?.Controle);
}
#endregion
@ -254,15 +600,16 @@ namespace OperationControl.Windows
private void MAP_MarkerClicked(object? sender, MapMarkerManager.MarkerClickedEventArgs e)
{
Variaveis.MostrarLog($"Rover em foco: {e.MarkerId}");
if (string.IsNullOrEmpty(e.MarkerId))
{
LimparDadosTela_Telemetria();
Variaveis.MostrarLog($"Sem rover em foco");
LimparDadosTela_Telemetria(e.MarkerId);
}
else
{
VariaveisControleOperacao.SelectedRoverId = e.MarkerId;
AtualizarDadosTela_Telemetria(e.MarkerId);
Variaveis.MostrarLog($"Rover em foco: {e.MarkerId}");
int idx = cmbDispositivo.Items.IndexOf(e.MarkerId);
cmbDispositivo.SelectedIndex = idx;
}
}
@ -271,6 +618,156 @@ namespace OperationControl.Windows
Variaveis.MostrarLog($"Rua clicada: {e.StreetId}. Ruas selecionadas: {string.Join(",", e.SelectedStreetsIds)}");
}
private void AtualizarDadosTela_Mapa(AgroBase.Models.OperacaoSensoriamentoLogTrajetoriaModel Trajetoria)
{
lblMapaInfo_Debug.Content = $"" +
$"Próximo Ponto: {Trajetoria.ProximoPonto.idxPonto} | " +
(Trajetoria.ProximoPonto.Aproximando ? "Aproximando" : "Afastando") + " | " +
$"Distância próximo ponto: {Trajetoria.ProximoPonto.DistanciaAtual.ToString("0.00")} m | " +
$"Distância ponto anterior: {Trajetoria.PontoAtual.DistanciaAtual.ToString("0.00")} m | " +
$"Corredor: " + (Trajetoria.CorredorAtual.Dentro ? "Dentro" : "Fora") + " | " +
$"Margem: " + (Trajetoria.NaMargemDoCorredor ? "Sim" : "Não") + " | " +
$"Disância Esquerda: {(Trajetoria.DistanciaEsquerda * 100.0).ToString("0.00")} cm | " +
$"Distância Direita: {(Trajetoria.DistanciaDireita * 100.0).ToString("0.00")} cm | " +
$"Status: {Trajetoria.StatusCarro}";
double erroLateral = (Trajetoria.DistanciaEsquerda - Trajetoria.DistanciaDireita) / 2.0 * 100.0;
AtualizarDadosTela_IMU(erro_lateral: erroLateral);
}
#endregion
#region HEADING
public void AtualizarDadosTela_Heading(double headingRover, double headingCourse = double.NaN)
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
HDG.Heading = headingRover;
HDG.CourseHeading = headingCourse;
}
catch (Exception exUi)
{
Variaveis.MostrarLog($"Erro ao atualizar UI Heading: {exUi.Message}");
}
}));
}
#endregion
#region IMU
public void AtualizarDadosTela_IMU(double? roll = null, double? pitch = null, double? erro_lateral = null)
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
if (roll != null) IMU.RollDeg = (double)roll;
if (pitch != null) IMU.PitchDeg = (double)pitch;
if (erro_lateral != null) IMU.LateralError = (double)erro_lateral;
}
catch (Exception exUi)
{
Variaveis.MostrarLog($"Erro ao atualizar UI IMU: {exUi.Message}");
}
}));
}
#endregion
#region CAMERA FRONTAL
private void IniciarStreamCameraFrontal()
{
var path = @"streams\camera_frontal.sdp";
if (!File.Exists(path))
{
string stream =
"v=0\r\n" +
"o=- 0 0 IN IP4 0.0.0.0\r\n" +
"s=OAK H264\r\n" +
"c=IN IP4 0.0.0.0\r\n" +
"t=0 0\r\n" +
"m=video 5000 RTP/AVP 96\r\n" +
"a=rtpmap:96 H264/90000\r\n" +
"a=fmtp:96 packetization-mode=1\r\n";
File.WriteAllText(path, stream);
}
_mediaFront?.Dispose(); // limpa antigo, se existir
_mediaFront = new Media(_libVLC, path, FromType.FromPath);
// _mediaFront.AddOption(":network-caching=150"); // se quiser por arquivo
_playerFront.Play(_mediaFront);
VariaveisControleOperacao.EnviarComandoTransmissaoVideo(AgroBase.Models.Enums.T_Code.Snr, true);
}
private void PararStreamCameraFrontal(bool finalizar = false)
{
_playerFront?.Stop();
if (finalizar)
{
_mediaFront?.Dispose();
_mediaFront = null;
_playerFront?.Dispose();
_playerFront = null;
}
VariaveisControleOperacao.EnviarComandoTransmissaoVideo(AgroBase.Models.Enums.T_Code.Snr, false);
}
#endregion
#region CAMERA ERVAS
private void IniciarStreamCameraErvas()
{
var path = @"streams\camera_ervas.sdp";
if (!File.Exists(path))
{
string stream =
"v=0\r\n" +
"o=- 0 0 IN IP4 0.0.0.0\r\n" +
"s=OAK H264\r\n" +
"c=IN IP4 0.0.0.0\r\n" +
"t=0 0\r\n" +
"m=video 5002 RTP/AVP 96\r\n" + // <- porta 5001
"a=rtpmap:96 H264/90000\r\n" +
"a=fmtp:96 packetization-mode=1\r\n";
File.WriteAllText(path, stream);
}
_mediaWeed?.Dispose();
_mediaWeed = new Media(_libVLC, path, FromType.FromPath);
// _mediaWeed.AddOption(":network-caching=150");
_playerWeed.Play(_mediaWeed);
VariaveisControleOperacao.EnviarComandoTransmissaoVideo(AgroBase.Models.Enums.T_Code.Cam, true);
}
private void PararStreamCameraErvas(bool finalizar = false)
{
_playerWeed?.Stop();
if (finalizar)
{
_mediaWeed?.Dispose();
_mediaWeed = null;
_playerWeed?.Dispose();
_playerWeed = null;
}
VariaveisControleOperacao.EnviarComandoTransmissaoVideo(AgroBase.Models.Enums.T_Code.Cam, false);
}
#endregion
#region PULVERIZADOR
@ -282,85 +779,26 @@ namespace OperationControl.Windows
#endregion
#region POSICAO
public void AtualizarDadosTela_GNSS(AgroBase.Models.GPSModel dados, string marker_id = null, double progresso = double.NaN)
{
lblGNSS_Posicao.Foreground = dados.Inicializado ? new SolidColorBrush(System.Windows.Media.Colors.Green) : new SolidColorBrush(System.Windows.Media.Colors.Red);
lblGNSS_Correcao.Content = $"Correção {dados.QualidadeFix} " +
(dados.QualidadeFix == AgroBase.Models.Enums.TiposCorrecaoGPS.BaseFix ?
(dados.OrientacaoReal.ToString("0.00") + "°") :
((dados.Ntrip_ativado ? "N" : "B") + $" {dados.IdadeCorrecao.ToString("0.0")} s"));
lblGNSS_Satelites.Content = $"Satélites {dados.NumeroSatelites} ({dados.PrecisaoCm.ToString("0.00")} cm)";
lblGNSS_Altitude.Content = $"Altitude {dados.Altitude.ToString("0.00")} m";
if (double.IsNaN(progresso))
{
lblGNSS_Progresso.Visibility = Visibility.Hidden;
btnGNSS_FixarBase.Visibility = Visibility.Hidden;
}
else
{
lblGNSS_Progresso.Visibility = Visibility.Visible;
btnGNSS_FixarBase.Visibility = Visibility.Visible;
lblGNSS_Progresso.Content = $"{progresso.ToString("0.00")}%";
if ((Variaveis.GpsService?.BaseFix?.CorrecaoAbsoluta ?? false) && Variaveis.GpsService.BaseFix.FixLiberado && btnGNSS_FixarBase.Content.ToString() == "Parar")
{
Variaveis.GpsService.BaseFix.FixLiberado = false;
btnGNSS_FixarBase.Content = "Fixar";
}
}
if (!string.IsNullOrEmpty(marker_id))
MAP.markers.UpdateMarkerPosition(marker_id, dados.Latitude, dados.Longitude, dados.OrientacaoReal);
}
private void btnGNSS_FixarBase_Click(object sender, RoutedEventArgs e)
{
if (!Variaveis.GpsService.BaseFix.FixLiberado)
{
if (Variaveis.GpsService.BaseFix.CorrecaoAbsoluta)
{
var res = MessageBox.Show("Mudar posição da base?", "Tem certeza que deseja fixar a posição da base novamente?", MessageBoxButton.YesNo, MessageBoxImage.Question);
if (res == MessageBoxResult.Yes)
{
btnGNSS_FixarBase.Content = "Parar";
Variaveis.GpsService.BaseFix.FixLiberado = true;
Task.Run(async () => await Variaveis.GpsService.ConfigurarModulo());
}
}
else
{
btnGNSS_FixarBase.Content = "Parar";
Variaveis.GpsService.BaseFix.FixLiberado = true;
}
}
else
{
btnGNSS_FixarBase.Content = "Fixar";
Variaveis.GpsService.BaseFix.FixLiberado = false;
}
}
#endregion
#region LIDAR
public void AtualizarDadostela_LIDAR(List<AgroBase.Models.LivoxBboxModel> bboxes)
{
BBoxes3D.SetBboxes(bboxes);
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
BBoxes3D.SetBboxes(bboxes);
}
catch (Exception exUi)
{
Variaveis.MostrarLog($"Erro ao atualizar UI Lidar: {exUi.Message}");
}
}));
}
#endregion
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,2 +0,0 @@
from .modeling import *
from ._deeplab import convert_to_separable_conv

View File

@ -1,178 +0,0 @@
import torch
from torch import nn
from torch.nn import functional as F
from .utils import _SimpleSegmentationModel
__all__ = ["DeepLabV3"]
class DeepLabV3(_SimpleSegmentationModel):
"""
Implements DeepLabV3 model from
`"Rethinking Atrous Convolution for Semantic Image Segmentation"
<https://arxiv.org/abs/1706.05587>`_.
Arguments:
backbone (nn.Module): the network used to compute the features for the model.
The backbone should return an OrderedDict[Tensor], with the key being
"out" for the last feature map used, and "aux" if an auxiliary classifier
is used.
classifier (nn.Module): module that takes the "out" element returned from
the backbone and returns a dense prediction.
aux_classifier (nn.Module, optional): auxiliary classifier used during training
"""
pass
class DeepLabHeadV3Plus(nn.Module):
def __init__(self, in_channels, low_level_channels, num_classes, aspp_dilate=[12, 24, 36]):
super(DeepLabHeadV3Plus, self).__init__()
self.project = nn.Sequential(
nn.Conv2d(low_level_channels, 48, 1, bias=False),
nn.BatchNorm2d(48),
nn.ReLU(inplace=True),
)
self.aspp = ASPP(in_channels, aspp_dilate)
self.classifier = nn.Sequential(
nn.Conv2d(304, 256, 3, padding=1, bias=False),
nn.BatchNorm2d(256),
nn.ReLU(inplace=True),
nn.Conv2d(256, num_classes, 1)
)
self._init_weight()
def forward(self, feature):
low_level_feature = self.project( feature['low_level'] )
output_feature = self.aspp(feature['out'])
output_feature = F.interpolate(output_feature, size=low_level_feature.shape[2:], mode='bilinear', align_corners=False)
return self.classifier( torch.cat( [ low_level_feature, output_feature ], dim=1 ) )
def _init_weight(self):
for m in self.modules():
if isinstance(m, nn.Conv2d):
nn.init.kaiming_normal_(m.weight)
elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):
nn.init.constant_(m.weight, 1)
nn.init.constant_(m.bias, 0)
class DeepLabHead(nn.Module):
def __init__(self, in_channels, num_classes, aspp_dilate=[12, 24, 36]):
super(DeepLabHead, self).__init__()
self.classifier = nn.Sequential(
ASPP(in_channels, aspp_dilate),
nn.Conv2d(256, 256, 3, padding=1, bias=False),
nn.BatchNorm2d(256),
nn.ReLU(inplace=True),
nn.Conv2d(256, num_classes, 1)
)
self._init_weight()
def forward(self, feature):
return self.classifier( feature['out'] )
def _init_weight(self):
for m in self.modules():
if isinstance(m, nn.Conv2d):
nn.init.kaiming_normal_(m.weight)
elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):
nn.init.constant_(m.weight, 1)
nn.init.constant_(m.bias, 0)
class AtrousSeparableConvolution(nn.Module):
""" Atrous Separable Convolution
"""
def __init__(self, in_channels, out_channels, kernel_size,
stride=1, padding=0, dilation=1, bias=True):
super(AtrousSeparableConvolution, self).__init__()
self.body = nn.Sequential(
# Separable Conv
nn.Conv2d( in_channels, in_channels, kernel_size=kernel_size, stride=stride, padding=padding, dilation=dilation, bias=bias, groups=in_channels ),
# PointWise Conv
nn.Conv2d( in_channels, out_channels, kernel_size=1, stride=1, padding=0, bias=bias),
)
self._init_weight()
def forward(self, x):
return self.body(x)
def _init_weight(self):
for m in self.modules():
if isinstance(m, nn.Conv2d):
nn.init.kaiming_normal_(m.weight)
elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):
nn.init.constant_(m.weight, 1)
nn.init.constant_(m.bias, 0)
class ASPPConv(nn.Sequential):
def __init__(self, in_channels, out_channels, dilation):
modules = [
nn.Conv2d(in_channels, out_channels, 3, padding=dilation, dilation=dilation, bias=False),
nn.BatchNorm2d(out_channels),
nn.ReLU(inplace=True)
]
super(ASPPConv, self).__init__(*modules)
class ASPPPooling(nn.Sequential):
def __init__(self, in_channels, out_channels):
super(ASPPPooling, self).__init__(
nn.AdaptiveAvgPool2d(1),
nn.Conv2d(in_channels, out_channels, 1, bias=False),
nn.BatchNorm2d(out_channels),
nn.ReLU(inplace=True))
def forward(self, x):
size = x.shape[-2:]
x = super(ASPPPooling, self).forward(x)
return F.interpolate(x, size=size, mode='bilinear', align_corners=False)
class ASPP(nn.Module):
def __init__(self, in_channels, atrous_rates):
super(ASPP, self).__init__()
out_channels = 256
modules = []
modules.append(nn.Sequential(
nn.Conv2d(in_channels, out_channels, 1, bias=False),
nn.BatchNorm2d(out_channels),
nn.ReLU(inplace=True)))
rate1, rate2, rate3 = tuple(atrous_rates)
modules.append(ASPPConv(in_channels, out_channels, rate1))
modules.append(ASPPConv(in_channels, out_channels, rate2))
modules.append(ASPPConv(in_channels, out_channels, rate3))
modules.append(ASPPPooling(in_channels, out_channels))
self.convs = nn.ModuleList(modules)
self.project = nn.Sequential(
nn.Conv2d(5 * out_channels, out_channels, 1, bias=False),
nn.BatchNorm2d(out_channels),
nn.ReLU(inplace=True),
nn.Dropout(0.1),)
def forward(self, x):
res = []
for conv in self.convs:
res.append(conv(x))
res = torch.cat(res, dim=1)
return self.project(res)
def convert_to_separable_conv(module):
new_module = module
if isinstance(module, nn.Conv2d) and module.kernel_size[0]>1:
new_module = AtrousSeparableConvolution(module.in_channels,
module.out_channels,
module.kernel_size,
module.stride,
module.padding,
module.dilation,
module.bias)
for name, child in module.named_children():
new_module.add_module(name, convert_to_separable_conv(child))
return new_module

View File

@ -1,4 +0,0 @@
from . import resnet
from . import mobilenetv2
from . import hrnetv2
from . import xception

View File

@ -1,345 +0,0 @@
import torch
from torch import nn
import torch.nn.functional as F
import os
__all__ = ['HRNet', 'hrnetv2_48', 'hrnetv2_32']
# Checkpoint path of pre-trained backbone (edit to your path). Download backbone pretrained model hrnetv2-32 @
# https://drive.google.com/file/d/1NxCK7Zgn5PmeS7W1jYLt5J9E0RRZ2oyF/view?usp=sharing .Personally, I added the backbone
# weights to the folder /checkpoints
model_urls = {
'hrnetv2_32': './checkpoints/model_best_epoch96_edit.pth',
'hrnetv2_48': None
}
def check_pth(arch):
CKPT_PATH = model_urls[arch]
if os.path.exists(CKPT_PATH):
print(f"Backbone HRNet Pretrained weights at: {CKPT_PATH}, only usable for HRNetv2-32")
else:
print("No backbone checkpoint found for HRNetv2, please set pretrained=False when calling model")
return CKPT_PATH
# HRNetv2-48 not available yet, but you can train the whole model from scratch.
class Bottleneck(nn.Module):
expansion = 4
def __init__(self, inplanes, planes, stride=1, downsample=None):
super(Bottleneck, self).__init__()
self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False)
self.bn1 = nn.BatchNorm2d(planes)
self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
self.bn2 = nn.BatchNorm2d(planes)
self.conv3 = nn.Conv2d(planes, planes * self.expansion, kernel_size=1, bias=False)
self.bn3 = nn.BatchNorm2d(planes * self.expansion)
self.relu = nn.ReLU(inplace=True)
self.downsample = downsample
def forward(self, x):
identity = x
out = self.conv1(x)
out = self.bn1(out)
out = self.relu(out)
out = self.conv2(out)
out = self.bn2(out)
out = self.relu(out)
out = self.conv3(out)
out = self.bn3(out)
if self.downsample is not None:
identity = self.downsample(x)
out += identity
out = self.relu(out)
return out
class BasicBlock(nn.Module):
expansion = 1
def __init__(self, inplanes, planes, stride=1, downsample=None):
super(BasicBlock, self).__init__()
self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
self.bn1 = nn.BatchNorm2d(planes)
self.relu = nn.ReLU(inplace=True)
self.conv2 = nn.Conv2d(inplanes, planes, kernel_size=3, stride=1, padding=1, bias=False)
self.bn2 = nn.BatchNorm2d(planes)
self.downsample = downsample
def forward(self, x):
identity = x
out = self.conv1(x)
out = self.bn1(out)
out = self.relu(out)
out = self.conv2(out)
out = self.bn2(out)
if self.downsample is not None:
identity = self.downsample(x)
out += identity
out = self.relu(out)
return out
class StageModule(nn.Module):
def __init__(self, stage, output_branches, c):
super(StageModule, self).__init__()
self.number_of_branches = stage # number of branches is equivalent to the stage configuration.
self.output_branches = output_branches
self.branches = nn.ModuleList()
# Note: Resolution + Number of channels maintains the same throughout respective branch.
for i in range(self.number_of_branches): # Stage scales with the number of branches. Ex: Stage 2 -> 2 branch
channels = c * (2 ** i) # Scale channels by 2x for branch with lower resolution,
# Paper does x4 basic block for each forward sequence in each branch (x4 basic block considered as a block)
branch = nn.Sequential(*[BasicBlock(channels, channels) for _ in range(4)])
self.branches.append(branch) # list containing all forward sequence of individual branches.
# For each branch requires repeated fusion with all other branches after passing through x4 basic blocks.
self.fuse_layers = nn.ModuleList()
for branch_output_number in range(self.output_branches):
self.fuse_layers.append(nn.ModuleList())
for branch_number in range(self.number_of_branches):
if branch_number == branch_output_number:
self.fuse_layers[-1].append(nn.Sequential()) # Used in place of "None" because it is callable
elif branch_number > branch_output_number:
self.fuse_layers[-1].append(nn.Sequential(
nn.Conv2d(c * (2 ** branch_number), c * (2 ** branch_output_number), kernel_size=1, stride=1,
bias=False),
nn.BatchNorm2d(c * (2 ** branch_output_number), eps=1e-05, momentum=0.1, affine=True,
track_running_stats=True),
nn.Upsample(scale_factor=(2.0 ** (branch_number - branch_output_number)), mode='nearest'),
))
elif branch_number < branch_output_number:
downsampling_fusion = []
for _ in range(branch_output_number - branch_number - 1):
downsampling_fusion.append(nn.Sequential(
nn.Conv2d(c * (2 ** branch_number), c * (2 ** branch_number), kernel_size=3, stride=2,
padding=1,
bias=False),
nn.BatchNorm2d(c * (2 ** branch_number), eps=1e-05, momentum=0.1, affine=True,
track_running_stats=True),
nn.ReLU(inplace=True),
))
downsampling_fusion.append(nn.Sequential(
nn.Conv2d(c * (2 ** branch_number), c * (2 ** branch_output_number), kernel_size=3,
stride=2, padding=1,
bias=False),
nn.BatchNorm2d(c * (2 ** branch_output_number), eps=1e-05, momentum=0.1, affine=True,
track_running_stats=True),
))
self.fuse_layers[-1].append(nn.Sequential(*downsampling_fusion))
self.relu = nn.ReLU(inplace=True)
def forward(self, x):
# input to each stage is a list of inputs for each branch
x = [branch(branch_input) for branch, branch_input in zip(self.branches, x)]
x_fused = []
for branch_output_index in range(
self.output_branches): # Amount of output branches == total length of fusion layers
for input_index in range(self.number_of_branches): # The inputs of other branches to be fused.
if input_index == 0:
x_fused.append(self.fuse_layers[branch_output_index][input_index](x[input_index]))
else:
x_fused[branch_output_index] = x_fused[branch_output_index] + self.fuse_layers[branch_output_index][
input_index](x[input_index])
# After fusing all streams together, you will need to pass the fused layers
for i in range(self.output_branches):
x_fused[i] = self.relu(x_fused[i])
return x_fused # returning a list of fused outputs
class HRNet(nn.Module):
def __init__(self, c=48, num_blocks=[1, 4, 3], num_classes=1000):
super(HRNet, self).__init__()
# Stem:
self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=2, padding=1, bias=False)
self.bn1 = nn.BatchNorm2d(64, eps=1e-05, affine=True, track_running_stats=True)
self.conv2 = nn.Conv2d(64, 64, kernel_size=3, stride=2, padding=1, bias=False)
self.bn2 = nn.BatchNorm2d(64, eps=1e-05, affine=True, track_running_stats=True)
self.relu = nn.ReLU(inplace=True)
# Stage 1:
downsample = nn.Sequential(
nn.Conv2d(64, 256, kernel_size=1, stride=1, bias=False),
nn.BatchNorm2d(256, eps=1e-05, affine=True, track_running_stats=True),
)
# Note that bottleneck module will expand the output channels according to the output channels*block.expansion
bn_expansion = Bottleneck.expansion # The channel expansion is set in the bottleneck class.
self.layer1 = nn.Sequential(
Bottleneck(64, 64, downsample=downsample), # Input is 64 for first module connection
Bottleneck(bn_expansion * 64, 64),
Bottleneck(bn_expansion * 64, 64),
Bottleneck(bn_expansion * 64, 64),
)
# Transition 1 - Creation of the first two branches (one full and one half resolution)
# Need to transition into high resolution stream and mid resolution stream
self.transition1 = nn.ModuleList([
nn.Sequential(
nn.Conv2d(256, c, kernel_size=3, stride=1, padding=1, bias=False),
nn.BatchNorm2d(c, eps=1e-05, affine=True, track_running_stats=True),
nn.ReLU(inplace=True),
),
nn.Sequential(nn.Sequential( # Double Sequential to fit with official pretrained weights
nn.Conv2d(256, c * 2, kernel_size=3, stride=2, padding=1, bias=False),
nn.BatchNorm2d(c * 2, eps=1e-05, affine=True, track_running_stats=True),
nn.ReLU(inplace=True),
)),
])
# Stage 2:
number_blocks_stage2 = num_blocks[0]
self.stage2 = nn.Sequential(
*[StageModule(stage=2, output_branches=2, c=c) for _ in range(number_blocks_stage2)])
# Transition 2 - Creation of the third branch (1/4 resolution)
self.transition2 = self._make_transition_layers(c, transition_number=2)
# Stage 3:
number_blocks_stage3 = num_blocks[1] # number blocks you want to create before fusion
self.stage3 = nn.Sequential(
*[StageModule(stage=3, output_branches=3, c=c) for _ in range(number_blocks_stage3)])
# Transition - Creation of the fourth branch (1/8 resolution)
self.transition3 = self._make_transition_layers(c, transition_number=3)
# Stage 4:
number_blocks_stage4 = num_blocks[2] # number blocks you want to create before fusion
self.stage4 = nn.Sequential(
*[StageModule(stage=4, output_branches=4, c=c) for _ in range(number_blocks_stage4)])
# Classifier (extra module if want to use for classification):
# pool, reduce dimensionality, flatten, connect to linear layer for classification:
out_channels = sum([c * 2 ** i for i in range(len(num_blocks)+1)]) # total output channels of HRNetV2
pool_feature_map = 8
self.bn_classifier = nn.Sequential(
nn.Conv2d(out_channels, out_channels // 4, kernel_size=1, bias=False),
nn.BatchNorm2d(out_channels // 4, eps=1e-05, affine=True, track_running_stats=True),
nn.ReLU(inplace=True),
nn.AdaptiveAvgPool2d(pool_feature_map),
nn.Flatten(),
nn.Linear(pool_feature_map * pool_feature_map * (out_channels // 4), num_classes),
)
@staticmethod
def _make_transition_layers(c, transition_number):
return nn.Sequential(
nn.Conv2d(c * (2 ** (transition_number - 1)), c * (2 ** transition_number), kernel_size=3, stride=2,
padding=1, bias=False),
nn.BatchNorm2d(c * (2 ** transition_number), eps=1e-05, affine=True,
track_running_stats=True),
nn.ReLU(inplace=True),
)
def forward(self, x):
# Stem:
x = self.conv1(x)
x = self.bn1(x)
x = self.relu(x)
x = self.conv2(x)
x = self.bn2(x)
x = self.relu(x)
# Stage 1
x = self.layer1(x)
x = [trans(x) for trans in self.transition1] # split to 2 branches, form a list.
# Stage 2
x = self.stage2(x)
x.append(self.transition2(x[-1]))
# Stage 3
x = self.stage3(x)
x.append(self.transition3(x[-1]))
# Stage 4
x = self.stage4(x)
# HRNetV2 Example: (follow paper, upsample via bilinear interpolation and to highest resolution size)
output_h, output_w = x[0].size(2), x[0].size(3) # Upsample to size of highest resolution stream
x1 = F.interpolate(x[1], size=(output_h, output_w), mode='bilinear', align_corners=False)
x2 = F.interpolate(x[2], size=(output_h, output_w), mode='bilinear', align_corners=False)
x3 = F.interpolate(x[3], size=(output_h, output_w), mode='bilinear', align_corners=False)
# Upsampling all the other resolution streams and then concatenate all (rather than adding/fusing like HRNetV1)
x = torch.cat([x[0], x1, x2, x3], dim=1)
x = self.bn_classifier(x)
return x
def _hrnet(arch, channels, num_blocks, pretrained, progress, **kwargs):
model = HRNet(channels, num_blocks, **kwargs)
if pretrained:
CKPT_PATH = check_pth(arch)
checkpoint = torch.load(CKPT_PATH)
model.load_state_dict(checkpoint['state_dict'])
return model
def hrnetv2_48(pretrained=False, progress=True, number_blocks=[1, 4, 3], **kwargs):
w_channels = 48
return _hrnet('hrnetv2_48', w_channels, number_blocks, pretrained, progress,
**kwargs)
def hrnetv2_32(pretrained=False, progress=True, number_blocks=[1, 4, 3], **kwargs):
w_channels = 32
return _hrnet('hrnetv2_32', w_channels, number_blocks, pretrained, progress,
**kwargs)
if __name__ == '__main__':
try:
CKPT_PATH = os.path.join(os.path.abspath("."), '../../checkpoints/hrnetv2_32_model_best_epoch96.pth')
print("--- Running file as MAIN ---")
print(f"Backbone HRNET Pretrained weights as __main__ at: {CKPT_PATH}")
except:
print("No backbone checkpoint found for HRNetv2, please set pretrained=False when calling model")
# Models
model = hrnetv2_32(pretrained=True)
#model = hrnetv2_48(pretrained=False)
if torch.cuda.is_available():
torch.backends.cudnn.deterministic = True
device = torch.device('cuda')
else:
device = torch.device('cpu')
model.to(device)
in_ = torch.ones(1, 3, 768, 768).to(device)
y = model(in_)
print(y.shape)
# Calculate total number of parameters:
# pytorch_total_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
# print(pytorch_total_params)

View File

@ -1,190 +0,0 @@
from torch import nn
try: # for torchvision<0.4
from torchvision.models.utils import load_state_dict_from_url
except: # for torchvision>=0.4
from torch.hub import load_state_dict_from_url
import torch.nn.functional as F
__all__ = ['MobileNetV2', 'mobilenet_v2']
model_urls = {
'mobilenet_v2': 'https://download.pytorch.org/models/mobilenet_v2-b0353104.pth',
}
def _make_divisible(v, divisor, min_value=None):
"""
This function is taken from the original tf repo.
It ensures that all layers have a channel number that is divisible by 8
It can be seen here:
https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet/mobilenet.py
:param v:
:param divisor:
:param min_value:
:return:
"""
if min_value is None:
min_value = divisor
new_v = max(min_value, int(v + divisor / 2) // divisor * divisor)
# Make sure that round down does not go down by more than 10%.
if new_v < 0.9 * v:
new_v += divisor
return new_v
class ConvBNReLU(nn.Sequential):
def __init__(self, in_planes, out_planes, kernel_size=3, stride=1, dilation=1, groups=1):
#padding = (kernel_size - 1) // 2
super(ConvBNReLU, self).__init__(
nn.Conv2d(in_planes, out_planes, kernel_size, stride, 0, dilation=dilation, groups=groups, bias=False),
nn.BatchNorm2d(out_planes),
nn.ReLU6(inplace=True)
)
def fixed_padding(kernel_size, dilation):
kernel_size_effective = kernel_size + (kernel_size - 1) * (dilation - 1)
pad_total = kernel_size_effective - 1
pad_beg = pad_total // 2
pad_end = pad_total - pad_beg
return (pad_beg, pad_end, pad_beg, pad_end)
class InvertedResidual(nn.Module):
def __init__(self, inp, oup, stride, dilation, expand_ratio):
super(InvertedResidual, self).__init__()
self.stride = stride
assert stride in [1, 2]
hidden_dim = int(round(inp * expand_ratio))
self.use_res_connect = self.stride == 1 and inp == oup
layers = []
if expand_ratio != 1:
# pw
layers.append(ConvBNReLU(inp, hidden_dim, kernel_size=1))
layers.extend([
# dw
ConvBNReLU(hidden_dim, hidden_dim, stride=stride, dilation=dilation, groups=hidden_dim),
# pw-linear
nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False),
nn.BatchNorm2d(oup),
])
self.conv = nn.Sequential(*layers)
self.input_padding = fixed_padding( 3, dilation )
def forward(self, x):
x_pad = F.pad(x, self.input_padding)
if self.use_res_connect:
return x + self.conv(x_pad)
else:
return self.conv(x_pad)
class MobileNetV2(nn.Module):
def __init__(self, num_classes=1000, output_stride=8, width_mult=1.0, inverted_residual_setting=None, round_nearest=8):
"""
MobileNet V2 main class
Args:
num_classes (int): Number of classes
width_mult (float): Width multiplier - adjusts number of channels in each layer by this amount
inverted_residual_setting: Network structure
round_nearest (int): Round the number of channels in each layer to be a multiple of this number
Set to 1 to turn off rounding
"""
super(MobileNetV2, self).__init__()
block = InvertedResidual
input_channel = 32
last_channel = 1280
self.output_stride = output_stride
current_stride = 1
if inverted_residual_setting is None:
inverted_residual_setting = [
# t, c, n, s
[1, 16, 1, 1],
[6, 24, 2, 2],
[6, 32, 3, 2],
[6, 64, 4, 2],
[6, 96, 3, 1],
[6, 160, 3, 2],
[6, 320, 1, 1],
]
# only check the first element, assuming user knows t,c,n,s are required
if len(inverted_residual_setting) == 0 or len(inverted_residual_setting[0]) != 4:
raise ValueError("inverted_residual_setting should be non-empty "
"or a 4-element list, got {}".format(inverted_residual_setting))
# building first layer
input_channel = _make_divisible(input_channel * width_mult, round_nearest)
self.last_channel = _make_divisible(last_channel * max(1.0, width_mult), round_nearest)
features = [ConvBNReLU(3, input_channel, stride=2)]
current_stride *= 2
dilation=1
previous_dilation = 1
# building inverted residual blocks
for t, c, n, s in inverted_residual_setting:
output_channel = _make_divisible(c * width_mult, round_nearest)
previous_dilation = dilation
if current_stride == output_stride:
stride = 1
dilation *= s
else:
stride = s
current_stride *= s
output_channel = int(c * width_mult)
for i in range(n):
if i==0:
features.append(block(input_channel, output_channel, stride, previous_dilation, expand_ratio=t))
else:
features.append(block(input_channel, output_channel, 1, dilation, expand_ratio=t))
input_channel = output_channel
# building last several layers
features.append(ConvBNReLU(input_channel, self.last_channel, kernel_size=1))
# make it nn.Sequential
self.features = nn.Sequential(*features)
# building classifier
self.classifier = nn.Sequential(
nn.Dropout(0.2),
nn.Linear(self.last_channel, num_classes),
)
# weight initialization
for m in self.modules():
if isinstance(m, nn.Conv2d):
nn.init.kaiming_normal_(m.weight, mode='fan_out')
if m.bias is not None:
nn.init.zeros_(m.bias)
elif isinstance(m, nn.BatchNorm2d):
nn.init.ones_(m.weight)
nn.init.zeros_(m.bias)
elif isinstance(m, nn.Linear):
nn.init.normal_(m.weight, 0, 0.01)
nn.init.zeros_(m.bias)
def forward(self, x):
x = self.features(x)
x = x.mean([2, 3])
x = self.classifier(x)
return x
def mobilenet_v2(pretrained=False, progress=True, **kwargs):
"""
Constructs a MobileNetV2 architecture from
`"MobileNetV2: Inverted Residuals and Linear Bottlenecks" <https://arxiv.org/abs/1801.04381>`_.
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
model = MobileNetV2(**kwargs)
if pretrained:
state_dict = load_state_dict_from_url(model_urls['mobilenet_v2'],
progress=progress)
model.load_state_dict(state_dict)
return model

View File

@ -1,346 +0,0 @@
import torch
import torch.nn as nn
try: # for torchvision<0.4
from torchvision.models.utils import load_state_dict_from_url
except: # for torchvision>=0.4
from torch.hub import load_state_dict_from_url
__all__ = ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101',
'resnet152', 'resnext50_32x4d', 'resnext101_32x8d',
'wide_resnet50_2', 'wide_resnet101_2']
model_urls = {
'resnet18': 'https://download.pytorch.org/models/resnet18-5c106cde.pth',
'resnet34': 'https://download.pytorch.org/models/resnet34-333f7ec4.pth',
'resnet50': 'https://download.pytorch.org/models/resnet50-19c8e357.pth',
'resnet101': 'https://download.pytorch.org/models/resnet101-5d3b4d8f.pth',
'resnet152': 'https://download.pytorch.org/models/resnet152-b121ed2d.pth',
'resnext50_32x4d': 'https://download.pytorch.org/models/resnext50_32x4d-7cdf4587.pth',
'resnext101_32x8d': 'https://download.pytorch.org/models/resnext101_32x8d-8ba56ff5.pth',
'wide_resnet50_2': 'https://download.pytorch.org/models/wide_resnet50_2-95faca4d.pth',
'wide_resnet101_2': 'https://download.pytorch.org/models/wide_resnet101_2-32ee1156.pth',
}
def conv3x3(in_planes, out_planes, stride=1, groups=1, dilation=1):
"""3x3 convolution with padding"""
return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,
padding=dilation, groups=groups, bias=False, dilation=dilation)
def conv1x1(in_planes, out_planes, stride=1):
"""1x1 convolution"""
return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False)
class BasicBlock(nn.Module):
expansion = 1
def __init__(self, inplanes, planes, stride=1, downsample=None, groups=1,
base_width=64, dilation=1, norm_layer=None):
super(BasicBlock, self).__init__()
if norm_layer is None:
norm_layer = nn.BatchNorm2d
if groups != 1 or base_width != 64:
raise ValueError('BasicBlock only supports groups=1 and base_width=64')
if dilation > 1:
raise NotImplementedError("Dilation > 1 not supported in BasicBlock")
# Both self.conv1 and self.downsample layers downsample the input when stride != 1
self.conv1 = conv3x3(inplanes, planes, stride)
self.bn1 = norm_layer(planes)
self.relu = nn.ReLU(inplace=True)
self.conv2 = conv3x3(planes, planes)
self.bn2 = norm_layer(planes)
self.downsample = downsample
self.stride = stride
def forward(self, x):
identity = x
out = self.conv1(x)
out = self.bn1(out)
out = self.relu(out)
out = self.conv2(out)
out = self.bn2(out)
if self.downsample is not None:
identity = self.downsample(x)
out += identity
out = self.relu(out)
return out
class Bottleneck(nn.Module):
expansion = 4
def __init__(self, inplanes, planes, stride=1, downsample=None, groups=1,
base_width=64, dilation=1, norm_layer=None):
super(Bottleneck, self).__init__()
if norm_layer is None:
norm_layer = nn.BatchNorm2d
width = int(planes * (base_width / 64.)) * groups
# Both self.conv2 and self.downsample layers downsample the input when stride != 1
self.conv1 = conv1x1(inplanes, width)
self.bn1 = norm_layer(width)
self.conv2 = conv3x3(width, width, stride, groups, dilation)
self.bn2 = norm_layer(width)
self.conv3 = conv1x1(width, planes * self.expansion)
self.bn3 = norm_layer(planes * self.expansion)
self.relu = nn.ReLU(inplace=True)
self.downsample = downsample
self.stride = stride
def forward(self, x):
identity = x
out = self.conv1(x)
out = self.bn1(out)
out = self.relu(out)
out = self.conv2(out)
out = self.bn2(out)
out = self.relu(out)
out = self.conv3(out)
out = self.bn3(out)
if self.downsample is not None:
identity = self.downsample(x)
out += identity
out = self.relu(out)
return out
class ResNet(nn.Module):
def __init__(self, block, layers, num_classes=1000, zero_init_residual=False,
groups=1, width_per_group=64, replace_stride_with_dilation=None,
norm_layer=None):
super(ResNet, self).__init__()
if norm_layer is None:
norm_layer = nn.BatchNorm2d
self._norm_layer = norm_layer
self.inplanes = 64
self.dilation = 1
if replace_stride_with_dilation is None:
# each element in the tuple indicates if we should replace
# the 2x2 stride with a dilated convolution instead
replace_stride_with_dilation = [False, False, False]
if len(replace_stride_with_dilation) != 3:
raise ValueError("replace_stride_with_dilation should be None "
"or a 3-element tuple, got {}".format(replace_stride_with_dilation))
self.groups = groups
self.base_width = width_per_group
self.conv1 = nn.Conv2d(3, self.inplanes, kernel_size=7, stride=2, padding=3,
bias=False)
self.bn1 = norm_layer(self.inplanes)
self.relu = nn.ReLU(inplace=True)
self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
self.layer1 = self._make_layer(block, 64, layers[0])
self.layer2 = self._make_layer(block, 128, layers[1], stride=2,
dilate=replace_stride_with_dilation[0])
self.layer3 = self._make_layer(block, 256, layers[2], stride=2,
dilate=replace_stride_with_dilation[1])
self.layer4 = self._make_layer(block, 512, layers[3], stride=2,
dilate=replace_stride_with_dilation[2])
self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
self.fc = nn.Linear(512 * block.expansion, num_classes)
for m in self.modules():
if isinstance(m, nn.Conv2d):
nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):
nn.init.constant_(m.weight, 1)
nn.init.constant_(m.bias, 0)
# Zero-initialize the last BN in each residual branch,
# so that the residual branch starts with zeros, and each residual block behaves like an identity.
# This improves the model by 0.2~0.3% according to https://arxiv.org/abs/1706.02677
if zero_init_residual:
for m in self.modules():
if isinstance(m, Bottleneck):
nn.init.constant_(m.bn3.weight, 0)
elif isinstance(m, BasicBlock):
nn.init.constant_(m.bn2.weight, 0)
def _make_layer(self, block, planes, blocks, stride=1, dilate=False):
norm_layer = self._norm_layer
downsample = None
previous_dilation = self.dilation
if dilate:
self.dilation *= stride
stride = 1
if stride != 1 or self.inplanes != planes * block.expansion:
downsample = nn.Sequential(
conv1x1(self.inplanes, planes * block.expansion, stride),
norm_layer(planes * block.expansion),
)
layers = []
layers.append(block(self.inplanes, planes, stride, downsample, self.groups,
self.base_width, previous_dilation, norm_layer))
self.inplanes = planes * block.expansion
for _ in range(1, blocks):
layers.append(block(self.inplanes, planes, groups=self.groups,
base_width=self.base_width, dilation=self.dilation,
norm_layer=norm_layer))
return nn.Sequential(*layers)
def forward(self, x):
x = self.conv1(x)
x = self.bn1(x)
x = self.relu(x)
x = self.maxpool(x)
x = self.layer1(x)
x = self.layer2(x)
x = self.layer3(x)
x = self.layer4(x)
x = self.avgpool(x)
x = torch.flatten(x, 1)
x = self.fc(x)
return x
def _resnet(arch, block, layers, pretrained, progress, **kwargs):
model = ResNet(block, layers, **kwargs)
if pretrained:
state_dict = load_state_dict_from_url(model_urls[arch],
progress=progress)
model.load_state_dict(state_dict)
return model
def resnet18(pretrained=False, progress=True, **kwargs):
r"""ResNet-18 model from
`"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
return _resnet('resnet18', BasicBlock, [2, 2, 2, 2], pretrained, progress,
**kwargs)
def resnet34(pretrained=False, progress=True, **kwargs):
r"""ResNet-34 model from
`"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
return _resnet('resnet34', BasicBlock, [3, 4, 6, 3], pretrained, progress,
**kwargs)
def resnet50(pretrained=False, progress=True, **kwargs):
r"""ResNet-50 model from
`"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
return _resnet('resnet50', Bottleneck, [3, 4, 6, 3], pretrained, progress,
**kwargs)
def resnet101(pretrained=False, progress=True, **kwargs):
r"""ResNet-101 model from
`"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
return _resnet('resnet101', Bottleneck, [3, 4, 23, 3], pretrained, progress,
**kwargs)
def resnet152(pretrained=False, progress=True, **kwargs):
r"""ResNet-152 model from
`"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
return _resnet('resnet152', Bottleneck, [3, 8, 36, 3], pretrained, progress,
**kwargs)
def resnext50_32x4d(pretrained=False, progress=True, **kwargs):
r"""ResNeXt-50 32x4d model from
`"Aggregated Residual Transformation for Deep Neural Networks" <https://arxiv.org/pdf/1611.05431.pdf>`_
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
kwargs['groups'] = 32
kwargs['width_per_group'] = 4
return _resnet('resnext50_32x4d', Bottleneck, [3, 4, 6, 3],
pretrained, progress, **kwargs)
def resnext101_32x8d(pretrained=False, progress=True, **kwargs):
r"""ResNeXt-101 32x8d model from
`"Aggregated Residual Transformation for Deep Neural Networks" <https://arxiv.org/pdf/1611.05431.pdf>`_
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
kwargs['groups'] = 32
kwargs['width_per_group'] = 8
return _resnet('resnext101_32x8d', Bottleneck, [3, 4, 23, 3],
pretrained, progress, **kwargs)
def wide_resnet50_2(pretrained=False, progress=True, **kwargs):
r"""Wide ResNet-50-2 model from
`"Wide Residual Networks" <https://arxiv.org/pdf/1605.07146.pdf>`_
The model is the same as ResNet except for the bottleneck number of channels
which is twice larger in every block. The number of channels in outer 1x1
convolutions is the same, e.g. last block in ResNet-50 has 2048-512-2048
channels, and in Wide ResNet-50-2 has 2048-1024-2048.
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
kwargs['width_per_group'] = 64 * 2
return _resnet('wide_resnet50_2', Bottleneck, [3, 4, 6, 3],
pretrained, progress, **kwargs)
def wide_resnet101_2(pretrained=False, progress=True, **kwargs):
r"""Wide ResNet-101-2 model from
`"Wide Residual Networks" <https://arxiv.org/pdf/1605.07146.pdf>`_
The model is the same as ResNet except for the bottleneck number of channels
which is twice larger in every block. The number of channels in outer 1x1
convolutions is the same, e.g. last block in ResNet-50 has 2048-512-2048
channels, and in Wide ResNet-50-2 has 2048-1024-2048.
Args:
pretrained (bool): If True, returns a model pre-trained on ImageNet
progress (bool): If True, displays a progress bar of the download to stderr
"""
kwargs['width_per_group'] = 64 * 2
return _resnet('wide_resnet101_2', Bottleneck, [3, 4, 23, 3],
pretrained, progress, **kwargs)

View File

@ -1,238 +0,0 @@
"""
Xception is adapted from https://github.com/Cadene/pretrained-models.pytorch/blob/master/pretrainedmodels/models/xception.py
Ported to pytorch thanks to [tstandley](https://github.com/tstandley/Xception-PyTorch)
@author: tstandley
Adapted by cadene
Creates an Xception Model as defined in:
Francois Chollet
Xception: Deep Learning with Depthwise Separable Convolutions
https://arxiv.org/pdf/1610.02357.pdf
This weights ported from the Keras implementation. Achieves the following performance on the validation set:
Loss:0.9173 Prec@1:78.892 Prec@5:94.292
REMEMBER to set your image size to 3x299x299 for both test and validation
normalize = transforms.Normalize(mean=[0.5, 0.5, 0.5],
std=[0.5, 0.5, 0.5])
The resize parameter of the validation transform should be 333, and make sure to center crop at 299x299
"""
from __future__ import print_function, division, absolute_import
import math
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.utils.model_zoo as model_zoo
from torch.nn import init
__all__ = ['xception']
pretrained_settings = {
'xception': {
'imagenet': {
'url': 'http://data.lip6.fr/cadene/pretrainedmodels/xception-43020ad28.pth',
'input_space': 'RGB',
'input_size': [3, 299, 299],
'input_range': [0, 1],
'mean': [0.5, 0.5, 0.5],
'std': [0.5, 0.5, 0.5],
'num_classes': 1000,
'scale': 0.8975 # The resize parameter of the validation transform should be 333, and make sure to center crop at 299x299
}
}
}
class SeparableConv2d(nn.Module):
def __init__(self,in_channels,out_channels,kernel_size=1,stride=1,padding=0,dilation=1,bias=False):
super(SeparableConv2d,self).__init__()
self.conv1 = nn.Conv2d(in_channels,in_channels,kernel_size,stride,padding,dilation,groups=in_channels,bias=bias)
self.pointwise = nn.Conv2d(in_channels,out_channels,1,1,0,1,1,bias=bias)
def forward(self,x):
x = self.conv1(x)
x = self.pointwise(x)
return x
class Block(nn.Module):
def __init__(self,in_filters,out_filters,reps,strides=1,start_with_relu=True,grow_first=True, dilation=1):
super(Block, self).__init__()
if out_filters != in_filters or strides!=1:
self.skip = nn.Conv2d(in_filters,out_filters,1,stride=strides, bias=False)
self.skipbn = nn.BatchNorm2d(out_filters)
else:
self.skip=None
rep=[]
filters=in_filters
if grow_first:
rep.append(nn.ReLU(inplace=True))
rep.append(SeparableConv2d(in_filters,out_filters,3,stride=1,padding=dilation, dilation=dilation, bias=False))
rep.append(nn.BatchNorm2d(out_filters))
filters = out_filters
for i in range(reps-1):
rep.append(nn.ReLU(inplace=True))
rep.append(SeparableConv2d(filters,filters,3,stride=1,padding=dilation,dilation=dilation,bias=False))
rep.append(nn.BatchNorm2d(filters))
if not grow_first:
rep.append(nn.ReLU(inplace=True))
rep.append(SeparableConv2d(in_filters,out_filters,3,stride=1,padding=dilation,dilation=dilation,bias=False))
rep.append(nn.BatchNorm2d(out_filters))
if not start_with_relu:
rep = rep[1:]
else:
rep[0] = nn.ReLU(inplace=False)
if strides != 1:
rep.append(nn.MaxPool2d(3,strides,1))
self.rep = nn.Sequential(*rep)
def forward(self,inp):
x = self.rep(inp)
if self.skip is not None:
skip = self.skip(inp)
skip = self.skipbn(skip)
else:
skip = inp
x+=skip
return x
class Xception(nn.Module):
"""
Xception optimized for the ImageNet dataset, as specified in
https://arxiv.org/pdf/1610.02357.pdf
"""
def __init__(self, num_classes=1000, replace_stride_with_dilation=None):
""" Constructor
Args:
num_classes: number of classes
"""
super(Xception, self).__init__()
self.num_classes = num_classes
self.dilation = 1
if replace_stride_with_dilation is None:
# each element in the tuple indicates if we should replace
# the 2x2 stride with a dilated convolution instead
replace_stride_with_dilation = [False, False, False, False]
if len(replace_stride_with_dilation) != 4:
raise ValueError("replace_stride_with_dilation should be None "
"or a 4-element tuple, got {}".format(replace_stride_with_dilation))
self.conv1 = nn.Conv2d(3, 32, 3,2, 0, bias=False) # 1 / 2
self.bn1 = nn.BatchNorm2d(32)
self.relu1 = nn.ReLU(inplace=True)
self.conv2 = nn.Conv2d(32,64,3,bias=False)
self.bn2 = nn.BatchNorm2d(64)
self.relu2 = nn.ReLU(inplace=True)
#do relu here
self.block1=self._make_block(64,128,2,2,start_with_relu=False,grow_first=True, dilate=replace_stride_with_dilation[0]) # 1 / 4
self.block2=self._make_block(128,256,2,2,start_with_relu=True,grow_first=True, dilate=replace_stride_with_dilation[1]) # 1 / 8
self.block3=self._make_block(256,728,2,2,start_with_relu=True,grow_first=True, dilate=replace_stride_with_dilation[2]) # 1 / 16
self.block4=self._make_block(728,728,3,1,start_with_relu=True,grow_first=True, dilate=replace_stride_with_dilation[2])
self.block5=self._make_block(728,728,3,1,start_with_relu=True,grow_first=True, dilate=replace_stride_with_dilation[2])
self.block6=self._make_block(728,728,3,1,start_with_relu=True,grow_first=True, dilate=replace_stride_with_dilation[2])
self.block7=self._make_block(728,728,3,1,start_with_relu=True,grow_first=True, dilate=replace_stride_with_dilation[2])
self.block8=self._make_block(728,728,3,1,start_with_relu=True,grow_first=True, dilate=replace_stride_with_dilation[2])
self.block9=self._make_block(728,728,3,1,start_with_relu=True,grow_first=True, dilate=replace_stride_with_dilation[2])
self.block10=self._make_block(728,728,3,1,start_with_relu=True,grow_first=True, dilate=replace_stride_with_dilation[2])
self.block11=self._make_block(728,728,3,1,start_with_relu=True,grow_first=True, dilate=replace_stride_with_dilation[2])
self.block12=self._make_block(728,1024,2,2,start_with_relu=True,grow_first=False, dilate=replace_stride_with_dilation[3]) # 1 / 32
self.conv3 = SeparableConv2d(1024,1536,3,1,1, dilation=self.dilation)
self.bn3 = nn.BatchNorm2d(1536)
self.relu3 = nn.ReLU(inplace=True)
#do relu here
self.conv4 = SeparableConv2d(1536,2048,3,1,1, dilation=self.dilation)
self.bn4 = nn.BatchNorm2d(2048)
self.fc = nn.Linear(2048, num_classes)
# #------- init weights --------
# for m in self.modules():
# if isinstance(m, nn.Conv2d):
# n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
# m.weight.data.normal_(0, math.sqrt(2. / n))
# elif isinstance(m, nn.BatchNorm2d):
# m.weight.data.fill_(1)
# m.bias.data.zero_()
# #-----------------------------
def _make_block(self, in_filters,out_filters,reps,strides=1,start_with_relu=True,grow_first=True, dilate=False):
if dilate:
self.dilation *= strides
strides = 1
return Block(in_filters,out_filters,reps,strides,start_with_relu=start_with_relu,grow_first=grow_first, dilation=self.dilation)
def features(self, input):
x = self.conv1(input)
x = self.bn1(x)
x = self.relu1(x)
x = self.conv2(x)
x = self.bn2(x)
x = self.relu2(x)
x = self.block1(x)
x = self.block2(x)
x = self.block3(x)
x = self.block4(x)
x = self.block5(x)
x = self.block6(x)
x = self.block7(x)
x = self.block8(x)
x = self.block9(x)
x = self.block10(x)
x = self.block11(x)
x = self.block12(x)
x = self.conv3(x)
x = self.bn3(x)
x = self.relu3(x)
x = self.conv4(x)
x = self.bn4(x)
return x
def logits(self, features):
x = nn.ReLU(inplace=True)(features)
x = F.adaptive_avg_pool2d(x, (1, 1))
x = x.view(x.size(0), -1)
x = self.last_linear(x)
return x
def forward(self, input):
x = self.features(input)
x = self.logits(x)
return x
def xception(num_classes=1000, pretrained='imagenet', replace_stride_with_dilation=None):
model = Xception(num_classes=num_classes, replace_stride_with_dilation=replace_stride_with_dilation)
if pretrained:
settings = pretrained_settings['xception'][pretrained]
assert num_classes == settings['num_classes'], \
"num_classes should be {}, but is {}".format(settings['num_classes'], num_classes)
model = Xception(num_classes=num_classes, replace_stride_with_dilation=replace_stride_with_dilation)
model.load_state_dict(model_zoo.load_url(settings['url']))
# TODO: ugly
model.last_linear = model.fc
del model.fc
return model

View File

@ -1,222 +0,0 @@
from .utils import IntermediateLayerGetter
from ._deeplab import DeepLabHead, DeepLabHeadV3Plus, DeepLabV3
from .backbone import (
resnet,
mobilenetv2,
hrnetv2,
xception
)
def _segm_hrnet(name, backbone_name, num_classes, pretrained_backbone):
backbone = hrnetv2.__dict__[backbone_name](pretrained_backbone)
# HRNetV2 config:
# the final output channels is dependent on highest resolution channel config (c).
# output of backbone will be the inplanes to assp:
hrnet_channels = int(backbone_name.split('_')[-1])
inplanes = sum([hrnet_channels * 2 ** i for i in range(4)])
low_level_planes = 256 # all hrnet version channel output from bottleneck is the same
aspp_dilate = [12, 24, 36] # If follow paper trend, can put [24, 48, 72].
if name=='deeplabv3plus':
return_layers = {'stage4': 'out', 'layer1': 'low_level'}
classifier = DeepLabHeadV3Plus(inplanes, low_level_planes, num_classes, aspp_dilate)
elif name=='deeplabv3':
return_layers = {'stage4': 'out'}
classifier = DeepLabHead(inplanes, num_classes, aspp_dilate)
backbone = IntermediateLayerGetter(backbone, return_layers=return_layers, hrnet_flag=True)
model = DeepLabV3(backbone, classifier)
return model
def _segm_resnet(name, backbone_name, num_classes, output_stride, pretrained_backbone):
if output_stride==8:
replace_stride_with_dilation=[False, True, True]
aspp_dilate = [12, 24, 36]
else:
replace_stride_with_dilation=[False, False, True]
aspp_dilate = [6, 12, 18]
backbone = resnet.__dict__[backbone_name](
pretrained=pretrained_backbone,
replace_stride_with_dilation=replace_stride_with_dilation)
inplanes = 2048
low_level_planes = 256
if name=='deeplabv3plus':
return_layers = {'layer4': 'out', 'layer1': 'low_level'}
classifier = DeepLabHeadV3Plus(inplanes, low_level_planes, num_classes, aspp_dilate)
elif name=='deeplabv3':
return_layers = {'layer4': 'out'}
classifier = DeepLabHead(inplanes , num_classes, aspp_dilate)
backbone = IntermediateLayerGetter(backbone, return_layers=return_layers)
model = DeepLabV3(backbone, classifier)
return model
def _segm_xception(name, backbone_name, num_classes, output_stride, pretrained_backbone):
if output_stride==8:
replace_stride_with_dilation=[False, False, True, True]
aspp_dilate = [12, 24, 36]
else:
replace_stride_with_dilation=[False, False, False, True]
aspp_dilate = [6, 12, 18]
backbone = xception.xception(pretrained= 'imagenet' if pretrained_backbone else False, replace_stride_with_dilation=replace_stride_with_dilation)
inplanes = 2048
low_level_planes = 128
if name=='deeplabv3plus':
return_layers = {'conv4': 'out', 'block1': 'low_level'}
classifier = DeepLabHeadV3Plus(inplanes, low_level_planes, num_classes, aspp_dilate)
elif name=='deeplabv3':
return_layers = {'conv4': 'out'}
classifier = DeepLabHead(inplanes , num_classes, aspp_dilate)
backbone = IntermediateLayerGetter(backbone, return_layers=return_layers)
model = DeepLabV3(backbone, classifier)
return model
def _segm_mobilenet(name, backbone_name, num_classes, output_stride, pretrained_backbone):
if output_stride==8:
aspp_dilate = [12, 24, 36]
else:
aspp_dilate = [6, 12, 18]
backbone = mobilenetv2.mobilenet_v2(pretrained=pretrained_backbone, output_stride=output_stride)
# rename layers
backbone.low_level_features = backbone.features[0:4]
backbone.high_level_features = backbone.features[4:-1]
backbone.features = None
backbone.classifier = None
inplanes = 320
low_level_planes = 24
if name=='deeplabv3plus':
return_layers = {'high_level_features': 'out', 'low_level_features': 'low_level'}
classifier = DeepLabHeadV3Plus(inplanes, low_level_planes, num_classes, aspp_dilate)
elif name=='deeplabv3':
return_layers = {'high_level_features': 'out'}
classifier = DeepLabHead(inplanes , num_classes, aspp_dilate)
backbone = IntermediateLayerGetter(backbone, return_layers=return_layers)
model = DeepLabV3(backbone, classifier)
return model
def _load_model(arch_type, backbone, num_classes, output_stride, pretrained_backbone):
if backbone=='mobilenetv2':
model = _segm_mobilenet(arch_type, backbone, num_classes, output_stride=output_stride, pretrained_backbone=pretrained_backbone)
elif backbone.startswith('resnet'):
model = _segm_resnet(arch_type, backbone, num_classes, output_stride=output_stride, pretrained_backbone=pretrained_backbone)
elif backbone.startswith('hrnetv2'):
model = _segm_hrnet(arch_type, backbone, num_classes, pretrained_backbone=pretrained_backbone)
elif backbone=='xception':
model = _segm_xception(arch_type, backbone, num_classes, output_stride=output_stride, pretrained_backbone=pretrained_backbone)
else:
raise NotImplementedError
return model
# Deeplab v3
def deeplabv3_hrnetv2_48(num_classes=21, output_stride=4, pretrained_backbone=False): # no pretrained backbone yet
return _load_model('deeplabv3', 'hrnetv2_48', output_stride, num_classes, pretrained_backbone=pretrained_backbone)
def deeplabv3_hrnetv2_32(num_classes=21, output_stride=4, pretrained_backbone=True):
return _load_model('deeplabv3', 'hrnetv2_32', output_stride, num_classes, pretrained_backbone=pretrained_backbone)
def deeplabv3_resnet50(num_classes=21, output_stride=8, pretrained_backbone=True):
"""Constructs a DeepLabV3 model with a ResNet-50 backbone.
Args:
num_classes (int): number of classes.
output_stride (int): output stride for deeplab.
pretrained_backbone (bool): If True, use the pretrained backbone.
"""
return _load_model('deeplabv3', 'resnet50', num_classes, output_stride=output_stride, pretrained_backbone=pretrained_backbone)
def deeplabv3_resnet101(num_classes=21, output_stride=8, pretrained_backbone=True):
"""Constructs a DeepLabV3 model with a ResNet-101 backbone.
Args:
num_classes (int): number of classes.
output_stride (int): output stride for deeplab.
pretrained_backbone (bool): If True, use the pretrained backbone.
"""
return _load_model('deeplabv3', 'resnet101', num_classes, output_stride=output_stride, pretrained_backbone=pretrained_backbone)
def deeplabv3_mobilenet(num_classes=21, output_stride=8, pretrained_backbone=True, **kwargs):
"""Constructs a DeepLabV3 model with a MobileNetv2 backbone.
Args:
num_classes (int): number of classes.
output_stride (int): output stride for deeplab.
pretrained_backbone (bool): If True, use the pretrained backbone.
"""
return _load_model('deeplabv3', 'mobilenetv2', num_classes, output_stride=output_stride, pretrained_backbone=pretrained_backbone)
def deeplabv3_xception(num_classes=21, output_stride=8, pretrained_backbone=True, **kwargs):
"""Constructs a DeepLabV3 model with a Xception backbone.
Args:
num_classes (int): number of classes.
output_stride (int): output stride for deeplab.
pretrained_backbone (bool): If True, use the pretrained backbone.
"""
return _load_model('deeplabv3', 'xception', num_classes, output_stride=output_stride, pretrained_backbone=pretrained_backbone)
# Deeplab v3+
def deeplabv3plus_hrnetv2_48(num_classes=21, output_stride=4, pretrained_backbone=False): # no pretrained backbone yet
return _load_model('deeplabv3plus', 'hrnetv2_48', num_classes, output_stride, pretrained_backbone=pretrained_backbone)
def deeplabv3plus_hrnetv2_32(num_classes=21, output_stride=4, pretrained_backbone=True):
return _load_model('deeplabv3plus', 'hrnetv2_32', num_classes, output_stride, pretrained_backbone=pretrained_backbone)
def deeplabv3plus_resnet50(num_classes=21, output_stride=8, pretrained_backbone=True):
"""Constructs a DeepLabV3 model with a ResNet-50 backbone.
Args:
num_classes (int): number of classes.
output_stride (int): output stride for deeplab.
pretrained_backbone (bool): If True, use the pretrained backbone.
"""
return _load_model('deeplabv3plus', 'resnet50', num_classes, output_stride=output_stride, pretrained_backbone=pretrained_backbone)
def deeplabv3plus_resnet101(num_classes=21, output_stride=8, pretrained_backbone=True):
"""Constructs a DeepLabV3+ model with a ResNet-101 backbone.
Args:
num_classes (int): number of classes.
output_stride (int): output stride for deeplab.
pretrained_backbone (bool): If True, use the pretrained backbone.
"""
return _load_model('deeplabv3plus', 'resnet101', num_classes, output_stride=output_stride, pretrained_backbone=pretrained_backbone)
def deeplabv3plus_mobilenet(num_classes=21, output_stride=8, pretrained_backbone=True):
"""Constructs a DeepLabV3+ model with a MobileNetv2 backbone.
Args:
num_classes (int): number of classes.
output_stride (int): output stride for deeplab.
pretrained_backbone (bool): If True, use the pretrained backbone.
"""
return _load_model('deeplabv3plus', 'mobilenetv2', num_classes, output_stride=output_stride, pretrained_backbone=pretrained_backbone)
def deeplabv3plus_xception(num_classes=21, output_stride=8, pretrained_backbone=True):
"""Constructs a DeepLabV3+ model with a Xception backbone.
Args:
num_classes (int): number of classes.
output_stride (int): output stride for deeplab.
pretrained_backbone (bool): If True, use the pretrained backbone.
"""
return _load_model('deeplabv3plus', 'xception', num_classes, output_stride=output_stride, pretrained_backbone=pretrained_backbone)

View File

@ -1,93 +0,0 @@
import torch
import torch.nn as nn
import numpy as np
import torch.nn.functional as F
from collections import OrderedDict
class _SimpleSegmentationModel(nn.Module):
def __init__(self, backbone, classifier):
super(_SimpleSegmentationModel, self).__init__()
self.backbone = backbone
self.classifier = classifier
def forward(self, x):
input_shape = x.shape[-2:]
features = self.backbone(x)
x = self.classifier(features)
x = F.interpolate(x, size=input_shape, mode='bilinear', align_corners=False)
return x
class IntermediateLayerGetter(nn.ModuleDict):
"""
Module wrapper that returns intermediate layers from a model
It has a strong assumption that the modules have been registered
into the model in the same order as they are used.
This means that one should **not** reuse the same nn.Module
twice in the forward if you want this to work.
Additionally, it is only able to query submodules that are directly
assigned to the model. So if `model` is passed, `model.feature1` can
be returned, but not `model.feature1.layer2`.
Arguments:
model (nn.Module): model on which we will extract the features
return_layers (Dict[name, new_name]): a dict containing the names
of the modules for which the activations will be returned as
the key of the dict, and the value of the dict is the name
of the returned activation (which the user can specify).
Examples::
>>> m = torchvision.models.resnet18(pretrained=True)
>>> # extract layer1 and layer3, giving as names `feat1` and feat2`
>>> new_m = torchvision.models._utils.IntermediateLayerGetter(m,
>>> {'layer1': 'feat1', 'layer3': 'feat2'})
>>> out = new_m(torch.rand(1, 3, 224, 224))
>>> print([(k, v.shape) for k, v in out.items()])
>>> [('feat1', torch.Size([1, 64, 56, 56])),
>>> ('feat2', torch.Size([1, 256, 14, 14]))]
"""
def __init__(self, model, return_layers, hrnet_flag=False):
if not set(return_layers).issubset([name for name, _ in model.named_children()]):
raise ValueError("return_layers are not present in model")
self.hrnet_flag = hrnet_flag
orig_return_layers = return_layers
return_layers = {k: v for k, v in return_layers.items()}
layers = OrderedDict()
for name, module in model.named_children():
layers[name] = module
if name in return_layers:
del return_layers[name]
if not return_layers:
break
super(IntermediateLayerGetter, self).__init__(layers)
self.return_layers = orig_return_layers
def forward(self, x):
out = OrderedDict()
for name, module in self.named_children():
if self.hrnet_flag and name.startswith('transition'): # if using hrnet, you need to take care of transition
if name == 'transition1': # in transition1, you need to split the module to two streams first
x = [trans(x) for trans in module]
else: # all other transition is just an extra one stream split
x.append(module(x[-1]))
else: # other models (ex:resnet,mobilenet) are convolutions in series.
x = module(x)
if name in self.return_layers:
out_name = self.return_layers[name]
if name == 'stage4' and self.hrnet_flag: # In HRNetV2, we upsample and concat all outputs streams together
output_h, output_w = x[0].size(2), x[0].size(3) # Upsample to size of highest resolution stream
x1 = F.interpolate(x[1], size=(output_h, output_w), mode='bilinear', align_corners=False)
x2 = F.interpolate(x[2], size=(output_h, output_w), mode='bilinear', align_corners=False)
x3 = F.interpolate(x[3], size=(output_h, output_w), mode='bilinear', align_corners=False)
x = torch.cat([x[0], x1, x2, x3], dim=1)
out[out_name] = x
else:
out[out_name] = x
return out

Some files were not shown because too many files have changed in this diff Show More