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