implementado camera frontal

This commit is contained in:
Diego Freitas 2025-04-02 17:37:56 -03:00
parent bd4b9717cd
commit e107e7a810
62 changed files with 1351 additions and 658 deletions

Binary file not shown.

View File

@ -138,7 +138,7 @@ namespace AgroBase.Forms.IHM
private void frmAjustes_FormClosing(object sender, FormClosingEventArgs e)
{
Variaveis.OperacaoEmAndamento.AtualizaListaCameras(new List<Panel>() { pnlCaminho }, Variaveis.OperacaoEmAndamento.CamerasSolo.Select(x => x.panel).ToList(), false);
Variaveis.OperacaoEmAndamento.DesligarCameras();
}
#region COMUNICACAO
@ -276,6 +276,7 @@ namespace AgroBase.Forms.IHM
private void AtualizarCameras()
{
flwCamerasSolo.Controls.Clear();
OAKCameraService.AtualizarListaCameras(true);
Cameras = OAKCameraService.GetListaCameras();
for (int i = 0; i < Variaveis.OperacaoEmAndamento.QuantidadeCamerasSolo; i++)
{
@ -326,7 +327,11 @@ namespace AgroBase.Forms.IHM
}
CameraCaminho.camera.cameraIndex = CameraCaminho.combo.SelectedIndex;
IniciarCameras();
if (CameraCaminho.camera.cameraIndex > 0)
{
IniciarCameras();
}
}
private void GerarCameraSolo(int idx)
@ -416,7 +421,11 @@ namespace AgroBase.Forms.IHM
}
CameraSolo.camera.cameraIndex = CameraSolo.combo.SelectedIndex;
IniciarCameras();
if (CameraSolo.camera.cameraIndex > 0)
{
IniciarCameras();
}
}

View File

@ -33,7 +33,7 @@
this.pnlJoystick = new System.Windows.Forms.Panel();
this.pnlMapaDinamico = new System.Windows.Forms.Panel();
this.pnlCameraCaminho = new System.Windows.Forms.Panel();
this.pnlCameraSoloD = new System.Windows.Forms.Panel();
this.pnlCameraCaminhoHeat = new System.Windows.Forms.Panel();
this.pnlCameraSoloE = new System.Windows.Forms.Panel();
this.lblMapaCarregado = new System.Windows.Forms.Label();
this.txtStatusAtual = new System.Windows.Forms.TextBox();
@ -63,6 +63,14 @@
this.lblModoOperacao = new System.Windows.Forms.Label();
this.txtModoOperacao = new System.Windows.Forms.TextBox();
this.pnlSensores = new System.Windows.Forms.Panel();
this.txtDT = new System.Windows.Forms.TextBox();
this.lblDT = new System.Windows.Forms.Label();
this.txtET = new System.Windows.Forms.TextBox();
this.lblET = new System.Windows.Forms.Label();
this.txtDF = new System.Windows.Forms.TextBox();
this.lblDF = new System.Windows.Forms.Label();
this.txtEF = new System.Windows.Forms.TextBox();
this.lblEF = new System.Windows.Forms.Label();
this.txtStatusCarro = new System.Windows.Forms.TextBox();
this.lblStatusCarro = new System.Windows.Forms.Label();
this.txtMargemCorredor = new System.Windows.Forms.TextBox();
@ -96,14 +104,6 @@
this.tkbVelocidade = new System.Windows.Forms.TrackBar();
this.tabMapa = new System.Windows.Forms.TabPage();
this.picFechar = new System.Windows.Forms.PictureBox();
this.txtEF = new System.Windows.Forms.TextBox();
this.lblEF = new System.Windows.Forms.Label();
this.txtDF = new System.Windows.Forms.TextBox();
this.lblDF = new System.Windows.Forms.Label();
this.txtDT = new System.Windows.Forms.TextBox();
this.lblDT = new System.Windows.Forms.Label();
this.txtET = new System.Windows.Forms.TextBox();
this.lblET = new System.Windows.Forms.Label();
this.pnlMapa.SuspendLayout();
this.pnlSensores.SuspendLayout();
this.statusStrip1.SuspendLayout();
@ -148,12 +148,12 @@
this.pnlCameraCaminho.Size = new System.Drawing.Size(210, 150);
this.pnlCameraCaminho.TabIndex = 18;
//
// pnlCameraSoloD
// pnlCameraCaminhoHeat
//
this.pnlCameraSoloD.Location = new System.Drawing.Point(484, 2);
this.pnlCameraSoloD.Name = "pnlCameraSoloD";
this.pnlCameraSoloD.Size = new System.Drawing.Size(210, 150);
this.pnlCameraSoloD.TabIndex = 18;
this.pnlCameraCaminhoHeat.Location = new System.Drawing.Point(484, 2);
this.pnlCameraCaminhoHeat.Name = "pnlCameraCaminhoHeat";
this.pnlCameraCaminhoHeat.Size = new System.Drawing.Size(210, 150);
this.pnlCameraCaminhoHeat.TabIndex = 18;
//
// pnlCameraSoloE
//
@ -466,6 +466,86 @@
this.pnlSensores.Size = new System.Drawing.Size(307, 497);
this.pnlSensores.TabIndex = 32;
//
// txtDT
//
this.txtDT.Font = new System.Drawing.Font("Microsoft Sans Serif", 12.25F);
this.txtDT.Location = new System.Drawing.Point(195, 819);
this.txtDT.Name = "txtDT";
this.txtDT.ReadOnly = true;
this.txtDT.Size = new System.Drawing.Size(89, 26);
this.txtDT.TabIndex = 51;
this.txtDT.Text = "0,00";
this.txtDT.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// lblDT
//
this.lblDT.AutoSize = true;
this.lblDT.Location = new System.Drawing.Point(160, 822);
this.lblDT.Name = "lblDT";
this.lblDT.Size = new System.Drawing.Size(30, 20);
this.lblDT.TabIndex = 50;
this.lblDT.Text = "DT";
//
// txtET
//
this.txtET.Font = new System.Drawing.Font("Microsoft Sans Serif", 12.25F);
this.txtET.Location = new System.Drawing.Point(41, 822);
this.txtET.Name = "txtET";
this.txtET.ReadOnly = true;
this.txtET.Size = new System.Drawing.Size(89, 26);
this.txtET.TabIndex = 49;
this.txtET.Text = "0,00";
this.txtET.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// lblET
//
this.lblET.AutoSize = true;
this.lblET.Location = new System.Drawing.Point(6, 825);
this.lblET.Name = "lblET";
this.lblET.Size = new System.Drawing.Size(29, 20);
this.lblET.TabIndex = 48;
this.lblET.Text = "ET";
//
// txtDF
//
this.txtDF.Font = new System.Drawing.Font("Microsoft Sans Serif", 12.25F);
this.txtDF.Location = new System.Drawing.Point(195, 787);
this.txtDF.Name = "txtDF";
this.txtDF.ReadOnly = true;
this.txtDF.Size = new System.Drawing.Size(89, 26);
this.txtDF.TabIndex = 47;
this.txtDF.Text = "0,00";
this.txtDF.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// lblDF
//
this.lblDF.AutoSize = true;
this.lblDF.Location = new System.Drawing.Point(160, 790);
this.lblDF.Name = "lblDF";
this.lblDF.Size = new System.Drawing.Size(31, 20);
this.lblDF.TabIndex = 46;
this.lblDF.Text = "DF";
//
// txtEF
//
this.txtEF.Font = new System.Drawing.Font("Microsoft Sans Serif", 12.25F);
this.txtEF.Location = new System.Drawing.Point(41, 790);
this.txtEF.Name = "txtEF";
this.txtEF.ReadOnly = true;
this.txtEF.Size = new System.Drawing.Size(89, 26);
this.txtEF.TabIndex = 45;
this.txtEF.Text = "0,00";
this.txtEF.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// lblEF
//
this.lblEF.AutoSize = true;
this.lblEF.Location = new System.Drawing.Point(6, 793);
this.lblEF.Name = "lblEF";
this.lblEF.Size = new System.Drawing.Size(30, 20);
this.lblEF.TabIndex = 44;
this.lblEF.Text = "EF";
//
// txtStatusCarro
//
this.txtStatusCarro.Font = new System.Drawing.Font("Microsoft Sans Serif", 12.25F);
@ -796,86 +876,6 @@
this.picFechar.TabIndex = 1;
this.picFechar.TabStop = false;
//
// txtEF
//
this.txtEF.Font = new System.Drawing.Font("Microsoft Sans Serif", 12.25F);
this.txtEF.Location = new System.Drawing.Point(41, 790);
this.txtEF.Name = "txtEF";
this.txtEF.ReadOnly = true;
this.txtEF.Size = new System.Drawing.Size(89, 26);
this.txtEF.TabIndex = 45;
this.txtEF.Text = "0,00";
this.txtEF.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// lblEF
//
this.lblEF.AutoSize = true;
this.lblEF.Location = new System.Drawing.Point(6, 793);
this.lblEF.Name = "lblEF";
this.lblEF.Size = new System.Drawing.Size(30, 20);
this.lblEF.TabIndex = 44;
this.lblEF.Text = "EF";
//
// txtDF
//
this.txtDF.Font = new System.Drawing.Font("Microsoft Sans Serif", 12.25F);
this.txtDF.Location = new System.Drawing.Point(195, 787);
this.txtDF.Name = "txtDF";
this.txtDF.ReadOnly = true;
this.txtDF.Size = new System.Drawing.Size(89, 26);
this.txtDF.TabIndex = 47;
this.txtDF.Text = "0,00";
this.txtDF.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// lblDF
//
this.lblDF.AutoSize = true;
this.lblDF.Location = new System.Drawing.Point(160, 790);
this.lblDF.Name = "lblDF";
this.lblDF.Size = new System.Drawing.Size(31, 20);
this.lblDF.TabIndex = 46;
this.lblDF.Text = "DF";
//
// txtDT
//
this.txtDT.Font = new System.Drawing.Font("Microsoft Sans Serif", 12.25F);
this.txtDT.Location = new System.Drawing.Point(195, 819);
this.txtDT.Name = "txtDT";
this.txtDT.ReadOnly = true;
this.txtDT.Size = new System.Drawing.Size(89, 26);
this.txtDT.TabIndex = 51;
this.txtDT.Text = "0,00";
this.txtDT.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// lblDT
//
this.lblDT.AutoSize = true;
this.lblDT.Location = new System.Drawing.Point(160, 822);
this.lblDT.Name = "lblDT";
this.lblDT.Size = new System.Drawing.Size(30, 20);
this.lblDT.TabIndex = 50;
this.lblDT.Text = "DT";
//
// txtET
//
this.txtET.Font = new System.Drawing.Font("Microsoft Sans Serif", 12.25F);
this.txtET.Location = new System.Drawing.Point(41, 822);
this.txtET.Name = "txtET";
this.txtET.ReadOnly = true;
this.txtET.Size = new System.Drawing.Size(89, 26);
this.txtET.TabIndex = 49;
this.txtET.Text = "0,00";
this.txtET.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// lblET
//
this.lblET.AutoSize = true;
this.lblET.Location = new System.Drawing.Point(6, 825);
this.lblET.Name = "lblET";
this.lblET.Size = new System.Drawing.Size(29, 20);
this.lblET.TabIndex = 48;
this.lblET.Text = "ET";
//
// frmDialogoMapa
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@ -886,7 +886,7 @@
this.Controls.Add(this.tabControl1);
this.Controls.Add(this.statusStrip1);
this.Controls.Add(this.pnlCameraCaminho);
this.Controls.Add(this.pnlCameraSoloD);
this.Controls.Add(this.pnlCameraCaminhoHeat);
this.Controls.Add(this.lblMapaCarregado);
this.Controls.Add(this.pnlCameraSoloE);
this.Controls.Add(this.pnlMapa);
@ -948,7 +948,7 @@
private System.Windows.Forms.Panel pnlOrientacao;
private System.Windows.Forms.Panel pnlInclinacao;
private System.Windows.Forms.Panel pnlCameraCaminho;
private System.Windows.Forms.Panel pnlCameraSoloD;
private System.Windows.Forms.Panel pnlCameraCaminhoHeat;
private System.Windows.Forms.Panel pnlCameraSoloE;
private System.Windows.Forms.Label lblModoOperacao;
private System.Windows.Forms.TextBox txtModoOperacao;

View File

@ -40,7 +40,7 @@ namespace AgroBase.Forms.IHM
FuncoesGlobais.DefinirEventosPicBtn(picFechar, "", async () =>
{
if (Variaveis.OperacaoEmAndamento.Iniciado)
if (Variaveis.OperacaoEmAndamento.Iniciado && !Variaveis.OperacaoEmAndamento.Finalizando)
{
var res = CustomDialog.ShowDialog(
"Interromper Operação",
@ -54,7 +54,7 @@ namespace AgroBase.Forms.IHM
);
if (res == DialogResult.Yes)
{
await Variaveis.OperacaoEmAndamento.FinalizarOperacao();
Task.Run(async () => await Variaveis.OperacaoEmAndamento.FinalizarOperacao());
if (Variaveis.OperacaoEmAndamento.Modo == Enums.ModoOperacao.Manual)
{
this.Close();
@ -63,7 +63,15 @@ namespace AgroBase.Forms.IHM
}
else
{
this.Hide();
if (Variaveis.OperacaoEmAndamento.StatusAtual == Enums.StatusOperacao.Parametrizando)
{
Variaveis.OperacaoEmAndamento.DesligarCameras();
this.Hide();
}
else
{
this.Close();
}
}
});
}
@ -91,15 +99,16 @@ namespace AgroBase.Forms.IHM
private void frmDialogoMapa_FormClosing(object sender, FormClosingEventArgs e)
{
tmrLeitura.Dispose();
tmrLeitura?.Dispose();
Variaveis.OperacaoEmAndamento.DesligarCameras();
}
public async Task AtualizarRuasSelecionadas(List<string> ruasSelecionadas)
{
Variaveis.OperacaoEmAndamento.AtualizaListaCameras(new List<Panel>() { pnlCameraCaminho }, new List<Panel>(){ pnlCameraSoloE, pnlCameraSoloD }, true);
Variaveis.OperacaoEmAndamento.AtualizaListaCameras(new List<Panel>() { pnlCameraCaminho, pnlCameraCaminhoHeat }, new List<Panel>() { pnlCameraSoloE }, true);
await Task.Delay(1000);
GPSService.AtualizarRuasSelecionadas(ruasSelecionadas);
}
@ -117,16 +126,19 @@ namespace AgroBase.Forms.IHM
var _Sensoriamento = Variaveis.OperacaoEmAndamento.Sensoriamento;
var _Trajetoria = Variaveis.OperacaoEmAndamento.Trajetoria;
MapaDinamico.AtualizarDados(
KinectService.Iniciado && KinectService.Leitura.StatusDetecao ? KinectService.Leitura.ObstaculoCritico : null,
(float)_Sensoriamento.Trajetoria.AnguloCaminho,
(float)_Sensoriamento.Gps.AnguloCarroDefinido,
_Sensoriamento.Gps,
_Trajetoria._TrajetoriaDinamica,
_Trajetoria.CorredorAtual.Pontos,
Variaveis.OperacaoEmAndamento.GPSTrajetoria,
_Trajetoria.RuasPlantacao
);
if (_Trajetoria != null && _Trajetoria.CorredorAtual != null)
{
MapaDinamico.AtualizarDados(
KinectService.Iniciado && KinectService.Leitura.StatusDetecao ? KinectService.Leitura.ObstaculoCritico : null,
(float)_Trajetoria.AnguloCaminho,
(float)_Sensoriamento.Gps.AnguloCarroDefinido,
_Sensoriamento.Gps,
_Trajetoria._TrajetoriaDinamica,
_Trajetoria.CorredorAtual.Pontos,
Variaveis.OperacaoEmAndamento.GPSTrajetoria,
_Trajetoria.RuasPlantacao
);
}
}
private async Task tmrLeitura_Tick()
@ -303,27 +315,35 @@ namespace AgroBase.Forms.IHM
joystickPosition = joystickCenter;
// Evento de pintura do painel
pnlJoystick.Paint -= PanelJoystickBack_Paint;
pnlJoystick.Paint += PanelJoystickBack_Paint;
// Eventos de toque/mouse
pnlJoystick.MouseDown -= PanelJoystickBack_MouseDown;
pnlJoystick.MouseDown += PanelJoystickBack_MouseDown;
pnlJoystick.MouseMove -= PanelJoystickBack_MouseMove;
pnlJoystick.MouseMove += PanelJoystickBack_MouseMove;
pnlJoystick.MouseUp -= PanelJoystickBack_MouseUp;
pnlJoystick.MouseUp += PanelJoystickBack_MouseUp;
pnlFreio.BackColor = Color.LightGray;
pnlFreio.BorderStyle = BorderStyle.FixedSingle;
// Eventos de toque/pressão
pnlFreio.Paint -= BrakePanel_Paint;
pnlFreio.Paint += BrakePanel_Paint;
pnlFreio.MouseDown -= BrakePanel_MouseDown;
pnlFreio.MouseDown += BrakePanel_MouseDown;
pnlFreio.MouseMove -= BrakePanel_MouseMove;
pnlFreio.MouseMove += BrakePanel_MouseMove;
pnlFreio.MouseUp -= BrakePanel_MouseUp;
pnlFreio.MouseUp += BrakePanel_MouseUp;
// Configuração inicial do freio
freioStartPosition = new Point(pnlFreio.Width / 2 - 20, 10);
freioPosition = freioStartPosition;
Variaveis.OperacaoEmAndamento.AtualizaListaCameras(new List<Panel>() { pnlCameraCaminho }, new List<Panel>() { pnlCameraSoloE, pnlCameraSoloD }, true);
Variaveis.OperacaoEmAndamento.AtualizaListaCameras(new List<Panel>() { pnlCameraCaminho, pnlCameraCaminhoHeat }, new List<Panel>() { pnlCameraSoloE }, true);
IniciarOperacao();
}

View File

@ -52,7 +52,7 @@ namespace AgroBase.Forms.IHM
{
CustomDialog.ShowDialog(
"Iniciar Operação Manual",
$"{Variaveis.OperacaoEmAndamento.ErroOperacaoLiberada}",
$"{Variaveis.OperacaoEmAndamento.ErroOperacaoLiberada ?? ""}",
MessageBoxIcon.Error,
new Dictionary<(string, dynamic), Action>()
{
@ -63,27 +63,27 @@ namespace AgroBase.Forms.IHM
});
FuncoesGlobais.DefinirEventosPicBtn(picDesligar, "Erro ao desligar equipamento!", async () =>
{
var res = CustomDialog.ShowDialog(
"Desligar",
"Deseja Desligar o Equipamento?",
MessageBoxIcon.Question,
new Dictionary<(string, DialogResult?), Action>()
{
{ ("Sim", DialogResult.Yes), () => { } },
{ ("Não", DialogResult.No), () => { } },
}
);
if (res == DialogResult.Yes)
if (Variaveis.Producao)
{
if (!Variaveis.Producao)
{
this.Close();
}
else
var res = CustomDialog.ShowDialog(
"Desligar",
"Deseja Desligar o Equipamento?",
MessageBoxIcon.Question,
new Dictionary<(string, DialogResult?), Action>()
{
{ ("Sim", DialogResult.Yes), () => { } },
{ ("Não", DialogResult.No), () => { } },
}
);
if (res == DialogResult.Yes)
{
Process.Start("shutdown", "/s /t 0");
}
}
else
{
this.Close();
}
});
FuncoesGlobais.DefinirEventosPicBtn(picWifi, "Erro ao procurar por atualizações!", async () =>
{
@ -126,9 +126,11 @@ namespace AgroBase.Forms.IHM
{
lblVersao.Text = "v " + Variaveis.Versao;
tmrDispositivos?.Dispose();
tmrDispositivos = new AsyncTaskTimerModel("tmrDispositivos", tmrDispositivos_Tick, 1000, this);
tmrDispositivos.Start();
lblCodigoFalha.Click -= LblCodigoFalha_Click;
lblCodigoFalha.Click += LblCodigoFalha_Click;
}

View File

@ -499,6 +499,7 @@
this.Name = "frmInicioOperacao";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Preparando operação...";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.frmInicioOperacao_FormClosing);
this.Load += new System.EventHandler(this.frmInicioOperacao_Load);
this.fpnlInformacoes.ResumeLayout(false);
this.fpnlInformacoes.PerformLayout();

View File

@ -207,11 +207,16 @@ namespace AgroBase.Forms.Operacoes
{
try
{
(bool sucesso, List<string> ruas) = await Variaveis.OperacaoEmAndamento.CarregarParametrizacaoOperacao(frmDialogo.pnlMapa, frmDialogo.lblMapaCarregado, path);
(bool sucesso, List<string> ruas) = Variaveis.OperacaoEmAndamento.CarregarParametrizacaoOperacao(frmDialogo.pnlMapa, frmDialogo.lblMapaCarregado, path);
bool condicaoOperacaoCarregada() => Variaveis.OperacaoEmAndamento.Trajetoria?.CorredorAtual != null;
bool resultado = await FuncoesGlobais.AguardarCondicaoAsync(condicaoOperacaoCarregada, 5000, 200);
if (!resultado)
{
throw new Exception("Erro ao carregar a trajetória do mapa!");
}
ruasSelecionadas = ruas;
foreach (var chb in fpnlInformacoes.Controls.OfType<CheckBox>())
@ -235,7 +240,7 @@ namespace AgroBase.Forms.Operacoes
{
CustomDialog.ShowDialog(
"Erro",
"Erro ao carregar operação!",
$"Erro ao carregar operação!{Environment.NewLine}{ex.Message}",
MessageBoxIcon.Error,
new Dictionary<(string, dynamic), Action>()
{
@ -336,6 +341,12 @@ namespace AgroBase.Forms.Operacoes
return icon.ToBitmap();
}
private void frmInicioOperacao_FormClosing(object sender, FormClosingEventArgs e)
{
if (!frmDialogo.IsDisposed)
{
frmDialogo.Close();
}
}
}
}

View File

@ -139,7 +139,7 @@ namespace AgroBase.Forms.Operacoes
//LogsKinect = JsonConvert.DeserializeObject<KinectModel[]>(DeserializarDadosOperacao(ofd.FileName, data.knt ?? Enums.T_Code.Knt.ToString())).ToList();
LogsCam_Caminho = JsonConvert.DeserializeObject<CamCaminhoSensoriamentoLogModel[]>(OperacaoModel.DeserializarDadosOperacao(ofd.FileName, data.cam_caminho)).ToList();
pathImagensSonarRGB = ofd.FileName.Replace("data.lgop", data.knt + "/rgb_");
pathImagensMapaCalor = ofd.FileName.Replace("data.lgop", data.knt + "/heat_");
pathImagensMapaCalor = ofd.FileName.Replace("data.lgop", data.cam_caminho + "/");
pathImagensCaminho = ofd.FileName.Replace("data.lgop", data.cam_caminho + "/");
LogsCam_Solo = new List<List<CamSoloSensoriamentoLogModel>>();
@ -974,9 +974,13 @@ namespace AgroBase.Forms.Operacoes
}
}
private Bitmap CarregarImagemCamera(string Caminho)
private Bitmap CarregarImagemCamera(string Caminho, string complemento = "")
{
string caminhoCompleto = Caminho + trbMomento.Value + ".jpg";
if (!string.IsNullOrEmpty(complemento))
{
caminhoCompleto = caminhoCompleto.Replace(".jpg", $"{complemento}.jpg");
}
Bitmap frame = new Bitmap(1, 1);
using (Graphics g = Graphics.FromImage(frame))
{
@ -1132,6 +1136,7 @@ namespace AgroBase.Forms.Operacoes
private void AtualizarInformacoesCameras()
{
picCameraCaminho.Image = CarregarImagemCamera(pathImagensCaminho);
picMapaCalor.Image = CarregarImagemCamera(pathImagensMapaCalor, "_heat");
AtualizarInformacoesCameraCaminho();
for (int i = 0; i < LogsCam_Solo.Count(); i++)
@ -1180,7 +1185,7 @@ namespace AgroBase.Forms.Operacoes
txtGPS_Velocidade.Text = (Log?.Velocidade ?? 0).ToString("0.00") + " (" + ((Log?.Velocidade ?? 0) * GPSUtils.ConversaoNosKmh).ToString("0.00") + " km/h)";
int ID = Convert.ToInt32(Variaveis.IsAgroMonitor ? Variaveis.OperacaoEmAndamento.DispSen.Dados.LoRaParametrosBase.address : Variaveis.ConexaoLoRa.parametros.address);
GPSService.EnviarCoordenadasParaMapa(Log?.Latitude ?? 0, Log?.Longitude ?? 0, Log?.CursoVerdadeiro ?? 0, true, ID);
GPSService.EnviarCoordenadasParaMapa(Log?.Latitude ?? 0, Log?.Longitude ?? 0, Log?.AnguloCarroDefinido ?? 0, true, ID);
lblGPS.ForeColor = !Log.Inicializado ? Color.Red : Color.Black;
@ -1200,7 +1205,7 @@ namespace AgroBase.Forms.Operacoes
null, //LogKnt.Iniciado && LogKnt.StatusDetecao ? LogKnt.ObstaculoCritico : null,
(float)LogOpe.Trajetoria.AnguloCaminho,
(float)LogOpe.Gps.AnguloCarroDefinido,
new GPSModel() { Latitude = Log.Latitude, Longitude = Log.Longitude },
Log,
_trajaetoria,
null, //Variaveis.OperacaoEmAndamento.Mapa.TrajetoriaProjetada.FirstOrDefault(),
new List<GPSModel>(LogsGPS.Take(LogsGPS.IndexOf(Log) + 1)),
@ -1385,7 +1390,7 @@ namespace AgroBase.Forms.Operacoes
lblMagnetometro.ForeColor = !LogWit.Inicializado ? Color.Red : Color.Black;
pnlOrientacaoMagnetometro.Invalidate();
pnlInclinacao.Invalidate();
visualizador3D.AtualizarAngulos(LogWit.AngleX, LogWit.AngleY, LogWit.AngleZ);
visualizador3D.AtualizarAngulos(-LogWit.AngleX, -LogWit.AngleY, LogWit.AngleZ);
txtTemperatura.Text = LogWit.Temperatura.ToString("0.00");
txtAltitude.Text = LogWit.Altitude.ToString("0.00");
txtPressao.Text = LogWit.Pressao + " Pa (" + (LogWit.Pressao / 101300.0).ToString("0.00") + " atm)";

View File

@ -2,7 +2,6 @@
using AgroBase.Models;
using AgroBase.Services;
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
@ -37,7 +36,7 @@ namespace AgroBase.Forms
GeneralJoystick.IniciarRotinas();
VersionamentoService.IniciarRotinas();
EncerrarProcessosPython();
PythonService.EncerrarProcessos();
}
private void frmInstancial_Shown(object sender, EventArgs e)
@ -107,30 +106,12 @@ namespace AgroBase.Forms
await Task.Delay(500);
}
EncerrarProcessosPython();
PythonService.EncerrarProcessos();
Environment.Exit(0);
}
private static void EncerrarProcessosPython()
{
foreach (var processo in Process.GetProcessesByName("python"))
{
try
{
// Verifica os argumentos do processo
string argumentos = processo.StartInfo.Arguments;
if (argumentos.Contains("--source=" + Variaveis.NomeAplicacao) || true)
{
processo.Kill(); // Encerra apenas os processos marcados pelo sistema
}
}
catch (Exception ex)
{
Console.WriteLine($"Erro ao encerrar processo: {ex.Message}");
}
}
}

View File

@ -62,9 +62,14 @@ namespace AgroBase.Models
}
browserRgb = null;
Task.Run(async () => await Variaveis.MqttService.UnsubscribeAsync(camera._mqttTopico));
if (camera.pythonProcess != null)
lock (camera.processLock)
{
camera.pythonProcess.Kill();
if (camera.pythonProcess != null)
{
camera.pythonProcess.Kill();
camera.pythonProcess = null;
}
}
}
catch (Exception ex)
@ -150,7 +155,10 @@ namespace AgroBase.Models
var depth_data = Leitura.depth_data;
if (depth_data == null || depth_data.Count == 0)
throw new InvalidOperationException("Dados de profundidade inválidos.");
{
return null;
//throw new InvalidOperationException("Dados de profundidade inválidos.");
}
int height = depth_data.Count;
int width = depth_data[0].Count;

View File

@ -59,6 +59,7 @@ namespace AgroBase.Models
public OAKCameraModel device_data { get; set; }
public double x_max { get; set; }
public double y_max { get; set; }
public OAKDLiteSubdivisoesModel subdivisoes { get; set; }
public List<List<int>> depth_data { get; set; } = new List<List<int>>();
public List<CameraDeepLabV3PlusClasseModel> Classes { get; set; } = new List<CameraDeepLabV3PlusClasseModel>();
@ -71,11 +72,64 @@ namespace AgroBase.Models
x_max = x_max,
y_max = y_max,
depth_data = new List<List<int>>(depth_data),
Classes = new List<CameraDeepLabV3PlusClasseModel>(Classes)
Classes = new List<CameraDeepLabV3PlusClasseModel>(Classes),
subdivisoes = subdivisoes?.Clone()
};
}
}
public class OAKDLiteSubdivisoesModel
{
public int x_max { get; set; }
public int y_max { get; set; }
public SubdivisaoModel subdivisoes_cima { get; set; }
public SubdivisaoModel subdivisoes_chao { get; set; }
public OAKDLiteSubdivisoesModel Clone()
{
return new OAKDLiteSubdivisoesModel()
{
x_max = x_max,
y_max = y_max,
subdivisoes_chao = subdivisoes_chao?.Clone(),
subdivisoes_cima = subdivisoes_cima?.Clone()
};
}
}
public class SubdivisaoModel
{
public int num_linhas { get; set; }
public int num_colunas { get; set; }
public List<CelulaModel> celulas { get; set; }
public SubdivisaoModel Clone()
{
return new SubdivisaoModel()
{
num_linhas = num_linhas,
num_colunas = num_colunas,
celulas = new List<CelulaModel>(celulas)
};
}
}
public class CelulaModel
{
public int linha { get; set; }
public int coluna { get; set; }
public int x { get; set; }
public int y { get; set; }
public int largura { get; set; }
public int altura { get; set; }
public double profundidade_media { get; set; }
public double profundidade_calibragem { get; set; }
}
public class CameraDeepLabV3PlusClasseModel
{
public string Classe { get; set; }

View File

@ -24,10 +24,14 @@ namespace AgroBase.Models
panel.Controls.Remove(browser);
}
browser = null;
Task.Run(async () => Variaveis.MqttService.UnsubscribeAsync(camera._mqttTopico));
if (camera.pythonProcess != null && !camera.pythonProcess.HasExited)
Task.Run(async () => await Variaveis.MqttService.UnsubscribeAsync(camera._mqttTopico));
lock (camera.processLock)
{
camera.pythonProcess.Kill();
if (camera.pythonProcess != null)
{
camera.pythonProcess.Kill();
camera.pythonProcess = null;
}
}
}
catch (Exception ex)

View File

@ -107,7 +107,7 @@ namespace AgroBase.Models
{
try
{
lock (mapaService.pythonProcess)
lock (mapaService.processLock)
{
if (mapaService.pythonProcess == null)
{
@ -137,7 +137,7 @@ namespace AgroBase.Models
IniciarProcessamento();
lock (mapaService.pythonProcess)
lock (mapaService.processLock)
{
mapaService.pythonProcess.Dispose();
mapaService.pythonProcess = null;

View File

@ -353,7 +353,7 @@ namespace AgroBase.Models
return true;
}
public async Task<(bool, List<string>)> CarregarParametrizacaoOperacao(Panel pnlMapa, Label lblMapa, string opPath = "")
public (bool, List<string>) CarregarParametrizacaoOperacao(Panel pnlMapa, Label lblMapa, string opPath = "")
{
string path = Variaveis.CaminhoSistema + Variaveis.CaminhoOperacoes + MapasVariaveisModel.NomeArquivoMapaInterativoSaida;
@ -418,8 +418,8 @@ namespace AgroBase.Models
Variaveis.OperacaoEmAndamento.Mapa.btnCarregar_Click(new object(), new EventArgs(), path);
bool condicaoMapaCarregado() => Variaveis.OperacaoEmAndamento.Mapa.mapaService.Carregado;
bool resultado = await FuncoesGlobais.AguardarCondicaoAsync(condicaoMapaCarregado, 5000, 200);
//bool condicaoMapaCarregado() => Variaveis.OperacaoEmAndamento.Mapa.mapaService.Carregado;
//bool resultado = await FuncoesGlobais.AguardarCondicaoAsync(condicaoMapaCarregado, 5000, 200);
}
return (true, ruasSelecionadas);
@ -761,6 +761,8 @@ namespace AgroBase.Models
Variaveis.OperacaoEmAndamento.Controle.Angulo = Variaveis.OperacaoEmAndamento.Controle.Angulo_Max;
Variaveis.OperacaoEmAndamento.Controle.PercentualVelocidadeSP = Variaveis.OperacaoEmAndamento.Controle.PercentualVelocidadeMin;
Variaveis.OperacaoEmAndamento.Sensoriamento.AtualizarDados();
}
@ -830,13 +832,14 @@ namespace AgroBase.Models
Variaveis.OperacaoEmAndamento.Finalizando = true;
PararCarroOperacaoInterrompida(true);
Variaveis.OperacaoEmAndamento.Trajetoria?.LoopAtualizaDados();
Variaveis.OperacaoEmAndamento.Trajetoria.LoopAtualizaDados();
Variaveis.OperacaoEmAndamento.PararCarroOperacaoInterrompida(true);
await Task.Delay(2000);
Variaveis.OperacaoEmAndamento.Iniciado = false;
Variaveis.OperacaoEmAndamento.DataFim = DateTime.Now;
tmrLogs?.Stop();
@ -1022,11 +1025,11 @@ namespace AgroBase.Models
return;
}
Variaveis.OperacaoEmAndamento.DesligarCameras();
//var listaCameras = CameraService.ObterListaCameras().Values.ToArray();
var listaCameras = OAKCameraService.GetListaCameras();
CamerasSolo.ForEach(cam => cam.DesligarCamera());
CamerasSolo.Clear();
for (int i = 0; i < QuantidadeCamerasSolo; i++)
{
@ -1093,11 +1096,11 @@ namespace AgroBase.Models
CameraCaminho.camera.cameraIndex = listaCameras.FirstOrDefault(x => x.Id == CameraCaminho.DeviceID)?.Index ?? -1;
if (CameraCaminho.camera.cameraIndex > -1 && Iniciar) // && Variaveis.OperacaoEmAndamento.Controle.SegmentacaoSemantica
{
if (pnlCameraCaminho.Count() > 0)
if (pnlCameraCaminho.Count > 0)
{
CameraCaminho.panelRgb = pnlCameraCaminho[0];
}
if (pnlCameraCaminho.Count() > 1)
if (pnlCameraCaminho.Count > 1)
{
CameraCaminho.panelHeatmap = pnlCameraCaminho[1];
}
@ -1136,18 +1139,16 @@ namespace AgroBase.Models
{
CameraSolo.camera.ProntoEm = Mensagem.Momento;
if (CameraSolo.browser == null)
if (CameraSolo.browser == null && CameraSolo.panel != null)
{
CameraSolo.Iniciada = true;
CameraSolo.browser = new ChromiumWebBrowser(CameraSolo.camera.URLcamera[0]);
CameraSolo.browser.Dock = DockStyle.Fill;
CameraSolo.panel.Invoke(new Action(async () =>
CameraSolo.panel.Invoke(new Action(() =>
{
CameraSolo.panel.Controls.Add(CameraSolo.browser);
CameraSolo.panel.Refresh();
await Task.Delay(500);
CameraSolo.panel.Refresh();
}));
}
}
@ -1189,7 +1190,7 @@ namespace AgroBase.Models
async (Mensagem) =>
{
cameraCaminho.UltimaMensagemRecebida = DateTime.Now;
if (Mensagem.Momento > cameraCaminho.camera.IniciadoEm && Mensagem.Mensagem == "OK")
if (Mensagem.Momento > cameraCaminho.camera.IniciadoEm && Mensagem.Mensagem == "OK_1")
{
cameraCaminho.camera.ProntoEm = Mensagem.Momento;
@ -1197,32 +1198,37 @@ namespace AgroBase.Models
{
cameraCaminho.Iniciada = true;
if (cameraCaminho.camera.URLcamera.Count() > 0)
if (cameraCaminho.camera.URLcamera.Count > 0)
{
cameraCaminho.browserRgb = new ChromiumWebBrowser(cameraCaminho.camera.URLcamera[0]);
cameraCaminho.browserRgb.Dock = DockStyle.Fill;
cameraCaminho.panelRgb.Invoke(new Action(async () =>
cameraCaminho.panelRgb.Invoke(new Action(() =>
{
cameraCaminho.panelRgb.Controls.Add(cameraCaminho.browserRgb);
cameraCaminho.panelRgb.Refresh();
await Task.Delay(500);
cameraCaminho.panelRgb.Refresh();
cameraCaminho.browserRgb.Refresh();
}));
FuncoesGlobais.ValidarImagemCameraBrowser(cameraCaminho.browserRgb, cameraCaminho.panelRgb);
}
await Task.Delay(1000);
if (cameraCaminho.camera.URLcamera.Count() > 1)
}
}
else if (Mensagem.Momento > cameraCaminho.camera.IniciadoEm && Mensagem.Mensagem == "OK_2")
{
cameraCaminho.camera.ProntoEm = Mensagem.Momento;
if (cameraCaminho.browserHeatmap == null && cameraCaminho.panelHeatmap != null)
{
cameraCaminho.Iniciada = true;
if (cameraCaminho.camera.URLcamera.Count > 1)
{
cameraCaminho.browserHeatmap = new ChromiumWebBrowser(cameraCaminho.camera.URLcamera[1]);
cameraCaminho.browserHeatmap.Dock = DockStyle.Fill;
cameraCaminho.panelHeatmap.Invoke(new Action(async () =>
cameraCaminho.panelHeatmap.Invoke(new Action(() =>
{
cameraCaminho.panelHeatmap.Controls.Add(cameraCaminho.browserHeatmap);
cameraCaminho.panelHeatmap.Refresh();
await Task.Delay(500);
cameraCaminho.panelHeatmap.Refresh();
cameraCaminho.browserHeatmap.Refresh();
}));
FuncoesGlobais.ValidarImagemCameraBrowser(cameraCaminho.browserHeatmap, cameraCaminho.panelHeatmap);
}
}
}
@ -1242,7 +1248,7 @@ namespace AgroBase.Models
{
Camera.DesligarCamera();
});
Variaveis.OperacaoEmAndamento.CameraCaminho.DesligarCamera();
Variaveis.OperacaoEmAndamento.CameraCaminho?.DesligarCamera();
}
#endregion
@ -1251,13 +1257,8 @@ namespace AgroBase.Models
public void AtualizaInformacoesControleOperacao()
{
if (Variaveis.OperacaoEmAndamento.Modo == ModoOperacao.Manual)
if (Variaveis.OperacaoEmAndamento.Modo == ModoOperacao.MapaGPS)
{
VerificarDesvioPorObstaculos();
}
else
{
//Variaveis.OperacaoEmAndamento.OpMapaGPS.CalculaDadosMovimentacaoAutonoma();
Variaveis.OperacaoEmAndamento.AtualizarDadosControle(false);
}
}
@ -1268,7 +1269,7 @@ namespace AgroBase.Models
var _Controle = Variaveis.OperacaoEmAndamento.Controle;
bool MovimentoLiberado = Variaveis.OperacaoEmAndamento.StatusAtual != StatusOperacao.Aguardando && Variaveis.OperacaoEmAndamento.StatusAtual != StatusOperacao.Parado && !MKS057DService.Referenciando;
bool MovimentoLiberado = Variaveis.OperacaoEmAndamento.StatusAtual == StatusOperacao.EmAndamento && !MKS057DService.Referenciando;
if (MovimentoLiberado || ForcarEnvio)
{
@ -1401,41 +1402,44 @@ namespace AgroBase.Models
private void VerificarDesvioPorObstaculos()
{
var Sonar = Variaveis.OperacaoEmAndamento.Sensoriamento.SonarFrontal_Kinect;
if (Variaveis.OperacaoEmAndamento.Controle.SonarAtivado && (Sonar?.Iniciado ?? false) && (Sonar?.DesvioNecessario ?? false))
if (Variaveis.OperacaoEmAndamento.Controle.SonarAtivado)
{
Keys TeclaComando =
Sonar.DirecaoDesvio == Direcao.Esquerda ? Keys.Left :
Sonar.DirecaoDesvio == Direcao.Direita ? Keys.Right :
Keys.Escape;
var Sonar = Variaveis.OperacaoEmAndamento.Sensoriamento.SonarFrontal_Kinect;
if ((Sonar?.Iniciado ?? false) && (Sonar?.DesvioNecessario ?? false))
{
Keys TeclaComando =
Sonar.DirecaoDesvio == Direcao.Esquerda ? Keys.Left :
Sonar.DirecaoDesvio == Direcao.Direita ? Keys.Right :
Keys.Escape;
if (Variaveis.OperacaoEmAndamento.Controle.SonarDesvioAutomatico)
{
Variaveis.OperacaoEmAndamento.Controle.Angulo = Sonar.AnguloDesvio;
GeneralJoystick.EnviaComandoMotor(TeclaComando, T_Code.Dir);
if (Variaveis.OperacaoEmAndamento.Controle.SonarDesvioAutomatico)
{
Variaveis.OperacaoEmAndamento.Controle.Angulo = Sonar.AnguloDesvio;
GeneralJoystick.EnviaComandoMotor(TeclaComando, T_Code.Dir);
}
if (Sonar.DirecaoDesvio == Direcao.Parado)
{
GeneralJoystick.EnviaComandoMotor(Keys.Escape, T_Code.Mov);
}
}
if (Sonar.DirecaoDesvio == Direcao.Parado)
{
GeneralJoystick.EnviaComandoMotor(Keys.Escape, T_Code.Mov);
}
}
var Ultrassom = UltrasonicA05Service.DadosLeitura.Configuracao;
if (UltrasonicA05Service.Iniciado)
{
Keys TeclaComando =
Ultrassom.DirecaoDesvio == Direcao.Esquerda ? Keys.Left :
Ultrassom.DirecaoDesvio == Direcao.Direita ? Keys.Right :
Keys.Escape;
var Ultrassom = UltrasonicA05Service.DadosLeitura.Configuracao;
if (UltrasonicA05Service.Iniciado && Ultrassom.DesvioNecessario)
{
Keys TeclaComando =
Ultrassom.DirecaoDesvio == Direcao.Esquerda ? Keys.Left :
Ultrassom.DirecaoDesvio == Direcao.Direita ? Keys.Right :
Keys.Escape;
if (Ultrassom.ParadaNecessaria)
{
GeneralJoystick.EnviaComandoMotor(Keys.Escape, T_Code.Mov);
}
else if (Variaveis.OperacaoEmAndamento.Controle.SonarDesvioAutomatico && Ultrassom.DesvioNecessario)
{
Variaveis.OperacaoEmAndamento.Controle.Angulo = Variaveis.OperacaoEmAndamento.Controle.Angulo_Max;
GeneralJoystick.EnviaComandoMotor(TeclaComando, T_Code.Dir);
if (Ultrassom.ParadaNecessaria)
{
GeneralJoystick.EnviaComandoMotor(Keys.Escape, T_Code.Mov);
}
else if (Ultrassom.DesvioNecessario)
{
Variaveis.OperacaoEmAndamento.Controle.Angulo = Variaveis.OperacaoEmAndamento.Controle.Angulo_Max;
GeneralJoystick.EnviaComandoMotor(TeclaComando, T_Code.Dir);
}
}
}
}
@ -1595,13 +1599,14 @@ namespace AgroBase.Models
}
var MqttTopico = cameraCaminho.camera._mqttTopico;
if (MqttTopico != null && MqttTopico.Mensagens.Any(x => x.Momento > cameraCaminho.camera.IniciadoEm))
if (MqttTopico != null && MqttTopico.Mensagens.Any(x => x.Momento > cameraCaminho.camera.IniciadoEm && !x.Mensagem.StartsWith("OK")))
{
try
{
var Mensagem = MqttTopico.Mensagens.LastOrDefault(x => x.Momento > cameraCaminho.camera.IniciadoEm);
if (Mensagem != null)
{
Console.WriteLine(Mensagem.Mensagem);
cameraCaminho.Leitura = JsonConvert.DeserializeObject<CameraDeepLabV3PlusModel>(Mensagem.Mensagem);
}
}
@ -1797,7 +1802,21 @@ namespace AgroBase.Models
private void PararCarroOperacaoInterrompida(bool finalizar)
{
AtualizarDadosControle(true);
var Controle = Variaveis.OperacaoEmAndamento.Controle;
if (Variaveis.OperacaoEmAndamento.Modo == ModoOperacao.MapaGPS)
{
Variaveis.OperacaoEmAndamento.AtualizarDadosControle(true);
}
else
{
GeneralJoystick.EnviaComandoMotor(Keys.Escape, T_Code.Mov, true);
GeneralJoystick.EnviaComandoMotor(Keys.Escape, T_Code.Dir, true);
foreach (var bico in Variaveis.OperacaoEmAndamento.DispAtu.Dados.BicosPulverizadores)
{
GeneralJoystick.EnviarComandoAtuador(S_Code.sBIC, false, bico.ID, true);
}
}
if (finalizar)
{
@ -1808,7 +1827,7 @@ namespace AgroBase.Models
}
}
Variaveis.OperacaoEmAndamento.Controle.TiposControle.ForEach(x => x.UltimaDirecao = Direcao.Parado);
Controle.TiposControle.ForEach(x => x.UltimaDirecao = Direcao.Parado);
}
@ -2060,13 +2079,14 @@ namespace AgroBase.Models
{
tipo = typeof(CamSoloSensoriamentoLogModel),
nome = x.Nome,
browser = x.browser
browsers = new List<ChromiumWebBrowser>() { x.browser }
})
.Union(new[] {
new {
tipo = typeof(CamCaminhoSensoriamentoLogModel),
nome = cameraCaminho.Nome,
browser = cameraCaminho.browserRgb
browsers = new List<ChromiumWebBrowser>() { cameraCaminho.browserRgb, cameraCaminho.browserHeatmap },
}
})
.ToList();
@ -2093,8 +2113,11 @@ namespace AgroBase.Models
};
SalvarLog(Camera.nome, logCam, false);
frame = await FuncoesGlobais.GetBrowserImage(Camera.browser);
FuncoesGlobais.SalvarImagemComprimida(frame, Caminho, 100L, 716, 403);
foreach (var browser in Camera.browsers)
{
frame = await FuncoesGlobais.GetBrowserImage(browser);
FuncoesGlobais.SalvarImagemComprimida(frame, Caminho, 100L, 716, 403);
}
}
else if (Camera.tipo == typeof(CamCaminhoSensoriamentoLogModel))
{
@ -2112,11 +2135,18 @@ namespace AgroBase.Models
};
SalvarLog(Camera.nome, logCam, false);
frame = await FuncoesGlobais.GetBrowserImage(Camera.browser);
FuncoesGlobais.SalvarImagemComprimida(frame, Caminho, 100L, 716, 403);
foreach (var browser in Camera.browsers)
{
int idx = Camera.browsers.IndexOf(browser);
frame = await FuncoesGlobais.GetBrowserImage(browser);
if (idx == 1)
{
Caminho = Caminho.Replace(".jpg", "_heat.jpg");
}
FuncoesGlobais.SalvarImagemComprimida(frame, Caminho, 30L, 716, 403);
}
Bitmap heatBitmap = cameraCaminho.GenerateHeatmapBitmap();
FuncoesGlobais.SalvarImagemComprimida(heatBitmap, Caminho.Replace(".jpg", "_heat.jpg"), 30L);
//Bitmap heatBitmap = cameraCaminho.GenerateHeatmapBitmap();
}
}
}

View File

@ -87,7 +87,7 @@ namespace AgroBase.Models
}
public List<PontoTrajetoriaModel> _TrajetoriaFixa { get; set; }
private bool _TrajetoriaFixaDefinida
public bool _TrajetoriaFixaDefinida
{
get
{
@ -895,11 +895,22 @@ namespace AgroBase.Models
if (_trajetoriaFixa.Count() > 1 && idxEsq == 0 && idxDir == 0)
{
var p0 = _trajetoriaFixa.Where(x => x.Tipo == TipoPontoRua.Rua).Skip(2).FirstOrDefault();
var p1 = _trajetoriaFixa.Where(x => x.Tipo == TipoPontoRua.Rua).Skip(3).FirstOrDefault();
(List<GPSModel> ruaEsq, List<GPSModel> ruaDir) = DeterminarRuasLaterais(p0.Posicao, p1.Posicao, RuasPlantacao[0], RuasPlantacao[1]);
idxEsq = RuasPlantacao.IndexOf(ruaEsq);
idxDir = RuasPlantacao.IndexOf(ruaDir);
var pontos = _trajetoriaFixa.Where(x => x.Tipo == TipoPontoRua.Rua).ToList();
if (pontos.Count >= 2)
{
var p0 = pontos[0];
var p1 = pontos[1];
(List<GPSModel> ruaEsq, List<GPSModel> ruaDir) = DeterminarRuasLaterais(p0.Posicao, p1.Posicao, RuasPlantacao[0], RuasPlantacao[1]);
idxEsq = RuasPlantacao.IndexOf(ruaEsq);
idxDir = RuasPlantacao.IndexOf(ruaDir);
}
else
{
// ⚠️ Caso de erro: não há dois pontos de rua, mesmo com mais de 1 ponto na trajetória.
Console.WriteLine("Não há ao menos dois pontos do tipo Rua.");
}
}
bool ultimoCorredor = idx == Corredores.Count() - 1;
@ -1391,6 +1402,11 @@ namespace AgroBase.Models
private void AtualizarDistanciaTrajeto()
{
if (!Variaveis.OperacaoEmAndamento.Trajetoria._TrajetoriaFixaDefinida)
{
return;
}
var pontoAtual = Variaveis.OperacaoEmAndamento.Trajetoria.PontoAtual;
int idxPontoAtual = pontoAtual.idxPonto + 1;
int qtdPontos = Math.Abs(idxPonto - idxPontoAtual) + 1; // Sempre positivo

View File

@ -15,6 +15,7 @@ using CefSharp.WinForms;
using System.IO;
using System.Threading;
using AgroBase.Models.Components;
using CefSharp;
namespace AgroBase.Models
{
@ -1064,7 +1065,55 @@ namespace AgroBase.Models
}
}
public static void ValidarImagemCameraBrowser(ChromiumWebBrowser nav, Control parent)
{
nav.LoadingStateChanged += async (sender, args) =>
{
// Aguarde até terminar de carregar
if (!args.IsLoading)
{
var browser = (ChromiumWebBrowser)sender;
try
{
// Espera um pequeno tempo para o conteúdo estar disponível
await Task.Delay(500);
// Executa JavaScript para verificar o conteúdo da página
var response = await browser.EvaluateScriptAsync(
"document.body ? document.body.innerText : ''");
if (response.Success && response.Result != null)
{
string conteudo = response.Result.ToString();
// Verifica mensagens de erro comuns
if (conteudo.Contains("Internal Server Error") || conteudo.Contains("Not Found") || conteudo.Length < 20)
{
Console.WriteLine("Falha no carregamento do stream, recarregando...");
await Task.Delay(1000);
if (parent.IsHandleCreated)
{
parent.Invoke(new Action(() =>
{
browser.Refresh();
}));
}
}
else
{
Console.WriteLine("Câmera carregada com sucesso.");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Erro ao verificar página: {ex.Message}");
}
}
};
}
}

View File

@ -14,6 +14,7 @@ namespace AgroBase.Services
public static Dictionary<string, string> CamerasConectadas = new Dictionary<string, string>();
public Process pythonProcess;
public readonly object processLock = new object();
public DateTime? IniciadoEm = null;
public DateTime? ProntoEm = null;
public DateTime? FinalizadoEm = null;
@ -34,8 +35,11 @@ namespace AgroBase.Services
{
_mqttTopico = await Variaveis.MqttService.AdicionarNovoTopico(MqttTopico, true, 2, mqttCallback);
pythonProcess = new Process();
pythonProcess = PythonService.RunScript(Script, Argumentos);
lock (processLock)
{
pythonProcess = new Process();
pythonProcess = PythonService.RunScript(Script, Argumentos);
}
IniciadoEm = DateTime.Now;
foreach (string url in FlaskUrl)

View File

@ -455,7 +455,7 @@ namespace AgroBase.Services
PenultimaLeitura.TipoOrientacao = UltimaLeitura.TipoOrientacao;
UltimaLeitura.Momento = DateTime.Now;
UltimaLeitura.OrientacaoReal = (headingTrue + 180) % 360; // Inverter o angulo lido para normalizar com o angulo calculado entre leituras
UltimaLeitura.OrientacaoReal = headingTrue;
UltimaLeitura.TipoOrientacao = status;
// ✅ Atualiza o ângulo unificado no GPSService
@ -662,8 +662,8 @@ namespace AgroBase.Services
// ✅ Se a trajetória estiver vazia, não há o que calcular
if (GPSTrajetoria == null || GPSTrajetoria.Count == 0)
{
Angulo = GPSUtils.CalcularOrientacao(UltimaLeitura, PenultimaLeitura);
DistAngulo = GPSUtils.DistanciaEntrePontos(UltimaLeitura, PenultimaLeitura);
Angulo = GPSUtils.CalcularOrientacao(PenultimaLeitura, UltimaLeitura);
DistAngulo = GPSUtils.DistanciaEntrePontos(PenultimaLeitura, UltimaLeitura);
}
else
{
@ -729,9 +729,9 @@ namespace AgroBase.Services
double distAnguloGPS = UltimaLeitura.Distancia;
//anguloFinal = CalcularAnguloUnificado(anguloGPS, UltimaLeitura.QualidadeFix, anguloGPSMovimento, distAnguloGPS);
anguloFinal = GPSUtils.MisturarAngulosPorDistancia(anguloGPS, anguloGPSMovimento, distAnguloGPS, TrajetoriaMapaOperacaoModel.DistanciaMaximaEntreLeituras, 0.03, 0.3);
//anguloFinal = GPSUtils.MisturarAngulosPorDistancia(anguloGPS, anguloGPSMovimento, distAnguloGPS, TrajetoriaMapaOperacaoModel.DistanciaMaximaEntreLeituras, 0.03, 0.3);
//anguloFinal = anguloGPS;
anguloFinal = anguloGPS;
}
else if (witIniciado)
{

View File

@ -1,5 +1,4 @@
using AgroBase.Models;
using CefSharp.WinForms;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
@ -7,7 +6,6 @@ using System.Diagnostics;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.Xml.Linq;
namespace AgroBase.Services
{
@ -25,6 +23,7 @@ namespace AgroBase.Services
{
public OpenFileDialog opfMapa;
public Process pythonProcess;
public readonly object processLock = new object();
private string CaminhoSaida = Variaveis.CaminhoSistema + PythonService.CaminhoGeral + PythonService.CaminhoLeitura;
public string NomeArquivoMapa = "";
public string NomeArquivos = "";
@ -56,17 +55,20 @@ namespace AgroBase.Services
NomeArquivos = CaminhoArquivo.Split('\\')[CaminhoArquivo.Split('\\').Length - 1].Replace(extensao, "");
CaminhoMapa = CaminhoArquivo.Replace(NomeArquivos, "").Replace(extensao, "").Replace("\\", "/");
pythonProcess = PythonService.RunScript(script, new string[]
lock (processLock)
{
CaminhoMapa,
NomeArquivos,
ArquivoSaida,
NomeArquivoMapa,
MapasVariaveisModel.TopicoCoordenadasGPS,
MapasVariaveisModel.TopicoSelecaoRuasMapa,
MapasVariaveisModel.TopicoTrajetoriaDinamica,
extensao == ".json" ? "1" : "0"
});
pythonProcess = PythonService.RunScript(script, new string[]
{
CaminhoMapa,
NomeArquivos,
ArquivoSaida,
NomeArquivoMapa,
MapasVariaveisModel.TopicoCoordenadasGPS,
MapasVariaveisModel.TopicoSelecaoRuasMapa,
MapasVariaveisModel.TopicoTrajetoriaDinamica,
extensao == ".json" ? "1" : "0"
});
}
MapaUrl = new Uri(CaminhoSaida + NomeArquivoMapa).AbsoluteUri;
CaminhoDadosMapa = CaminhoSaida + ArquivoSaida;

View File

@ -71,7 +71,17 @@ public class MqttService
if (topico.Callback != null)
{
Task.Run(async () => await FuncoesGlobais.SafeExecuteAsync(async () => await topico.Callback(Mensagem)));
_ = Task.Run(async () =>
{
try
{
await topico.Callback(Mensagem); // await real e funcional
}
catch (Exception ex)
{
Console.WriteLine($"Erro no callback do tópico '{topico.Topico}': {ex}");
}
});
}
}
});

View File

@ -79,7 +79,7 @@ namespace AgroBase.Services
StartInfo = new ProcessStartInfo
{
FileName = "python",
Arguments = $"{ScriptPath} {Args}",
Arguments = $"{ScriptPath} {Args} --source={Variaveis.NomeAplicacao}",
UseShellExecute = false,
RedirectStandardOutput = false,
RedirectStandardError = false,
@ -88,7 +88,7 @@ namespace AgroBase.Services
}
};
Console.WriteLine($"{ScriptPath} {Args}");
Console.WriteLine($"{pythonProcess.StartInfo.Arguments}");
//pythonProcess.Exited += PythonProcess_Exited;
//pythonProcess.OutputDataReceived += PythonProcess_OutputDataReceived;
@ -196,13 +196,26 @@ namespace AgroBase.Services
}
}
public static void EncerrarProcessos()
public static void EncerrarProcessos(int processId = -1)
{
foreach (var processo in processosIniciados)
foreach (var processo in Process.GetProcessesByName("python"))
{
if (!processo.HasExited)
try
{
processo.Kill();
// Verifica os argumentos do processo
string argumentos = processo.StartInfo.Arguments;
if ((processId > -1 && processo.Id == processId))
{
processo.Kill();
}
else if (processId == -1)
{
processo.Kill();
}
}
catch (Exception ex)
{
Console.WriteLine($"Erro ao encerrar processo: {ex.Message}");
}
}
}

View File

@ -5,7 +5,6 @@ using System.Collections.Generic;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Management;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@ -936,11 +935,23 @@ namespace AgroBase.Services
Console.WriteLine(msg);
if (!Variaveis.IsAgroMonitor)
{
frmInstancial.frmPrincipal.Invoke((MethodInvoker)(() =>
if (frmInstancial.frmPrincipal.IsHandleCreated)
{
frmInstancial.frmPrincipal.lblStatusConexao.Text = msg;
frmInstancial.frmIHM.lblStatus.Text = msg;
}));
frmInstancial.frmPrincipal.Invoke((MethodInvoker)(() =>
{
frmInstancial.frmPrincipal.lblStatusConexao.Text = msg;
if (frmInstancial.frmIHM != null && frmInstancial.frmIHM.IsHandleCreated)
{
frmInstancial.frmIHM.lblStatus.Text = msg;
}
}));
}
else
{
// Opcional: armazenar a mensagem e aplicar depois
Console.WriteLine("frmPrincipal ainda não está pronto para receber Invoke.");
}
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -142,12 +142,12 @@
{
"id": 13,
"Diretorio": "Python\\Scripts\\",
"Arquivo": "street_detector",
"Arquivo": "street_detector_oak",
"Extensao": ".py",
"Versao": "1_0",
"ArquivoDownload": "street_detector-1_0.py",
"NomeArquivoLocal": "street_detector-1_0.py",
"CaminhoCompleto": "Python\\Scripts\\street_detector-1_0.py",
"ArquivoDownload": "street_detector_oak-1_0.py",
"NomeArquivoLocal": "street_detector_oak-1_0.py",
"CaminhoCompleto": "Python\\Scripts\\street_detector_oak-1_0.py",
"Atualizado": true,
"ArquivoAtualizado": true,
"TipoArquivo": 8

View File

@ -1,221 +1 @@
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"Id": "1",
"Name": "CidadeJardimTerreno2",
"Length": 14.558011415731592,
"Dist1": 14.558011415731592,
"Dist2": 0.0
},
"geometry": {
"id": null,
"type": "LineString",
"coordinates": [
[
-47.395205344,
-22.172559531333334
],
[
-47.395212610166666,
-22.172614638833334
],
[
-47.395219157,
-22.172656417833334
],
[
-47.395223544833335,
-22.1726892105
],
[
-47.39522414098443,
-22.17269369161165
],
[
-47.395225326538004,
-22.172702654611555
]
]
}
},
{
"type": "Feature",
"properties": {
"Id": "2",
"Name": "CidadeJardimTerreno2",
"Length": 14.771318274761821,
"Dist1": 14.558011415731592,
"Dist2": 0.0
},
"geometry": {
"id": null,
"type": "LineString",
"coordinates": [
[
-47.39521090233333,
-22.172708800833334
],
[
-47.395206943666665,
-22.172679811
],
[
-47.395202420666664,
-22.1726491015
],
[
-47.395198865666664,
-22.172615782833333
],
[
-47.395193255833334,
-22.172577132833332
],
[
-47.395192610024395,
-22.17257265769541
],
[
-47.395191325698136,
-22.172563706509337
]
]
}
},
{
"type": "Feature",
"properties": {
"Id": "3",
"Name": "CidadeJardimTerreno2",
"Length": 14.827915524386164,
"Dist1": 14.558011415731592,
"Dist2": 0.0
},
"geometry": {
"id": null,
"type": "LineString",
"coordinates": [
[
-47.3951762925,
-22.172561603
],
[
-47.395180824166665,
-22.172591686166665
],
[
-47.395185745333336,
-22.172623080166666
],
[
-47.395190433,
-22.172656367166667
],
[
-47.395195199,
-22.172693641833334
],
[
-47.39519576904436,
-22.172698125891035
],
[
-47.39519690267159,
-22.172707094716973
]
]
}
},
{
"type": "Feature",
"properties": {
"Id": "4",
"Name": "CidadeJardimTerreno2",
"Length": 14.785159385903514,
"Dist1": 14.558011415731592,
"Dist2": 0.0
},
"geometry": {
"id": null,
"type": "LineString",
"coordinates": [
[
-47.39518293216667,
-22.1727127985
],
[
-47.39517819266667,
-22.172680514833335
],
[
-47.3951732595,
-22.172646752833334
],
[
-47.39516880516667,
-22.1726149155
],
[
-47.39516381233334,
-22.172581167166665
],
[
-47.39516315429932,
-22.172576693573966
],
[
-47.39516184565584,
-22.172567745443878
]
]
}
},
{
"type": "Feature",
"properties": {
"Id": "5",
"Name": "CidadeJardimTerreno2",
"Length": 14.80117692191233,
"Dist1": 14.558011415731592,
"Dist2": 0.0
},
"geometry": {
"id": null,
"type": "LineString",
"coordinates": [
[
-47.395147317833334,
-22.172566031
],
[
-47.395151503166666,
-22.172595452333333
],
[
-47.3951561855,
-22.172628011166665
],
[
-47.39516159866667,
-22.172663757333332
],
[
-47.39516672716667,
-22.172697770833334
],
[
-47.395167397572706,
-22.172702242832194
],
[
-47.39516873082615,
-22.17271118781009
]
]
}
}
]
}
{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"Id":"1","Name":"02_04_2025_17_20_50","Length":0.0,"Dist1":0.0,"Dist2":0.0},"geometry":{"id":null,"type":"LineString","coordinates":[[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0],[0.0,0.0]]}}]}

View File

@ -25,7 +25,7 @@
<meta name="viewport" content="width=device-width,
initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<style>
#map_c17ce78bff49a7401eff2508c6dcc0c3 {
#map_084fd12da6e91f44659dd95dda10e013 {
position: relative;
width: 100.0%;
height: 100.0%;
@ -39,14 +39,14 @@
<body>
<div class="folium-map" id="map_c17ce78bff49a7401eff2508c6dcc0c3" ></div>
<div class="folium-map" id="map_084fd12da6e91f44659dd95dda10e013" ></div>
</body>
<script>
var map_c17ce78bff49a7401eff2508c6dcc0c3 = L.map(
"map_c17ce78bff49a7401eff2508c6dcc0c3",
var map_084fd12da6e91f44659dd95dda10e013 = L.map(
"map_084fd12da6e91f44659dd95dda10e013",
{
center: [0.0, 0.0],
crs: L.CRS.EPSG3857,
@ -60,13 +60,13 @@
var tile_layer_b68aee685770afdb7f454cf948fb9b33 = L.tileLayer(
var tile_layer_67f4a27d47a2b4494d6ed3f07cc58c1c = L.tileLayer(
"https://tile.openstreetmap.org/{z}/{x}/{y}.png",
{"attribution": "\u0026copy; \u003ca href=\"https://www.openstreetmap.org/copyright\"\u003eOpenStreetMap\u003c/a\u003e contributors", "detectRetina": false, "maxNativeZoom": 19, "maxZoom": 19, "minZoom": 0, "noWrap": false, "opacity": 1, "subdomains": "abc", "tms": false}
);
tile_layer_b68aee685770afdb7f454cf948fb9b33.addTo(map_c17ce78bff49a7401eff2508c6dcc0c3);
tile_layer_67f4a27d47a2b4494d6ed3f07cc58c1c.addTo(map_084fd12da6e91f44659dd95dda10e013);
</script>
@ -87,7 +87,7 @@
}
trajeto_json_add({"features": []});
trajeto_json.addTo(map_c17ce78bff49a7401eff2508c6dcc0c3);
trajeto_json.addTo(map_084fd12da6e91f44659dd95dda10e013);
function adicionarGeometria(novaGeometria) {
trajeto_json.addData(novaGeometria);
@ -145,7 +145,7 @@
var marcadorDinamico = L.marker([0, 0], {
icon: customIcon
}).addTo(map_c17ce78bff49a7401eff2508c6dcc0c3);
}).addTo(map_084fd12da6e91f44659dd95dda10e013);
// Conectar ao broker MQTT
const client = mqtt.connect('ws://localhost:9001'); // Use wss para conexão segura
@ -183,7 +183,7 @@
marcadorDinamico.setRotationAngle(angulo);
adicionarCoordenada("Tj", [novaLongitude, novaLatitude]);
map_c17ce78bff49a7401eff2508c6dcc0c3.setView(novaPosicao, map_c17ce78bff49a7401eff2508c6dcc0c3.getZoom());
map_084fd12da6e91f44659dd95dda10e013.setView(novaPosicao, map_084fd12da6e91f44659dd95dda10e013.getZoom());
});
function calcularOrientacao(P1latitude, P1longitude, P2latitude, P2longitude) {

View File

@ -25,7 +25,7 @@
<meta name="viewport" content="width=device-width,
initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<style>
#map_68dcaf9dd7545b82e750e9f498ab7095 {
#map_6db772d0d8d14e2d02efe2b399e87581 {
position: relative;
width: 100.0%;
height: 100.0%;
@ -39,16 +39,16 @@
<body>
<div class="folium-map" id="map_68dcaf9dd7545b82e750e9f498ab7095" ></div>
<div class="folium-map" id="map_6db772d0d8d14e2d02efe2b399e87581" ></div>
</body>
<script>
var map_68dcaf9dd7545b82e750e9f498ab7095 = L.map(
"map_68dcaf9dd7545b82e750e9f498ab7095",
var map_6db772d0d8d14e2d02efe2b399e87581 = L.map(
"map_6db772d0d8d14e2d02efe2b399e87581",
{
center: [-22.172636164916668, -47.395186322185666],
center: [0.0, 0.0],
crs: L.CRS.EPSG3857,
zoom: 12,
zoomControl: true,
@ -60,13 +60,13 @@
var tile_layer_18ed5e620d2365ae2eea37d711c8da92 = L.tileLayer(
var tile_layer_53d89bd6580a52ed08e8b535dbe73fc5 = L.tileLayer(
"https://tile.openstreetmap.org/{z}/{x}/{y}.png",
{"attribution": "\u0026copy; \u003ca href=\"https://www.openstreetmap.org/copyright\"\u003eOpenStreetMap\u003c/a\u003e contributors", "detectRetina": false, "maxNativeZoom": 19, "maxZoom": 19, "minZoom": 0, "noWrap": false, "opacity": 1, "subdomains": "abc", "tms": false}
);
tile_layer_18ed5e620d2365ae2eea37d711c8da92.addTo(map_68dcaf9dd7545b82e750e9f498ab7095);
tile_layer_53d89bd6580a52ed08e8b535dbe73fc5.addTo(map_6db772d0d8d14e2d02efe2b399e87581);
@ -82,7 +82,7 @@
}*/
});
}
function geo_json_377712b0416695b2616e159ce6022a2d_onEachFeature(feature, layer) {
function geo_json_3dd7e60984a746b98c90d1ccb69ef337_onEachFeature(feature, layer) {
layer.on({
click: function(e) {
@ -118,20 +118,20 @@
}*/
});
};
var geo_json_377712b0416695b2616e159ce6022a2d = L.geoJson(null, {
onEachFeature: geo_json_377712b0416695b2616e159ce6022a2d_onEachFeature,
var geo_json_3dd7e60984a746b98c90d1ccb69ef337 = L.geoJson(null, {
onEachFeature: geo_json_3dd7e60984a746b98c90d1ccb69ef337_onEachFeature,
});
function geo_json_377712b0416695b2616e159ce6022a2d_add (data) {
geo_json_377712b0416695b2616e159ce6022a2d
function geo_json_3dd7e60984a746b98c90d1ccb69ef337_add (data) {
geo_json_3dd7e60984a746b98c90d1ccb69ef337
.addData(data);
}
geo_json_377712b0416695b2616e159ce6022a2d_add({"features": [{"geometry": {"coordinates": [[-47.395205344, -22.172559531333334], [-47.395212610166666, -22.172614638833334], [-47.395219157, -22.172656417833334], [-47.395223544833335, -22.1726892105], [-47.39522414098443, -22.17269369161165], [-47.395225326538004, -22.172702654611555]], "id": null, "type": "LineString"}, "id": 0, "properties": {"Dist1": 14.558011415731592, "Dist2": 0.0, "Id": "1", "Length": 14.558011415731592, "Name": "CidadeJardimTerreno2"}, "type": "Feature"}, {"geometry": {"coordinates": [[-47.39521090233333, -22.172708800833334], [-47.395206943666665, -22.172679811], [-47.395202420666664, -22.1726491015], [-47.395198865666664, -22.172615782833333], [-47.395193255833334, -22.172577132833332], [-47.395192610024395, -22.17257265769541], [-47.395191325698136, -22.172563706509337]], "id": null, "type": "LineString"}, "id": 1, "properties": {"Dist1": 14.558011415731592, "Dist2": 0.0, "Id": "2", "Length": 14.771318274761821, "Name": "CidadeJardimTerreno2"}, "type": "Feature"}, {"geometry": {"coordinates": [[-47.3951762925, -22.172561603], [-47.395180824166665, -22.172591686166665], [-47.395185745333336, -22.172623080166666], [-47.395190433, -22.172656367166667], [-47.395195199, -22.172693641833334], [-47.39519576904436, -22.172698125891035], [-47.39519690267159, -22.172707094716973]], "id": null, "type": "LineString"}, "id": 2, "properties": {"Dist1": 14.558011415731592, "Dist2": 0.0, "Id": "3", "Length": 14.827915524386164, "Name": "CidadeJardimTerreno2"}, "type": "Feature"}, {"geometry": {"coordinates": [[-47.39518293216667, -22.1727127985], [-47.39517819266667, -22.172680514833335], [-47.3951732595, -22.172646752833334], [-47.39516880516667, -22.1726149155], [-47.39516381233334, -22.172581167166665], [-47.39516315429932, -22.172576693573966], [-47.39516184565584, -22.172567745443878]], "id": null, "type": "LineString"}, "id": 3, "properties": {"Dist1": 14.558011415731592, "Dist2": 0.0, "Id": "4", "Length": 14.785159385903514, "Name": "CidadeJardimTerreno2"}, "type": "Feature"}, {"geometry": {"coordinates": [[-47.395147317833334, -22.172566031], [-47.395151503166666, -22.172595452333333], [-47.3951561855, -22.172628011166665], [-47.39516159866667, -22.172663757333332], [-47.39516672716667, -22.172697770833334], [-47.395167397572706, -22.172702242832194], [-47.39516873082615, -22.17271118781009]], "id": null, "type": "LineString"}, "id": 4, "properties": {"Dist1": 14.558011415731592, "Dist2": 0.0, "Id": "5", "Length": 14.80117692191233, "Name": "CidadeJardimTerreno2"}, "type": "Feature"}], "type": "FeatureCollection"});
geo_json_3dd7e60984a746b98c90d1ccb69ef337_add({"features": [{"geometry": {"coordinates": [[0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0]], "id": null, "type": "LineString"}, "id": 0, "properties": {"Dist1": 0.0, "Dist2": 0.0, "Id": "1", "Length": 0.0, "Name": "02_04_2025_17_20_50"}, "type": "Feature"}], "type": "FeatureCollection"});
geo_json_377712b0416695b2616e159ce6022a2d.addTo(map_68dcaf9dd7545b82e750e9f498ab7095);
geo_json_3dd7e60984a746b98c90d1ccb69ef337.addTo(map_6db772d0d8d14e2d02efe2b399e87581);
</script>
@ -152,7 +152,7 @@
}
trajeto_json_add({"features": []});
trajeto_json.addTo(map_68dcaf9dd7545b82e750e9f498ab7095);
trajeto_json.addTo(map_6db772d0d8d14e2d02efe2b399e87581);
function adicionarGeometria(novaGeometria) {
trajeto_json.addData(novaGeometria);
@ -210,7 +210,7 @@
}
trajeto_dinamico_json_add({"features": []});
trajeto_dinamico_json.addTo(map_68dcaf9dd7545b82e750e9f498ab7095);
trajeto_dinamico_json.addTo(map_6db772d0d8d14e2d02efe2b399e87581);
function adicionarGeometriaDinamica(novaGeometria) {
trajeto_dinamico_json.addData(novaGeometria);
@ -263,9 +263,9 @@
var marcadorEquipamento = L.marker([0, 0], {
icon: customIcon
}).addTo(map_68dcaf9dd7545b82e750e9f498ab7095);
}).addTo(map_6db772d0d8d14e2d02efe2b399e87581);
var marcadorBase = L.marker([0, 0], {}).addTo(map_68dcaf9dd7545b82e750e9f498ab7095);
var marcadorBase = L.marker([0, 0], {}).addTo(map_6db772d0d8d14e2d02efe2b399e87581);
var icon = L.AwesomeMarkers.icon(
{"extraClasses": "fa-rotate-0", "icon": "info-sign", "iconColor": "white", "markerColor": "red", "prefix": "glyphicon"}
);
@ -347,7 +347,7 @@
}
if (foco) {
map_68dcaf9dd7545b82e750e9f498ab7095.setView(novaPosicao, map_68dcaf9dd7545b82e750e9f498ab7095.getZoom());
map_6db772d0d8d14e2d02efe2b399e87581.setView(novaPosicao, map_6db772d0d8d14e2d02efe2b399e87581.getZoom());
}
}
@ -364,7 +364,7 @@
function atualizarSelecaoRuas(selecionadas) {
selecionadas = JSON.parse(selecionadas);
RuasSelecionadas = Array.isArray(selecionadas) ? [...selecionadas] : [];
geo_json_377712b0416695b2616e159ce6022a2d.eachLayer(function (layer) {
geo_json_3dd7e60984a746b98c90d1ccb69ef337.eachLayer(function (layer) {
if (RuasSelecionadas.includes(parseInt(layer.feature.id))) {
layer.setStyle({ color: 'blue' });
} else {

View File

@ -7,7 +7,7 @@ import sys
import threading
import paho.mqtt.client as mqtt
import uuid
from flask import Flask, Response, request
from flask import Flask, Response
# 🔹 Configurações MQTT
mqtt_client = mqtt.Client(f"client_oak_d_lite_{uuid.uuid4()}")
@ -15,57 +15,149 @@ mqtt_client.connect("localhost", port=1883)
# 🔹 Parâmetros de entrada
output_folder = 'Python/Output/'
mqtt_topic = sys.argv[1] # Tópico MQTT para envio dos dados de profundidade
mqtt_topic = sys.argv[1] # Tópico MQTT para envio dos dados
porta = int(sys.argv[2]) # Porta do Flask
url = sys.argv[3] # URL do vídeo
max_readings = int(sys.argv[4])
url_rgb = sys.argv[3] # URL do vídeo RGB
url_heatmap = sys.argv[4] # URL do vídeo do Heatmap
max_readings = int(sys.argv[5])
camera_index = int(sys.argv[6])
# 🔹 Flask App
app = Flask(__name__)
# 🔹 Criando o pipeline
# Função para calcular a moda de um array unidimensional
def calc_mode(values):
# Arredonda os valores para eliminar pequenas variações
rounded = np.round(values, 0)
vals, counts = np.unique(rounded, return_counts=True)
return vals[np.argmax(counts)]
# Configuração de filtros
NUM_FRAMES_SMOOTH = 5 # Número de frames para suavização temporal
SMOOTH_KERNEL = (5, 5) # Tamanho do kernel para suavização espacial
OUTLIER_THRESHOLD = 50 # Limiar para remoção de outliers
depth_buffer = [] # Buffer para armazenar os últimos frames de profundidade
# Suavização Temporal
def smooth_depth(depth_frame):
global depth_buffer
if len(depth_buffer) >= NUM_FRAMES_SMOOTH:
depth_buffer.pop(0) # Remove o frame mais antigo
depth_buffer.append(depth_frame) # Adiciona o novo frame
return np.mean(depth_buffer, axis=0).astype(np.uint16) # Retorna a média
# Suavização Espacial (Filtro Gaussiano)
def gaussian_smooth(depth_frame):
return cv2.GaussianBlur(depth_frame, SMOOTH_KERNEL, 0)
# Filtro de Mediana para Remover Ruídos
def median_filter(depth_frame):
return cv2.medianBlur(depth_frame, 5)
# Remover Outliers (Saltos Extremos)
def remove_outliers(depth_frame):
depth_median = cv2.medianBlur(depth_frame, 5)
diff = np.abs(depth_frame - depth_median)
depth_frame[diff > OUTLIER_THRESHOLD] = depth_median[diff > OUTLIER_THRESHOLD]
return depth_frame
# Aplicar filtros no depthFrame
def apply_depth_filters(depth_frame):
if filtro1:
depth_frame = smooth_depth(depth_frame) # 1. Suavização Temporal
if filtro2:
depth_frame = gaussian_smooth(depth_frame) # 2. Suavização Espacial
if filtro3:
depth_frame = median_filter(depth_frame) # 3. Filtro de Mediana
if filtro4:
depth_frame = remove_outliers(depth_frame) # 4. Remoção de Outliers
return depth_frame
# Função para gerar o mapa de calor da profundidade
def generate_heatmap(depth_frame):
normalized_depth = cv2.normalize(depth_frame, None, 0, 255, cv2.NORM_MINMAX)
heatmap = cv2.applyColorMap(normalized_depth.astype(np.uint8), cv2.COLORMAP_JET)
return heatmap
# ───────────────────────────────────────────────
# Configurações da câmera e das matrizes
# ───────────────────────────────────────────────
RGB_WIDTH, RGB_HEIGHT = 640, 480
WIDTH, HEIGHT = 320, 240
# Região do solo (grid A - parte inferior): ocupa 50% da altura da imagem
GROUND_ROWS = 10 # Número de linhas da matriz do solo
GROUND_CELLS = 10 # Número de células por linha
GROUND_REGION_HEIGHT = int(HEIGHT * 0.5) # 50% da altura da imagem
GROUND_TOP_SCALE = 0.5 # A linha mais distante (superior da região) terá 35% da largura total
DEPTH_LIMIT = 50 # (Valor de referência para comparação, mas agora usamos calibração)
# Região aérea (parte superior): ocupa o restante da imagem
AIR_ROWS = 10 # Número de linhas na matriz aérea
AIR_COLS = 15 # Número de colunas na matriz aérea
AIR_REGION_HEIGHT = HEIGHT - GROUND_REGION_HEIGHT # Altura da região aérea
# ───────────────────────────────────────────────
# Parâmetros para calibração e detecção com moda
# ───────────────────────────────────────────────
NUM_CALIB_FRAMES = 100 # Número de frames para calibração
NUM_DETECT_FRAMES = 10 # Número de frames para acumulação antes de calcular a moda na detecção
# Variável global para armazenar o frame de profundidade atual (para uso no callback)
current_depth_frame = None
show_grid = False
filtro1 = True
filtro2 = True
filtro3 = True
filtro4 = True
# ───────────────────────────────────────────────
# Criação do pipeline DepthAI
# ───────────────────────────────────────────────
pipeline = dai.Pipeline()
width, height = 1280, 720
# 📷 Câmera RGB
# Nó da câmera RGB
cam_rgb = pipeline.create(dai.node.ColorCamera)
cam_rgb.setPreviewSize(width, height)
cam_rgb.setPreviewSize(RGB_WIDTH, RGB_HEIGHT)
cam_rgb.setBoardSocket(dai.CameraBoardSocket.RGB)
cam_rgb.setInterleaved(False)
# Criar XLinkOut para saída RGB
xout_rgb = pipeline.create(dai.node.XLinkOut)
xout_rgb.setStreamName("rgb")
cam_rgb.preview.link(xout_rgb.input)
# 🔹 Câmera de Profundidade
# Nó de profundidade
mono_left = pipeline.create(dai.node.MonoCamera)
mono_right = pipeline.create(dai.node.MonoCamera)
stereo = pipeline.create(dai.node.StereoDepth)
mono_left.setResolution(dai.MonoCameraProperties.SensorResolution.THE_400_P)
mono_right.setResolution(dai.MonoCameraProperties.SensorResolution.THE_400_P)
mono_left.setResolution(dai.MonoCameraProperties.SensorResolution.THE_480_P)
mono_right.setResolution(dai.MonoCameraProperties.SensorResolution.THE_480_P)
mono_left.setBoardSocket(dai.CameraBoardSocket.LEFT)
mono_right.setBoardSocket(dai.CameraBoardSocket.RIGHT)
# Configuração do StereoDepth
stereo.setDefaultProfilePreset(dai.node.StereoDepth.PresetMode.HIGH_DENSITY)
stereo.setLeftRightCheck(True)
stereo.setSubpixel(True)
stereo = pipeline.create(dai.node.StereoDepth)
stereo.setDefaultProfilePreset(dai.node.StereoDepth.PresetMode.ROBOTICS)
#stereo.initialConfig.setConfidenceThreshold(250) # Remove ruído, mantendo apenas pontos confiáveis
#stereo.initialConfig.setMedianFilter(dai.MedianFilter.KERNEL_7x7) # Usa filtro de mediana forte
#stereo.setLeftRightCheck(True) # Ativa verificação para evitar erros
#stereo.setExtendedDisparity(False) # Reduz ruído em distâncias curtas
#stereo.setSubpixel(True) # Aumenta a precisão da profundidade
mono_left.out.link(stereo.left)
mono_right.out.link(stereo.right)
# Criar XLinkOut para profundidade
xout_depth = pipeline.create(dai.node.XLinkOut)
xout_depth.setStreamName("depth")
stereo.depth.link(xout_depth.input)
device_global = None
selected_device_info = None
camera_iniciada = False
def initialize_device():
global device_global, selected_device_info, camera_iniciada
# 🔹 Função para enviar vídeo via Flask
def generate_video(camera_index):
# Listar todas as câmeras conectadas
devices = dai.Device.getAllAvailableDevices()
@ -80,101 +172,436 @@ def generate_video(camera_index):
selected_device_info = devices[camera_index] # Seleciona a câmera correta pelo índice
print(f"Usando câmera: {selected_device_info.name} (ID: {selected_device_info.mxid})")
with dai.Device(pipeline, selected_device_info) as device: # 🔹 Agora usa a câmera correta
rgb_queue = device.getOutputQueue(name="rgb", maxSize=4, blocking=False)
depth_queue = device.getOutputQueue(name="depth", maxSize=4, blocking=False)
device_global = dai.Device(pipeline, selected_device_info)
camera_iniciada = True
readings = []
# 🔹 Função para enviar vídeo via Flask
def process_depth_data():
while True:
frame_data = rgb_queue.get()
if frame_data is None:
continue
if camera_iniciada == False:
initialize_device()
global device_global, selected_device_info
timestamp = time.time()
depth_queue = device_global.getOutputQueue(name="depth", maxSize=1, blocking=False)
# 📏 Captura Profundidade
# Função para calibrar a região do solo utilizando a moda
def calibrate_ground():
print("Calibrando região do solo: coletando {} frames...".format(NUM_CALIB_FRAMES))
calib_data = np.zeros((GROUND_ROWS, GROUND_CELLS, NUM_CALIB_FRAMES))
for frame_idx in range(NUM_CALIB_FRAMES):
depth_frame = depth_queue.get().getFrame()
depth_frame = apply_depth_filters(depth_frame)
for i in range(GROUND_ROWS):
y_start = HEIGHT - GROUND_REGION_HEIGHT + i * row_height_ground
y_end = y_start + row_height_ground
scale = GROUND_TOP_SCALE + (i / (GROUND_ROWS - 1)) * (1 - GROUND_TOP_SCALE) if GROUND_ROWS > 1 else 1
effective_width = int(WIDTH * scale)
cell_width = effective_width / GROUND_CELLS
for j in range(GROUND_CELLS):
x_start = int(WIDTH / 2 - effective_width / 2 + j * cell_width)
x_end = int(x_start + cell_width)
calib_data[i, j, frame_idx] = np.mean(depth_frame[y_start:y_end, x_start:x_end])
ground_ref = np.zeros((GROUND_ROWS, GROUND_CELLS))
for i in range(GROUND_ROWS):
for j in range(GROUND_CELLS):
ground_ref[i, j] = calc_mode(calib_data[i, j, :])
print("Calibração da região do solo concluída!")
return ground_ref
# Normaliza a profundidade para visualização (mapa de calor)
depth_visual = cv2.normalize(depth_frame, None, 0, 255, cv2.NORM_MINMAX, dtype=cv2.CV_8U)
depth_visual = cv2.applyColorMap(depth_visual, cv2.COLORMAP_JET)
# Função para calibrar a região aérea utilizando a moda
def calibrate_air():
print("Calibrando região aérea: coletando {} frames...".format(NUM_CALIB_FRAMES))
calib_data_air = np.zeros((AIR_ROWS, AIR_COLS, NUM_CALIB_FRAMES))
row_height_air = AIR_REGION_HEIGHT // AIR_ROWS
cell_width_air = WIDTH // AIR_COLS
for frame_idx in range(NUM_CALIB_FRAMES):
depth_frame = depth_queue.get().getFrame()
depth_frame = apply_depth_filters(depth_frame)
for i in range(AIR_ROWS):
y_start = i * row_height_air
y_end = y_start + row_height_air
for j in range(AIR_COLS):
x_start = j * cell_width_air
x_end = x_start + cell_width_air
calib_data_air[i, j, frame_idx] = np.mean(depth_frame[y_start:y_end, x_start:x_end])
air_ref = np.zeros((AIR_ROWS, AIR_COLS))
for i in range(AIR_ROWS):
for j in range(AIR_COLS):
air_ref[i, j] = calc_mode(calib_data_air[i, j, :])
print("Calibração da região aérea concluída!")
return air_ref
# 📡 Enviar dados via MQTT (Apenas a matriz de profundidade reduzida)
depth_data = depth_frame.tolist() # Converte a matriz para lista JSON
# Função para calibrar a distância utilizando a moda
def calibrate_distance(alvo=2500):
global GROUND_REGION_HEIGHT, AIR_REGION_HEIGHT # Garantir que estamos alterando as variáveis globais
NUM_LINHAS_ANALISE = 80 # Número de linhas horizontais para análise
ALTURA_LINHA = HEIGHT // NUM_LINHAS_ANALISE # Altura de cada linha
PROFUNDIDADE_ALVO = alvo # Profundidade alvo em cm para definir a região do solo dinamicamente
media_profundidade_acumulada = np.zeros((NUM_LINHAS_ANALISE, NUM_CALIB_FRAMES))
print("Calibrando profundidade média com {} frames...".format(NUM_CALIB_FRAMES))
for frame_idx in range(NUM_CALIB_FRAMES):
depth_frame = depth_queue.get().getFrame()
depth_frame = apply_depth_filters(depth_frame)
for i in range(NUM_LINHAS_ANALISE):
y_start = HEIGHT - (i + 1) * ALTURA_LINHA
y_end = y_start + ALTURA_LINHA
x_start_crop = int(WIDTH * 0.0)
x_end_crop = int(WIDTH * 1.0)
region_values = depth_frame[y_start:y_end, x_start_crop:x_end_crop].flatten()
valid_values = region_values[(region_values > 0) & (region_values < 10000)]
if valid_values.size > 0:
media_profundidade_acumulada[i, frame_idx] = np.mean(valid_values)
else:
media_profundidade_acumulada[i, frame_idx] = 9999
media_profundidade = np.array([calc_mode(media_profundidade_acumulada[i, :]) for i in range(NUM_LINHAS_ANALISE)])
#print("Médias de profundidade por linha (usando moda):", media_profundidade)
erro_minimo = float('inf')
linha_alvo = None
for i in range(NUM_LINHAS_ANALISE):
erro = abs(media_profundidade[i] - PROFUNDIDADE_ALVO)
if erro < erro_minimo:
erro_minimo = erro
linha_alvo = i
if linha_alvo is not None:
linha_alvo += 1
GROUND_REGION_HEIGHT = HEIGHT - ((NUM_LINHAS_ANALISE - linha_alvo) * ALTURA_LINHA)
else:
GROUND_REGION_HEIGHT = HEIGHT // 2
AIR_REGION_HEIGHT = HEIGHT - GROUND_REGION_HEIGHT
v = GROUND_REGION_HEIGHT // GROUND_ROWS
print("Novo GROUND_REGION_HEIGHT:", GROUND_REGION_HEIGHT)
print("Novo AIR_REGION_HEIGHT:", AIR_REGION_HEIGHT)
print("Novo tamanho das linhas do solo:", v)
return v
# Gerar json dos dados das subdivisoes
def gerar_json_subdivisoes():
data = {
"x_max": WIDTH,
"y_max": HEIGHT,
"subdivisoes_cima": {
"num_linhas": AIR_ROWS,
"num_colunas": AIR_COLS,
"celulas": []
},
"subdivisoes_chao": {
"num_linhas": GROUND_ROWS,
"num_colunas": GROUND_CELLS,
"celulas": []
}
}
# Subdivisões da região aérea
row_height_air = AIR_REGION_HEIGHT // AIR_ROWS
cell_width_air = WIDTH // AIR_COLS
for i in range(AIR_ROWS):
for j in range(AIR_COLS):
x_start = j * cell_width_air
y_start = i * row_height_air
data["subdivisoes_cima"]["celulas"].append({
"linha": i,
"coluna": j,
"x": x_start,
"y": y_start,
"largura": cell_width_air,
"altura": row_height_air,
"profundidade_media": smoothed_air[i, j],
"profundidade_calibragem": air_reference[i, j]
})
# Subdivisões da região do solo
row_height_ground = GROUND_REGION_HEIGHT // GROUND_ROWS
for i in range(GROUND_ROWS):
scale = (GROUND_TOP_SCALE + (i / (GROUND_ROWS - 1)) * (1 - GROUND_TOP_SCALE)) if GROUND_ROWS > 1 else 1
effective_width = int(WIDTH * scale)
cell_width = effective_width / GROUND_CELLS
y_start = HEIGHT - GROUND_REGION_HEIGHT + i * row_height_ground
start_x = int(WIDTH / 2 - effective_width / 2)
try:
memory_usage = device.getDdrMemoryUsage()
for j in range(GROUND_CELLS):
x_start = int(start_x + j * cell_width)
data["subdivisoes_chao"]["celulas"].append({
"linha": i,
"coluna": j,
"x": x_start,
"y": y_start,
"largura": int(cell_width),
"altura": row_height_ground,
"profundidade_media": smoothed_ground[i, j],
"profundidade_calibragem": ground_reference[i, j]
})
return data
# Calibração inicial
row_height_ground = calibrate_distance()
ground_reference = calibrate_ground()
air_reference = calibrate_air()
# Preparação para a detecção usando moda (acumula dados de alguns frames)
detect_counter = 0
detect_data_ground = np.zeros((GROUND_ROWS, GROUND_CELLS, NUM_DETECT_FRAMES))
detect_data_air = np.zeros((AIR_ROWS, AIR_COLS, NUM_DETECT_FRAMES))
last_detect_ground = np.zeros((GROUND_ROWS, GROUND_CELLS))
last_detect_air = np.zeros((AIR_ROWS, AIR_COLS))
# Parâmetro para o filtro de média móvel
alpha = 0.4 # ajuste entre 0 e 1 (valores menores = mais suave)
# Inicialize as grids filtradas com os valores de calibração (ou com zeros, se preferir)
smoothed_ground = ground_reference.copy()
smoothed_air = air_reference.copy()
last_time = time.time()
target_fps = 30 # Limita o FPS
readings = []
while True:
current_time = time.time()
if current_time - last_time < 1 / target_fps:
time.sleep(0.01)
continue
last_time = current_time
in_depth = depth_queue.tryGet()
if in_depth is None:
continue
depth_frame = in_depth.getFrame()
# Aplicação dos filtros em sequência
depth_frame = apply_depth_filters(depth_frame)
# Gera o mapa de calor
heatmap = generate_heatmap(depth_frame)
# Cria uma cópia do heatmap para desenhar o overlay
heatmap_overlay = heatmap.copy()
# ─────────────────────────────────────────────
# Atualiza a grid do SOLO (região inferior) com média móvel
# ─────────────────────────────────────────────
for i in range(GROUND_ROWS):
y_start = HEIGHT - GROUND_REGION_HEIGHT + i * row_height_ground
y_end = y_start + row_height_ground
scale = (GROUND_TOP_SCALE +
(i / (GROUND_ROWS - 1)) * (1 - GROUND_TOP_SCALE)) if GROUND_ROWS > 1 else 1
effective_width = int(WIDTH * scale)
cell_width = effective_width / GROUND_CELLS
for j in range(GROUND_CELLS):
x_start = int(WIDTH / 2 - effective_width / 2 + j * cell_width)
x_end = int(x_start + cell_width)
# Obtém os valores válidos da região
region_values = depth_frame[y_start:y_end, x_start:x_end].flatten()
valid_values = region_values[(region_values > 0) & (region_values < 10000)] # Remove valores inválidos
# Calcula a média da célula e atualiza as variáveis
if valid_values.size > 0:
measurement = np.mean(valid_values)
else:
measurement = 9999 # Define um valor alto se não houver dados válidos
# Atualiza a grid suavizada com a média móvel
smoothed_ground[i, j] = alpha * measurement + (1 - alpha) * smoothed_ground[i, j]
# Atualiza a matriz last_detect_ground com a média real da célula
last_detect_ground[i, j] = measurement
# ─────────────────────────────────────────────
# Atualiza a grid da REGIÃO AÉREA (parte superior) com média móvel
# ─────────────────────────────────────────────
row_height_air = AIR_REGION_HEIGHT // AIR_ROWS
cell_width_air = WIDTH // AIR_COLS
for i in range(AIR_ROWS):
y_start = i * row_height_air
y_end = y_start + row_height_air
for j in range(AIR_COLS):
x_start = j * cell_width_air
x_end = x_start + cell_width_air
# Obtém os valores válidos da região
region_values = depth_frame[y_start:y_end, x_start:x_end].flatten()
valid_values = region_values[(region_values > 0) & (region_values < 10000)] # Remove valores inválidos
# Calcula a média da célula e atualiza as variáveis
if valid_values.size > 0:
measurement = np.mean(valid_values)
else:
measurement = 9999 # Define um valor alto se não houver dados válidos
# Atualiza a grid suavizada com a média móvel
smoothed_air[i, j] = alpha * measurement + (1 - alpha) * smoothed_air[i, j]
# Atualiza a matriz last_detect_air com a média real da célula
last_detect_air[i, j] = measurement
# ─────────────────────────────────────────────
# Processamento da detecção: Região do SOLO
# ─────────────────────────────────────────────
for i in range(GROUND_ROWS):
y_start = HEIGHT - GROUND_REGION_HEIGHT + i * row_height_ground
y_end = y_start + row_height_ground
scale = (GROUND_TOP_SCALE + (i / (GROUND_ROWS - 1)) * (1 - GROUND_TOP_SCALE)) if GROUND_ROWS > 1 else 1
effective_width = int(WIDTH * scale)
cell_width = effective_width / GROUND_CELLS
for j in range(GROUND_CELLS):
x_start = int(WIDTH / 2 - effective_width / 2 + j * cell_width)
x_end = int(x_start + cell_width)
# Compara o valor suavizado com a referência calibrada
if smoothed_ground[i, j] < (ground_reference[i, j] - DEPTH_LIMIT):
# Obstáculo (valor menor: objeto mais próximo)
cv2.rectangle(heatmap_overlay, (x_start, y_start), (x_end, y_end), (0, 0, 255), -1)
elif smoothed_ground[i, j] > (ground_reference[i, j] + DEPTH_LIMIT):
# Erosão (valor maior: superfície rebaixada)
cv2.rectangle(heatmap_overlay, (x_start, y_start), (x_end, y_end), (0, 255, 255), -1)
if show_grid:
cv2.rectangle(heatmap, (x_start, y_start), (x_end, y_end), (255, 255, 255), 1)
# ─────────────────────────────────────────────
# Processamento da detecção: Região AÉREA
# ─────────────────────────────────────────────
for i in range(AIR_ROWS):
y_start = i * row_height_air
y_end = y_start + row_height_air
for j in range(AIR_COLS):
x_start = j * cell_width_air
x_end = x_start + cell_width_air
if smoothed_air[i, j] < (air_reference[i, j] - DEPTH_LIMIT):
cv2.rectangle(heatmap_overlay, (x_start, y_start), (x_end, y_end), (0, 255, 0), -1)
if show_grid:
cv2.rectangle(heatmap, (x_start, y_start), (x_end, y_end), (255, 255, 255), 1)
try:
memory_usage = device_global.getDdrMemoryUsage()
memory_info = {
"remaining": memory_usage.remaining,
"total": memory_usage.total,
"used": memory_usage.used
}
except:
except:
memory_info = None # Se houver erro, define como None
try:
temp = device.getChipTemperature()
try:
temp = device_global.getChipTemperature()
temp_info = {
"css": temp.css,
"mss": temp.mss,
"upa": temp.upa,
"dss": temp.dss
}
except:
except:
temp_info = None # Se houver erro, define como None
device_data = {
"id": selected_device_info.getMxId(), # ID do dispositivo
"name": selected_device_info.name, # Nome do dispositivo
"state": selected_device_info.state.name, # Estado do dispositivo
"usb_speed": str(device.getUsbSpeed().name) if hasattr(device, 'getUsbSpeed') else None, # Velocidade USB
"available_camera_sensors": [sensor.name for sensor in device.getConnectedCameras()], # Sensores de câmera disponíveis
"version": str(device.getDeviceInfo().protocol) if hasattr(device, 'getDeviceInfo') else None, # Versão do protocolo
"memory_usage": memory_info, # Uso de memória DDR
"temperature": temp_info, # Temperatura do chip
"bootloader_version": str(device.getBootloaderVersion()) if hasattr(device, 'getBootloaderVersion') else None, # Bootloader
"is_pipeline_running": device.isPipelineRunning() if hasattr(device, 'isPipelineRunning') else None # Pipeline rodando?
}
device_data = {
"id": selected_device_info.getMxId(), # ID do dispositivo
"name": selected_device_info.name, # Nome do dispositivo
"state": selected_device_info.state.name, # Estado do dispositivo
"usb_speed": str(device_global.getUsbSpeed().name) if hasattr(device_global, 'getUsbSpeed') else None, # Velocidade USB
"available_camera_sensors": [sensor.name for sensor in device_global.getConnectedCameras()], # Sensores de câmera disponíveis
"version": str(device_global.getDeviceInfo().protocol) if hasattr(device_global, 'getDeviceInfo') else None, # Versão do protocolo
"memory_usage": memory_info, # Uso de memória DDR
"temperature": temp_info, # Temperatura do chip
"bootloader_version": str(device_global.getBootloaderVersion()) if hasattr(device_global, 'getBootloaderVersion') else None, # Bootloader
"is_pipeline_running": device_global.isPipelineRunning() if hasattr(device_global, 'isPipelineRunning') else None # Pipeline rodando?
}
json_data = {
'timestamp': timestamp,
'device_data': device_data,
'x_max': width,
'y_max': height,
'depth_data': depth_data,
}
json_data = {
'timestamp': current_time,
'device_data': device_data,
'x_max': WIDTH,
'y_max': HEIGHT,
'subdivisoes': gerar_json_subdivisoes(),
}
readings.append(json_data)
readings.append(json_data)
# Enviar apenas a cada max_readings capturas
if len(readings) >= max_readings:
mensagem_relevante = readings[-1]
mqtt_client.publish(mqtt_topic, json.dumps(mensagem_relevante).encode('utf-8'))
readings.clear()
# Enviar apenas a cada max_readings capturas
if len(readings) >= max_readings:
mensagem_relevante = readings[-1]
mqtt_client.publish(mqtt_topic, json.dumps(mensagem_relevante).encode('utf-8'))
readings.clear()
frame = frame_data.getCvFrame()
ret, buffer = cv2.imencode('.jpg', frame)
frame = buffer.tobytes()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
video_frame = heatmap
ret, buffer = cv2.imencode('.jpg', video_frame, [cv2.IMWRITE_JPEG_QUALITY, 80]) # Reduz qualidade para 80%
frame = buffer.tobytes()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
# 🔹 Função para enviar vídeo via Flask
def view_rgb_video():
if camera_iniciada == False:
initialize_device()
global device_global, selected_device_info
rgb_queue = device_global.getOutputQueue(name="rgb", maxSize=1, blocking=False)
while True:
in_rgb = rgb_queue.tryGet()
if in_rgb is None:
continue
rgb_frame = in_rgb.getCvFrame()
video_frame = rgb_frame
ret, buffer = cv2.imencode('.jpg', video_frame, [cv2.IMWRITE_JPEG_QUALITY, 80]) # Reduz qualidade para 80%
frame = buffer.tobytes()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
def send_script_ready():
mqtt_client.publish(mqtt_topic, "OK")
def send_script_ready1():
mqtt_client.publish(mqtt_topic, "OK_1")
def send_script_ready2():
mqtt_client.publish(mqtt_topic, "OK_2")
def run_flask_server():
app.run(host='0.0.0.0', port=porta, threaded=True, debug=False)
@app.route('/' + url, methods=['GET'])
def video_feed():
camera_index = int(request.args.get('camera_index'))
return Response(generate_video(camera_index), mimetype='multipart/x-mixed-replace; boundary=frame')
# 🔹 Servidores Flask para RGB e Heatmap
@app.route('/' + url_rgb, methods=['GET'])
def video_feed_rgb():
return Response(view_rgb_video(), mimetype='multipart/x-mixed-replace; boundary=frame')
@app.route('/' + url_heatmap, methods=['GET'])
def video_feed_heatmap():
return Response(process_depth_data(), mimetype='multipart/x-mixed-replace; boundary=frame')
if __name__ == '__main__':
mqtt_thread = threading.Thread(target=send_script_ready)
mqtt_thread.start()
run_flask_server()
flask_thread = threading.Thread(target=run_flask_server)
flask_thread.start()
time.sleep(1)
mqtt_thread1 = threading.Thread(target=send_script_ready1)
mqtt_thread1.start()
time.sleep(5)
mqtt_thread2 = threading.Thread(target=send_script_ready2)
mqtt_thread2.start()

View File

@ -185,8 +185,18 @@ namespace AgroMonitor.Forms
private async Task CarregarOperacao()
{
(bool carregado, List<string> ruasSelecionadas) = await Variaveis.OperacaoEmAndamento.CarregarParametrizacaoOperacao(pnlMapa, lblMapaCarregado);
if (carregado)
(bool carregado, List<string> ruasSelecionadas) = Variaveis.OperacaoEmAndamento.CarregarParametrizacaoOperacao(pnlMapa, lblMapaCarregado);
bool condicaoOperacaoCarregada() => Variaveis.OperacaoEmAndamento.Trajetoria?.CorredorAtual != null;
bool resultado = await FuncoesGlobais.AguardarCondicaoAsync(condicaoOperacaoCarregada, 5000, 200);
if (!resultado)
{
MessageBox.Show($"Erro ao carregar operação!{Environment.NewLine}Erro ao carregar a trajetória do mapa!", "Erro", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
if (carregado && resultado)
{
tabControl1.SelectedIndex = 1;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long