diff --git a/AgroBase/.vs/AgroBase/FileContentIndex/23296f30-29ae-48a6-aa25-c44041c646a8.vsidx b/AgroBase/.vs/AgroBase/FileContentIndex/23296f30-29ae-48a6-aa25-c44041c646a8.vsidx
new file mode 100644
index 000000000..d1606cbd6
Binary files /dev/null and b/AgroBase/.vs/AgroBase/FileContentIndex/23296f30-29ae-48a6-aa25-c44041c646a8.vsidx differ
diff --git a/AgroBase/.vs/AgroBase/FileContentIndex/2b2025f3-b12f-47ce-99ac-d4181ffe23bc.vsidx b/AgroBase/.vs/AgroBase/FileContentIndex/2b2025f3-b12f-47ce-99ac-d4181ffe23bc.vsidx
new file mode 100644
index 000000000..387d73827
Binary files /dev/null and b/AgroBase/.vs/AgroBase/FileContentIndex/2b2025f3-b12f-47ce-99ac-d4181ffe23bc.vsidx differ
diff --git a/AgroBase/.vs/AgroBase/FileContentIndex/306e5ebe-4c11-4859-bdb3-7ab6e1be4a57.vsidx b/AgroBase/.vs/AgroBase/FileContentIndex/306e5ebe-4c11-4859-bdb3-7ab6e1be4a57.vsidx
new file mode 100644
index 000000000..d6e14b3f4
Binary files /dev/null and b/AgroBase/.vs/AgroBase/FileContentIndex/306e5ebe-4c11-4859-bdb3-7ab6e1be4a57.vsidx differ
diff --git a/AgroBase/.vs/AgroBase/FileContentIndex/57495774-0927-42cd-aef0-dbe63597ddaa.vsidx b/AgroBase/.vs/AgroBase/FileContentIndex/57495774-0927-42cd-aef0-dbe63597ddaa.vsidx
new file mode 100644
index 000000000..748c83cb7
Binary files /dev/null and b/AgroBase/.vs/AgroBase/FileContentIndex/57495774-0927-42cd-aef0-dbe63597ddaa.vsidx differ
diff --git a/AgroBase/.vs/AgroBase/FileContentIndex/6b665804-6afd-4566-a1e3-e84faee08e57.vsidx b/AgroBase/.vs/AgroBase/FileContentIndex/6b665804-6afd-4566-a1e3-e84faee08e57.vsidx
deleted file mode 100644
index 59b835d71..000000000
Binary files a/AgroBase/.vs/AgroBase/FileContentIndex/6b665804-6afd-4566-a1e3-e84faee08e57.vsidx and /dev/null differ
diff --git a/AgroBase/.vs/AgroBase/FileContentIndex/b2b64049-8e44-4fe4-9531-6446f4086864.vsidx b/AgroBase/.vs/AgroBase/FileContentIndex/b2b64049-8e44-4fe4-9531-6446f4086864.vsidx
new file mode 100644
index 000000000..89197f170
Binary files /dev/null and b/AgroBase/.vs/AgroBase/FileContentIndex/b2b64049-8e44-4fe4-9531-6446f4086864.vsidx differ
diff --git a/AgroBase/.vs/AgroBase/v17/.suo b/AgroBase/.vs/AgroBase/v17/.suo
index 61d3ab95c..df3fa1df0 100644
Binary files a/AgroBase/.vs/AgroBase/v17/.suo and b/AgroBase/.vs/AgroBase/v17/.suo differ
diff --git a/AgroBase/AgroBase/AgroBase.csproj b/AgroBase/AgroBase/AgroBase.csproj
index 473db3d17..6c7a4e87f 100644
--- a/AgroBase/AgroBase/AgroBase.csproj
+++ b/AgroBase/AgroBase/AgroBase.csproj
@@ -341,6 +341,12 @@
frmOID.cs
+
+ Form
+
+
+ frmOperarioSonar.cs
+
Form
@@ -511,6 +517,7 @@
+
@@ -557,6 +564,7 @@
+
@@ -781,6 +789,9 @@
frmOID.cs
+
+ frmOperarioSonar.cs
+
frmPinout.cs
diff --git a/AgroBase/AgroBase/Forms/frmOperarioSonar.Designer.cs b/AgroBase/AgroBase/Forms/frmOperarioSonar.Designer.cs
new file mode 100644
index 000000000..445792df1
--- /dev/null
+++ b/AgroBase/AgroBase/Forms/frmOperarioSonar.Designer.cs
@@ -0,0 +1,511 @@
+namespace AgroBase.Forms
+{
+ partial class frmOperarioSonar
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea2 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
+ System.Windows.Forms.DataVisualization.Charting.Legend legend2 = new System.Windows.Forms.DataVisualization.Charting.Legend();
+ System.Windows.Forms.DataVisualization.Charting.Series series2 = new System.Windows.Forms.DataVisualization.Charting.Series();
+ this.picRGB = new System.Windows.Forms.PictureBox();
+ this.picHeatmap = new System.Windows.Forms.PictureBox();
+ this.lblRGB = new System.Windows.Forms.Label();
+ this.lblHeatmap = new System.Windows.Forms.Label();
+ this.btnLeituraRGB = new System.Windows.Forms.Button();
+ this.lblLeituraRGB = new System.Windows.Forms.Label();
+ this.lblLeituraHeatmap = new System.Windows.Forms.Label();
+ this.btnLeituraHeatmap = new System.Windows.Forms.Button();
+ this.btnIniciarProcessamento = new System.Windows.Forms.Button();
+ this.lblCameras = new System.Windows.Forms.Label();
+ this.cmbCameras = new System.Windows.Forms.ComboBox();
+ this.btnAtualizarCameras = new System.Windows.Forms.Button();
+ this.btnPing = new System.Windows.Forms.Button();
+ this.btnCalibrarGrades = new System.Windows.Forms.Button();
+ this.lblUltimaLeitura = new System.Windows.Forms.Label();
+ this.btnReqStatusDispositivo = new System.Windows.Forms.Button();
+ this.btnReqAnomalias = new System.Windows.Forms.Button();
+ this.btnReqSolo = new System.Windows.Forms.Button();
+ this.chbIniciarScript = new System.Windows.Forms.CheckBox();
+ this.lblDebugFrame = new System.Windows.Forms.Label();
+ this.picDebug = new System.Windows.Forms.PictureBox();
+ this.lblLeituraDebug = new System.Windows.Forms.Label();
+ this.dgvAnomalias = new System.Windows.Forms.DataGridView();
+ this.dgvSolo = new System.Windows.Forms.DataGridView();
+ this.chartPerfilSolo = new System.Windows.Forms.DataVisualization.Charting.Chart();
+ this.lblAnomalias = new System.Windows.Forms.Label();
+ this.lblSolo = new System.Windows.Forms.Label();
+ this.lblPerfilSolo = new System.Windows.Forms.Label();
+ this.txtVelocidade = new System.Windows.Forms.TextBox();
+ this.txtDistanciaMax = new System.Windows.Forms.TextBox();
+ this.lblVelocidade = new System.Windows.Forms.Label();
+ this.lblDistanciaMax = new System.Windows.Forms.Label();
+ this.lblTamanhoMin = new System.Windows.Forms.Label();
+ this.txtTamanhoMin = new System.Windows.Forms.TextBox();
+ this.chbReqAutomatico = new System.Windows.Forms.CheckBox();
+ ((System.ComponentModel.ISupportInitialize)(this.picRGB)).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)(this.picHeatmap)).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)(this.picDebug)).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)(this.dgvAnomalias)).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)(this.dgvSolo)).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)(this.chartPerfilSolo)).BeginInit();
+ this.SuspendLayout();
+ //
+ // picRGB
+ //
+ this.picRGB.Location = new System.Drawing.Point(15, 25);
+ this.picRGB.Name = "picRGB";
+ this.picRGB.Size = new System.Drawing.Size(288, 267);
+ this.picRGB.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
+ this.picRGB.TabIndex = 0;
+ this.picRGB.TabStop = false;
+ //
+ // picHeatmap
+ //
+ this.picHeatmap.Location = new System.Drawing.Point(309, 25);
+ this.picHeatmap.Name = "picHeatmap";
+ this.picHeatmap.Size = new System.Drawing.Size(288, 267);
+ this.picHeatmap.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
+ this.picHeatmap.TabIndex = 1;
+ this.picHeatmap.TabStop = false;
+ //
+ // lblRGB
+ //
+ this.lblRGB.AutoSize = true;
+ this.lblRGB.Location = new System.Drawing.Point(12, 9);
+ this.lblRGB.Name = "lblRGB";
+ this.lblRGB.Size = new System.Drawing.Size(62, 13);
+ this.lblRGB.TabIndex = 2;
+ this.lblRGB.Text = "RGB Frame";
+ //
+ // lblHeatmap
+ //
+ this.lblHeatmap.AutoSize = true;
+ this.lblHeatmap.Location = new System.Drawing.Point(309, 9);
+ this.lblHeatmap.Name = "lblHeatmap";
+ this.lblHeatmap.Size = new System.Drawing.Size(82, 13);
+ this.lblHeatmap.TabIndex = 3;
+ this.lblHeatmap.Text = "Heatmap Frame";
+ //
+ // btnLeituraRGB
+ //
+ this.btnLeituraRGB.Location = new System.Drawing.Point(15, 298);
+ this.btnLeituraRGB.Name = "btnLeituraRGB";
+ this.btnLeituraRGB.Size = new System.Drawing.Size(75, 23);
+ this.btnLeituraRGB.TabIndex = 4;
+ this.btnLeituraRGB.Text = "Requisitar";
+ this.btnLeituraRGB.UseVisualStyleBackColor = true;
+ this.btnLeituraRGB.Click += new System.EventHandler(this.btnLeituraRGB_Click);
+ //
+ // lblLeituraRGB
+ //
+ this.lblLeituraRGB.AutoSize = true;
+ this.lblLeituraRGB.Location = new System.Drawing.Point(96, 303);
+ this.lblLeituraRGB.Name = "lblLeituraRGB";
+ this.lblLeituraRGB.Size = new System.Drawing.Size(62, 13);
+ this.lblLeituraRGB.TabIndex = 5;
+ this.lblLeituraRGB.Text = "Leitura em: ";
+ //
+ // lblLeituraHeatmap
+ //
+ this.lblLeituraHeatmap.AutoSize = true;
+ this.lblLeituraHeatmap.Location = new System.Drawing.Point(390, 303);
+ this.lblLeituraHeatmap.Name = "lblLeituraHeatmap";
+ this.lblLeituraHeatmap.Size = new System.Drawing.Size(62, 13);
+ this.lblLeituraHeatmap.TabIndex = 6;
+ this.lblLeituraHeatmap.Text = "Leitura em: ";
+ //
+ // btnLeituraHeatmap
+ //
+ this.btnLeituraHeatmap.Location = new System.Drawing.Point(309, 298);
+ this.btnLeituraHeatmap.Name = "btnLeituraHeatmap";
+ this.btnLeituraHeatmap.Size = new System.Drawing.Size(75, 23);
+ this.btnLeituraHeatmap.TabIndex = 7;
+ this.btnLeituraHeatmap.Text = "Requisitar";
+ this.btnLeituraHeatmap.UseVisualStyleBackColor = true;
+ this.btnLeituraHeatmap.Click += new System.EventHandler(this.btnLeituraHeatmap_Click);
+ //
+ // btnIniciarProcessamento
+ //
+ this.btnIniciarProcessamento.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.btnIniciarProcessamento.Location = new System.Drawing.Point(923, 81);
+ this.btnIniciarProcessamento.Name = "btnIniciarProcessamento";
+ this.btnIniciarProcessamento.Size = new System.Drawing.Size(179, 23);
+ this.btnIniciarProcessamento.TabIndex = 8;
+ this.btnIniciarProcessamento.Text = "Iniciar Processamento";
+ this.btnIniciarProcessamento.UseVisualStyleBackColor = true;
+ this.btnIniciarProcessamento.Click += new System.EventHandler(this.btnIniciarProcessamento_Click);
+ //
+ // lblCameras
+ //
+ this.lblCameras.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.lblCameras.AutoSize = true;
+ this.lblCameras.Location = new System.Drawing.Point(920, 9);
+ this.lblCameras.Name = "lblCameras";
+ this.lblCameras.Size = new System.Drawing.Size(108, 13);
+ this.lblCameras.TabIndex = 9;
+ this.lblCameras.Text = "Cameras Conectadas";
+ //
+ // cmbCameras
+ //
+ this.cmbCameras.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.cmbCameras.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.cmbCameras.FormattingEnabled = true;
+ this.cmbCameras.Location = new System.Drawing.Point(923, 25);
+ this.cmbCameras.Name = "cmbCameras";
+ this.cmbCameras.Size = new System.Drawing.Size(179, 21);
+ this.cmbCameras.TabIndex = 10;
+ //
+ // btnAtualizarCameras
+ //
+ this.btnAtualizarCameras.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.btnAtualizarCameras.Location = new System.Drawing.Point(923, 52);
+ this.btnAtualizarCameras.Name = "btnAtualizarCameras";
+ this.btnAtualizarCameras.Size = new System.Drawing.Size(179, 23);
+ this.btnAtualizarCameras.TabIndex = 11;
+ this.btnAtualizarCameras.Text = "Atualizar Cameras";
+ this.btnAtualizarCameras.UseVisualStyleBackColor = true;
+ this.btnAtualizarCameras.Click += new System.EventHandler(this.btnAtualizarCameras_Click);
+ //
+ // btnPing
+ //
+ this.btnPing.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.btnPing.Location = new System.Drawing.Point(923, 133);
+ this.btnPing.Name = "btnPing";
+ this.btnPing.Size = new System.Drawing.Size(179, 23);
+ this.btnPing.TabIndex = 12;
+ this.btnPing.Text = "Requisitar Ping";
+ this.btnPing.UseVisualStyleBackColor = true;
+ this.btnPing.Click += new System.EventHandler(this.btnPing_Click);
+ //
+ // btnCalibrarGrades
+ //
+ this.btnCalibrarGrades.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.btnCalibrarGrades.Location = new System.Drawing.Point(923, 162);
+ this.btnCalibrarGrades.Name = "btnCalibrarGrades";
+ this.btnCalibrarGrades.Size = new System.Drawing.Size(179, 23);
+ this.btnCalibrarGrades.TabIndex = 13;
+ this.btnCalibrarGrades.Text = "Calibrar Grades";
+ this.btnCalibrarGrades.UseVisualStyleBackColor = true;
+ this.btnCalibrarGrades.Click += new System.EventHandler(this.btnCalibrarGrades_Click);
+ //
+ // lblUltimaLeitura
+ //
+ this.lblUltimaLeitura.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
+ this.lblUltimaLeitura.AutoSize = true;
+ this.lblUltimaLeitura.Location = new System.Drawing.Point(12, 737);
+ this.lblUltimaLeitura.Name = "lblUltimaLeitura";
+ this.lblUltimaLeitura.Size = new System.Drawing.Size(94, 13);
+ this.lblUltimaLeitura.TabIndex = 14;
+ this.lblUltimaLeitura.Text = "Ultima Leitura em: ";
+ //
+ // btnReqStatusDispositivo
+ //
+ this.btnReqStatusDispositivo.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.btnReqStatusDispositivo.Location = new System.Drawing.Point(923, 191);
+ this.btnReqStatusDispositivo.Name = "btnReqStatusDispositivo";
+ this.btnReqStatusDispositivo.Size = new System.Drawing.Size(179, 23);
+ this.btnReqStatusDispositivo.TabIndex = 15;
+ this.btnReqStatusDispositivo.Text = "Requisitar Status do Dispositivo";
+ this.btnReqStatusDispositivo.UseVisualStyleBackColor = true;
+ this.btnReqStatusDispositivo.Click += new System.EventHandler(this.btnReqStatusDispositivo_Click);
+ //
+ // btnReqAnomalias
+ //
+ this.btnReqAnomalias.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.btnReqAnomalias.Location = new System.Drawing.Point(923, 220);
+ this.btnReqAnomalias.Name = "btnReqAnomalias";
+ this.btnReqAnomalias.Size = new System.Drawing.Size(179, 23);
+ this.btnReqAnomalias.TabIndex = 16;
+ this.btnReqAnomalias.Text = "Requisitar Análise de Anomalias";
+ this.btnReqAnomalias.UseVisualStyleBackColor = true;
+ this.btnReqAnomalias.Click += new System.EventHandler(this.btnReqAnomalias_Click);
+ //
+ // btnReqSolo
+ //
+ this.btnReqSolo.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+ this.btnReqSolo.Location = new System.Drawing.Point(923, 249);
+ this.btnReqSolo.Name = "btnReqSolo";
+ this.btnReqSolo.Size = new System.Drawing.Size(179, 23);
+ this.btnReqSolo.TabIndex = 17;
+ this.btnReqSolo.Text = "Requisitar Análise do Solo";
+ this.btnReqSolo.UseVisualStyleBackColor = true;
+ this.btnReqSolo.Click += new System.EventHandler(this.btnReqSolo_Click);
+ //
+ // chbIniciarScript
+ //
+ this.chbIniciarScript.AutoSize = true;
+ this.chbIniciarScript.Location = new System.Drawing.Point(923, 110);
+ this.chbIniciarScript.Name = "chbIniciarScript";
+ this.chbIniciarScript.Size = new System.Drawing.Size(84, 17);
+ this.chbIniciarScript.TabIndex = 24;
+ this.chbIniciarScript.Text = "Iniciar Script";
+ this.chbIniciarScript.UseVisualStyleBackColor = true;
+ //
+ // lblDebugFrame
+ //
+ this.lblDebugFrame.AutoSize = true;
+ this.lblDebugFrame.Location = new System.Drawing.Point(603, 9);
+ this.lblDebugFrame.Name = "lblDebugFrame";
+ this.lblDebugFrame.Size = new System.Drawing.Size(71, 13);
+ this.lblDebugFrame.TabIndex = 26;
+ this.lblDebugFrame.Text = "Debug Frame";
+ //
+ // picDebug
+ //
+ this.picDebug.Location = new System.Drawing.Point(603, 25);
+ this.picDebug.Name = "picDebug";
+ this.picDebug.Size = new System.Drawing.Size(288, 267);
+ this.picDebug.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
+ this.picDebug.TabIndex = 25;
+ this.picDebug.TabStop = false;
+ //
+ // lblLeituraDebug
+ //
+ this.lblLeituraDebug.AutoSize = true;
+ this.lblLeituraDebug.Location = new System.Drawing.Point(603, 303);
+ this.lblLeituraDebug.Name = "lblLeituraDebug";
+ this.lblLeituraDebug.Size = new System.Drawing.Size(62, 13);
+ this.lblLeituraDebug.TabIndex = 27;
+ this.lblLeituraDebug.Text = "Leitura em: ";
+ //
+ // dgvAnomalias
+ //
+ this.dgvAnomalias.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
+ this.dgvAnomalias.Location = new System.Drawing.Point(15, 347);
+ this.dgvAnomalias.Name = "dgvAnomalias";
+ this.dgvAnomalias.Size = new System.Drawing.Size(582, 175);
+ this.dgvAnomalias.TabIndex = 28;
+ //
+ // dgvSolo
+ //
+ this.dgvSolo.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
+ this.dgvSolo.Location = new System.Drawing.Point(15, 542);
+ this.dgvSolo.Name = "dgvSolo";
+ this.dgvSolo.Size = new System.Drawing.Size(582, 175);
+ this.dgvSolo.TabIndex = 29;
+ //
+ // chartPerfilSolo
+ //
+ chartArea2.Name = "ChartArea1";
+ this.chartPerfilSolo.ChartAreas.Add(chartArea2);
+ legend2.Name = "Legend1";
+ this.chartPerfilSolo.Legends.Add(legend2);
+ this.chartPerfilSolo.Location = new System.Drawing.Point(606, 412);
+ this.chartPerfilSolo.Name = "chartPerfilSolo";
+ series2.ChartArea = "ChartArea1";
+ series2.Legend = "Legend1";
+ series2.Name = "Series1";
+ this.chartPerfilSolo.Series.Add(series2);
+ this.chartPerfilSolo.Size = new System.Drawing.Size(496, 305);
+ this.chartPerfilSolo.TabIndex = 30;
+ this.chartPerfilSolo.Text = "chart1";
+ //
+ // lblAnomalias
+ //
+ this.lblAnomalias.AutoSize = true;
+ this.lblAnomalias.Location = new System.Drawing.Point(12, 331);
+ this.lblAnomalias.Name = "lblAnomalias";
+ this.lblAnomalias.Size = new System.Drawing.Size(113, 13);
+ this.lblAnomalias.TabIndex = 31;
+ this.lblAnomalias.Text = "Anomalias Detectadas";
+ //
+ // lblSolo
+ //
+ this.lblSolo.AutoSize = true;
+ this.lblSolo.Location = new System.Drawing.Point(12, 526);
+ this.lblSolo.Name = "lblSolo";
+ this.lblSolo.Size = new System.Drawing.Size(154, 13);
+ this.lblSolo.TabIndex = 32;
+ this.lblSolo.Text = "Anomalias Detectadas No Solo";
+ //
+ // lblPerfilSolo
+ //
+ this.lblPerfilSolo.AutoSize = true;
+ this.lblPerfilSolo.Location = new System.Drawing.Point(603, 396);
+ this.lblPerfilSolo.Name = "lblPerfilSolo";
+ this.lblPerfilSolo.Size = new System.Drawing.Size(69, 13);
+ this.lblPerfilSolo.TabIndex = 33;
+ this.lblPerfilSolo.Text = "Perfil do Solo";
+ //
+ // txtVelocidade
+ //
+ this.txtVelocidade.Location = new System.Drawing.Point(606, 347);
+ this.txtVelocidade.Name = "txtVelocidade";
+ this.txtVelocidade.Size = new System.Drawing.Size(88, 20);
+ this.txtVelocidade.TabIndex = 34;
+ this.txtVelocidade.Text = "0,00";
+ this.txtVelocidade.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
+ //
+ // txtDistanciaMax
+ //
+ this.txtDistanciaMax.Location = new System.Drawing.Point(794, 347);
+ this.txtDistanciaMax.Name = "txtDistanciaMax";
+ this.txtDistanciaMax.Size = new System.Drawing.Size(88, 20);
+ this.txtDistanciaMax.TabIndex = 35;
+ this.txtDistanciaMax.Text = "2,00";
+ this.txtDistanciaMax.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
+ //
+ // lblVelocidade
+ //
+ this.lblVelocidade.AutoSize = true;
+ this.lblVelocidade.Location = new System.Drawing.Point(603, 331);
+ this.lblVelocidade.Name = "lblVelocidade";
+ this.lblVelocidade.Size = new System.Drawing.Size(87, 13);
+ this.lblVelocidade.TabIndex = 36;
+ this.lblVelocidade.Text = "Velocidade (m/s)";
+ //
+ // lblDistanciaMax
+ //
+ this.lblDistanciaMax.AutoSize = true;
+ this.lblDistanciaMax.Location = new System.Drawing.Point(791, 331);
+ this.lblDistanciaMax.Name = "lblDistanciaMax";
+ this.lblDistanciaMax.Size = new System.Drawing.Size(91, 13);
+ this.lblDistanciaMax.TabIndex = 37;
+ this.lblDistanciaMax.Text = "Distancia Max (m)";
+ //
+ // lblTamanhoMin
+ //
+ this.lblTamanhoMin.AutoSize = true;
+ this.lblTamanhoMin.Location = new System.Drawing.Point(697, 331);
+ this.lblTamanhoMin.Name = "lblTamanhoMin";
+ this.lblTamanhoMin.Size = new System.Drawing.Size(89, 13);
+ this.lblTamanhoMin.TabIndex = 39;
+ this.lblTamanhoMin.Text = "Tamanho Min (m)";
+ //
+ // txtTamanhoMin
+ //
+ this.txtTamanhoMin.Location = new System.Drawing.Point(700, 347);
+ this.txtTamanhoMin.Name = "txtTamanhoMin";
+ this.txtTamanhoMin.Size = new System.Drawing.Size(88, 20);
+ this.txtTamanhoMin.TabIndex = 38;
+ this.txtTamanhoMin.Text = "0,30";
+ this.txtTamanhoMin.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
+ //
+ // chbReqAutomatico
+ //
+ this.chbReqAutomatico.AutoSize = true;
+ this.chbReqAutomatico.Location = new System.Drawing.Point(1013, 110);
+ this.chbReqAutomatico.Name = "chbReqAutomatico";
+ this.chbReqAutomatico.Size = new System.Drawing.Size(102, 17);
+ this.chbReqAutomatico.TabIndex = 40;
+ this.chbReqAutomatico.Text = "Req Automatico";
+ this.chbReqAutomatico.UseVisualStyleBackColor = true;
+ //
+ // frmOperarioSonar
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(1114, 759);
+ this.Controls.Add(this.chbReqAutomatico);
+ this.Controls.Add(this.lblTamanhoMin);
+ this.Controls.Add(this.txtTamanhoMin);
+ this.Controls.Add(this.lblDistanciaMax);
+ this.Controls.Add(this.lblVelocidade);
+ this.Controls.Add(this.txtDistanciaMax);
+ this.Controls.Add(this.txtVelocidade);
+ this.Controls.Add(this.lblPerfilSolo);
+ this.Controls.Add(this.lblSolo);
+ this.Controls.Add(this.lblAnomalias);
+ this.Controls.Add(this.chartPerfilSolo);
+ this.Controls.Add(this.dgvSolo);
+ this.Controls.Add(this.dgvAnomalias);
+ this.Controls.Add(this.lblLeituraDebug);
+ this.Controls.Add(this.lblDebugFrame);
+ this.Controls.Add(this.picDebug);
+ this.Controls.Add(this.chbIniciarScript);
+ this.Controls.Add(this.btnReqSolo);
+ this.Controls.Add(this.btnReqAnomalias);
+ this.Controls.Add(this.btnReqStatusDispositivo);
+ this.Controls.Add(this.lblUltimaLeitura);
+ this.Controls.Add(this.btnCalibrarGrades);
+ this.Controls.Add(this.btnPing);
+ this.Controls.Add(this.btnAtualizarCameras);
+ this.Controls.Add(this.cmbCameras);
+ this.Controls.Add(this.lblCameras);
+ this.Controls.Add(this.btnIniciarProcessamento);
+ this.Controls.Add(this.btnLeituraHeatmap);
+ this.Controls.Add(this.lblLeituraHeatmap);
+ this.Controls.Add(this.lblLeituraRGB);
+ this.Controls.Add(this.btnLeituraRGB);
+ this.Controls.Add(this.lblHeatmap);
+ this.Controls.Add(this.lblRGB);
+ this.Controls.Add(this.picHeatmap);
+ this.Controls.Add(this.picRGB);
+ this.Name = "frmOperarioSonar";
+ this.Text = "frmOperarioSonar";
+ this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.frmOperarioSonar_FormClosing);
+ this.Load += new System.EventHandler(this.frmOperarioSonar_Load);
+ ((System.ComponentModel.ISupportInitialize)(this.picRGB)).EndInit();
+ ((System.ComponentModel.ISupportInitialize)(this.picHeatmap)).EndInit();
+ ((System.ComponentModel.ISupportInitialize)(this.picDebug)).EndInit();
+ ((System.ComponentModel.ISupportInitialize)(this.dgvAnomalias)).EndInit();
+ ((System.ComponentModel.ISupportInitialize)(this.dgvSolo)).EndInit();
+ ((System.ComponentModel.ISupportInitialize)(this.chartPerfilSolo)).EndInit();
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.PictureBox picRGB;
+ private System.Windows.Forms.PictureBox picHeatmap;
+ private System.Windows.Forms.Label lblRGB;
+ private System.Windows.Forms.Label lblHeatmap;
+ private System.Windows.Forms.Button btnLeituraRGB;
+ private System.Windows.Forms.Label lblLeituraRGB;
+ private System.Windows.Forms.Label lblLeituraHeatmap;
+ private System.Windows.Forms.Button btnLeituraHeatmap;
+ private System.Windows.Forms.Button btnIniciarProcessamento;
+ private System.Windows.Forms.Label lblCameras;
+ private System.Windows.Forms.ComboBox cmbCameras;
+ private System.Windows.Forms.Button btnAtualizarCameras;
+ private System.Windows.Forms.Button btnPing;
+ private System.Windows.Forms.Button btnCalibrarGrades;
+ private System.Windows.Forms.Label lblUltimaLeitura;
+ private System.Windows.Forms.Button btnReqStatusDispositivo;
+ private System.Windows.Forms.Button btnReqAnomalias;
+ private System.Windows.Forms.Button btnReqSolo;
+ private System.Windows.Forms.CheckBox chbIniciarScript;
+ private System.Windows.Forms.Label lblDebugFrame;
+ private System.Windows.Forms.PictureBox picDebug;
+ private System.Windows.Forms.Label lblLeituraDebug;
+ private System.Windows.Forms.DataGridView dgvAnomalias;
+ private System.Windows.Forms.DataGridView dgvSolo;
+ private System.Windows.Forms.DataVisualization.Charting.Chart chartPerfilSolo;
+ private System.Windows.Forms.Label lblAnomalias;
+ private System.Windows.Forms.Label lblSolo;
+ private System.Windows.Forms.Label lblPerfilSolo;
+ private System.Windows.Forms.TextBox txtVelocidade;
+ private System.Windows.Forms.TextBox txtDistanciaMax;
+ private System.Windows.Forms.Label lblVelocidade;
+ private System.Windows.Forms.Label lblDistanciaMax;
+ private System.Windows.Forms.Label lblTamanhoMin;
+ private System.Windows.Forms.TextBox txtTamanhoMin;
+ private System.Windows.Forms.CheckBox chbReqAutomatico;
+ }
+}
\ No newline at end of file
diff --git a/AgroBase/AgroBase/Forms/frmOperarioSonar.cs b/AgroBase/AgroBase/Forms/frmOperarioSonar.cs
new file mode 100644
index 000000000..b1ac83670
--- /dev/null
+++ b/AgroBase/AgroBase/Forms/frmOperarioSonar.cs
@@ -0,0 +1,221 @@
+using AgroBase.Models;
+using AgroBase.Models.Operadores;
+using AgroBase.Services;
+using AgroBase.Services.Operadores;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using System.Windows.Forms.DataVisualization.Charting;
+
+namespace AgroBase.Forms
+{
+ public partial class frmOperarioSonar : Form
+ {
+ VisualWorkerService visualWorker = new VisualWorkerService();
+ AsyncTaskTimerModel tmrLeitura;
+
+ public frmOperarioSonar()
+ {
+ InitializeComponent();
+ }
+
+ private void frmOperarioSonar_Load(object sender, EventArgs e)
+ {
+ AtualizarListaCameras();
+ ConfigurarGridDeteccoes(dgvAnomalias);
+ ConfigurarGridDeteccoes(dgvSolo);
+ tmrLeitura = new AsyncTaskTimerModel("tmrLeitura_VisalWorker", tmrLeitura_Tick, 500, this);
+ tmrLeitura.Start();
+ }
+
+ private async void frmOperarioSonar_FormClosing(object sender, FormClosingEventArgs e)
+ {
+ tmrLeitura?.Stop();
+ await visualWorker.Encerrar();
+ }
+
+ private void AtualizarListaCameras()
+ {
+ cmbCameras.Items.Clear();
+ cmbCameras.Items.AddRange(OAKCameraService.GetListaCameras().Skip(1).Select(x => x.Id).ToArray());
+ cmbCameras.SelectedIndex = -1;
+ }
+
+ private async Task tmrLeitura_Tick()
+ {
+ if (!chbReqAutomatico.Checked) return;
+
+ btnLeituraRGB_Click(new object(), new EventArgs());
+ btnLeituraHeatmap_Click(new object(), new EventArgs());
+ btnReqAnomalias_Click(new object(), new EventArgs());
+ btnReqSolo_Click(new object(), new EventArgs());
+ }
+
+ private void btnAtualizarCameras_Click(object sender, EventArgs e)
+ {
+ OAKCameraService.AtualizarListaCameras(true);
+ AtualizarListaCameras();
+ }
+
+ private async void btnIniciarProcessamento_Click(object sender, EventArgs e)
+ {
+ bool sucesso = await visualWorker.IniciarProcessamento(cmbCameras.SelectedIndex, chbIniciarScript.Checked);
+ AtualizarLabelLeitura($", Comando: Iniciar, Sucesso: {sucesso}");
+ if (!sucesso)
+ {
+ MessageBox.Show("Selecione uma camera para iniciar o processamento!");
+ }
+ else
+ {
+ MessageBox.Show("Processamento iniciado com sucesso!");
+ }
+ }
+
+ private async Task EnviarComando(VisualWorkerCommandType cmd, int timeout = 1000, dynamic payload = null)
+ {
+ bool sucesso = await visualWorker.EnviarComando(cmd, true, timeout, payload);
+ AtualizarLabelLeitura($", Comando: {cmd.ToString()}, Sucesso: {sucesso}");
+ }
+
+ private void AtualizarLabelLeitura(string texto)
+ {
+ lblUltimaLeitura.Text = $"Ultima Leitura em: {visualWorker.DadosLeitura.Leitura._Momento.ToString("dd/MM/yyyy HH:mm:ss.fff")} {texto}";
+ }
+
+ private async void btnPing_Click(object sender, EventArgs e)
+ {
+ await EnviarComando(VisualWorkerCommandType.Ping);
+ }
+
+ private async void btnCalibrarGrades_Click(object sender, EventArgs e)
+ {
+ await EnviarComando(VisualWorkerCommandType.Calibrar_Grades, 10000);
+ }
+
+ private async void btnLeituraRGB_Click(object sender, EventArgs e)
+ {
+ await EnviarComando(VisualWorkerCommandType.Get_RGB_Frame);
+ VisualWorkerMessageFrameModel frame = visualWorker.DadosLeitura.Leitura.obj.rgb_frame;
+ picRGB.Image?.Dispose();
+ picRGB.Image = frame?.image;
+ lblLeituraRGB.Text = $"Leitura em: {FuncoesGlobais.TimestampToDate(frame?.timestamp ?? 0)}";
+ }
+
+ private async void btnLeituraHeatmap_Click(object sender, EventArgs e)
+ {
+ await EnviarComando(VisualWorkerCommandType.Get_Heatmap_Frame);
+ VisualWorkerMessageFrameModel frame = visualWorker.DadosLeitura.Leitura.obj.heatmap_frame;
+ picHeatmap.Image?.Dispose();
+ picHeatmap.Image = frame?.image;
+ lblLeituraHeatmap.Text = $"Leitura em: {FuncoesGlobais.TimestampToDate(frame?.timestamp ?? 0)}";
+ }
+
+ private async void btnReqStatusDispositivo_Click(object sender, EventArgs e)
+ {
+ await EnviarComando(VisualWorkerCommandType.Get_Status_Dispositivo);
+ }
+
+ private async void btnReqAnomalias_Click(object sender, EventArgs e)
+ {
+ await EnviarComando(VisualWorkerCommandType.Get_Analise_Anomalia, 1000, new { velocidade_ms = txtVelocidade.Text.Replace(",", "."), distancia_max = txtDistanciaMax.Text.Replace(",", "."), tamanho_min = txtTamanhoMin.Text.Replace(",", ".") });
+ AtualizarDadosAnalise();
+ }
+
+ private async void btnReqSolo_Click(object sender, EventArgs e)
+ {
+ await EnviarComando(VisualWorkerCommandType.Get_Analise_Solo, 1000, new { velocidade_ms = txtVelocidade.Text.Replace(",", "."), distancia_max = txtDistanciaMax.Text.Replace(",", "."), tamanho_min = txtTamanhoMin.Text.Replace(",", ".") });
+ AtualizarDadosAnalise();
+ }
+
+ private void AtualizarDadosAnalise()
+ {
+ lblLeituraDebug.Text = $"Leitura em: {FuncoesGlobais.TimestampToDate(visualWorker.DadosLeitura.Leitura.obj.analise?.timestamp ?? 0)}";
+ VisualWorkerMessageAnaliseModel analise = visualWorker.DadosLeitura.Leitura.obj.analise;
+ VisualWorkerMessageFrameModel frame = visualWorker.DadosLeitura.Leitura.obj.heatmap_frame;
+ picDebug.Image?.Dispose();
+ picDebug.Image = analise.PlotarAnalise(frame);
+ PreencherGridAnomalias(analise.anomalias ?? new List());
+ PreencherGridSolo(analise.solo?.bbox_list ?? new List());
+ PlotarGraficoPerfilSolo(analise.solo?.perfil ?? new List());
+ }
+
+ void ConfigurarGridDeteccoes(DataGridView dgv)
+ {
+ dgv.Columns.Clear();
+
+ dgv.Columns.Add("Tipo", "Tipo");
+ dgv.Columns.Add("X", "X");
+ dgv.Columns.Add("Y", "Y");
+ dgv.Columns.Add("W", "Largura (px)");
+ dgv.Columns.Add("H", "Altura (px)");
+ dgv.Columns.Add("Centro", "Centro (%)");
+ dgv.Columns.Add("Distancia", "Distância (m)");
+ dgv.Columns.Add("LarguraM", "Largura (m)");
+ dgv.Columns.Add("AlturaM", "Altura (m)");
+ dgv.Columns.Add("Variacao", "Variação (mm)");
+
+ dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
+ dgv.ReadOnly = true;
+ dgv.AllowUserToAddRows = false;
+ dgv.AllowUserToDeleteRows = false;
+ }
+
+ void PreencherGridAnomalias(List bboxes)
+ {
+ dgvAnomalias.Rows.Clear();
+
+ foreach (var bbox in bboxes)
+ {
+ int rowIndex = dgvAnomalias.Rows.Add(
+ bbox.tipo,
+ bbox.bbox[0], bbox.bbox[1], bbox.bbox[2], bbox.bbox[3],
+ $"{bbox.centro_percentual[0]:0.0}%, {bbox.centro_percentual[1]:0.0}%",
+ bbox.distancia_m?.ToString("0.00") ?? "-",
+ bbox.largura_m?.ToString("0.00") ?? "-",
+ bbox.altura_m?.ToString("0.00") ?? "-",
+ bbox.variacao?.ToString("0.0") ?? "-"
+ );
+
+ if (bbox.distancia_m < 1.0)
+ {
+ dgvAnomalias.Rows[rowIndex].DefaultCellStyle.BackColor = Color.LightCoral;
+ }
+ }
+ }
+
+ void PreencherGridSolo(List bboxes)
+ {
+ dgvSolo.Rows.Clear();
+
+ foreach (var bbox in bboxes)
+ {
+ dgvSolo.Rows.Add(
+ bbox.tipo,
+ bbox.bbox[0], bbox.bbox[1], bbox.bbox[2], bbox.bbox[3],
+ $"{bbox.centro_percentual[0]:0.0}%, {bbox.centro_percentual[1]:0.0}%",
+ bbox.distancia_m?.ToString("0.00") ?? "-",
+ bbox.largura_m?.ToString("0.00") ?? "-",
+ bbox.altura_m?.ToString("0.00") ?? "-",
+ bbox.variacao?.ToString("0.0") ?? "-"
+ );
+ }
+ }
+
+ void PlotarGraficoPerfilSolo(List perfil)
+ {
+ chartPerfilSolo.Series.Clear();
+ var serie = chartPerfilSolo.Series.Add("Perfil");
+ serie.ChartType = SeriesChartType.Line;
+
+ for (int i = 0; i < perfil.Count; i++)
+ {
+ serie.Points.AddXY(i + 1, perfil[i]);
+ }
+ }
+
+
+ }
+}
diff --git a/AgroBase/AgroBase/Forms/frmOperarioSonar.resx b/AgroBase/AgroBase/Forms/frmOperarioSonar.resx
new file mode 100644
index 000000000..1af7de150
--- /dev/null
+++ b/AgroBase/AgroBase/Forms/frmOperarioSonar.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/AgroBase/AgroBase/Forms/frmPrincipal.Designer.cs b/AgroBase/AgroBase/Forms/frmPrincipal.Designer.cs
index ed1caf3b3..1ab7edf51 100644
--- a/AgroBase/AgroBase/Forms/frmPrincipal.Designer.cs
+++ b/AgroBase/AgroBase/Forms/frmPrincipal.Designer.cs
@@ -105,6 +105,7 @@ namespace AgroBase
this.btnForcarAtualizacao = new System.Windows.Forms.Button();
this.clbRotinas = new System.Windows.Forms.CheckedListBox();
this.btnAtualizarRotinas = new System.Windows.Forms.Button();
+ this.btnVisualWorker = new System.Windows.Forms.Button();
this.gpbAcoes.SuspendLayout();
this.erroStrip.SuspendLayout();
this.pnlLateral.SuspendLayout();
@@ -646,6 +647,7 @@ namespace AgroBase
// pnlAtalhos
//
this.pnlAtalhos.AutoScroll = true;
+ this.pnlAtalhos.Controls.Add(this.btnVisualWorker);
this.pnlAtalhos.Controls.Add(this.btnTreinamentoIA);
this.pnlAtalhos.Controls.Add(this.btnOID);
this.pnlAtalhos.Controls.Add(this.btnEthernet);
@@ -961,6 +963,17 @@ namespace AgroBase
this.btnAtualizarRotinas.UseVisualStyleBackColor = true;
this.btnAtualizarRotinas.Click += new System.EventHandler(this.btnAtualizarRotinas_Click);
//
+ // btnVisualWorker
+ //
+ this.btnVisualWorker.Location = new System.Drawing.Point(5, 463);
+ this.btnVisualWorker.Margin = new System.Windows.Forms.Padding(2);
+ this.btnVisualWorker.Name = "btnVisualWorker";
+ this.btnVisualWorker.Size = new System.Drawing.Size(84, 20);
+ this.btnVisualWorker.TabIndex = 33;
+ this.btnVisualWorker.Text = "Visual Worker";
+ this.btnVisualWorker.UseVisualStyleBackColor = true;
+ this.btnVisualWorker.Click += new System.EventHandler(this.btnVisualWorker_Click);
+ //
// frmPrincipal
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@@ -1091,6 +1104,7 @@ namespace AgroBase
private System.Windows.Forms.TextBox txtCodErro;
private System.Windows.Forms.Button btnOID;
private System.Windows.Forms.Button btnTreinamentoIA;
+ private System.Windows.Forms.Button btnVisualWorker;
}
}
diff --git a/AgroBase/AgroBase/Forms/frmPrincipal.cs b/AgroBase/AgroBase/Forms/frmPrincipal.cs
index 384d86fa9..7dde2ed84 100644
--- a/AgroBase/AgroBase/Forms/frmPrincipal.cs
+++ b/AgroBase/AgroBase/Forms/frmPrincipal.cs
@@ -499,7 +499,11 @@ namespace AgroBase
frm.Show();
}
-
+ private void btnVisualWorker_Click(object sender, EventArgs e)
+ {
+ frmOperarioSonar frm = new frmOperarioSonar();
+ frm.Show();
+ }
#endregion
@@ -513,5 +517,7 @@ namespace AgroBase
MessageBox.Show(desc);
}
}
+
+
}
}
diff --git a/AgroBase/AgroBase/Models/OAKCameraModel.cs b/AgroBase/AgroBase/Models/OAKCameraModel.cs
index c401cb7a0..cfb2d2316 100644
--- a/AgroBase/AgroBase/Models/OAKCameraModel.cs
+++ b/AgroBase/AgroBase/Models/OAKCameraModel.cs
@@ -15,6 +15,8 @@ namespace AgroBase.Models
public OAKCameraTemperaturaModel Temperature { get; set; }
public string Bootloader_Version { get; set; }
public bool Is_Pipeline_Running { get; set; }
+ public double fx { get; set; }
+ public double baseline { get; set; }
public OAKCameraModel Clone()
{
@@ -30,7 +32,9 @@ namespace AgroBase.Models
Is_Pipeline_Running = Is_Pipeline_Running,
Memory_Usage = Memory_Usage?.Clone(),
Temperature = Temperature?.Clone(),
- Version = Version
+ Version = Version,
+ fx = fx,
+ baseline = baseline,
};
}
}
diff --git a/AgroBase/AgroBase/Models/Operadores/VisualWorkerModel.cs b/AgroBase/AgroBase/Models/Operadores/VisualWorkerModel.cs
new file mode 100644
index 000000000..e53127a0f
--- /dev/null
+++ b/AgroBase/AgroBase/Models/Operadores/VisualWorkerModel.cs
@@ -0,0 +1,342 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Drawing;
+using System.Linq;
+using static AgroBase.Models.Enums;
+
+namespace AgroBase.Models.Operadores
+{
+ public class VisualWorkerModel
+ {
+ public bool Iniciado { get; set; }
+ public DateTime IniciadoEm { get; set; }
+ public bool Pronto { get; set; }
+ public DateTime ProntoEm { get; set; }
+ public VisualWorkerMessageModel UltimaMensagem { get; set; }
+ public VisualWorkerMessageModel Leitura { get; set; } = new VisualWorkerMessageModel();
+
+ public void ReiniciarEstado()
+ {
+ Iniciado = false;
+ IniciadoEm = DateTime.MinValue;
+ Pronto = false;
+ ProntoEm = DateTime.MinValue;
+ UltimaMensagem = new VisualWorkerMessageModel();
+ Leitura = new VisualWorkerMessageModel();
+ }
+ }
+
+ public class VisualWorkerMessageModel
+ {
+ public DateTime _Momento { get; set; } = DateTime.MinValue;
+ public long momento { get; set; }
+ public VisualWorkerMessageType tipo_cmd { get; set; }
+ public VisualWorkerCommandType cmd { get; set; }
+ public VisualWorkerMessageResponseModel obj { get; set; } = new VisualWorkerMessageResponseModel();
+ public dynamic payload { get; set; }
+ }
+
+ public class VisualWorkerMessageResponseModel
+ {
+ public OAKCameraModel device_status { get; set; }
+ public VisualWorkerMessageFrameModel rgb_frame { get; set; }
+ public VisualWorkerMessageFrameModel heatmap_frame { get; set; }
+ public VisualWorkerMessageFrameModel debug_frame { get; set; }
+ public VisualWorkerMessageSetupModel ping { get; set; }
+ public VisualWorkerMessageSetupModel calibragem { get; set; }
+ public VisualWorkerMessageObstaculosModel obstaculos { get; set; }
+ public VisualWorkerMessageCorredorModel corredor { get; set; }
+ public VisualWorkerMessageMapaProfundidadeModel mapa_profundidade { get; set; }
+ public VisualWorkerMessageObstaculos3DModel obstaculos_3d { get; set; }
+ public VisualWorkerMessageAnaliseModel analise { get; set; } = new VisualWorkerMessageAnaliseModel();
+ }
+
+ public class VisualWorkerMessageFrameModel
+ {
+ public long timestamp { get; set; }
+ public string frame { get; set; }
+ public Bitmap image { get; set; }
+ public VisualWorkerMessageFrameModel Clone()
+ {
+ return new VisualWorkerMessageFrameModel()
+ {
+ timestamp = timestamp,
+ frame = frame,
+ image = FuncoesGlobais.Base64ToBitmap(frame),
+ };
+ }
+ }
+
+ public class VisualWorkerMessageSetupModel
+ {
+ public long timestamp { get; set; }
+ public bool status { get; set; }
+ public VisualWorkerMessageSetupModel Clone()
+ {
+ return new VisualWorkerMessageSetupModel()
+ {
+ timestamp = timestamp,
+ status = status,
+ };
+ }
+ }
+
+ public class VisualWorkerMessageObstaculosModel
+ {
+ public long timestamp { get; set; }
+ public bool precisa_micro { get; set; }
+ public bool alerta { get; set; }
+ public int quantidade { get; set; }
+ public bool frontal_bloqueado { get; set; }
+ public Dictionary laterais { get; set; }
+ public Direcao zona_livre { get; set; }
+ public double distancia_minima { get; set; }
+ public List detalhes { get; set; }
+ public VisualWorkerMessageObstaculosModel Clone()
+ {
+ return new VisualWorkerMessageObstaculosModel()
+ {
+ timestamp = timestamp,
+ precisa_micro = precisa_micro,
+ alerta = alerta,
+ quantidade = quantidade,
+ frontal_bloqueado = frontal_bloqueado,
+ laterais = new Dictionary(laterais),
+ zona_livre = zona_livre,
+ distancia_minima = distancia_minima,
+ detalhes = new List(detalhes)
+ };
+ }
+ }
+
+ public class VisualWorkerMessageGridModel
+ {
+ public int linha { get; set; }
+ public int coluna { get; set; }
+ public double distancia { get; set; }
+ public VisualWorkerDetectionType tipo { get; set; }
+ public VisualWorkerRegionType regiao { get; set; }
+ }
+
+ public class VisualWorkerMessageCorredorModel
+ {
+ public long timestamp { get; set; }
+ public double largura_corredor_mm { get; set; }
+ public double posicao_central_fracao { get; set; }
+ public double[][] pontos_debug { get; set; }
+ public VisualWorkerMessageCorredorModel Clone()
+ {
+ return new VisualWorkerMessageCorredorModel()
+ {
+ timestamp = timestamp,
+ largura_corredor_mm = largura_corredor_mm,
+ posicao_central_fracao = posicao_central_fracao,
+ pontos_debug = pontos_debug
+ };
+ }
+ }
+
+ public class VisualWorkerMessageMapaProfundidadeModel
+ {
+ public long timestamp { get; set; }
+ public string resolucao { get; set; }
+ public string unidade { get; set; }
+ public double?[][] grid { get; set; }
+ public VisualWorkerMessageMapaProfundidadeModel Clone()
+ {
+ return new VisualWorkerMessageMapaProfundidadeModel()
+ {
+ timestamp = timestamp,
+ resolucao = resolucao,
+ unidade = unidade,
+ grid = grid
+ };
+ }
+ }
+
+ public class VisualWorkerMessageObstaculos3DModel
+ {
+ public long timestamp { get; set; }
+ public List obstaculos_detectados { get; set; }
+ public VisualWorkerMessageObstaculos3DModel Clone()
+ {
+ return new VisualWorkerMessageObstaculos3DModel()
+ {
+ timestamp = timestamp,
+ obstaculos_detectados = new List(obstaculos_detectados)
+ };
+ }
+ }
+
+ public class VisualWorkerMessageObstaculos3DDetectadosModel
+ {
+ public double posicao { get; set; }
+ public double distancia { get; set; }
+ public int largura_px { get; set; }
+ }
+
+ public class VisualWorkerMessageAnaliseModel
+ {
+ public long timestamp { get; set; }
+ public List anomalias { get; set; }
+ public VisualWorkerMessageAnaliseSoloModel solo { get; set; }
+ public VisualWorkerMessageAnaliseModel Clone()
+ {
+ return new VisualWorkerMessageAnaliseModel()
+ {
+ timestamp = timestamp,
+ anomalias = new List(anomalias),
+ solo = solo.Clone(),
+ };
+ }
+
+ public Bitmap PlotarAnalise(VisualWorkerMessageFrameModel frame)
+ {
+ if (frame?.image == null) return null;
+
+ Bitmap img = new Bitmap(frame.image);
+ using (Graphics g = Graphics.FromImage(img))
+ {
+ Pen penObstaculo = new Pen(Color.Red, 2);
+ Pen penErosao = new Pen(Color.Blue, 2);
+ Pen penLombada = new Pen(Color.Orange, 2);
+ Pen penFaixaSolo = new Pen(Color.Black, 2);
+ Pen penGrafico = new Pen(Color.DarkGreen, 2);
+
+ Font font = new Font("Arial", 8);
+ Brush brush = Brushes.Black;
+
+ int imgWidth = img.Width;
+ int imgHeight = img.Height;
+
+ // 🔸 Desenhar Bounding Boxes (Anomalias + Solo)
+ List bboxes = new List();
+ if (anomalias != null) bboxes.AddRange(anomalias);
+ if (solo?.bbox_list != null) bboxes.AddRange(solo.bbox_list);
+
+ foreach (var bbox in bboxes)
+ {
+ var pen = penObstaculo;
+ if (bbox.tipo == "erosao") pen = penErosao;
+ if (bbox.tipo == "lombada") pen = penLombada;
+
+ var rect = new Rectangle(bbox.bbox[0], bbox.bbox[1], bbox.bbox[2], bbox.bbox[3]);
+ g.DrawRectangle(pen, rect);
+
+ string label = $"{bbox.tipo} {bbox.distancia_m}m Δ{bbox.variacao}mm";
+ g.DrawString(label, font, brush, rect.X, rect.Y - 12);
+ }
+
+ // 🔸 Desenhar linha da faixa do solo
+ if (solo != null)
+ {
+ int yInicio = solo.y_inicio;
+ g.DrawLine(penFaixaSolo, 0, yInicio, imgWidth, yInicio);
+ }
+
+ // 🔸 Desenhar gráfico do perfil de solo
+ if (solo?.perfil != null && solo.perfil.Count > 1)
+ {
+ var perfil = solo.perfil;
+ int setores = solo.n_setores;
+ int yInicio = solo.y_inicio;
+ int alturaRegiao = solo.altura_regiao;
+
+ double maxZ = perfil.Max();
+ double minZ = perfil.Min();
+ if (maxZ == minZ) maxZ += 1; // evita divisão por zero
+
+ for (int i = 0; i < perfil.Count - 1; i++)
+ {
+ float x1 = (float)(i * imgWidth / setores + imgWidth / (2.0 * setores));
+ float x2 = (float)((i + 1) * imgWidth / setores + imgWidth / (2.0 * setores));
+
+ float y1 = (float)(yInicio + alturaRegiao - ((perfil[i] - minZ) / (maxZ - minZ)) * alturaRegiao);
+ float y2 = (float)(yInicio + alturaRegiao - ((perfil[i + 1] - minZ) / (maxZ - minZ)) * alturaRegiao);
+
+ g.DrawLine(penGrafico, x1, y1, x2, y2);
+ g.FillEllipse(Brushes.DarkGreen, x1 - 3, y1 - 3, 6, 6);
+ }
+
+ // Desenha o último ponto
+ float xLast = (float)((perfil.Count - 1) * imgWidth / setores + imgWidth / (2.0 * setores));
+ float yLast = (float)(yInicio + alturaRegiao - ((perfil.Last() - minZ) / (maxZ - minZ)) * alturaRegiao);
+ g.FillEllipse(Brushes.DarkGreen, xLast - 3, yLast - 3, 6, 6);
+ }
+ }
+
+ return img;
+ }
+
+ }
+
+ public class VisualWorkerMessageAnaliseSoloModel
+ {
+ public List perfil { get; set; }
+ public List bbox_list { get; set; }
+ public int y_inicio { get; set; }
+ public int altura_regiao { get; set; }
+ public int n_setores { get; set; }
+ public VisualWorkerMessageAnaliseSoloModel Clone()
+ {
+ return new VisualWorkerMessageAnaliseSoloModel()
+ {
+ perfil = new List(perfil),
+ bbox_list = new List(bbox_list),
+ y_inicio = y_inicio,
+ altura_regiao = altura_regiao,
+ n_setores = n_setores
+ };
+ }
+ }
+
+ public class VisualWorkerMessageAnaliseBBoxModel
+ {
+ public string tipo { get; set; }
+ public List bbox { get; set; } // [x, y, w, h]
+ public List centro_percentual { get; set; } // [x%, y%]
+ public double? distancia_m { get; set; }
+ public double? largura_m { get; set; }
+ public double? altura_m { get; set; }
+ public List profundidades { get; set; } // [z1, z2] ou null
+ public double? variacao { get; set; } // delta Z ou null
+ }
+
+ public enum VisualWorkerMessageType
+ {
+ TX = 1,
+ RX = 2
+ }
+
+ public enum VisualWorkerCommandType
+ {
+ Ping = 1,
+ Get_Status_Dispositivo = 2,
+ Get_RGB_Frame = 3,
+ Get_Heatmap_Frame = 4,
+ Calibrar_Grades = 5,
+ Get_Analise_Anomalia = 6,
+ Get_Analise_Solo = 7,
+ }
+
+ public enum VisualWorkerDetectionType
+ {
+ Seguro = 1,
+ Obstaculo = 2,
+ Depressao = 3,
+ }
+
+ public enum VisualWorkerRegionType
+ {
+ Solo = 1,
+ Aereo = 2,
+ }
+
+ public enum VisualWorkerAnaliseType
+ {
+ Anomalia = 1,
+ Solo = 2,
+ }
+
+}
diff --git a/AgroBase/AgroBase/Models/Variaveis.cs b/AgroBase/AgroBase/Models/Variaveis.cs
index 4d07463bb..801e9c34b 100644
--- a/AgroBase/AgroBase/Models/Variaveis.cs
+++ b/AgroBase/AgroBase/Models/Variaveis.cs
@@ -1137,6 +1137,18 @@ namespace AgroBase.Models
return "0x" + _bt.ToString("X").PadLeft(2, '0');
}
+ public static Bitmap Base64ToBitmap(string base64String)
+ {
+ if (string.IsNullOrEmpty(base64String))
+ return null;
+
+ byte[] imageBytes = Convert.FromBase64String(base64String);
+ using (var ms = new MemoryStream(imageBytes))
+ {
+ return new Bitmap(ms);
+ }
+ }
+
}
public static class FuncoesMatematicas
diff --git a/AgroBase/AgroBase/Program.cs b/AgroBase/AgroBase/Program.cs
index 3672aa242..0bc571d68 100644
--- a/AgroBase/AgroBase/Program.cs
+++ b/AgroBase/AgroBase/Program.cs
@@ -1,8 +1,5 @@
using AgroBase.Forms;
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
using System.Windows.Forms;
namespace AgroBase
diff --git a/AgroBase/AgroBase/Services/Operadores/VisualWorkerService.cs b/AgroBase/AgroBase/Services/Operadores/VisualWorkerService.cs
new file mode 100644
index 000000000..f702ab15c
--- /dev/null
+++ b/AgroBase/AgroBase/Services/Operadores/VisualWorkerService.cs
@@ -0,0 +1,170 @@
+using AgroBase.Models;
+using AgroBase.Models.Operadores;
+using Newtonsoft.Json;
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Threading.Tasks;
+using static MqttService;
+
+namespace AgroBase.Services.Operadores
+{
+ public class VisualWorkerService
+ {
+ private string mqtt_topico = "agrobot/operador/sonar";
+ private MqttTopicosModel topico;
+ private Process pythonProcess;
+ private int cameraIndex = -1;
+ public VisualWorkerModel DadosLeitura = new VisualWorkerModel();
+
+ private bool DebugMode = true;
+
+ private void MostrarLog(string message, int limite = 500)
+ {
+ if (DebugMode)
+ {
+ Console.WriteLine($"[VisualWorker] {message.Substring(0, Math.Min(limite, message.Length))}{(message.Length > limite ? "..." : "")}");
+ }
+ }
+
+ public async Task IniciarProcessamento(int _cameraIndex, bool iniciarScript = true)
+ {
+ if (_cameraIndex == -1)
+ {
+ MostrarLog("Camera nao selecionada");
+ DadosLeitura.ReiniciarEstado();
+ return false;
+ }
+
+ cameraIndex = _cameraIndex;
+
+ topico = await Variaveis.MqttService.AdicionarNovoTopico(mqtt_topico, true, 2, MqttCallback);
+
+ if (iniciarScript)
+ {
+ pythonProcess = PythonService.RunScript(Path.Combine("visual_worker", "main.py"), new string[] { mqtt_topico, cameraIndex.ToString() });
+ }
+
+ DadosLeitura.IniciadoEm = DateTime.Now;
+ DadosLeitura.Iniciado = true;
+
+ bool pronto() => DadosLeitura.Pronto;
+ await FuncoesGlobais.AguardarCondicaoAsync(pronto);
+ if (pronto())
+ {
+ MostrarLog("Processamento iniciado com sucesso");
+ return true;
+ }
+
+ MostrarLog("Timeout ao iniciar script");
+ DadosLeitura.ReiniciarEstado();
+ return false;
+ }
+
+ public async Task Encerrar()
+ {
+ pythonProcess?.Kill();
+ pythonProcess = null;
+ await Variaveis.MqttService.UnsubscribeAsync(topico);
+ topico = null;
+ return true;
+ }
+
+ public async Task EnviarComando(VisualWorkerCommandType cmd, bool waitCallback = false, int timeout = 1000, dynamic payload = null)
+ {
+ VisualWorkerMessageModel msg = new VisualWorkerMessageModel()
+ {
+ tipo_cmd = VisualWorkerMessageType.TX,
+ cmd = cmd,
+ payload = payload
+ };
+
+ DateTime EnviadoEm = DateTime.Now;
+ await Variaveis.MqttService.PublishAsync(
+ topico,
+ JsonConvert.SerializeObject(msg, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }),
+ true
+ );
+
+ if (waitCallback)
+ {
+ bool respondido() => DadosLeitura.Leitura._Momento > EnviadoEm;
+ await FuncoesGlobais.AguardarCondicaoAsync(respondido, timeout);
+ return respondido();
+ }
+
+ return true;
+ }
+
+ private async Task MqttCallback(MqttTopicosMensagensModel Mensagem)
+ {
+ if (!DadosLeitura.Pronto && Mensagem.Momento > DadosLeitura.IniciadoEm && Mensagem.Mensagem == "OK")
+ {
+ DadosLeitura.ProntoEm = DateTime.Now;
+ DadosLeitura.Pronto = true;
+ }
+ else
+ {
+ var msg = JsonConvert.DeserializeObject(Mensagem.Mensagem);
+
+ if (msg == null || msg.tipo_cmd == VisualWorkerMessageType.TX)
+ {
+ return false;
+ }
+
+ DadosLeitura.UltimaMensagem = msg;
+ AtualizarDadosLeitura(msg);
+ }
+ MostrarLog(Mensagem.Mensagem);
+ return true;
+ }
+
+ private void AtualizarDadosLeitura(VisualWorkerMessageModel msg)
+ {
+ switch (msg.cmd)
+ {
+ case VisualWorkerCommandType.Ping:
+ {
+ DadosLeitura.Leitura.obj.ping = msg.obj.ping.Clone();
+ break;
+ }
+ case VisualWorkerCommandType.Get_Status_Dispositivo:
+ {
+ DadosLeitura.Leitura.obj.device_status = msg.obj.device_status?.Clone();
+ break;
+ }
+ case VisualWorkerCommandType.Get_RGB_Frame:
+ {
+ DadosLeitura.Leitura.obj.rgb_frame = msg.obj.rgb_frame.Clone();
+ break;
+ }
+ case VisualWorkerCommandType.Get_Heatmap_Frame:
+ {
+ DadosLeitura.Leitura.obj.heatmap_frame = msg.obj.heatmap_frame.Clone();
+ break;
+ }
+ case VisualWorkerCommandType.Calibrar_Grades:
+ {
+ DadosLeitura.Leitura.obj.calibragem = msg.obj.calibragem.Clone();
+ break;
+ }
+ case VisualWorkerCommandType.Get_Analise_Anomalia:
+ {
+ DadosLeitura.Leitura.obj.analise.timestamp = msg.obj.analise.timestamp;
+ DadosLeitura.Leitura.obj.analise.anomalias = new System.Collections.Generic.List(msg.obj.analise.anomalias);
+ break;
+ }
+ case VisualWorkerCommandType.Get_Analise_Solo:
+ {
+ DadosLeitura.Leitura.obj.analise.timestamp = msg.obj.analise.timestamp;
+ DadosLeitura.Leitura.obj.analise.solo = msg.obj.analise.solo.Clone();
+ break;
+ }
+ }
+ DadosLeitura.Leitura._Momento = DateTime.Now;
+ }
+
+
+
+ }
+}
diff --git a/AgroBase/AgroBase/bin/x64/Debug/AgroBase.exe b/AgroBase/AgroBase/bin/x64/Debug/AgroBase.exe
index 779bad81d..d14e5fa2f 100644
Binary files a/AgroBase/AgroBase/bin/x64/Debug/AgroBase.exe and b/AgroBase/AgroBase/bin/x64/Debug/AgroBase.exe differ
diff --git a/AgroBase/AgroBase/bin/x64/Debug/AgroBase.pdb b/AgroBase/AgroBase/bin/x64/Debug/AgroBase.pdb
index 28b7d7271..fbb475097 100644
Binary files a/AgroBase/AgroBase/bin/x64/Debug/AgroBase.pdb and b/AgroBase/AgroBase/bin/x64/Debug/AgroBase.pdb differ
diff --git a/AgroBase/AgroBase/bin/x64/Debug/Parametros/parametersMvd-2_0.par b/AgroBase/AgroBase/bin/x64/Debug/Parametros/parametersMvd-2_0.par
index 28d65e617..f01bb5474 100644
--- a/AgroBase/AgroBase/bin/x64/Debug/Parametros/parametersMvd-2_0.par
+++ b/AgroBase/AgroBase/bin/x64/Debug/Parametros/parametersMvd-2_0.par
@@ -1 +1 @@
-{"tmrRegistrador":{"_uiControl":null,"State":2,"IsRunning":false,"IsStopped":true,"IsCreated":false,"Interval":1000,"StackTrace":"MovimentacaoUnificadaModel.IniciarRegistrador","Id":"tmrRegistrador_Mvd","TimeTick":"00:00:00"},"tmrRegistradorMOV":{"_uiControl":null,"State":2,"IsRunning":false,"IsStopped":true,"IsCreated":false,"Interval":1000,"StackTrace":"MovimentacaoUnificadaModel.IniciarRegistrador","Id":"tmrRegistrador_Mov","TimeTick":"00:00:00"},"tmrRegistradorDIR":{"_uiControl":null,"State":2,"IsRunning":false,"IsStopped":true,"IsCreated":false,"Interval":500,"StackTrace":"MovimentacaoUnificadaModel.IniciarRegistrador","Id":"tmrRegistrador_Dir","TimeTick":"00:00:00"},"Dispositivo":109,"_EnderecoCAN_Tx":0,"_EnderecoCAN_Rx":0,"Conectado":true,"_TaxaAmostragem":1000,"DistanciaPercorridaOperacao":0.0,"TempoEmAtividade":0.0,"DistanciaPercorridaTotal":0.0,"DistanciaPercorridaParcial":0.0,"VelocidadeMedia":0.0,"DiametroRoda":0.365,"ReducaoMotorBLDC":5.0,"RPM_Max_MotorBLDC":500.0,"IP_Mov":"192.168.105.10","IP_Dir":"192.168.105.11","Modulos":[{"Modulo_ID":"ET","Disponivel":false,"RequisitarDados":false,"Conectado":true,"MovMotor":{"ID":"Mov","_EnderecoCAN_Tx":5,"_EnderecoCAN_Rx":5,"heartBeatValue":1,"Mod_ID":"ET","LeituraLigado":false,"LeituraRPM":0.0,"ComandoLigado":false,"CodigoAlarme":0,"AlarmeMotor":false,"RPM_SP":0,"RPM_SP_Controle":0,"RPM_SP_Leitura":0,"Sentido_SP":0,"NumeroPolos":10,"Rampa":1,"CorrenteTorqueMaximo":40,"OffsetLeitura":1.0,"AlarmeComando":false,"RPM_Roda":0.0,"Sentido":0,"Temperatura":0.0,"TemperaturaDriver":18.0,"Tensao":40.0,"Corrente_Barramento":0.0,"Corrente_Motor":0.0,"Potencia":0.0,"CicloTrabalho":0.4,"RPM_Motor":0.0,"VelocidadeInstantanea":0.0,"Comandar":true,"AlarmeSensores":false,"Inicializado":true,"Leitura":{"EnderecoTx":5,"EnderecoRx":5,"Iniciado":true,"Configurado":true,"UltimoComandoRecebido":"2025-05-19T07:54:58.4670145-03:00","ModoControle":0,"CodigoAlarme":0,"ERPM":0,"CorrenteMotor":0.0,"CorrenteBarramento":0.0,"Direcao":0,"RPM":0.0,"Tensao":40.0,"Temperatura":18.0,"Potencia":0.0,"CicloTrabalho":0.4,"Freado":false,"PosicaoAbsoluta":0.0,"PosicaoRelativa":0.0,"ModoCodificador":0.0,"ErroHistorico":0.0,"IO_Status":0.0},"CompensacaoNecessaria":false,"ConfigSentidos":{"RodasDianteiras":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"RodasTraseiras":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"MovimentoDiagonal":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"MovimentoArco":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"RotacionarNoEixo":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"MovimentoLateral":{"Frente":2,"Tras":1,"Esquerda":0,"Direita":0,"Parado":0},"Diagnostico":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0}},"Funcoes":[12,14,9,5,10],"LogGrafico":[],"Alarmes":[{"Tipo":411,"Valor":-1.0,"Minimo":true,"Maximo":false,"ParaMinimo":false,"ParaMaximo":false},{"Tipo":4,"Valor":33.64,"Minimo":false,"Maximo":true,"ParaMinimo":false,"ParaMaximo":false}],"ConfigFreio":{"Incremental":true,"AnguloInicial":10,"Leitura":false,"Controle":false}},"DirMotor":{"ID":"Dir","_EnderecoCAN_Tx":1,"_EnderecoCAN_Rx":1,"Mod_ID":"ET","Sentido_SP":0,"Angulo_SP":0.0,"FolgaMecanica":0.0,"Velocidade_Max":600.0,"Velocidade":240,"Sentido":0,"SentidoReal":1,"Angulo":0.0,"RPM":0.0,"IN1_Atuado":true,"IN2_Atuado":true,"Referenciando":false,"Comandar":false,"Inicializado":false,"Leitura":null,"UltimaDirecao":0,"UltimoComandoEnviado":"2025-05-07T15:27:09.8024491-03:00","RetornandoAzero":false,"EmMovimento":false,"AtingiuAnguloSP":true,"ConfigSentidos":{"RodasDianteiras":{"Frente":0,"Tras":0,"Esquerda":0,"Direita":0,"Parado":0},"RodasTraseiras":{"Frente":0,"Tras":0,"Esquerda":2,"Direita":1,"Parado":0},"MovimentoDiagonal":{"Frente":0,"Tras":0,"Esquerda":1,"Direita":2,"Parado":0},"MovimentoArco":{"Frente":0,"Tras":0,"Esquerda":2,"Direita":1,"Parado":0},"RotacionarNoEixo":{"Frente":0,"Tras":0,"Esquerda":1,"Direita":1,"Parado":0},"MovimentoLateral":{"Frente":0,"Tras":0,"Esquerda":1,"Direita":2,"Parado":0},"Diagnostico":{"Frente":2,"Tras":1,"Esquerda":1,"Direita":2,"Parado":0}},"Funcoes":[13,9,14,41]}},{"Modulo_ID":"EF","Disponivel":false,"RequisitarDados":false,"Conectado":true,"MovMotor":{"ID":"Mov","_EnderecoCAN_Tx":7,"_EnderecoCAN_Rx":7,"heartBeatValue":1,"Mod_ID":"EF","LeituraLigado":false,"LeituraRPM":0.0,"ComandoLigado":false,"CodigoAlarme":0,"AlarmeMotor":false,"RPM_SP":0,"RPM_SP_Controle":0,"RPM_SP_Leitura":0,"Sentido_SP":0,"NumeroPolos":10,"Rampa":1,"CorrenteTorqueMaximo":40,"OffsetLeitura":1.0,"AlarmeComando":false,"RPM_Roda":0.0,"Sentido":0,"Temperatura":0.0,"TemperaturaDriver":18.0,"Tensao":40.0,"Corrente_Barramento":0.0,"Corrente_Motor":0.0,"Potencia":0.0,"CicloTrabalho":0.6,"RPM_Motor":0.0,"VelocidadeInstantanea":0.0,"Comandar":true,"AlarmeSensores":false,"Inicializado":true,"Leitura":{"EnderecoTx":7,"EnderecoRx":7,"Iniciado":true,"Configurado":true,"UltimoComandoRecebido":"2025-05-19T07:54:58.5306891-03:00","ModoControle":0,"CodigoAlarme":0,"ERPM":0,"CorrenteMotor":0.0,"CorrenteBarramento":0.0,"Direcao":0,"RPM":0.0,"Tensao":40.0,"Temperatura":18.0,"Potencia":0.0,"CicloTrabalho":0.6,"Freado":false,"PosicaoAbsoluta":0.0,"PosicaoRelativa":0.0,"ModoCodificador":0.0,"ErroHistorico":0.0,"IO_Status":0.0},"CompensacaoNecessaria":false,"ConfigSentidos":{"RodasDianteiras":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"RodasTraseiras":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"MovimentoDiagonal":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"MovimentoArco":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"RotacionarNoEixo":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"MovimentoLateral":{"Frente":2,"Tras":1,"Esquerda":0,"Direita":0,"Parado":0},"Diagnostico":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0}},"Funcoes":[12,14,9,5,10],"LogGrafico":[],"Alarmes":[{"Tipo":411,"Valor":-1.0,"Minimo":true,"Maximo":false,"ParaMinimo":false,"ParaMaximo":false},{"Tipo":4,"Valor":15.86,"Minimo":false,"Maximo":true,"ParaMinimo":false,"ParaMaximo":false}],"ConfigFreio":{"Incremental":true,"AnguloInicial":10,"Leitura":false,"Controle":false}},"DirMotor":{"ID":"Dir","_EnderecoCAN_Tx":3,"_EnderecoCAN_Rx":3,"Mod_ID":"EF","Sentido_SP":0,"Angulo_SP":0.0,"FolgaMecanica":9.0,"Velocidade_Max":600.0,"Velocidade":240,"Sentido":0,"SentidoReal":1,"Angulo":0.0,"RPM":0.0,"IN1_Atuado":false,"IN2_Atuado":false,"Referenciando":false,"Comandar":true,"Inicializado":true,"Leitura":{"EnderecoTx":3,"EnderecoRx":3,"Iniciado":true,"UltimoComandoRecebido":"2025-05-19T07:54:57.5409192-03:00","ErroCarregado":0.0,"ErroCarregado_Hex":null,"ErroAcumulado":0.0,"ErroAcumulado_Hex":null,"RPM":0.0,"RPM_Hex":null,"NumeroPulsos":0,"AnguloPulsos":0.0,"NumeroPulsos_Hex":null,"NumeroPulsosAbsoluto":0,"AnguloPulsosAbsoluto":0.0,"NumeroPulsosRelativo":0,"AnguloPulsosRelativo":0.0,"ErroAngulo":0.0,"ErroAngulo_Hex":null,"StatusDriver":0,"StatusModoLimiteZero":0,"StatusTravaMotor":0,"StatusBloqueioMotor":0,"StatusMovimentoMotor":0,"Sentido":0,"Velocidade":0.0,"Aceleracao":0.0,"Mensagem":null,"HV":null,"FV":"20.1.0.6","Entradas":[true,true],"Saidas":[true,true],"StatusMovimento":0,"AnguloSP":0.0},"UltimaDirecao":0,"UltimoComandoEnviado":"2025-05-16T16:03:32.9874024-03:00","RetornandoAzero":false,"EmMovimento":false,"AtingiuAnguloSP":true,"ConfigSentidos":{"RodasDianteiras":{"Frente":0,"Tras":0,"Esquerda":2,"Direita":1,"Parado":0},"RodasTraseiras":{"Frente":0,"Tras":0,"Esquerda":0,"Direita":0,"Parado":0},"MovimentoDiagonal":{"Frente":0,"Tras":0,"Esquerda":2,"Direita":1,"Parado":0},"MovimentoArco":{"Frente":0,"Tras":0,"Esquerda":2,"Direita":1,"Parado":0},"RotacionarNoEixo":{"Frente":0,"Tras":0,"Esquerda":1,"Direita":1,"Parado":0},"MovimentoLateral":{"Frente":0,"Tras":0,"Esquerda":2,"Direita":1,"Parado":0},"Diagnostico":{"Frente":2,"Tras":1,"Esquerda":1,"Direita":2,"Parado":0}},"Funcoes":[13,9,14,41]}},{"Modulo_ID":"DT","Disponivel":false,"RequisitarDados":false,"Conectado":true,"MovMotor":{"ID":"Mov","_EnderecoCAN_Tx":6,"_EnderecoCAN_Rx":6,"heartBeatValue":0,"Mod_ID":"DT","LeituraLigado":false,"LeituraRPM":0.0,"ComandoLigado":false,"CodigoAlarme":0,"AlarmeMotor":false,"RPM_SP":0,"RPM_SP_Controle":0,"RPM_SP_Leitura":0,"Sentido_SP":0,"NumeroPolos":10,"Rampa":1,"CorrenteTorqueMaximo":40,"OffsetLeitura":1.0,"AlarmeComando":false,"RPM_Roda":0.0,"Sentido":0,"Temperatura":0.0,"TemperaturaDriver":18.0,"Tensao":39.0,"Corrente_Barramento":0.0,"Corrente_Motor":0.0,"Potencia":0.0,"CicloTrabalho":0.6,"RPM_Motor":0.0,"VelocidadeInstantanea":0.0,"Comandar":true,"AlarmeSensores":false,"Inicializado":true,"Leitura":{"EnderecoTx":6,"EnderecoRx":6,"Iniciado":true,"Configurado":true,"UltimoComandoRecebido":"2025-05-19T07:54:58.4830073-03:00","ModoControle":0,"CodigoAlarme":0,"ERPM":0,"CorrenteMotor":0.0,"CorrenteBarramento":0.0,"Direcao":0,"RPM":0.0,"Tensao":39.0,"Temperatura":18.0,"Potencia":0.0,"CicloTrabalho":0.6,"Freado":false,"PosicaoAbsoluta":0.0,"PosicaoRelativa":0.0,"ModoCodificador":0.0,"ErroHistorico":0.0,"IO_Status":0.0},"CompensacaoNecessaria":false,"ConfigSentidos":{"RodasDianteiras":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"RodasTraseiras":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"MovimentoDiagonal":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"MovimentoArco":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"RotacionarNoEixo":{"Frente":2,"Tras":1,"Esquerda":0,"Direita":0,"Parado":0},"MovimentoLateral":{"Frente":2,"Tras":1,"Esquerda":0,"Direita":0,"Parado":0},"Diagnostico":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0}},"Funcoes":[12,14,9,5,10],"LogGrafico":[],"Alarmes":[{"Tipo":411,"Valor":-1.0,"Minimo":true,"Maximo":false,"ParaMinimo":false,"ParaMaximo":false},{"Tipo":4,"Valor":15.18,"Minimo":false,"Maximo":true,"ParaMinimo":false,"ParaMaximo":false}],"ConfigFreio":{"Incremental":false,"AnguloInicial":170,"Leitura":false,"Controle":false}},"DirMotor":{"ID":"Dir","_EnderecoCAN_Tx":2,"_EnderecoCAN_Rx":2,"Mod_ID":"DT","Sentido_SP":0,"Angulo_SP":0.0,"FolgaMecanica":3.0,"Velocidade_Max":600.0,"Velocidade":240,"Sentido":0,"SentidoReal":2,"Angulo":0.0,"RPM":0.0,"IN1_Atuado":true,"IN2_Atuado":true,"Referenciando":false,"Comandar":false,"Inicializado":false,"Leitura":null,"UltimaDirecao":0,"UltimoComandoEnviado":"2025-05-16T15:58:30.0322588-03:00","RetornandoAzero":false,"EmMovimento":false,"AtingiuAnguloSP":true,"ConfigSentidos":{"RodasDianteiras":{"Frente":0,"Tras":0,"Esquerda":0,"Direita":0,"Parado":0},"RodasTraseiras":{"Frente":0,"Tras":0,"Esquerda":1,"Direita":2,"Parado":0},"MovimentoDiagonal":{"Frente":0,"Tras":0,"Esquerda":2,"Direita":1,"Parado":0},"MovimentoArco":{"Frente":0,"Tras":0,"Esquerda":1,"Direita":2,"Parado":0},"RotacionarNoEixo":{"Frente":0,"Tras":0,"Esquerda":1,"Direita":1,"Parado":0},"MovimentoLateral":{"Frente":0,"Tras":0,"Esquerda":2,"Direita":1,"Parado":0},"Diagnostico":{"Frente":2,"Tras":1,"Esquerda":1,"Direita":2,"Parado":0}},"Funcoes":[13,9,14,41]}},{"Modulo_ID":"DF","Disponivel":false,"RequisitarDados":false,"Conectado":true,"MovMotor":{"ID":"Mov","_EnderecoCAN_Tx":8,"_EnderecoCAN_Rx":8,"heartBeatValue":0,"Mod_ID":"DF","LeituraLigado":false,"LeituraRPM":0.0,"ComandoLigado":false,"CodigoAlarme":0,"AlarmeMotor":false,"RPM_SP":0,"RPM_SP_Controle":0,"RPM_SP_Leitura":0,"Sentido_SP":0,"NumeroPolos":10,"Rampa":1,"CorrenteTorqueMaximo":40,"OffsetLeitura":1.0,"AlarmeComando":false,"RPM_Roda":0.0,"Sentido":0,"Temperatura":0.0,"TemperaturaDriver":18.0,"Tensao":40.0,"Corrente_Barramento":0.0,"Corrente_Motor":0.0,"Potencia":0.0,"CicloTrabalho":0.1,"RPM_Motor":0.0,"VelocidadeInstantanea":0.0,"Comandar":true,"AlarmeSensores":false,"Inicializado":true,"Leitura":{"EnderecoTx":8,"EnderecoRx":8,"Iniciado":true,"Configurado":true,"UltimoComandoRecebido":"2025-05-19T07:54:58.5462447-03:00","ModoControle":0,"CodigoAlarme":0,"ERPM":0,"CorrenteMotor":0.0,"CorrenteBarramento":0.0,"Direcao":0,"RPM":0.0,"Tensao":40.0,"Temperatura":18.0,"Potencia":0.0,"CicloTrabalho":0.1,"Freado":false,"PosicaoAbsoluta":0.0,"PosicaoRelativa":0.0,"ModoCodificador":0.0,"ErroHistorico":0.0,"IO_Status":0.0},"CompensacaoNecessaria":false,"ConfigSentidos":{"RodasDianteiras":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"RodasTraseiras":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"MovimentoDiagonal":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"MovimentoArco":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"RotacionarNoEixo":{"Frente":2,"Tras":1,"Esquerda":0,"Direita":0,"Parado":0},"MovimentoLateral":{"Frente":2,"Tras":1,"Esquerda":0,"Direita":0,"Parado":0},"Diagnostico":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0}},"Funcoes":[12,14,9,5,10],"LogGrafico":[],"Alarmes":[{"Tipo":411,"Valor":-1.0,"Minimo":true,"Maximo":false,"ParaMinimo":false,"ParaMaximo":false},{"Tipo":4,"Valor":32.47,"Minimo":false,"Maximo":true,"ParaMinimo":false,"ParaMaximo":false}],"ConfigFreio":{"Incremental":false,"AnguloInicial":170,"Leitura":false,"Controle":false}},"DirMotor":{"ID":"Dir","_EnderecoCAN_Tx":4,"_EnderecoCAN_Rx":4,"Mod_ID":"DF","Sentido_SP":0,"Angulo_SP":0.0,"FolgaMecanica":6.0,"Velocidade_Max":600.0,"Velocidade":240,"Sentido":0,"SentidoReal":1,"Angulo":0.0,"RPM":0.0,"IN1_Atuado":true,"IN2_Atuado":false,"Referenciando":false,"Comandar":true,"Inicializado":true,"Leitura":{"EnderecoTx":4,"EnderecoRx":4,"Iniciado":true,"UltimoComandoRecebido":"2025-05-19T07:54:58.1888816-03:00","ErroCarregado":0.0,"ErroCarregado_Hex":null,"ErroAcumulado":0.0,"ErroAcumulado_Hex":null,"RPM":0.0,"RPM_Hex":null,"NumeroPulsos":0,"AnguloPulsos":0.0,"NumeroPulsos_Hex":null,"NumeroPulsosAbsoluto":0,"AnguloPulsosAbsoluto":0.0,"NumeroPulsosRelativo":0,"AnguloPulsosRelativo":0.0,"ErroAngulo":0.0,"ErroAngulo_Hex":null,"StatusDriver":0,"StatusModoLimiteZero":0,"StatusTravaMotor":0,"StatusBloqueioMotor":0,"StatusMovimentoMotor":0,"Sentido":0,"Velocidade":0.0,"Aceleracao":0.0,"Mensagem":null,"HV":null,"FV":"20.1.0.6","Entradas":[false,true],"Saidas":[true,true],"StatusMovimento":0,"AnguloSP":0.0},"UltimaDirecao":0,"UltimoComandoEnviado":"2025-05-16T16:03:32.9874024-03:00","RetornandoAzero":false,"EmMovimento":false,"AtingiuAnguloSP":true,"ConfigSentidos":{"RodasDianteiras":{"Frente":0,"Tras":0,"Esquerda":1,"Direita":2,"Parado":0},"RodasTraseiras":{"Frente":0,"Tras":0,"Esquerda":0,"Direita":0,"Parado":0},"MovimentoDiagonal":{"Frente":0,"Tras":0,"Esquerda":1,"Direita":2,"Parado":0},"MovimentoArco":{"Frente":0,"Tras":0,"Esquerda":1,"Direita":2,"Parado":0},"RotacionarNoEixo":{"Frente":0,"Tras":0,"Esquerda":1,"Direita":1,"Parado":0},"MovimentoLateral":{"Frente":0,"Tras":0,"Esquerda":1,"Direita":2,"Parado":0},"Diagnostico":{"Frente":2,"Tras":1,"Esquerda":1,"Direita":2,"Parado":0}},"Funcoes":[13,9,14,41]}}]}
\ No newline at end of file
+{"tmrRegistrador":{"_uiControl":null,"State":2,"IsRunning":false,"IsStopped":true,"IsCreated":false,"Interval":1000,"StackTrace":"MovimentacaoUnificadaModel.IniciarRegistrador","Id":"tmrRegistrador_Mvd","TimeTick":"00:00:00"},"tmrRegistradorMOV":{"_uiControl":null,"State":2,"IsRunning":false,"IsStopped":true,"IsCreated":false,"Interval":1000,"StackTrace":"MovimentacaoUnificadaModel.IniciarRegistrador","Id":"tmrRegistrador_Mov","TimeTick":"00:00:00"},"tmrRegistradorDIR":{"_uiControl":null,"State":2,"IsRunning":false,"IsStopped":true,"IsCreated":false,"Interval":500,"StackTrace":"MovimentacaoUnificadaModel.IniciarRegistrador","Id":"tmrRegistrador_Dir","TimeTick":"00:00:00"},"Dispositivo":109,"_EnderecoCAN_Tx":0,"_EnderecoCAN_Rx":0,"Conectado":false,"_TaxaAmostragem":1000,"DistanciaPercorridaOperacao":0.0,"TempoEmAtividade":0.0,"DistanciaPercorridaTotal":0.0,"DistanciaPercorridaParcial":0.0,"VelocidadeMedia":0.0,"DiametroRoda":0.365,"ReducaoMotorBLDC":5.0,"RPM_Max_MotorBLDC":500.0,"IP_Mov":"192.168.105.10","IP_Dir":"192.168.105.11","Modulos":[{"Modulo_ID":"ET","Disponivel":false,"RequisitarDados":false,"Conectado":false,"MovMotor":{"ID":"Mov","_EnderecoCAN_Tx":5,"_EnderecoCAN_Rx":5,"heartBeatValue":1,"Mod_ID":"ET","LeituraLigado":true,"LeituraRPM":0.0,"ComandoLigado":false,"CodigoAlarme":0,"AlarmeMotor":false,"RPM_SP":0,"RPM_SP_Controle":0,"RPM_SP_Leitura":0,"Sentido_SP":0,"NumeroPolos":10,"Rampa":1,"CorrenteTorqueMaximo":40,"OffsetLeitura":1.0,"AlarmeComando":false,"RPM_Roda":0.0,"Sentido":0,"Temperatura":0.0,"TemperaturaDriver":0.0,"Tensao":0.0,"Corrente_Barramento":0.0,"Corrente_Motor":0.0,"Potencia":0.0,"CicloTrabalho":0.0,"RPM_Motor":0.0,"VelocidadeInstantanea":0.0,"Comandar":true,"AlarmeSensores":false,"Inicializado":false,"Leitura":null,"CompensacaoNecessaria":false,"ConfigSentidos":{"RodasDianteiras":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"RodasTraseiras":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"MovimentoDiagonal":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"MovimentoArco":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"RotacionarNoEixo":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"MovimentoLateral":{"Frente":2,"Tras":1,"Esquerda":0,"Direita":0,"Parado":0},"Diagnostico":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0}},"Funcoes":[12,14,9,5,10],"LogGrafico":[],"Alarmes":[{"Tipo":411,"Valor":-1.0,"Minimo":true,"Maximo":false,"ParaMinimo":false,"ParaMaximo":false},{"Tipo":4,"Valor":33.64,"Minimo":false,"Maximo":true,"ParaMinimo":false,"ParaMaximo":false}],"ConfigFreio":{"Incremental":true,"AnguloInicial":10,"Leitura":false,"Controle":false}},"DirMotor":{"ID":"Dir","_EnderecoCAN_Tx":1,"_EnderecoCAN_Rx":1,"Mod_ID":"ET","Sentido_SP":0,"Angulo_SP":0.0,"FolgaMecanica":0.0,"Velocidade_Max":600.0,"Velocidade":240,"Sentido":0,"SentidoReal":1,"Angulo":0.0,"RPM":0.0,"IN1_Atuado":true,"IN2_Atuado":true,"Referenciando":false,"Comandar":false,"Inicializado":false,"Leitura":null,"UltimaDirecao":0,"UltimoComandoEnviado":"2025-05-07T15:27:09.8024491-03:00","RetornandoAzero":false,"EmMovimento":false,"AtingiuAnguloSP":true,"ConfigSentidos":{"RodasDianteiras":{"Frente":0,"Tras":0,"Esquerda":0,"Direita":0,"Parado":0},"RodasTraseiras":{"Frente":0,"Tras":0,"Esquerda":2,"Direita":1,"Parado":0},"MovimentoDiagonal":{"Frente":0,"Tras":0,"Esquerda":1,"Direita":2,"Parado":0},"MovimentoArco":{"Frente":0,"Tras":0,"Esquerda":2,"Direita":1,"Parado":0},"RotacionarNoEixo":{"Frente":0,"Tras":0,"Esquerda":1,"Direita":1,"Parado":0},"MovimentoLateral":{"Frente":0,"Tras":0,"Esquerda":1,"Direita":2,"Parado":0},"Diagnostico":{"Frente":2,"Tras":1,"Esquerda":1,"Direita":2,"Parado":0}},"Funcoes":[13,9,14,41]}},{"Modulo_ID":"EF","Disponivel":false,"RequisitarDados":false,"Conectado":false,"MovMotor":{"ID":"Mov","_EnderecoCAN_Tx":7,"_EnderecoCAN_Rx":7,"heartBeatValue":1,"Mod_ID":"EF","LeituraLigado":true,"LeituraRPM":0.0,"ComandoLigado":false,"CodigoAlarme":0,"AlarmeMotor":false,"RPM_SP":0,"RPM_SP_Controle":0,"RPM_SP_Leitura":0,"Sentido_SP":0,"NumeroPolos":10,"Rampa":1,"CorrenteTorqueMaximo":40,"OffsetLeitura":1.0,"AlarmeComando":false,"RPM_Roda":0.0,"Sentido":0,"Temperatura":0.0,"TemperaturaDriver":0.0,"Tensao":0.0,"Corrente_Barramento":0.0,"Corrente_Motor":0.0,"Potencia":0.0,"CicloTrabalho":0.0,"RPM_Motor":0.0,"VelocidadeInstantanea":0.0,"Comandar":true,"AlarmeSensores":false,"Inicializado":false,"Leitura":null,"CompensacaoNecessaria":false,"ConfigSentidos":{"RodasDianteiras":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"RodasTraseiras":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"MovimentoDiagonal":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"MovimentoArco":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"RotacionarNoEixo":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"MovimentoLateral":{"Frente":2,"Tras":1,"Esquerda":0,"Direita":0,"Parado":0},"Diagnostico":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0}},"Funcoes":[12,14,9,5,10],"LogGrafico":[],"Alarmes":[{"Tipo":411,"Valor":-1.0,"Minimo":true,"Maximo":false,"ParaMinimo":false,"ParaMaximo":false},{"Tipo":4,"Valor":15.86,"Minimo":false,"Maximo":true,"ParaMinimo":false,"ParaMaximo":false}],"ConfigFreio":{"Incremental":true,"AnguloInicial":10,"Leitura":false,"Controle":false}},"DirMotor":{"ID":"Dir","_EnderecoCAN_Tx":3,"_EnderecoCAN_Rx":3,"Mod_ID":"EF","Sentido_SP":0,"Angulo_SP":0.0,"FolgaMecanica":9.0,"Velocidade_Max":600.0,"Velocidade":240,"Sentido":0,"SentidoReal":2,"Angulo":0.0,"RPM":0.0,"IN1_Atuado":true,"IN2_Atuado":true,"Referenciando":false,"Comandar":true,"Inicializado":false,"Leitura":null,"UltimaDirecao":0,"UltimoComandoEnviado":"2025-05-16T16:03:32.9874024-03:00","RetornandoAzero":false,"EmMovimento":false,"AtingiuAnguloSP":true,"ConfigSentidos":{"RodasDianteiras":{"Frente":0,"Tras":0,"Esquerda":2,"Direita":1,"Parado":0},"RodasTraseiras":{"Frente":0,"Tras":0,"Esquerda":0,"Direita":0,"Parado":0},"MovimentoDiagonal":{"Frente":0,"Tras":0,"Esquerda":2,"Direita":1,"Parado":0},"MovimentoArco":{"Frente":0,"Tras":0,"Esquerda":2,"Direita":1,"Parado":0},"RotacionarNoEixo":{"Frente":0,"Tras":0,"Esquerda":1,"Direita":1,"Parado":0},"MovimentoLateral":{"Frente":0,"Tras":0,"Esquerda":2,"Direita":1,"Parado":0},"Diagnostico":{"Frente":2,"Tras":1,"Esquerda":1,"Direita":2,"Parado":0}},"Funcoes":[13,9,14,41]}},{"Modulo_ID":"DT","Disponivel":false,"RequisitarDados":false,"Conectado":false,"MovMotor":{"ID":"Mov","_EnderecoCAN_Tx":6,"_EnderecoCAN_Rx":6,"heartBeatValue":0,"Mod_ID":"DT","LeituraLigado":true,"LeituraRPM":0.0,"ComandoLigado":false,"CodigoAlarme":0,"AlarmeMotor":false,"RPM_SP":0,"RPM_SP_Controle":0,"RPM_SP_Leitura":0,"Sentido_SP":0,"NumeroPolos":10,"Rampa":1,"CorrenteTorqueMaximo":40,"OffsetLeitura":1.0,"AlarmeComando":false,"RPM_Roda":0.0,"Sentido":0,"Temperatura":0.0,"TemperaturaDriver":0.0,"Tensao":0.0,"Corrente_Barramento":0.0,"Corrente_Motor":0.0,"Potencia":0.0,"CicloTrabalho":0.0,"RPM_Motor":0.0,"VelocidadeInstantanea":0.0,"Comandar":true,"AlarmeSensores":false,"Inicializado":false,"Leitura":null,"CompensacaoNecessaria":false,"ConfigSentidos":{"RodasDianteiras":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"RodasTraseiras":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"MovimentoDiagonal":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"MovimentoArco":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"RotacionarNoEixo":{"Frente":2,"Tras":1,"Esquerda":0,"Direita":0,"Parado":0},"MovimentoLateral":{"Frente":2,"Tras":1,"Esquerda":0,"Direita":0,"Parado":0},"Diagnostico":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0}},"Funcoes":[12,14,9,5,10],"LogGrafico":[],"Alarmes":[{"Tipo":411,"Valor":-1.0,"Minimo":true,"Maximo":false,"ParaMinimo":false,"ParaMaximo":false},{"Tipo":4,"Valor":15.18,"Minimo":false,"Maximo":true,"ParaMinimo":false,"ParaMaximo":false}],"ConfigFreio":{"Incremental":false,"AnguloInicial":170,"Leitura":false,"Controle":false}},"DirMotor":{"ID":"Dir","_EnderecoCAN_Tx":2,"_EnderecoCAN_Rx":2,"Mod_ID":"DT","Sentido_SP":0,"Angulo_SP":0.0,"FolgaMecanica":3.0,"Velocidade_Max":600.0,"Velocidade":240,"Sentido":0,"SentidoReal":2,"Angulo":0.0,"RPM":0.0,"IN1_Atuado":true,"IN2_Atuado":true,"Referenciando":false,"Comandar":false,"Inicializado":false,"Leitura":null,"UltimaDirecao":0,"UltimoComandoEnviado":"2025-05-16T15:58:30.0322588-03:00","RetornandoAzero":false,"EmMovimento":false,"AtingiuAnguloSP":true,"ConfigSentidos":{"RodasDianteiras":{"Frente":0,"Tras":0,"Esquerda":0,"Direita":0,"Parado":0},"RodasTraseiras":{"Frente":0,"Tras":0,"Esquerda":1,"Direita":2,"Parado":0},"MovimentoDiagonal":{"Frente":0,"Tras":0,"Esquerda":2,"Direita":1,"Parado":0},"MovimentoArco":{"Frente":0,"Tras":0,"Esquerda":1,"Direita":2,"Parado":0},"RotacionarNoEixo":{"Frente":0,"Tras":0,"Esquerda":1,"Direita":1,"Parado":0},"MovimentoLateral":{"Frente":0,"Tras":0,"Esquerda":2,"Direita":1,"Parado":0},"Diagnostico":{"Frente":2,"Tras":1,"Esquerda":1,"Direita":2,"Parado":0}},"Funcoes":[13,9,14,41]}},{"Modulo_ID":"DF","Disponivel":false,"RequisitarDados":false,"Conectado":false,"MovMotor":{"ID":"Mov","_EnderecoCAN_Tx":8,"_EnderecoCAN_Rx":8,"heartBeatValue":0,"Mod_ID":"DF","LeituraLigado":true,"LeituraRPM":0.0,"ComandoLigado":false,"CodigoAlarme":0,"AlarmeMotor":false,"RPM_SP":0,"RPM_SP_Controle":0,"RPM_SP_Leitura":0,"Sentido_SP":0,"NumeroPolos":10,"Rampa":1,"CorrenteTorqueMaximo":40,"OffsetLeitura":1.0,"AlarmeComando":false,"RPM_Roda":0.0,"Sentido":0,"Temperatura":0.0,"TemperaturaDriver":0.0,"Tensao":0.0,"Corrente_Barramento":0.0,"Corrente_Motor":0.0,"Potencia":0.0,"CicloTrabalho":0.0,"RPM_Motor":0.0,"VelocidadeInstantanea":0.0,"Comandar":true,"AlarmeSensores":false,"Inicializado":false,"Leitura":null,"CompensacaoNecessaria":false,"ConfigSentidos":{"RodasDianteiras":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"RodasTraseiras":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"MovimentoDiagonal":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"MovimentoArco":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0},"RotacionarNoEixo":{"Frente":2,"Tras":1,"Esquerda":0,"Direita":0,"Parado":0},"MovimentoLateral":{"Frente":2,"Tras":1,"Esquerda":0,"Direita":0,"Parado":0},"Diagnostico":{"Frente":1,"Tras":2,"Esquerda":0,"Direita":0,"Parado":0}},"Funcoes":[12,14,9,5,10],"LogGrafico":[],"Alarmes":[{"Tipo":411,"Valor":-1.0,"Minimo":true,"Maximo":false,"ParaMinimo":false,"ParaMaximo":false},{"Tipo":4,"Valor":32.47,"Minimo":false,"Maximo":true,"ParaMinimo":false,"ParaMaximo":false}],"ConfigFreio":{"Incremental":false,"AnguloInicial":170,"Leitura":false,"Controle":false}},"DirMotor":{"ID":"Dir","_EnderecoCAN_Tx":4,"_EnderecoCAN_Rx":4,"Mod_ID":"DF","Sentido_SP":0,"Angulo_SP":0.0,"FolgaMecanica":6.0,"Velocidade_Max":600.0,"Velocidade":240,"Sentido":0,"SentidoReal":1,"Angulo":0.0,"RPM":0.0,"IN1_Atuado":true,"IN2_Atuado":true,"Referenciando":false,"Comandar":true,"Inicializado":false,"Leitura":null,"UltimaDirecao":0,"UltimoComandoEnviado":"2025-05-16T16:03:32.9874024-03:00","RetornandoAzero":false,"EmMovimento":false,"AtingiuAnguloSP":true,"ConfigSentidos":{"RodasDianteiras":{"Frente":0,"Tras":0,"Esquerda":1,"Direita":2,"Parado":0},"RodasTraseiras":{"Frente":0,"Tras":0,"Esquerda":0,"Direita":0,"Parado":0},"MovimentoDiagonal":{"Frente":0,"Tras":0,"Esquerda":1,"Direita":2,"Parado":0},"MovimentoArco":{"Frente":0,"Tras":0,"Esquerda":1,"Direita":2,"Parado":0},"RotacionarNoEixo":{"Frente":0,"Tras":0,"Esquerda":1,"Direita":1,"Parado":0},"MovimentoLateral":{"Frente":0,"Tras":0,"Esquerda":1,"Direita":2,"Parado":0},"Diagnostico":{"Frente":2,"Tras":1,"Esquerda":1,"Direita":2,"Parado":0}},"Funcoes":[13,9,14,41]}}]}
\ No newline at end of file
diff --git a/AgroBase/AgroBase/bin/x64/Debug/Parametros/parametersSen-1_2.par b/AgroBase/AgroBase/bin/x64/Debug/Parametros/parametersSen-1_2.par
index ea4a4a5fa..c0c1668a7 100644
--- a/AgroBase/AgroBase/bin/x64/Debug/Parametros/parametersSen-1_2.par
+++ b/AgroBase/AgroBase/bin/x64/Debug/Parametros/parametersSen-1_2.par
@@ -1 +1 @@
-{"ContadorCarga":{"TempoEstimadoMinutos":2781.8655221310655,"CargaAtualAmp":19.99852214243111,"_Consumido":5.320287248,"ConsumidoAmp":0.0014778575688888889,"PercentualAtual":99.992610712155553,"PercentualConsumido":0.0073892878444444436,"PercentualBateria":"Infinity","ConsumidoWatts":0.0},"tmrRegistrador":{"_uiControl":null,"State":2,"IsRunning":false,"IsStopped":true,"IsCreated":false,"Interval":997,"StackTrace":"SensoriamentoModel.IniciarRegistrador","Id":"tmrRegistrador_Sen","TimeTick":"00:00:00"},"Dispositivo":102,"Modulo_ID":"Sen","_EnderecoCAN_Tx":17,"_EnderecoCAN_Rx":17,"_TaxaAmostragem":997,"RequisitarDados":true,"Conectado":false,"Sensores":[{"LogGrafico":[],"ID":"TMVET","ID_Num":1,"Descricao":"Temperatura Motor Esquerdo Trás","Componente":4,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":[12],"Parametros":[{"Descricao":"Offset","Valor":"0","QtdBytes":2,"Escalar":false,"Enviar":false},{"Descricao":"Canal MUX","Valor":"-1","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":"ºC","LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"TMVEF","ID_Num":2,"Descricao":"Temperatura Motor Esquerdo Frente","Componente":4,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":[12],"Parametros":[{"Descricao":"Offset","Valor":"0","QtdBytes":2,"Escalar":false,"Enviar":false},{"Descricao":"Canal MUX","Valor":"-1","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":"ºC","LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"TMVDT","ID_Num":3,"Descricao":"Temperatura Motor Direito Trás","Componente":4,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":[12],"Parametros":[{"Descricao":"Offset","Valor":"0","QtdBytes":2,"Escalar":false,"Enviar":false},{"Descricao":"Canal MUX","Valor":"-1","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":"ºC","LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"TMVDF","ID_Num":4,"Descricao":"Temperatura Motor Direito Frente","Componente":4,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":[12],"Parametros":[{"Descricao":"Offset","Valor":"0","QtdBytes":2,"Escalar":false,"Enviar":false},{"Descricao":"Canal MUX","Valor":"-1","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":"ºC","LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"TBAT","ID_Num":5,"Descricao":"Temperatura da bateria","Componente":4,"Aferir":false,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":[12],"Parametros":[{"Descricao":"Offset","Valor":"0","QtdBytes":2,"Escalar":false,"Enviar":false}],"UnidadeMedida":"ºC","LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"LUZABT","ID_Num":31,"Descricao":"Luminosidade ambiente","Componente":30,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":null,"Parametros":[{"Descricao":"Endereço I2C","Valor":"0x29","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Canal MUX","Valor":"-1","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":"lux","LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"AB3V","ID_Num":11,"Descricao":"Corrente no Barramento 3V","Componente":6,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":null,"Parametros":[{"Descricao":"Endereço I2C","Valor":"0x40","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Shunt","Valor":"0","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Canal MUX","Valor":"5","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":null,"LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"AB5V","ID_Num":12,"Descricao":"Corrente no Barramento 5V","Componente":6,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":null,"Parametros":[{"Descricao":"Endereço I2C","Valor":"0x40","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Shunt","Valor":"0","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Canal MUX","Valor":"4","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":null,"LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"AB7V2","ID_Num":13,"Descricao":"Corrente no Barramento 7,2V","Componente":6,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":null,"Parametros":[{"Descricao":"Endereço I2C","Valor":"0x40","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Shunt","Valor":"0","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Canal MUX","Valor":"2","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":null,"LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"AB12V","ID_Num":14,"Descricao":"Corrente no Barramento 12V","Componente":6,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":null,"Parametros":[{"Descricao":"Endereço I2C","Valor":"0x40","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Shunt","Valor":"2","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Canal MUX","Valor":"3","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":null,"LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"AB19V","ID_Num":15,"Descricao":"Corrente no Barramento 19V","Componente":6,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":null,"Parametros":[{"Descricao":"Endereço I2C","Valor":"0x40","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Shunt","Valor":"1","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Canal MUX","Valor":"1","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":null,"LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"AB24V","ID_Num":16,"Descricao":"Corrente no Barramento 24V","Componente":6,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":null,"Parametros":[{"Descricao":"Endereço I2C","Valor":"0x40","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Shunt","Valor":"2","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Canal MUX","Valor":"6","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":null,"LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"AB36V","ID_Num":17,"Descricao":"Corrente no Barramento 36V","Componente":6,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":null,"Parametros":[{"Descricao":"Endereço I2C","Valor":"0x40","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Shunt","Valor":"3","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Canal MUX","Valor":"7","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":null,"LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"GY91","ID_Num":30,"Descricao":"Inclinometro","Componente":25,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":[27],"Parametros":[{"Descricao":"Endereço MPU","Valor":"0x68","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Endereço BMP","Valor":"0x76","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":"","LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"IUVABT","ID_Num":32,"Descricao":"Indice de radiacao AUV ambiente","Componente":31,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":[51],"Parametros":[{"Descricao":"Canal MUX","Valor":"-1","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":"iuv","LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"MQ2","ID_Num":33,"Descricao":"Gas e Fumaca","Componente":28,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":[50],"Parametros":[{"Descricao":"Tipo","Valor":"0","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Canal MUX","Valor":"-1","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":"ppm","LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"MQ7","ID_Num":34,"Descricao":"Monoxido de Carbono","Componente":28,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":[50],"Parametros":[{"Descricao":"Tipo","Valor":"1","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Canal MUX","Valor":"-1","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":"ppm","LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"QARABT","ID_Num":35,"Descricao":"Qualidade do Ar","Componente":32,"Aferir":false,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":[27],"Parametros":[{"Descricao":"Canal MUX","Valor":"-1","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":"","LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"SHTABT","ID_Num":36,"Descricao":"Temperatura e Umidade ambiente","Componente":29,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":null,"Parametros":[{"Descricao":"Endereço I2C","Valor":"0x44","QtdBytes":1,"Escalar":false,"Enviar":false},{"Descricao":"Canal MUX","Valor":"-1","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":"ºC","LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"CHVABT","ID_Num":37,"Descricao":"Chuva","Componente":33,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":[52],"Parametros":[{"Descricao":"Canal MUX","Valor":"-1","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":"º%","LimiteMaximo":0.0,"LimiteMinimo":0.0}],"Sinaleiros":[{"ID":"LEDMN","ID_Num":21,"Descricao":"Sinaleiro indicação de modo Manual ativo","Componente":15,"Funcoes":[38],"Comportamento":{"statusLED":1,"QtdPiscadas":1,"TempoMs":1000,"PausaMs":1000},"Leitura":null,"Inicializado":false,"LeituraComando":0,"LeituraStatus":0},{"ID":"LEDAT","ID_Num":22,"Descricao":"Sinaleiro indicação de modo Automático ativo","Componente":15,"Funcoes":[38],"Comportamento":{"statusLED":0,"QtdPiscadas":1,"TempoMs":1000,"PausaMs":1000},"Leitura":null,"Inicializado":false,"LeituraComando":0,"LeituraStatus":0},{"ID":"LEDOP","ID_Num":23,"Descricao":"Sinaleiro indicação do status da operação ativa","Componente":15,"Funcoes":[38],"Comportamento":{"statusLED":2,"QtdPiscadas":2,"TempoMs":500,"PausaMs":2000},"Leitura":null,"Inicializado":false,"LeituraComando":0,"LeituraStatus":0}],"Reles":[],"Servos":[{"ID":"FRO_ET","ID_Num":41,"Descricao":"Freio Motor ET","Componente":22,"Funcoes":[45],"Incremental":true,"Controlar":true,"Mandatorio":false,"Liberado":true,"_AnguloControle":0,"Leitura":null,"Inicializado":false,"LeituraAngulo":0.0},{"ID":"FRO_EF","ID_Num":42,"Descricao":"Freio Motor EF","Componente":22,"Funcoes":[45],"Incremental":false,"Controlar":false,"Mandatorio":false,"Liberado":true,"_AnguloControle":180,"Leitura":null,"Inicializado":false,"LeituraAngulo":0.0},{"ID":"FRO_DT","ID_Num":43,"Descricao":"Freio Motor DT","Componente":22,"Funcoes":[45],"Incremental":false,"Controlar":true,"Mandatorio":false,"Liberado":true,"_AnguloControle":180,"Leitura":null,"Inicializado":false,"LeituraAngulo":0.0},{"ID":"FRO_DF","ID_Num":44,"Descricao":"Freio Motor DF","Componente":22,"Funcoes":[45],"Incremental":false,"Controlar":false,"Mandatorio":false,"Liberado":true,"_AnguloControle":180,"Leitura":null,"Inicializado":false,"LeituraAngulo":0.0}],"CameraID_Caminho":"","CameraID_Solo":["",""],"ConfiguracaoSensorUltrassom":{"Configuracao":0,"Sensores":[{"ID":1,"Posicao":0,"LimiteMinimo":false,"LimiteMinimoVal":0.0,"MargemMinimo":0.0,"LimiteMaximo":false,"LimiteMaximoVal":0.0,"MargemMaximo":0.0,"Desvio":false,"Parada":false,"DistanciaIdeal":0.0,"EmUso":false,"LeituraCm":0.0,"SensorAtuado":false},{"ID":2,"Posicao":0,"LimiteMinimo":false,"LimiteMinimoVal":0.0,"MargemMinimo":0.0,"LimiteMaximo":false,"LimiteMaximoVal":0.0,"MargemMaximo":0.0,"Desvio":false,"Parada":false,"DistanciaIdeal":0.0,"EmUso":false,"LeituraCm":0.0,"SensorAtuado":false},{"ID":3,"Posicao":0,"LimiteMinimo":false,"LimiteMinimoVal":0.0,"MargemMinimo":0.0,"LimiteMaximo":false,"LimiteMaximoVal":0.0,"MargemMaximo":0.0,"Desvio":false,"Parada":false,"DistanciaIdeal":0.0,"EmUso":false,"LeituraCm":0.0,"SensorAtuado":false},{"ID":4,"Posicao":0,"LimiteMinimo":false,"LimiteMinimoVal":0.0,"MargemMinimo":0.0,"LimiteMaximo":false,"LimiteMaximoVal":0.0,"MargemMaximo":0.0,"Desvio":false,"Parada":false,"DistanciaIdeal":0.0,"EmUso":false,"LeituraCm":0.0,"SensorAtuado":false}],"_paradaFrontal":false,"_paradaTraseira":false,"_paradaEsquerda":false,"_paradaDireita":false,"DesvioNecessario":false,"ParadaNecessaria":false,"DirecoesObstaculos":[],"DirecaoDesvio":1},"DadosLeitura":{"Momento":"0001-01-01T00:00:00","Conectado":false,"Dispositivo":0,"Versao":0,"Mod_ID":null,"QualidadeWifi":0,"LatenciaLoop":0,"SensoresTemperaturaNTC":[],"SensoresCorrente":[],"Sinaleiros":[],"Reles":[],"ServoFreios":[],"SensoresIMU":[],"SensoresGas":[],"SensoresTemperaturaSHT":[],"SensoresLuminosidade":[],"SensoresLuzUV":[],"SensoresQualidadeAr":[],"SensoresChuva":[],"UltimoComandoRespondido":"0001-01-01T00:00:00"},"loRaService":{"ID":"LoRa","ID_Num":251,"Componente":26,"Conectado":false,"Configurado":false,"Iniciado":false,"ParametrosSet":{"UltimaLeitura":"0001-01-01T00:00:00","PortaCOM":"","baudRate":96,"airRate":0,"baudAndAirRate":96,"parity":0,"packetSize":192,"power":0,"packetSizeAndPower":192,"tranMode":64,"worCycle":3,"tranModeAndWorCycle":67,"channelRssi":0,"lbt":0,"packetRssi":0,"address":2,"channel":23,"key":0},"ParametrosGet":{"UltimaLeitura":"0001-01-01T00:00:00","PortaCOM":"","baudRate":96,"airRate":0,"baudAndAirRate":96,"parity":0,"packetSize":192,"power":0,"packetSizeAndPower":192,"tranMode":64,"worCycle":3,"tranModeAndWorCycle":67,"channelRssi":0,"lbt":0,"packetRssi":0,"address":2,"channel":23,"key":0},"Funcoes":[47,48,49,3,2]},"LoRaParametrosBase":{"UltimaLeitura":"0001-01-01T00:00:00","PortaCOM":"","baudRate":96,"airRate":2,"baudAndAirRate":104,"parity":0,"packetSize":0,"power":0,"packetSizeAndPower":0,"tranMode":64,"worCycle":7,"tranModeAndWorCycle":71,"channelRssi":0,"lbt":0,"packetRssi":0,"address":1,"channel":23,"key":0}}
\ No newline at end of file
+{"ContadorCarga":{"TempoEstimadoMinutos":0.0,"CargaAtualAmp":20.0,"_Consumido":0.0,"ConsumidoAmp":0.0,"PercentualAtual":100.0,"PercentualConsumido":0.0,"PercentualBateria":0.0,"ConsumidoWatts":0.0},"tmrRegistrador":{"_uiControl":null,"State":2,"IsRunning":false,"IsStopped":true,"IsCreated":false,"Interval":997,"StackTrace":"SensoriamentoModel.IniciarRegistrador","Id":"tmrRegistrador_Sen","TimeTick":"00:00:00"},"Dispositivo":102,"Modulo_ID":"Sen","_EnderecoCAN_Tx":17,"_EnderecoCAN_Rx":17,"_TaxaAmostragem":997,"RequisitarDados":true,"Conectado":false,"Sensores":[{"LogGrafico":[],"ID":"TMVET","ID_Num":1,"Descricao":"Temperatura Motor Esquerdo Trás","Componente":4,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":[12],"Parametros":[{"Descricao":"Offset","Valor":"0","QtdBytes":2,"Escalar":false,"Enviar":false},{"Descricao":"Canal MUX","Valor":"-1","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":"ºC","LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"TMVEF","ID_Num":2,"Descricao":"Temperatura Motor Esquerdo Frente","Componente":4,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":[12],"Parametros":[{"Descricao":"Offset","Valor":"0","QtdBytes":2,"Escalar":false,"Enviar":false},{"Descricao":"Canal MUX","Valor":"-1","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":"ºC","LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"TMVDT","ID_Num":3,"Descricao":"Temperatura Motor Direito Trás","Componente":4,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":[12],"Parametros":[{"Descricao":"Offset","Valor":"0","QtdBytes":2,"Escalar":false,"Enviar":false},{"Descricao":"Canal MUX","Valor":"-1","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":"ºC","LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"TMVDF","ID_Num":4,"Descricao":"Temperatura Motor Direito Frente","Componente":4,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":[12],"Parametros":[{"Descricao":"Offset","Valor":"0","QtdBytes":2,"Escalar":false,"Enviar":false},{"Descricao":"Canal MUX","Valor":"-1","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":"ºC","LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"TBAT","ID_Num":5,"Descricao":"Temperatura da bateria","Componente":4,"Aferir":false,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":[12],"Parametros":[{"Descricao":"Offset","Valor":"0","QtdBytes":2,"Escalar":false,"Enviar":false}],"UnidadeMedida":"ºC","LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"LUZABT","ID_Num":31,"Descricao":"Luminosidade ambiente","Componente":30,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":null,"Parametros":[{"Descricao":"Endereço I2C","Valor":"0x29","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Canal MUX","Valor":"-1","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":"lux","LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"AB3V","ID_Num":11,"Descricao":"Corrente no Barramento 3V","Componente":6,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":null,"Parametros":[{"Descricao":"Endereço I2C","Valor":"0x40","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Shunt","Valor":"0","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Canal MUX","Valor":"5","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":null,"LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"AB5V","ID_Num":12,"Descricao":"Corrente no Barramento 5V","Componente":6,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":null,"Parametros":[{"Descricao":"Endereço I2C","Valor":"0x40","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Shunt","Valor":"0","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Canal MUX","Valor":"4","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":null,"LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"AB7V2","ID_Num":13,"Descricao":"Corrente no Barramento 7,2V","Componente":6,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":null,"Parametros":[{"Descricao":"Endereço I2C","Valor":"0x40","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Shunt","Valor":"0","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Canal MUX","Valor":"2","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":null,"LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"AB12V","ID_Num":14,"Descricao":"Corrente no Barramento 12V","Componente":6,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":null,"Parametros":[{"Descricao":"Endereço I2C","Valor":"0x40","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Shunt","Valor":"2","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Canal MUX","Valor":"3","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":null,"LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"AB19V","ID_Num":15,"Descricao":"Corrente no Barramento 19V","Componente":6,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":null,"Parametros":[{"Descricao":"Endereço I2C","Valor":"0x40","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Shunt","Valor":"1","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Canal MUX","Valor":"1","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":null,"LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"AB24V","ID_Num":16,"Descricao":"Corrente no Barramento 24V","Componente":6,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":null,"Parametros":[{"Descricao":"Endereço I2C","Valor":"0x40","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Shunt","Valor":"2","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Canal MUX","Valor":"6","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":null,"LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"AB36V","ID_Num":17,"Descricao":"Corrente no Barramento 36V","Componente":6,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":null,"Parametros":[{"Descricao":"Endereço I2C","Valor":"0x40","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Shunt","Valor":"3","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Canal MUX","Valor":"7","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":null,"LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"GY91","ID_Num":30,"Descricao":"Inclinometro","Componente":25,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":[27],"Parametros":[{"Descricao":"Endereço MPU","Valor":"0x68","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Endereço BMP","Valor":"0x76","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":"","LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"IUVABT","ID_Num":32,"Descricao":"Indice de radiacao AUV ambiente","Componente":31,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":[51],"Parametros":[{"Descricao":"Canal MUX","Valor":"-1","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":"iuv","LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"MQ2","ID_Num":33,"Descricao":"Gas e Fumaca","Componente":28,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":[50],"Parametros":[{"Descricao":"Tipo","Valor":"0","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Canal MUX","Valor":"-1","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":"ppm","LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"MQ7","ID_Num":34,"Descricao":"Monoxido de Carbono","Componente":28,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":[50],"Parametros":[{"Descricao":"Tipo","Valor":"1","QtdBytes":1,"Escalar":false,"Enviar":true},{"Descricao":"Canal MUX","Valor":"-1","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":"ppm","LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"QARABT","ID_Num":35,"Descricao":"Qualidade do Ar","Componente":32,"Aferir":false,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":[27],"Parametros":[{"Descricao":"Canal MUX","Valor":"-1","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":"","LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"SHTABT","ID_Num":36,"Descricao":"Temperatura e Umidade ambiente","Componente":29,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":null,"Parametros":[{"Descricao":"Endereço I2C","Valor":"0x44","QtdBytes":1,"Escalar":false,"Enviar":false},{"Descricao":"Canal MUX","Valor":"-1","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":"ºC","LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"CHVABT","ID_Num":37,"Descricao":"Chuva","Componente":33,"Aferir":true,"Mandatorio":false,"Liberado":true,"Leitura":null,"Inicializado":false,"Funcoes":[52],"Parametros":[{"Descricao":"Canal MUX","Valor":"-1","QtdBytes":1,"Escalar":false,"Enviar":true}],"UnidadeMedida":"º%","LimiteMaximo":0.0,"LimiteMinimo":0.0}],"Sinaleiros":[{"ID":"LEDMN","ID_Num":21,"Descricao":"Sinaleiro indicação de modo Manual ativo","Componente":15,"Funcoes":[38],"Comportamento":{"statusLED":1,"QtdPiscadas":1,"TempoMs":1000,"PausaMs":1000},"Leitura":null,"Inicializado":false,"LeituraComando":0,"LeituraStatus":0},{"ID":"LEDAT","ID_Num":22,"Descricao":"Sinaleiro indicação de modo Automático ativo","Componente":15,"Funcoes":[38],"Comportamento":{"statusLED":0,"QtdPiscadas":1,"TempoMs":1000,"PausaMs":1000},"Leitura":null,"Inicializado":false,"LeituraComando":0,"LeituraStatus":0},{"ID":"LEDOP","ID_Num":23,"Descricao":"Sinaleiro indicação do status da operação ativa","Componente":15,"Funcoes":[38],"Comportamento":{"statusLED":2,"QtdPiscadas":2,"TempoMs":500,"PausaMs":2000},"Leitura":null,"Inicializado":false,"LeituraComando":0,"LeituraStatus":0}],"Reles":[],"Servos":[{"ID":"FRO_ET","ID_Num":41,"Descricao":"Freio Motor ET","Componente":22,"Funcoes":[45],"Incremental":true,"Controlar":true,"Mandatorio":false,"Liberado":true,"_AnguloControle":0,"Leitura":null,"Inicializado":false,"LeituraAngulo":0.0},{"ID":"FRO_EF","ID_Num":42,"Descricao":"Freio Motor EF","Componente":22,"Funcoes":[45],"Incremental":false,"Controlar":false,"Mandatorio":false,"Liberado":true,"_AnguloControle":180,"Leitura":null,"Inicializado":false,"LeituraAngulo":0.0},{"ID":"FRO_DT","ID_Num":43,"Descricao":"Freio Motor DT","Componente":22,"Funcoes":[45],"Incremental":false,"Controlar":true,"Mandatorio":false,"Liberado":true,"_AnguloControle":180,"Leitura":null,"Inicializado":false,"LeituraAngulo":0.0},{"ID":"FRO_DF","ID_Num":44,"Descricao":"Freio Motor DF","Componente":22,"Funcoes":[45],"Incremental":false,"Controlar":false,"Mandatorio":false,"Liberado":true,"_AnguloControle":180,"Leitura":null,"Inicializado":false,"LeituraAngulo":0.0}],"CameraID_Caminho":"","CameraID_Solo":["",""],"ConfiguracaoSensorUltrassom":{"Configuracao":0,"Sensores":[{"ID":1,"Posicao":0,"LimiteMinimo":false,"LimiteMinimoVal":0.0,"MargemMinimo":0.0,"LimiteMaximo":false,"LimiteMaximoVal":0.0,"MargemMaximo":0.0,"Desvio":false,"Parada":false,"DistanciaIdeal":0.0,"EmUso":false,"LeituraCm":0.0,"SensorAtuado":false},{"ID":2,"Posicao":0,"LimiteMinimo":false,"LimiteMinimoVal":0.0,"MargemMinimo":0.0,"LimiteMaximo":false,"LimiteMaximoVal":0.0,"MargemMaximo":0.0,"Desvio":false,"Parada":false,"DistanciaIdeal":0.0,"EmUso":false,"LeituraCm":0.0,"SensorAtuado":false},{"ID":3,"Posicao":0,"LimiteMinimo":false,"LimiteMinimoVal":0.0,"MargemMinimo":0.0,"LimiteMaximo":false,"LimiteMaximoVal":0.0,"MargemMaximo":0.0,"Desvio":false,"Parada":false,"DistanciaIdeal":0.0,"EmUso":false,"LeituraCm":0.0,"SensorAtuado":false},{"ID":4,"Posicao":0,"LimiteMinimo":false,"LimiteMinimoVal":0.0,"MargemMinimo":0.0,"LimiteMaximo":false,"LimiteMaximoVal":0.0,"MargemMaximo":0.0,"Desvio":false,"Parada":false,"DistanciaIdeal":0.0,"EmUso":false,"LeituraCm":0.0,"SensorAtuado":false}],"_paradaFrontal":false,"_paradaTraseira":false,"_paradaEsquerda":false,"_paradaDireita":false,"DesvioNecessario":false,"ParadaNecessaria":false,"DirecoesObstaculos":[],"DirecaoDesvio":1},"DadosLeitura":{"Momento":"0001-01-01T00:00:00","Conectado":false,"Dispositivo":0,"Versao":0,"Mod_ID":null,"QualidadeWifi":0,"LatenciaLoop":0,"SensoresTemperaturaNTC":[],"SensoresCorrente":[],"Sinaleiros":[],"Reles":[],"ServoFreios":[],"SensoresIMU":[],"SensoresGas":[],"SensoresTemperaturaSHT":[],"SensoresLuminosidade":[],"SensoresLuzUV":[],"SensoresQualidadeAr":[],"SensoresChuva":[],"UltimoComandoRespondido":"0001-01-01T00:00:00"},"loRaService":{"ID":"LoRa","ID_Num":251,"Componente":26,"Conectado":false,"Configurado":false,"Iniciado":false,"ParametrosSet":{"UltimaLeitura":"0001-01-01T00:00:00","PortaCOM":"","baudRate":96,"airRate":0,"baudAndAirRate":96,"parity":0,"packetSize":192,"power":0,"packetSizeAndPower":192,"tranMode":64,"worCycle":3,"tranModeAndWorCycle":67,"channelRssi":0,"lbt":0,"packetRssi":0,"address":2,"channel":23,"key":0},"ParametrosGet":{"UltimaLeitura":"0001-01-01T00:00:00","PortaCOM":"","baudRate":96,"airRate":0,"baudAndAirRate":96,"parity":0,"packetSize":192,"power":0,"packetSizeAndPower":192,"tranMode":64,"worCycle":3,"tranModeAndWorCycle":67,"channelRssi":0,"lbt":0,"packetRssi":0,"address":2,"channel":23,"key":0},"Funcoes":[47,48,49,3,2]},"LoRaParametrosBase":{"UltimaLeitura":"0001-01-01T00:00:00","PortaCOM":"","baudRate":96,"airRate":2,"baudAndAirRate":104,"parity":0,"packetSize":0,"power":0,"packetSizeAndPower":0,"tranMode":64,"worCycle":7,"tranModeAndWorCycle":71,"channelRssi":0,"lbt":0,"packetRssi":0,"address":1,"channel":23,"key":0}}
\ No newline at end of file
diff --git a/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/camera_manager.py b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/camera_manager.py
new file mode 100644
index 000000000..02d21f2c3
--- /dev/null
+++ b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/camera_manager.py
@@ -0,0 +1,248 @@
+# camera_manager.py
+
+import depthai as dai
+import cv2
+import numpy as np
+import time
+
+# Parâmetros da câmera
+RGB_WIDTH, RGB_HEIGHT = 640, 480
+#DEPTH_WIDTH, DEPTH_HEIGHT = 320, 240
+DEPTH_WIDTH, DEPTH_HEIGHT = 640, 400
+FX = 440.0 # distância focal em pixels (aproximado)
+FY = 440.0 # distância focal em pixels (aproximado)
+BASELINE = 0.075 # distância entre câmeras estéreo (em metros)
+FOV_H = 1
+FOV_V = 1
+DISTANCIA_MAXIMA = 3000.0
+
+# Variáveis globais
+device = None
+device_info = None
+camera_pronta = False
+rgb_queue = None
+depth_queue = None
+ultimo_frame_depth = None
+timestamp_ultimo_depth_frame = None
+ultimo_frame_rgb = None
+timestamp_ultimo_rgb_frame = None
+
+def iniciar_camera(index=0, distancia_max=3000.0):
+ global device, device_info, rgb_queue, depth_queue, camera_pronta
+
+ camera_pronta = False
+
+ print("Iniciando câmera OAK-D Lite...")
+
+ pipeline = dai.Pipeline()
+
+ # RGB
+ cam_rgb = pipeline.create(dai.node.ColorCamera)
+ cam_rgb.setPreviewSize(RGB_WIDTH, RGB_HEIGHT)
+ cam_rgb.setInterleaved(False)
+ cam_rgb.setBoardSocket(dai.CameraBoardSocket.RGB)
+
+ xout_rgb = pipeline.create(dai.node.XLinkOut)
+ xout_rgb.setStreamName("rgb")
+ cam_rgb.preview.link(xout_rgb.input)
+
+ # 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_480_P)
+ mono_right.setResolution(dai.MonoCameraProperties.SensorResolution.THE_480_P)
+ mono_left.setBoardSocket(dai.CameraBoardSocket.LEFT)
+ mono_right.setBoardSocket(dai.CameraBoardSocket.RIGHT)
+
+ stereo.setDefaultProfilePreset(dai.node.StereoDepth.PresetMode.ROBOTICS)
+
+ mono_left.out.link(stereo.left)
+ mono_right.out.link(stereo.right)
+
+ xout_depth = pipeline.create(dai.node.XLinkOut)
+ xout_depth.setStreamName("depth")
+ stereo.depth.link(xout_depth.input)
+
+ # Dispositivo
+ available_devices = dai.Device.getAllAvailableDevices()
+ if index >= len(available_devices):
+ raise ValueError(f"Câmera de índice {index} não encontrada.")
+
+ device_info = available_devices[index]
+ device = dai.Device(pipeline, device_info)
+
+ rgb_queue = device.getOutputQueue(name="rgb", maxSize=1, blocking=False)
+ depth_queue = device.getOutputQueue(name="depth", maxSize=1, blocking=False)
+
+ camera_pronta = True
+
+ print(f"Câmera iniciada: {device_info.name} (ID: {device_info.getMxId()})")
+
+ set_camera_calib(distancia_max)
+
+def set_camera_calib(distancia_max):
+ if not verificar_camera_ativa():
+ return
+
+ global FX, FY, BASELINE, FOV_H, FOV_V, DISTANCIA_MAXIMA
+ calib = device.readCalibration()
+
+ DISTANCIA_MAXIMA = distancia_max
+
+ # Obtem matriz intrínseca da câmera LEFT (com resolução padrão 640x400)
+ intrinsics = calib.getCameraIntrinsics(dai.CameraBoardSocket.LEFT, DEPTH_WIDTH, DEPTH_HEIGHT)
+ FX = intrinsics[0][0] # fx
+ FY = intrinsics[1][1] # fy
+ BASELINE = calib.getBaselineDistance() / 100.0 # de cm → m
+
+ FOV_H = 2 * np.arctan(DEPTH_WIDTH / (2 * FX))
+ FOV_V = 2 * np.arctan(DEPTH_HEIGHT / (2 * FY))
+
+ print(f"[CALIB] FX: {FX:.2f} px, FY: {FY:.2f} px, FOV_H: {FOV_H:.2f}, FOV_V: {FOV_V:.2f}, BASELINE: {BASELINE:.4f} m")
+
+def get_camera_calib():
+ return {
+ "rgb_width": RGB_WIDTH,
+ "rgb_height": RGB_HEIGHT,
+ "depth_width": DEPTH_WIDTH,
+ "depth_height": DEPTH_HEIGHT,
+ "fx": FX,
+ "fy": FY,
+ "baseline": BASELINE,
+ "fov_h": FOV_H,
+ "fov_v": FOV_V,
+ "distancia_maxima": DISTANCIA_MAXIMA
+ }
+
+def verificar_camera_ativa():
+ global device, depth_queue, rgb_queue, camera_pronta
+
+ # Se a câmera ainda não foi inicializada
+ if device is None or not camera_pronta:
+ print("[INFO] Câmera não ativa. Tentando reiniciar...")
+
+ try:
+ iniciar_camera() # essa função já configura tudo
+ return True
+ except Exception as e:
+ print(f"[ERRO] Falha ao reiniciar a câmera: {e}")
+ return False
+
+ return camera_pronta
+
+ # Se o device existe mas o pipeline caiu (fila morta)
+ try:
+ test = depth_queue.tryGet()
+ except Exception as e:
+ print(f"[ERRO] Falha ao acessar depth_queue: {e}. Tentando reiniciar câmera...")
+ try:
+ device.close()
+ except:
+ pass
+ device = None
+ camera_pronta = False
+ return verificar_camera_ativa() # tenta de novo
+
+ return True
+
+def get_rgb_frame():
+ if not verificar_camera_ativa():
+ return None, None
+ global ultimo_frame_rgb, timestamp_ultimo_rgb_frame
+ if rgb_queue is None:
+ return None, None
+ frame = rgb_queue.tryGet()
+ if frame is not None:
+ ultimo_frame_rgb = frame.getCvFrame()
+ timestamp_ultimo_rgb_frame = time.time()
+ return ultimo_frame_rgb, timestamp_ultimo_rgb_frame
+
+def get_depth_frame():
+ if not verificar_camera_ativa():
+ return None, None
+ global ultimo_frame_depth, timestamp_ultimo_depth_frame
+ if depth_queue is None:
+ return None, None
+
+ frame = depth_queue.tryGet()
+ if frame is not None:
+ ultimo_frame_depth = frame.getFrame()
+ timestamp_ultimo_depth_frame = time.time()
+ return ultimo_frame_depth, timestamp_ultimo_depth_frame
+
+def get_heatmap_frame():
+ frame, timestamp = get_depth_frame()
+ if frame is not None:
+ from visual_worker.utils import gerar_heatmap
+ return gerar_heatmap(frame, DISTANCIA_MAXIMA), timestamp
+ return None, None
+
+def get_status_dispositivo():
+ if not verificar_camera_ativa():
+ return None
+
+ from depthai import UsbSpeed
+
+ try:
+ memory = device.getDdrMemoryUsage()
+ memory_info = {
+ "used": memory.used,
+ "remaining": memory.remaining,
+ "total": memory.total
+ }
+ except:
+ memory_info = None
+
+ try:
+ temp = device.getChipTemperature()
+ temp_info = {
+ "css": temp.css,
+ "mss": temp.mss,
+ "upa": temp.upa,
+ "dss": temp.dss
+ }
+ except:
+ temp_info = None
+
+ try:
+ info = device.getDeviceInfo()
+ protocol = str(info.protocol)
+ except:
+ protocol = None
+
+ try:
+ bootloader = str(device.getBootloaderVersion())
+ except:
+ bootloader = None
+
+ try:
+ usb_speed = str(device.getUsbSpeed().name)
+ except:
+ usb_speed = None
+
+ try:
+ pipeline_running = device.isPipelineRunning()
+ except:
+ pipeline_running = None
+
+ try:
+ cameras = [sensor.name for sensor in device.getConnectedCameras()]
+ except:
+ cameras = None
+
+ return {
+ "id": device_info.getMxId(),
+ "name": device_info.name,
+ "state": device_info.state.name,
+ "usb_speed": usb_speed,
+ "available_camera_sensors": cameras,
+ "version": protocol,
+ "bootloader_version": bootloader,
+ "is_pipeline_running": pipeline_running,
+ "memory_usage": memory_info,
+ "temperature": temp_info,
+ "fx": FX,
+ "baseline": BASELINE
+ }
diff --git a/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/enums.py b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/enums.py
new file mode 100644
index 000000000..495f2dfa9
--- /dev/null
+++ b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/enums.py
@@ -0,0 +1,40 @@
+from enum import IntEnum
+
+class Comando(IntEnum):
+ PING = 1
+ GET_STATUS_DISPOSITIVO = 2
+ GET_RGB_FRAME = 3
+ GET_HEATMAP_FRAME = 4
+ CALIBRAR_GRADES = 5
+ GET_ANALISE_ANOMALIA = 6
+ GET_ANALISE_SOLO = 7
+
+class TipoComando(IntEnum):
+ TX = 1
+ RX = 2
+
+class TipoDeteccao(IntEnum):
+ SEGURO = 1
+ OBSTACULO = 2
+ DEPRESSAO = 3
+
+class TipoRegiaoRadar(IntEnum):
+ SOLO = 1
+ AEREO = 2
+
+class Direcao(IntEnum):
+ PARADO = 0
+ FRENTE = 1
+ TRAS = 2
+ ESQUERDA = 3
+ DIREITA = 4
+ CIMA = 5
+ BAIXO = 6
+ ESQUERDABAIXO = 7
+ ESQUERDACIMA = 8
+ DIREITABAIXO = 9
+ DIREITACIMA = 10
+
+class TipoAnalise(IntEnum):
+ ANOMALIA = 1
+ SOLO = 2
\ No newline at end of file
diff --git a/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/filtros.py b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/filtros.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/main.py b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/main.py
new file mode 100644
index 000000000..d8d85fa8d
--- /dev/null
+++ b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/main.py
@@ -0,0 +1,144 @@
+import sys
+import os
+import time
+import json
+
+from enums import Comando, TipoAnalise, TipoComando
+
+from mqtt_handler import enviar_mensagem_mqtt
+
+sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
+
+
+# ─────────────────────────────
+# 🔹 Parâmetros de Execução
+# ─────────────────────────────
+mqtt_topic = sys.argv[1] if len(sys.argv) > 1 else "agrobot/operador/sonar"
+camera_index = int(sys.argv[2]) if len(sys.argv) > 2 else 0
+
+
+# ─────────────────────────────
+# 🔹 Callback de Comando MQTT
+# ─────────────────────────────
+def ao_receber_comando(topico, payload):
+ try:
+ comando = json.loads(payload.decode())
+ tipo_cmd = int(comando.get("tipo_cmd"))
+ codigo = int(comando.get("cmd"))
+ payload = comando.get("payload", {})
+
+ # Ignora mensagens enviadas por si proprio
+ if (tipo_cmd == TipoComando.RX):
+ return
+
+ resposta = {}
+
+ if codigo == Comando.PING:
+ resposta = {
+ "ping": {
+ "timestamp": time.time(),
+ "status": True
+ }
+ }
+
+ elif codigo == Comando.GET_STATUS_DISPOSITIVO:
+ from camera_manager import get_status_dispositivo
+ resposta = {
+ "device_status": get_status_dispositivo()
+ }
+
+ elif codigo == Comando.GET_RGB_FRAME:
+ from camera_manager import get_rgb_frame
+ frame, timestamp = get_rgb_frame()
+ base64_img = None
+ if frame is not None:
+ from utils import encode_image_base64
+ base64_img = encode_image_base64(frame)
+ resposta = {
+ "rgb_frame": {
+ "timestamp": timestamp,
+ "frame": base64_img
+ }
+ }
+
+ elif codigo == Comando.GET_HEATMAP_FRAME:
+ from camera_manager import get_heatmap_frame
+ frame, timestamp = get_heatmap_frame()
+ base64_img = None
+ if frame is not None:
+ from utils import encode_image_base64
+ base64_img = encode_image_base64(frame)
+ resposta = {
+ "heatmap_frame": {
+ "timestamp": timestamp,
+ "frame": base64_img
+ }
+ }
+
+ elif codigo == Comando.CALIBRAR_GRADES:
+ from camera_manager import get_depth_frame
+ from processamento.percepcao3d import calibrar
+ sucesso = calibrar(get_depth_frame, n_frames=50)
+ resposta = {
+ "calibragem": {
+ "timestamp": time.time(),
+ "status": sucesso
+ }
+ }
+
+ elif codigo == Comando.GET_ANALISE_ANOMALIA:
+ from camera_manager import get_depth_frame, get_camera_calib
+ from processamento.percepcao3d import analisar
+ calib = get_camera_calib()
+ velocidade_ms = float(payload.get("velocidade_ms", 0.0))
+ distancia_max = float(payload.get("distancia_max", 2.0))
+ tamanho_min = float(payload.get("tamanho_min", 0.25))
+ resultado = analisar(TipoAnalise.ANOMALIA, get_depth_frame, calib, velocidade_ms, distancia_max, tamanho_min)
+ resposta = {
+ "timestamp": time.time(),
+ "analise": resultado
+ }
+
+ elif codigo == Comando.GET_ANALISE_SOLO:
+ from camera_manager import get_depth_frame, get_camera_calib
+ from processamento.percepcao3d import analisar
+ calib = get_camera_calib()
+ velocidade_ms = float(payload.get("velocidade_ms", 0.0))
+ distancia_max = float(payload.get("distancia_max", 2.0))
+ tamanho_min = float(payload.get("tamanho_min", 0.25))
+ resultado = analisar(TipoAnalise.SOLO, get_depth_frame, calib, velocidade_ms, distancia_max, tamanho_min)
+ resposta = {
+ "timestamp": time.time(),
+ "analise": resultado
+ }
+
+ enviar_mensagem_mqtt(codigo, resposta)
+
+ except Exception as e:
+ print("❌ Erro ao processar comando MQTT:", e)
+
+# ─────────────────────────────
+# 🔹 Execução Principal
+# ─────────────────────────────
+if __name__ == "__main__":
+ print("🚀 Iniciando Operário Visual com OAK-D Lite...")
+
+ # 1. Inicia a câmera
+ from camera_manager import iniciar_camera
+ iniciar_camera(camera_index)
+
+ from mqtt_handler import iniciar_mqtt, enviar_mensagem_script_carregado
+
+ # 2. Inicia MQTT e registra callback
+ iniciar_mqtt(mqtt_topic, ao_receber_comando)
+
+ print(f"✅ Escutando comandos no tópico: {mqtt_topic}")
+
+ enviar_mensagem_script_carregado()
+
+ # 3. Loop principal
+ try:
+ while True:
+ time.sleep(1)
+ except KeyboardInterrupt:
+ print("Encerrando...")
diff --git a/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/mqtt_handler.py b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/mqtt_handler.py
new file mode 100644
index 000000000..363cf8b57
--- /dev/null
+++ b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/mqtt_handler.py
@@ -0,0 +1,51 @@
+import paho.mqtt.client as mqtt
+import uuid
+import json
+import time
+
+from enums import TipoComando
+
+mqtt_client = None
+mqtt_topic = None
+
+def iniciar_mqtt(topico, funcao_callback, broker="localhost", porta=1883):
+ """
+ Inicia conexão MQTT e escuta o tópico.
+ :param tópico: string com o nome do tópico
+ :param funcao_callback: função que será chamada ao receber mensagem
+ """
+ global mqtt_client, mqtt_topic
+
+ mqtt_client = mqtt.Client(f"visual_worker_{uuid.uuid4()}")
+ mqtt_topic = topico
+
+ def on_connect(client, userdata, flags, rc):
+ if rc == 0:
+ print(f"[MQTT] Conectado ao broker em {broker}:{porta}")
+ client.subscribe(mqtt_topic)
+ else:
+ print("[MQTT] Falha ao conectar, código de retorno:", rc)
+
+ def on_message(client, userdata, msg):
+ try:
+ funcao_callback(msg.topic, msg.payload)
+ except Exception as e:
+ print("[MQTT] Erro no callback:", e)
+
+ mqtt_client.on_connect = on_connect
+ mqtt_client.on_message = on_message
+
+ mqtt_client.connect(broker, porta)
+ mqtt_client.loop_start()
+
+def enviar_mensagem_script_carregado():
+ mqtt_client.publish(mqtt_topic, "OK")
+
+def enviar_mensagem_mqtt(comando, objeto):
+ mensagem = {
+ "momento": time.time(),
+ "tipo_cmd": TipoComando.RX,
+ "cmd": comando,
+ "obj": objeto
+ }
+ mqtt_client.publish(mqtt_topic, json.dumps(mensagem))
diff --git a/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/processamento/analise_anomalias.py b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/processamento/analise_anomalias.py
new file mode 100644
index 000000000..c70d84ccb
--- /dev/null
+++ b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/processamento/analise_anomalias.py
@@ -0,0 +1,157 @@
+import numpy as np
+import cv2
+
+
+def detectar_anomalias(depth_frame, depth_referencia, limiar, distancia_max, tamanho_min, calib):
+ # Gera mapa de anomalias
+ mapa = gerar_mapa_anomalias(depth_frame, depth_referencia, limiar)
+ mapa_anomalia = aplicar_filtros_mapa_anomalias(mapa)
+
+ # Extrai bounding boxes
+ lista_bboxes = extrair_bounding_boxes(mapa_anomalia, depth_frame, depth_referencia, calib)
+ # Filtra as detecções relevantes
+ from visual_worker.utils import filtrar_deteccoes
+ lista_bboxes_filtrada = filtrar_deteccoes(lista_bboxes, distancia_max, tamanho_min)
+
+ return lista_bboxes_filtrada
+
+
+# Geração do Mapa de Anomalias
+def gerar_mapa_anomalias(frame, referencia, threshold=200):
+ diferenca = frame - referencia
+ mask_proximo = diferenca < -threshold
+ mask_distante = diferenca > threshold
+
+ mapa = np.ones(frame.shape + (3,), dtype=np.uint8) * 255
+
+ mapa[mask_proximo] = (0, 0, 255) # Obstáculo (vermelho)
+ mapa[mask_distante] = (255, 0, 0) # Erosão (azul)
+
+ return mapa
+
+
+# Aplicação dos filtros (morfologia + área)
+def aplicar_filtros_mapa_anomalias(mapa):
+ kernel = np.ones((5, 5), np.uint8)
+
+ # Separa máscaras binárias
+ mask_proximo = (mapa == [0, 0, 255]).all(axis=2).astype(np.uint8) # Vermelho
+ mask_distante = (mapa == [255, 0, 0]).all(axis=2).astype(np.uint8) # Azul
+
+ # Morfologia (remove ruído e preenche buracos)
+ mask_proximo = cv2.morphologyEx(mask_proximo, cv2.MORPH_OPEN, kernel)
+ mask_proximo = cv2.morphologyEx(mask_proximo, cv2.MORPH_CLOSE, kernel)
+
+ mask_distante = cv2.morphologyEx(mask_distante, cv2.MORPH_OPEN, kernel)
+ mask_distante = cv2.morphologyEx(mask_distante, cv2.MORPH_CLOSE, kernel)
+
+ # Filtro por área mínima
+ mask_proximo = filtrar_por_area(mask_proximo, area_minima=100)
+ mask_distante = filtrar_por_area(mask_distante, area_minima=100)
+
+ # Reconstrói o mapa colorido
+ mapa_filtrado = np.ones(mapa.shape, dtype=np.uint8) * 255 # Fundo branco
+ mapa_filtrado[mask_proximo == 1] = (0, 0, 255) # Vermelho
+ mapa_filtrado[mask_distante == 1] = (255, 0, 0) # Azul
+
+ return mapa_filtrado
+
+
+# Função para filtrar blobs menores que área mínima
+def filtrar_por_area(mask, area_minima=100):
+ contornos, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
+ mask_filtrada = np.zeros_like(mask)
+
+ for cnt in contornos:
+ area = cv2.contourArea(cnt)
+ if area >= area_minima:
+ cv2.drawContours(mask_filtrada, [cnt], -1, 1, -1)
+
+ return mask_filtrada
+
+
+def extrair_bounding_boxes(mapa, depth_frame, depth_referencia, calib):
+ altura, largura = mapa.shape[:2]
+
+ resultados = []
+
+ # Processa obstáculos (vermelho)
+ resultados += processar_cor(mapa, depth_frame, depth_referencia, (0, 0, 255), "obstaculo", largura, altura, calib)
+
+ # Processa erosões (azul)
+ resultados += processar_cor(mapa, depth_frame, depth_referencia, (255, 0, 0), "erosao", largura, altura, calib)
+
+ return resultados
+
+
+def processar_cor(mapa, depth_frame, depth_referencia, cor_bgr, tipo, largura, altura, calib):
+ mask = (mapa == cor_bgr).all(axis=2).astype(np.uint8)
+
+ contornos, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
+
+ lista = []
+
+ for cnt in contornos:
+ area = cv2.contourArea(cnt)
+ if area < 100:
+ continue
+
+ x, y, w, h = cv2.boundingRect(cnt)
+
+ depth_crop = depth_frame[y:y+h, x:x+w]
+ from visual_worker.utils import filtrar_depth_valid
+ depth_crop_valid = filtrar_depth_valid(depth_crop, calib["distancia_maxima"])
+
+ if len(depth_crop_valid) == 0:
+ continue
+
+ z_atual = np.median(depth_crop_valid) / 1000.0 # 🔥 Em metros (mantém)
+ depth_ref_crop = depth_referencia[y:y+h, x:x+w]
+ depth_ref_valid = filtrar_depth_valid(depth_ref_crop, calib["distancia_maxima"])
+
+ z_ref = (np.median(depth_ref_valid) / 1000.0) if len(depth_ref_valid) > 0 else z_atual
+
+ # 🔥 Variacao em mm
+ variacao_mm = abs(z_atual - z_ref) * 1000.0 # Convertendo metros → mm
+
+ largura_real = z_atual * 2 * np.tan(calib["fov_h"] / 2) * (w / largura)
+ altura_real = z_atual * 2 * np.tan(calib["fov_v"] / 2) * (h / altura)
+
+ centro_x = (x + w / 2) / largura * 100
+ centro_y = (y + h / 2) / altura * 100
+
+ lista.append({
+ "tipo": tipo,
+ "bbox": (int(x), int(y), int(w), int(h)),
+ "centro_percentual": (float(centro_x), float(centro_y)),
+ "distancia_m": round(z_atual, 3),
+ "largura_m": round(largura_real, 3),
+ "altura_m": round(altura_real, 3),
+ "profundidades": (round(z_ref, 3), round(z_atual, 3)),
+ "variacao": round(variacao_mm, 1)
+ })
+
+ return lista
+
+
+def desenhar_bounding_boxes(mapa, lista):
+ mapa_bboxes = mapa.copy()
+
+ for obj in lista:
+ x, y, w, h = obj["bbox"]
+
+ if obj["tipo"] == "obstaculo":
+ cor = (0, 0, 255)
+ else:
+ cor = (255, 0, 0)
+
+ cv2.rectangle(mapa_bboxes, (x, y), (x + w, y + h), cor, 2)
+
+ texto = f'{obj["tipo"]} {obj["distancia_m"]}m'
+ cv2.putText(mapa_bboxes, texto, (x, y - 5),
+ cv2.FONT_HERSHEY_SIMPLEX, 0.5, cor, 2)
+
+ return mapa_bboxes
+
+
+
diff --git a/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/processamento/analise_solo.py b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/processamento/analise_solo.py
new file mode 100644
index 000000000..14ea34c64
--- /dev/null
+++ b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/processamento/analise_solo.py
@@ -0,0 +1,93 @@
+import numpy as np
+
+def analisar_solo(depth_frame, percentual_altura, n_setores, limiar_variacao_mm, distancia_max, tamanho_min, calib):
+ """
+ Analisa o perfil do solo na parte inferior da imagem.
+ Detecta variações como lombadas ou buracos.
+ """
+
+ altura, largura = depth_frame.shape
+
+ # Define a região do solo (parte inferior)
+ linhas_solo = int((percentual_altura / 100) * altura)
+ y_inicio = altura - linhas_solo
+ depth_solo = depth_frame[y_inicio:altura, :]
+
+ # Divide em setores laterais
+ largura_setor = largura // n_setores
+
+ profundidades = []
+
+ for i in range(n_setores):
+ x_inicio = i * largura_setor
+ x_fim = (i + 1) * largura_setor if (i < n_setores - 1) else largura
+
+ setor = depth_solo[:, x_inicio:x_fim]
+ from visual_worker.utils import filtrar_depth_valid
+ setor_valido = filtrar_depth_valid(setor, calib["distancia_maxima"])
+
+ if len(setor_valido) == 0:
+ z = 0
+ else:
+ z = np.median(setor_valido) # Usa mediana para robustez
+
+ profundidades.append(z)
+
+ profundidades = np.array(profundidades)
+
+ # Detecta variações abruptas
+ variacoes = np.abs(np.diff(profundidades))
+ indices_var = np.where(variacoes > limiar_variacao_mm)[0]
+
+ # Gera bounding boxes das variações
+ lista_bboxes = []
+
+ for idx in indices_var:
+ x = idx * largura_setor
+ y = y_inicio
+ w = largura_setor * 2
+ h = linhas_solo
+
+ tipo = "lombada" if profundidades[idx] > profundidades[idx + 1] else "erosao"
+
+ # Centro percentual na imagem
+ centro_x = (x + w / 2) / largura * 100
+ centro_y = (y + h / 2) / altura * 100
+
+ z1 = profundidades[idx]
+ z2 = profundidades[idx + 1]
+ variacao = abs(z1 - z2)
+
+ # Como no solo não usamos distância real na frente (Z em metros), podemos:
+ # → Calcular uma média se quiser, ou deixar como None/0
+ z_media = (z1 + z2) / 2000.0 # Converte de mm pra metros (aproximação)
+
+ largura_real = z_media * 2 * np.tan(calib["fov_h"] / 2) * (w / largura)
+ altura_real = z_media * 2 * np.tan(calib["fov_v"] / 2) * (h / altura)
+
+ # Pode calcular largura e altura em metros (opcional) — aqui deixei None, mas pode fazer igual fizemos na anomalia
+ lista_bboxes.append({
+ "tipo": tipo,
+ "bbox": (int(x), int(y), int(w), int(h)),
+ "centro_percentual": (float(centro_x), float(centro_y)),
+ "distancia_m": round(z_media, 3),
+ "largura_m": round(largura_real, 3),
+ "altura_m": round(altura_real, 3),
+ "profundidades": (round(z1, 1), round(z2, 1)),
+ "variacao": round(variacao, 1)
+ })
+
+ # Filtra as detecções relevantes
+ from visual_worker.utils import filtrar_deteccoes
+ lista_bboxes_filtrada = filtrar_deteccoes(lista_bboxes, distancia_max, tamanho_min)
+
+ # 🔥 Retorno estruturado
+ resultado = {
+ "perfil": [float(v) for v in profundidades.tolist()],
+ "bbox_list": lista_bboxes_filtrada,
+ "y_inicio": int(y_inicio),
+ "altura_regiao": int(linhas_solo),
+ "n_setores": int(n_setores)
+ }
+
+ return resultado
diff --git a/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/processamento/corredor.py b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/processamento/corredor.py
new file mode 100644
index 000000000..29318b239
--- /dev/null
+++ b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/processamento/corredor.py
@@ -0,0 +1,54 @@
+import numpy as np
+import cv2
+
+def estimar_largura_corredor(depth_frame, fx, baseline, largura_mm_max=2000):
+ """
+ Estima a largura do corredor com base no mapa de profundidade.
+
+ Parâmetros:
+ - depth_frame: imagem de profundidade (em disparidades)
+ - fx: distância focal da câmera (pixels)
+ - baseline: distância entre as câmeras estéreo (metros)
+ - largura_mm_max: largura máxima esperada do corredor (em mm)
+
+ Retorna:
+ - largura_estimada (em mm)
+ - posicao_central (0 a 1 → fração da imagem)
+ - lista de pontos com (x, distancia_mm)
+ """
+
+ altura, largura = depth_frame.shape
+ faixa_inicio = int(altura * 0.45)
+ faixa_fim = int(altura * 0.55)
+
+ # Recorte central horizontal
+ faixa = depth_frame[faixa_inicio:faixa_fim, :]
+
+ # Média por coluna
+ profundidade_media = np.median(faixa, axis=0)
+
+ # Converte de disparidade para distância (mm)
+ with np.errstate(divide='ignore'): # evita divisão por zero
+ distancias_mm = (fx * baseline * 1000) / profundidade_media
+ distancias_mm = np.clip(distancias_mm, 0, largura_mm_max)
+
+ # Aplica filtro para remover ruído (média móvel simples)
+ distancias_mm_suave = cv2.blur(distancias_mm.reshape(1, -1).astype(np.float32), (15, 1)).flatten()
+
+ # Detecta bordas esquerda e direita: picos de distância próxima
+ limite = 2500 # Limite máximo para considerar obstáculo lateral (em mm)
+ idx_validos = np.where((distancias_mm_suave > 100) & (distancias_mm_suave < limite))[0]
+
+ if len(idx_validos) < 2:
+ return None, None, []
+
+ esquerda = idx_validos[0]
+ direita = idx_validos[-1]
+
+ largura_estimada = abs(distancias_mm_suave[direita] - distancias_mm_suave[esquerda])
+ posicao_central = (esquerda + direita) / 2 / largura
+
+ # Para visualização/debug
+ pontos_debug = [(int(x), float(distancias_mm_suave[x])) for x in range(0, largura, 10)]
+
+ return largura_estimada, posicao_central, pontos_debug
diff --git a/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/processamento/obstaculos.py b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/processamento/obstaculos.py
new file mode 100644
index 000000000..2ed11962e
--- /dev/null
+++ b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/processamento/obstaculos.py
@@ -0,0 +1,236 @@
+# obstaculos.py
+
+import numpy as np
+import time
+from scipy import stats
+
+from visual_worker.enums import Direcao, TipoDeteccao, TipoRegiaoRadar
+
+LIMIAR_OBSTACULO = 1000 # mm
+LIMIAR_DEPRESSAO = 2500 # mm
+
+buffer_macro = None
+buffer_micro = None
+ref_macro = None
+ref_micro = None
+
+MACRO_ROWS = 3
+MACRO_COLS = 4
+MICRO_ROWS = 10
+MICRO_COLS = 10
+
+
+
+def analisar_macro_grid(depth_frame, velocidade):
+ global ref_macro
+
+ if ref_macro is None:
+ print("[ERRO] ref_macro não foi calibrado. Execute CALIBRAR_GRADES antes.")
+ return {
+ "erro": "Calibração ausente",
+ "precisa_micro": False
+ }
+
+ altura, largura = depth_frame.shape
+ row_h = altura // MACRO_ROWS
+ col_w = largura // MACRO_COLS
+
+ LIMIAR_OBSTACULO = calcular_limiar_dinamico(velocidade)
+ LIMIAR_DEPRESSAO = 2500 # Pode virar dinâmico depois
+
+ zonas_ocupadas = []
+ dist_min = 9999
+ frontal_bloqueado = False
+ laterais = { Direcao.ESQUERDA: False, Direcao.DIREITA: False }
+ zona_livre = Direcao.FRENTE
+
+ for i in range(MACRO_ROWS):
+ for j in range(MACRO_COLS):
+ y1, y2 = i * row_h, (i + 1) * row_h
+ x1, x2 = j * col_w, (j + 1) * col_w
+
+ area = depth_frame[y1:y2, x1:x2]
+ validos = area[(area > 0) & (area < 10000)]
+ if validos.size == 0:
+ continue
+
+ media = np.mean(validos)
+ erro = media - ref_macro[i][j]
+ dist_min = min(dist_min, media)
+
+ tipo = TipoDeteccao.SEGURO
+ if erro < LIMIAR_OBSTACULO:
+ tipo = TipoDeteccao.OBSTACULO
+ elif erro > LIMIAR_DEPRESSAO:
+ tipo = TipoDeteccao.DEPRESSAO
+
+ if tipo != TipoDeteccao.SEGURO:
+ regiao = TipoRegiaoRadar.SOLO if i == MACRO_ROWS - 1 else TipoRegiaoRadar.AEREO
+
+ zonas_ocupadas.append({
+ "linha": i,
+ "coluna": j,
+ "distancia": round(float(media) / 1000, 2),
+ "tipo": tipo,
+ "regiao": regiao
+ })
+
+ if i == MACRO_ROWS - 1 and j in [1, 2]:
+ frontal_bloqueado = True
+ if j == 0:
+ laterais[Direcao.ESQUERDA] = True
+ if j == MACRO_COLS - 1:
+ laterais[Direcao.DIREITA] = True
+
+ if not zonas_ocupadas:
+ zona_livre = Direcao.FRENTE
+ elif all(z["coluna"] < MACRO_COLS // 2 for z in zonas_ocupadas):
+ zona_livre = Direcao.DIREITA
+ elif all(z["coluna"] >= MACRO_COLS // 2 for z in zonas_ocupadas):
+ zona_livre = Direcao.ESQUERDA
+ else:
+ zona_livre = Direcao.PARADO
+
+ return {
+ "alerta": len(zonas_ocupadas) > 0,
+ "frontal_bloqueado": frontal_bloqueado,
+ "laterais": laterais,
+ "zona_livre": zona_livre,
+ "distancia_minima": round(float(dist_min) / 1000, 2),
+ "detalhes": zonas_ocupadas,
+ "precisa_micro": frontal_bloqueado
+ }
+
+def analisar_micro_grid(depth_frame):
+ altura, largura = depth_frame.shape
+ row_h = altura // MICRO_ROWS
+ col_w = largura // MICRO_COLS
+
+ detalhes = []
+ dist_min = 9999
+
+ for i in range(MICRO_ROWS):
+ for j in range(MICRO_COLS):
+ y1, y2 = i * row_h, (i + 1) * row_h
+ x1, x2 = j * col_w, (j + 1) * col_w
+
+ area = depth_frame[y1:y2, x1:x2]
+ validos = area[(area > 0) & (area < 10000)]
+ if validos.size == 0:
+ continue
+
+ media = np.mean(validos)
+ erro = media - ref_macro[i][j]
+ dist_min = min(dist_min, media)
+
+ tipo = TipoDeteccao.SEGURO
+ if erro < LIMIAR_OBSTACULO:
+ tipo = TipoDeteccao.OBSTACULO
+ elif erro > LIMIAR_DEPRESSAO:
+ tipo = TipoDeteccao.DEPRESSAO
+
+ if tipo != TipoDeteccao.SEGURO:
+ regiao = TipoRegiaoRadar.SOLO if i >= MICRO_ROWS * 0.6 else TipoRegiaoRadar.AEREO
+
+ detalhes.append({
+ "linha": i,
+ "coluna": j,
+ "distancia": round(float(media) / 1000, 2),
+ "tipo": tipo,
+ "regiao": regiao
+ })
+
+ return {
+ "alerta": len(detalhes) > 0,
+ "quantidade": len(detalhes),
+ "distancia_minima": round(float(dist_min) / 1000, 2),
+ "detalhes": detalhes
+ }
+
+
+def calcular_limiar_dinamico(velocidade):
+ # Exemplo: de 0.6m a 1.5m dependendo da velocidade
+ return int(min(max(600 + velocidade * 800, 600), 1500))
+
+def gerar_ref(buffer):
+ rows = len(buffer)
+ cols = len(buffer[0])
+ ref_out = np.zeros((rows, cols), dtype=np.float32)
+
+ for i in range(rows):
+ for j in range(cols):
+ valores = buffer[i][j]
+ if len(valores) == 0:
+ ref_out[i][j] = 0 # ou -1 para representar célula vazia
+ continue
+
+ # Tenta usar moda
+ moda = stats.mode(valores, keepdims=True).mode
+ if moda.size > 0:
+ ref_out[i][j] = moda[0]
+ else:
+ ref_out[i][j] = np.median(valores)
+
+ return ref_out
+
+def calibrar_macro(frame):
+ global buffer_macro
+ altura, largura = frame.shape
+ row_h = altura // MACRO_ROWS
+ col_w = largura // MACRO_COLS
+
+ for i in range(MACRO_ROWS):
+ for j in range(MACRO_COLS):
+ y1, y2 = i * row_h, (i + 1) * row_h
+ x1, x2 = j * col_w, (j + 1) * col_w
+
+ area = frame[y1:y2, x1:x2]
+ validos = area[(area > 0) & (area < 10000)]
+ if validos.size > 0:
+ buffer_macro[i][j].extend(validos.tolist())
+
+def calibrar_micro(frame):
+ global buffer_micro
+ altura, largura = frame.shape
+ row_h = altura // MICRO_ROWS
+ col_w = largura // MICRO_COLS
+
+ for i in range(MICRO_ROWS):
+ for j in range(MICRO_COLS):
+ y1, y2 = i * row_h, (i + 1) * row_h
+ x1, x2 = j * col_w, (j + 1) * col_w
+
+ area = frame[y1:y2, x1:x2]
+ validos = area[(area > 0) & (area < 10000)]
+ if validos.size > 0:
+ buffer_micro[i][j].extend(validos.tolist())
+
+def calibrar_grades(capturar_depth_frame, n_frames=50):
+ global buffer_macro, buffer_micro, ref_macro, ref_micro
+
+ buffer_macro = [[[] for _ in range(MACRO_COLS)] for _ in range(MACRO_ROWS)]
+ buffer_micro = [[[] for _ in range(MICRO_COLS)] for _ in range(MICRO_ROWS)]
+
+ print(f"📡 Iniciando calibração de {n_frames} frames...")
+
+ total_validos = 0
+ for i in range(n_frames):
+ frame, timestamp = capturar_depth_frame()
+ if frame is not None:
+ calibrar_macro(frame)
+ calibrar_micro(frame)
+ total_validos += 1
+ print(f"✔️ Frame {i+1}/{n_frames} calibrado.")
+ else:
+ print(f"⚠️ Frame {i+1}/{n_frames} inválido, ignorado.")
+ time.sleep(0.03) # pausa leve pra estabilizar captura
+
+ if total_validos == 0:
+ print("❌ Nenhum frame válido recebido. Calibração cancelada.")
+ return False
+
+ ref_macro = gerar_ref(buffer_macro)
+ ref_micro = gerar_ref(buffer_micro)
+
+ print("✅ Calibração concluída com sucesso!")
+ return True
diff --git a/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/processamento/percepcao3d.py b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/processamento/percepcao3d.py
new file mode 100644
index 000000000..af9063496
--- /dev/null
+++ b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/processamento/percepcao3d.py
@@ -0,0 +1,68 @@
+import numpy as np
+import time
+
+from visual_worker.enums import TipoAnalise
+from visual_worker.utils import aplicar_mascara_margens, calcular_threshold_anomalias
+
+# Variáveis globais
+depth_referencia = None
+calibrado = False
+
+# Calibração
+def calibrar(obter_depth_frame, n_frames=50):
+ global depth_referencia, calibrado
+
+ calibrado = False
+
+ print(f"📡 Iniciando calibração de {n_frames} frames...")
+ lista_frames = []
+ total_validos = 0
+
+ for i in range(n_frames):
+ frame, timestamp = obter_depth_frame()
+ if frame is not None:
+ lista_frames.append(frame)
+ print(f"✔️ Frame de timestamp {timestamp} {i+1}/{n_frames} calibrado.")
+ total_validos += 1
+ else:
+ print(f"⚠️ Frame de timestamp {timestamp} {i+1}/{n_frames} inválido, ignorado.")
+ time.sleep(0.05)
+
+ if total_validos == 0:
+ print("❌ Nenhum frame válido recebido. Calibração cancelada.")
+ return False
+
+ depth_referencia = np.median(np.stack(lista_frames), axis=0)
+ calibrado = True
+ print("✅ Calibração concluída com sucesso!")
+ return True
+
+
+def analisar(analise, obter_depth_frame, camera_calib, velocidade_ms, distancia_max, tamanho_min):
+ global depth_referencia, calibrado
+
+ resultado = {
+ "timestamp": None,
+ "anomalias": None,
+ "solo": None
+ }
+
+ if not calibrado:
+ print("[ERRO] Calibração não realizada!")
+ return resultado
+
+ frame, timestamp = obter_depth_frame()
+ resultado["timestamp"] = timestamp
+
+ depth_frame = aplicar_mascara_margens(frame)
+ limiar = calcular_threshold_anomalias(velocidade_ms)
+
+ if analise == TipoAnalise.ANOMALIA:
+ from visual_worker.processamento.analise_anomalias import detectar_anomalias
+ resultado["anomalias"] = detectar_anomalias(frame, depth_referencia, limiar, distancia_max, tamanho_min, camera_calib)
+ elif analise == TipoAnalise.SOLO:
+ from visual_worker.processamento.analise_solo import analisar_solo
+ resultado["solo"] = analisar_solo(frame, 20, 50, limiar, distancia_max, tamanho_min, camera_calib)
+
+ return resultado
+
diff --git a/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/processamento/visao3d.py b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/processamento/visao3d.py
new file mode 100644
index 000000000..17de6eeb2
--- /dev/null
+++ b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/processamento/visao3d.py
@@ -0,0 +1,48 @@
+import numpy as np
+
+def detectar_obstaculos_em_frente(depth_frame, fx, baseline, faixa_altura=(0.45, 0.55), max_distancia_mm=2500):
+ """
+ Detecta obstáculos com base no perfil de profundidade frontal.
+
+ Retorna uma lista de obstáculos com:
+ - posição_percentual (0 à 100)
+ - distancia (em metros)
+ - largura_aproximada (em px)
+ """
+
+ altura, largura = depth_frame.shape
+ y1 = int(altura * faixa_altura[0])
+ y2 = int(altura * faixa_altura[1])
+
+ faixa = depth_frame[y1:y2, :]
+
+ profundidade_media = np.median(faixa, axis=0)
+ with np.errstate(divide='ignore'):
+ distancias_mm = (fx * baseline * 1000) / profundidade_media
+ distancias_mm = np.clip(distancias_mm, 0, max_distancia_mm)
+
+ # Simplifica usando limiar: onde há objetos "próximos"
+ mascara = (distancias_mm > 100) & (distancias_mm < max_distancia_mm)
+
+ obstaculos = []
+ inicio = None
+
+ for x in range(largura):
+ if mascara[x]:
+ if inicio is None:
+ inicio = x
+ elif inicio is not None:
+ fim = x
+ centro = (inicio + fim) // 2
+ largura_px = fim - inicio
+ distancia = np.min(distancias_mm[inicio:fim])
+ posicao_pct = 100 * centro / largura
+
+ obstaculos.append({
+ "posicao": round(float(posicao_pct), 1),
+ "distancia": round(float(distancia) / 1000, 2),
+ "largura_px": largura_px
+ })
+ inicio = None
+
+ return obstaculos
diff --git a/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/utils.py b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/utils.py
new file mode 100644
index 000000000..a7496d728
--- /dev/null
+++ b/AgroBase/AgroBase/bin/x64/Debug/Python/Scripts/visual_worker/utils.py
@@ -0,0 +1,73 @@
+# utils.py
+
+import cv2
+import base64
+import numpy as np
+
+def encode_image_base64(frame):
+ """
+ Codifica uma imagem (np.ndarray) como string base64 JPEG.
+ """
+ ret, buffer = cv2.imencode('.jpg', frame, [cv2.IMWRITE_JPEG_QUALITY, 80])
+ if not ret:
+ return None
+ base64_str = base64.b64encode(buffer).decode('utf-8')
+ return base64_str
+
+def gerar_heatmap(depth_frame, dist_max_mm=3000.0):
+ mask_valid = depth_frame <= dist_max_mm
+ depth_normalized = np.zeros(depth_frame.shape, dtype=np.uint8)
+ depth_normalized[mask_valid] = (255 - ((depth_frame[mask_valid] / dist_max_mm) * 255)).astype(np.uint8)
+ heatmap = cv2.applyColorMap(depth_normalized, cv2.COLORMAP_JET)
+ heatmap[~mask_valid] = [0, 0, 0]
+ return heatmap
+
+def filtrar_deteccoes(lista, distancia_maxima=2.0, tamanho_minimo=0.25):
+ """
+ Filtra a lista de detecções baseado em:
+ - Distância máxima (em metros).
+ - Largura OU altura mínima (em metros).
+ """
+ lista_filtrada = []
+
+ for obj in lista:
+ if obj["distancia_m"] > distancia_maxima:
+ continue
+
+ if obj["largura_m"] < tamanho_minimo and obj["altura_m"] < tamanho_minimo:
+ continue
+
+ lista_filtrada.append(obj)
+
+ return lista_filtrada
+
+def aplicar_mascara_margens(depth_frame, margem_percentual=3, valor_mascara=0):
+ """
+ Aplica uma máscara nas bordas do frame, preenchendo com valor alto para ignorar nas análises.
+ """
+ frame_mascara = depth_frame.copy()
+ altura, largura = frame_mascara.shape
+
+ margem_x = int((margem_percentual / 100) * largura)
+ margem_y = int((margem_percentual / 100) * altura)
+
+ # Margens verticais (esquerda e direita)
+ frame_mascara[:, :margem_x] = valor_mascara
+ frame_mascara[:, largura - margem_x:] = valor_mascara
+
+ # Margens horizontais (superior e inferior)
+ frame_mascara[:margem_y, :] = valor_mascara
+ frame_mascara[altura - margem_y:, :] = valor_mascara
+
+ return frame_mascara
+
+def calcular_threshold_anomalias(velocidade_ms, threshold_base=200, fator_sensibilidade=100):
+ """
+ Calcula o threshold dinamicamente baseado na velocidade do robô.
+ - velocidade_ms: Velocidade em metros por segundo (m/s).
+ """
+ threshold = threshold_base + (velocidade_ms * fator_sensibilidade)
+ return round(threshold, 1)
+
+def filtrar_depth_valid(depth_array, max_value=3000.0):
+ return depth_array[(depth_array > 0) & (depth_array < max_value)]
diff --git a/AgroBase/AgroMonitor/obj/Debug/AgroMonitor.csproj.AssemblyReference.cache b/AgroBase/AgroMonitor/obj/Debug/AgroMonitor.csproj.AssemblyReference.cache
index d5c386cba..a87d3dc14 100644
Binary files a/AgroBase/AgroMonitor/obj/Debug/AgroMonitor.csproj.AssemblyReference.cache and b/AgroBase/AgroMonitor/obj/Debug/AgroMonitor.csproj.AssemblyReference.cache differ
diff --git a/AgroBase/AgroMonitor/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache b/AgroBase/AgroMonitor/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache
index 8042caad0..81316e109 100644
Binary files a/AgroBase/AgroMonitor/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache and b/AgroBase/AgroMonitor/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache differ
diff --git a/Python/OAK/visual_worker/camera_manager.py b/Python/OAK/visual_worker/camera_manager.py
new file mode 100644
index 000000000..e7e7313c5
--- /dev/null
+++ b/Python/OAK/visual_worker/camera_manager.py
@@ -0,0 +1,241 @@
+# camera_manager.py
+
+import depthai as dai
+import cv2
+import numpy as np
+import time
+
+# Parâmetros da câmera
+RGB_WIDTH, RGB_HEIGHT = 640, 480
+DEPTH_WIDTH, DEPTH_HEIGHT = 320, 240
+FX = 440.0 # distância focal em pixels (aproximado)
+BASELINE = 0.075 # distância entre câmeras estéreo (em metros)
+
+# Variáveis globais
+device = None
+device_info = None
+rgb_queue = None
+depth_queue = None
+ultimo_frame_depth = None
+timestamp_ultimo_depth_frame = None
+ultimo_frame_rgb = None
+timestamp_ultimo_rgb_frame = None
+
+def iniciar_camera(index=0):
+ global device, device_info, rgb_queue, depth_queue
+
+ print("Iniciando câmera OAK-D Lite...")
+
+ pipeline = dai.Pipeline()
+
+ # RGB
+ cam_rgb = pipeline.create(dai.node.ColorCamera)
+ cam_rgb.setPreviewSize(RGB_WIDTH, RGB_HEIGHT)
+ cam_rgb.setInterleaved(False)
+ cam_rgb.setBoardSocket(dai.CameraBoardSocket.RGB)
+
+ xout_rgb = pipeline.create(dai.node.XLinkOut)
+ xout_rgb.setStreamName("rgb")
+ cam_rgb.preview.link(xout_rgb.input)
+
+ # 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_480_P)
+ mono_right.setResolution(dai.MonoCameraProperties.SensorResolution.THE_480_P)
+ mono_left.setBoardSocket(dai.CameraBoardSocket.LEFT)
+ mono_right.setBoardSocket(dai.CameraBoardSocket.RIGHT)
+
+ stereo.setDefaultProfilePreset(dai.node.StereoDepth.PresetMode.HIGH_DENSITY)
+
+ mono_left.out.link(stereo.left)
+ mono_right.out.link(stereo.right)
+
+ xout_depth = pipeline.create(dai.node.XLinkOut)
+ xout_depth.setStreamName("depth")
+ stereo.depth.link(xout_depth.input)
+
+ # Dispositivo
+ available_devices = dai.Device.getAllAvailableDevices()
+ if index >= len(available_devices):
+ raise ValueError(f"Câmera de índice {index} não encontrada.")
+
+ device_info = available_devices[index]
+ device = dai.Device(pipeline, device_info)
+
+ rgb_queue = device.getOutputQueue(name="rgb", maxSize=1, blocking=False)
+ depth_queue = device.getOutputQueue(name="depth", maxSize=1, blocking=False)
+
+ print(f"Câmera iniciada: {device_info.name} (ID: {device_info.getMxId()})")
+
+ get_camera_calib()
+
+def get_camera_calib():
+ global FX, BASELINE
+ calib = device.readCalibration()
+
+ # Obtem matriz intrínseca da câmera LEFT (com resolução padrão 640x400)
+ intrinsics = calib.getCameraIntrinsics(dai.CameraBoardSocket.LEFT, 640, 400)
+ FX = intrinsics[0][0] # fx
+ BASELINE = calib.getBaselineDistance() / 1000.0 # de mm → m
+
+ print(f"[CALIB] FX: {FX:.2f} px, BASELINE: {BASELINE:.4f} m")
+
+def get_rgb_frame():
+ global ultimo_frame_rgb, timestamp_ultimo_rgb_frame
+ if rgb_queue is None:
+ return None, None
+ frame = rgb_queue.tryGet()
+ if frame is not None:
+ ultimo_frame_rgb = frame.getCvFrame()
+ timestamp_ultimo_rgb_frame = time.time()
+ return ultimo_frame_rgb, timestamp_ultimo_rgb_frame
+
+def get_heatmap_frame():
+ frame = get_depth_frame()
+ if frame is not None:
+ return gerar_heatmap(frame), timestamp_ultimo_depth_frame
+ return None, None
+
+def gerar_heatmap(depth_frame):
+ # Normaliza e aplica colormap
+ normalized = cv2.normalize(depth_frame, None, 0, 255, cv2.NORM_MINMAX)
+ heatmap = cv2.applyColorMap(normalized.astype(np.uint8), cv2.COLORMAP_JET)
+ return heatmap
+
+def get_depth_frame():
+ global ultimo_frame_depth, timestamp_ultimo_depth_frame
+ if depth_queue is None:
+ return None, None
+
+ frame = depth_queue.tryGet()
+ if frame is not None:
+ ultimo_frame_depth = frame.getFrame()
+ timestamp_ultimo_depth_frame = time.time()
+ return ultimo_frame_depth, timestamp_ultimo_depth_frame
+
+def get_status_dispositivo():
+ from depthai import UsbSpeed
+
+ try:
+ memory = device.getDdrMemoryUsage()
+ memory_info = {
+ "used": memory.used,
+ "remaining": memory.remaining,
+ "total": memory.total
+ }
+ except:
+ memory_info = None
+
+ try:
+ temp = device.getChipTemperature()
+ temp_info = {
+ "css": temp.css,
+ "mss": temp.mss,
+ "upa": temp.upa,
+ "dss": temp.dss
+ }
+ except:
+ temp_info = None
+
+ try:
+ info = device.getDeviceInfo()
+ protocol = str(info.protocol)
+ except:
+ protocol = None
+
+ try:
+ bootloader = str(device.getBootloaderVersion())
+ except:
+ bootloader = None
+
+ try:
+ usb_speed = str(device.getUsbSpeed().name)
+ except:
+ usb_speed = None
+
+ try:
+ pipeline_running = device.isPipelineRunning()
+ except:
+ pipeline_running = None
+
+ try:
+ cameras = [sensor.name for sensor in device.getConnectedCameras()]
+ except:
+ cameras = None
+
+ return {
+ "id": device_info.getMxId(),
+ "name": device_info.name,
+ "state": device_info.state.name,
+ "usb_speed": usb_speed,
+ "available_camera_sensors": cameras,
+ "version": protocol,
+ "bootloader_version": bootloader,
+ "is_pipeline_running": pipeline_running,
+ "memory_usage": memory_info,
+ "temperature": temp_info
+ }
+
+def analisar_obstaculos(velocidade=0.0, refinar=False):
+ from processamento.obstaculos import analisar_macro_grid, analisar_micro_grid
+ global timestamp_ultimo_depth_frame
+
+ frame = get_depth_frame()
+
+ if frame is None:
+ if ultimo_frame_depth is None:
+ return { "erro": "Sem frame disponível", "timestamp": None }
+ frame = ultimo_frame_depth
+
+ macro = analisar_macro_grid(frame, velocidade)
+
+ if macro["precisa_micro"] and refinar:
+ micro = analisar_micro_grid(frame)
+ micro["timestamp"] = timestamp_ultimo_depth_frame
+ return micro
+
+ macro["timestamp"] = timestamp_ultimo_depth_frame
+ return macro
+
+def analisar_corredor():
+ from processamento.corredor import estimar_largura_corredor
+ global timestamp_ultimo_depth_frame # precisa garantir que fx e baseline existam
+
+ frame = get_depth_frame()
+
+ if frame is None:
+ if ultimo_frame_depth is None:
+ return { "erro": "Sem frame disponível", "timestamp": None }
+ frame = ultimo_frame_depth
+
+ largura_mm, pos_central, pontos_debug = estimar_largura_corredor(frame, FX, BASELINE)
+
+ return {
+ "largura_corredor_mm": float(largura_mm) if largura_mm is not None else None,
+ "posicao_central_fracao": float(pos_central) if pos_central is not None else None,
+ "timestamp": timestamp_ultimo_depth_frame,
+ "pontos_debug": [ [int(x), float(y)] for x, y in pontos_debug ]
+ }
+
+def analisar_obstaculos_3d():
+ from processamento.visao3d import detectar_obstaculos_em_frente
+ global timestamp_ultimo_depth_frame
+
+ frame = get_depth_frame()
+
+ if frame is None:
+ if ultimo_frame_depth is None:
+ return { "erro": "Sem frame disponível", "timestamp": None }
+ frame = ultimo_frame_depth
+
+ lista = detectar_obstaculos_em_frente(frame, FX, BASELINE)
+
+ return {
+ "obstaculos_detectados": lista,
+ "timestamp": timestamp_ultimo_depth_frame
+ }
+
+
diff --git a/Python/OAK/visual_worker/enums.py b/Python/OAK/visual_worker/enums.py
new file mode 100644
index 000000000..6d0475ae4
--- /dev/null
+++ b/Python/OAK/visual_worker/enums.py
@@ -0,0 +1,38 @@
+from enum import IntEnum
+
+class Comando(IntEnum):
+ PING = 1
+ GET_RGB_FRAME = 2
+ GET_HEATMAP_FRAME = 3
+ GET_OBSTACULOS = 4
+ GET_STATUS_DISPOSITIVO = 5
+ CALIBRAR_GRADES = 6
+ GET_MAPA_PROFUNDIDADE = 7
+ GET_LARGURA_CORREDOR = 8
+ GET_OBSTACULOS_3D = 9
+
+class TipoComando(IntEnum):
+ TX = 1
+ RX = 2
+
+class TipoDeteccao(IntEnum):
+ SEGURO = 1
+ OBSTACULO = 2
+ DEPRESSAO = 3
+
+class TipoRegiaoRadar(IntEnum):
+ SOLO = 1
+ AEREO = 2
+
+class Direcao(IntEnum):
+ PARADO = 0
+ FRENTE = 1
+ TRAS = 2
+ ESQUERDA = 3
+ DIREITA = 4
+ CIMA = 5
+ BAIXO = 6
+ ESQUERDABAIXO = 7
+ ESQUERDACIMA = 8
+ DIREITABAIXO = 9
+ DIREITACIMA = 10
\ No newline at end of file
diff --git a/Python/OAK/visual_worker/filtros.py b/Python/OAK/visual_worker/filtros.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/Python/OAK/visual_worker/main.py b/Python/OAK/visual_worker/main.py
new file mode 100644
index 000000000..6302d7d55
--- /dev/null
+++ b/Python/OAK/visual_worker/main.py
@@ -0,0 +1,151 @@
+import sys
+import os
+import time
+import json
+
+from enums import Comando, TipoComando
+
+from mqtt_handler import enviar_mensagem_mqtt
+
+sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
+
+
+# ─────────────────────────────
+# 🔹 Parâmetros de Execução
+# ─────────────────────────────
+mqtt_topic = sys.argv[1] if len(sys.argv) > 1 else "agrobot/operador/sonar"
+camera_index = int(sys.argv[2]) if len(sys.argv) > 2 else 0
+
+
+# ─────────────────────────────
+# 🔹 Callback de Comando MQTT
+# ─────────────────────────────
+def ao_receber_comando(topico, payload):
+ try:
+ comando = json.loads(payload.decode())
+ tipo_cmd = int(comando.get("tipo_cmd"))
+ codigo = int(comando.get("cmd"))
+
+ # Ignora mensagens enviadas por si proprio
+ if (tipo_cmd == TipoComando.RX):
+ return
+
+ resposta = {}
+
+ if codigo == Comando.PING:
+ resposta = {
+ "ping": {
+ "timestamp": time.time(),
+ "status": True
+ }
+ }
+
+ elif codigo == Comando.GET_STATUS_DISPOSITIVO:
+ from camera_manager import get_status_dispositivo
+ resposta = {
+ "device_status": get_status_dispositivo()
+ }
+
+ elif codigo == Comando.GET_RGB_FRAME:
+ from camera_manager import get_rgb_frame
+ frame, timestamp = get_rgb_frame()
+ base64_img = None
+ if frame is not None:
+ from utils import encode_image_base64
+ base64_img = encode_image_base64(frame)
+ resposta = {
+ "timestamp": timestamp,
+ "frame": base64_img
+ }
+
+ elif codigo == Comando.GET_HEATMAP_FRAME:
+ from camera_manager import get_heatmap_frame
+ frame, timestamp = get_heatmap_frame()
+ base64_img = None
+ if frame is not None:
+ from utils import encode_image_base64
+ base64_img = encode_image_base64(frame)
+ resposta = {
+ "timestamp": timestamp,
+ "frame": base64_img
+ }
+
+ elif codigo == Comando.CALIBRAR_GRADES:
+ from camera_manager import get_depth_frame
+ from processamento.obstaculos import calibrar_grades
+ sucesso = calibrar_grades(get_depth_frame, n_frames=50)
+ resposta = {
+ "calibragem": {
+ "timestamp": time.time(),
+ "status": sucesso
+ }
+ }
+
+ elif codigo == Comando.GET_OBSTACULOS:
+ from camera_manager import analisar_obstaculos
+ velocidade = float(comando.get("velocidade", 0.0)) # padrão = 0.0 m/s, parado
+ precisao_micro = float(comando.get("precisao_micro", False))
+ resposta = {
+ "obstaculos": analisar_obstaculos(velocidade=velocidade, refinar=precisao_micro)
+ }
+
+ elif codigo == Comando.GET_LARGURA_CORREDOR:
+ from camera_manager import analisar_corredor
+ resposta = {
+ "corredor": analisar_corredor()
+ }
+
+ elif codigo == Comando.GET_MAPA_PROFUNDIDADE:
+ from camera_manager import get_depth_frame
+ from utils import gerar_mapa_profundidade
+
+ depth, timestamp = get_depth_frame()
+ if depth is not None:
+ resolucao = str(comando.get("resolucao", "10x10"))
+ try:
+ linhas, colunas = map(int, resolucao.lower().split("x"))
+ except:
+ linhas, colunas = 10, 10
+
+ grid = gerar_mapa_profundidade(depth, linhas, colunas)
+ grid["timestamp"] = timestamp
+ resposta = {
+ "mapa_profundidade": grid
+ }
+
+ elif codigo == Comando.GET_OBSTACULOS_3D:
+ from camera_manager import analisar_obstaculos_3d
+ resposta = {
+ "obstaculos_3d": analisar_obstaculos_3d()
+ }
+
+ enviar_mensagem_mqtt(codigo, resposta)
+
+ except Exception as e:
+ print("❌ Erro ao processar comando MQTT:", e)
+
+# ─────────────────────────────
+# 🔹 Execução Principal
+# ─────────────────────────────
+if __name__ == "__main__":
+ print("🚀 Iniciando Operário Visual com OAK-D Lite...")
+
+ # 1. Inicia a câmera
+ from camera_manager import iniciar_camera
+ iniciar_camera(camera_index)
+
+ from mqtt_handler import iniciar_mqtt, enviar_mensagem_script_carregado
+
+ # 2. Inicia MQTT e registra callback
+ iniciar_mqtt(mqtt_topic, ao_receber_comando)
+
+ print(f"✅ Escutando comandos no tópico: {mqtt_topic}")
+
+ enviar_mensagem_script_carregado()
+
+ # 3. Loop principal
+ try:
+ while True:
+ time.sleep(1)
+ except KeyboardInterrupt:
+ print("Encerrando...")
diff --git a/Python/OAK/visual_worker/mqtt_handler.py b/Python/OAK/visual_worker/mqtt_handler.py
new file mode 100644
index 000000000..363cf8b57
--- /dev/null
+++ b/Python/OAK/visual_worker/mqtt_handler.py
@@ -0,0 +1,51 @@
+import paho.mqtt.client as mqtt
+import uuid
+import json
+import time
+
+from enums import TipoComando
+
+mqtt_client = None
+mqtt_topic = None
+
+def iniciar_mqtt(topico, funcao_callback, broker="localhost", porta=1883):
+ """
+ Inicia conexão MQTT e escuta o tópico.
+ :param tópico: string com o nome do tópico
+ :param funcao_callback: função que será chamada ao receber mensagem
+ """
+ global mqtt_client, mqtt_topic
+
+ mqtt_client = mqtt.Client(f"visual_worker_{uuid.uuid4()}")
+ mqtt_topic = topico
+
+ def on_connect(client, userdata, flags, rc):
+ if rc == 0:
+ print(f"[MQTT] Conectado ao broker em {broker}:{porta}")
+ client.subscribe(mqtt_topic)
+ else:
+ print("[MQTT] Falha ao conectar, código de retorno:", rc)
+
+ def on_message(client, userdata, msg):
+ try:
+ funcao_callback(msg.topic, msg.payload)
+ except Exception as e:
+ print("[MQTT] Erro no callback:", e)
+
+ mqtt_client.on_connect = on_connect
+ mqtt_client.on_message = on_message
+
+ mqtt_client.connect(broker, porta)
+ mqtt_client.loop_start()
+
+def enviar_mensagem_script_carregado():
+ mqtt_client.publish(mqtt_topic, "OK")
+
+def enviar_mensagem_mqtt(comando, objeto):
+ mensagem = {
+ "momento": time.time(),
+ "tipo_cmd": TipoComando.RX,
+ "cmd": comando,
+ "obj": objeto
+ }
+ mqtt_client.publish(mqtt_topic, json.dumps(mensagem))
diff --git a/Python/OAK/visual_worker/processamento/corredor.py b/Python/OAK/visual_worker/processamento/corredor.py
new file mode 100644
index 000000000..29318b239
--- /dev/null
+++ b/Python/OAK/visual_worker/processamento/corredor.py
@@ -0,0 +1,54 @@
+import numpy as np
+import cv2
+
+def estimar_largura_corredor(depth_frame, fx, baseline, largura_mm_max=2000):
+ """
+ Estima a largura do corredor com base no mapa de profundidade.
+
+ Parâmetros:
+ - depth_frame: imagem de profundidade (em disparidades)
+ - fx: distância focal da câmera (pixels)
+ - baseline: distância entre as câmeras estéreo (metros)
+ - largura_mm_max: largura máxima esperada do corredor (em mm)
+
+ Retorna:
+ - largura_estimada (em mm)
+ - posicao_central (0 a 1 → fração da imagem)
+ - lista de pontos com (x, distancia_mm)
+ """
+
+ altura, largura = depth_frame.shape
+ faixa_inicio = int(altura * 0.45)
+ faixa_fim = int(altura * 0.55)
+
+ # Recorte central horizontal
+ faixa = depth_frame[faixa_inicio:faixa_fim, :]
+
+ # Média por coluna
+ profundidade_media = np.median(faixa, axis=0)
+
+ # Converte de disparidade para distância (mm)
+ with np.errstate(divide='ignore'): # evita divisão por zero
+ distancias_mm = (fx * baseline * 1000) / profundidade_media
+ distancias_mm = np.clip(distancias_mm, 0, largura_mm_max)
+
+ # Aplica filtro para remover ruído (média móvel simples)
+ distancias_mm_suave = cv2.blur(distancias_mm.reshape(1, -1).astype(np.float32), (15, 1)).flatten()
+
+ # Detecta bordas esquerda e direita: picos de distância próxima
+ limite = 2500 # Limite máximo para considerar obstáculo lateral (em mm)
+ idx_validos = np.where((distancias_mm_suave > 100) & (distancias_mm_suave < limite))[0]
+
+ if len(idx_validos) < 2:
+ return None, None, []
+
+ esquerda = idx_validos[0]
+ direita = idx_validos[-1]
+
+ largura_estimada = abs(distancias_mm_suave[direita] - distancias_mm_suave[esquerda])
+ posicao_central = (esquerda + direita) / 2 / largura
+
+ # Para visualização/debug
+ pontos_debug = [(int(x), float(distancias_mm_suave[x])) for x in range(0, largura, 10)]
+
+ return largura_estimada, posicao_central, pontos_debug
diff --git a/Python/OAK/visual_worker/processamento/obstaculos.py b/Python/OAK/visual_worker/processamento/obstaculos.py
new file mode 100644
index 000000000..12f5b9c38
--- /dev/null
+++ b/Python/OAK/visual_worker/processamento/obstaculos.py
@@ -0,0 +1,227 @@
+# obstaculos.py
+
+import numpy as np
+import time
+from scipy import stats
+
+from visual_worker.enums import Direcao, TipoDeteccao, TipoRegiaoRadar
+
+LIMIAR_OBSTACULO = 1000 # mm
+LIMIAR_DEPRESSAO = 2500 # mm
+
+buffer_macro = None
+buffer_micro = None
+ref_macro = None
+ref_micro = None
+
+MACRO_ROWS = 3
+MACRO_COLS = 4
+MICRO_ROWS = 10
+MICRO_COLS = 10
+
+
+
+def analisar_macro_grid(depth_frame, velocidade):
+ altura, largura = depth_frame.shape
+ row_h = altura // MACRO_ROWS
+ col_w = largura // MACRO_COLS
+
+ LIMIAR_OBSTACULO = calcular_limiar_dinamico(velocidade)
+ LIMIAR_DEPRESSAO = 2500 # Pode virar dinâmico depois
+
+ zonas_ocupadas = []
+ dist_min = 9999
+ frontal_bloqueado = False
+ laterais = { Direcao.ESQUERDA: False, Direcao.DIREITA: False }
+ zona_livre = Direcao.FRENTE
+
+ for i in range(MACRO_ROWS):
+ for j in range(MACRO_COLS):
+ y1, y2 = i * row_h, (i + 1) * row_h
+ x1, x2 = j * col_w, (j + 1) * col_w
+
+ area = depth_frame[y1:y2, x1:x2]
+ validos = area[(area > 0) & (area < 10000)]
+ if validos.size == 0:
+ continue
+
+ media = np.mean(validos)
+ erro = media - ref_macro[i][j]
+ dist_min = min(dist_min, media)
+
+ tipo = TipoDeteccao.SEGURO
+ if erro < LIMIAR_OBSTACULO:
+ tipo = TipoDeteccao.OBSTACULO
+ elif erro > LIMIAR_DEPRESSAO:
+ tipo = TipoDeteccao.DEPRESSAO
+
+ if tipo != TipoDeteccao.SEGURO:
+ regiao = TipoRegiaoRadar.SOLO if i == MACRO_ROWS - 1 else TipoRegiaoRadar.AEREO
+
+ zonas_ocupadas.append({
+ "linha": i,
+ "coluna": j,
+ "distancia": round(float(media) / 1000, 2),
+ "tipo": tipo,
+ "regiao": regiao
+ })
+
+ if i == MACRO_ROWS - 1 and j in [1, 2]:
+ frontal_bloqueado = True
+ if j == 0:
+ laterais[Direcao.ESQUERDA] = True
+ if j == MACRO_COLS - 1:
+ laterais[Direcao.DIREITA] = True
+
+ if not zonas_ocupadas:
+ zona_livre = Direcao.FRENTE
+ elif all(z["coluna"] < MACRO_COLS // 2 for z in zonas_ocupadas):
+ zona_livre = Direcao.DIREITA
+ elif all(z["coluna"] >= MACRO_COLS // 2 for z in zonas_ocupadas):
+ zona_livre = Direcao.ESQUERDA
+ else:
+ zona_livre = Direcao.PARADO
+
+ return {
+ "alerta": len(zonas_ocupadas) > 0,
+ "frontal_bloqueado": frontal_bloqueado,
+ "laterais": laterais,
+ "zona_livre": zona_livre,
+ "distancia_minima": round(float(dist_min) / 1000, 2),
+ "detalhes": zonas_ocupadas,
+ "precisa_micro": frontal_bloqueado
+ }
+
+def analisar_micro_grid(depth_frame):
+ altura, largura = depth_frame.shape
+ row_h = altura // MICRO_ROWS
+ col_w = largura // MICRO_COLS
+
+ detalhes = []
+ dist_min = 9999
+
+ for i in range(MICRO_ROWS):
+ for j in range(MICRO_COLS):
+ y1, y2 = i * row_h, (i + 1) * row_h
+ x1, x2 = j * col_w, (j + 1) * col_w
+
+ area = depth_frame[y1:y2, x1:x2]
+ validos = area[(area > 0) & (area < 10000)]
+ if validos.size == 0:
+ continue
+
+ media = np.mean(validos)
+ erro = media - ref_macro[i][j]
+ dist_min = min(dist_min, media)
+
+ tipo = TipoDeteccao.SEGURO
+ if erro < LIMIAR_OBSTACULO:
+ tipo = TipoDeteccao.OBSTACULO
+ elif erro > LIMIAR_DEPRESSAO:
+ tipo = TipoDeteccao.DEPRESSAO
+
+ if tipo != TipoDeteccao.SEGURO:
+ regiao = TipoRegiaoRadar.SOLO if i >= MICRO_ROWS * 0.6 else TipoRegiaoRadar.AEREO
+
+ detalhes.append({
+ "linha": i,
+ "coluna": j,
+ "distancia": round(float(media) / 1000, 2),
+ "tipo": tipo,
+ "regiao": regiao
+ })
+
+ return {
+ "alerta": len(detalhes) > 0,
+ "quantidade": len(detalhes),
+ "distancia_minima": round(float(dist_min) / 1000, 2),
+ "detalhes": detalhes
+ }
+
+
+def calcular_limiar_dinamico(velocidade):
+ # Exemplo: de 0.6m a 1.5m dependendo da velocidade
+ return int(min(max(600 + velocidade * 800, 600), 1500))
+
+def gerar_ref(buffer):
+ rows = len(buffer)
+ cols = len(buffer[0])
+ ref_out = np.zeros((rows, cols), dtype=np.float32)
+
+ for i in range(rows):
+ for j in range(cols):
+ valores = buffer[i][j]
+ if len(valores) == 0:
+ ref_out[i][j] = 0 # ou -1 para representar célula vazia
+ continue
+
+ # Tenta usar moda
+ moda = stats.mode(valores, keepdims=True).mode
+ if moda.size > 0:
+ ref_out[i][j] = moda[0]
+ else:
+ ref_out[i][j] = np.median(valores)
+
+ return ref_out
+
+def calibrar_macro(frame):
+ global buffer_macro
+ altura, largura = frame.shape
+ row_h = altura // MACRO_ROWS
+ col_w = largura // MACRO_COLS
+
+ for i in range(MACRO_ROWS):
+ for j in range(MACRO_COLS):
+ y1, y2 = i * row_h, (i + 1) * row_h
+ x1, x2 = j * col_w, (j + 1) * col_w
+
+ area = frame[y1:y2, x1:x2]
+ validos = area[(area > 0) & (area < 10000)]
+ if validos.size > 0:
+ buffer_macro[i][j].extend(validos.tolist())
+
+def calibrar_micro(frame):
+ global buffer_micro
+ altura, largura = frame.shape
+ row_h = altura // MICRO_ROWS
+ col_w = largura // MICRO_COLS
+
+ for i in range(MICRO_ROWS):
+ for j in range(MICRO_COLS):
+ y1, y2 = i * row_h, (i + 1) * row_h
+ x1, x2 = j * col_w, (j + 1) * col_w
+
+ area = frame[y1:y2, x1:x2]
+ validos = area[(area > 0) & (area < 10000)]
+ if validos.size > 0:
+ buffer_micro[i][j].extend(validos.tolist())
+
+def calibrar_grades(capturar_depth_frame, n_frames=50):
+ global buffer_macro, buffer_micro, ref_macro, ref_micro
+
+ buffer_macro = [[[] for _ in range(MACRO_COLS)] for _ in range(MACRO_ROWS)]
+ buffer_micro = [[[] for _ in range(MICRO_COLS)] for _ in range(MICRO_ROWS)]
+
+ print(f"📡 Iniciando calibração de {n_frames} frames...")
+
+ total_validos = 0
+ for i in range(n_frames):
+ frame = capturar_depth_frame()
+ if frame is not None:
+ calibrar_macro(frame)
+ calibrar_micro(frame)
+ total_validos += 1
+ print(f"✔️ Frame {i+1}/{n_frames} calibrado.")
+ else:
+ print(f"⚠️ Frame {i+1}/{n_frames} inválido, ignorado.")
+ time.sleep(0.03) # pausa leve pra estabilizar captura
+
+ if total_validos == 0:
+ print("❌ Nenhum frame válido recebido. Calibração cancelada.")
+ return False
+
+ ref_macro = gerar_ref(buffer_macro)
+ ref_micro = gerar_ref(buffer_micro)
+
+ print("✅ Calibração concluída com sucesso!")
+ return True
diff --git a/Python/OAK/visual_worker/processamento/visao3d.py b/Python/OAK/visual_worker/processamento/visao3d.py
new file mode 100644
index 000000000..17de6eeb2
--- /dev/null
+++ b/Python/OAK/visual_worker/processamento/visao3d.py
@@ -0,0 +1,48 @@
+import numpy as np
+
+def detectar_obstaculos_em_frente(depth_frame, fx, baseline, faixa_altura=(0.45, 0.55), max_distancia_mm=2500):
+ """
+ Detecta obstáculos com base no perfil de profundidade frontal.
+
+ Retorna uma lista de obstáculos com:
+ - posição_percentual (0 à 100)
+ - distancia (em metros)
+ - largura_aproximada (em px)
+ """
+
+ altura, largura = depth_frame.shape
+ y1 = int(altura * faixa_altura[0])
+ y2 = int(altura * faixa_altura[1])
+
+ faixa = depth_frame[y1:y2, :]
+
+ profundidade_media = np.median(faixa, axis=0)
+ with np.errstate(divide='ignore'):
+ distancias_mm = (fx * baseline * 1000) / profundidade_media
+ distancias_mm = np.clip(distancias_mm, 0, max_distancia_mm)
+
+ # Simplifica usando limiar: onde há objetos "próximos"
+ mascara = (distancias_mm > 100) & (distancias_mm < max_distancia_mm)
+
+ obstaculos = []
+ inicio = None
+
+ for x in range(largura):
+ if mascara[x]:
+ if inicio is None:
+ inicio = x
+ elif inicio is not None:
+ fim = x
+ centro = (inicio + fim) // 2
+ largura_px = fim - inicio
+ distancia = np.min(distancias_mm[inicio:fim])
+ posicao_pct = 100 * centro / largura
+
+ obstaculos.append({
+ "posicao": round(float(posicao_pct), 1),
+ "distancia": round(float(distancia) / 1000, 2),
+ "largura_px": largura_px
+ })
+ inicio = None
+
+ return obstaculos
diff --git a/Python/OAK/visual_worker/utils.py b/Python/OAK/visual_worker/utils.py
new file mode 100644
index 000000000..2096d4270
--- /dev/null
+++ b/Python/OAK/visual_worker/utils.py
@@ -0,0 +1,47 @@
+# utils.py
+
+import cv2
+import base64
+import numpy as np
+
+def encode_image_base64(frame):
+ """
+ Codifica uma imagem (np.ndarray) como string base64 JPEG.
+ """
+ ret, buffer = cv2.imencode('.jpg', frame, [cv2.IMWRITE_JPEG_QUALITY, 80])
+ if not ret:
+ return None
+ base64_str = base64.b64encode(buffer).decode('utf-8')
+ return base64_str
+
+def gerar_mapa_profundidade(depth_frame, linhas=10, colunas=10):
+ altura, largura = depth_frame.shape
+ h = altura // linhas
+ w = largura // colunas
+
+ grid = []
+ resposta = {
+ "resolucao": f"{linhas}x{colunas}",
+ "unidade": "cm",
+ "grid": grid
+ }
+
+ if depth_frame is None:
+ return resposta
+
+ for i in range(linhas):
+ linha = []
+ for j in range(colunas):
+ y1, y2 = i * h, (i + 1) * h
+ x1, x2 = j * w, (j + 1) * w
+ celula = depth_frame[y1:y2, x1:x2]
+ validos = celula[(celula > 0) & (celula < 10000)]
+ if validos.size == 0:
+ linha.append(None)
+ else:
+ media_cm = np.mean(validos) / 100.0
+ linha.append(round(float(media_cm), 2))
+ grid.append(linha)
+
+ resposta["grid"] = grid
+ return resposta