This commit is contained in:
Diego Note 2024-01-03 07:52:37 -03:00
parent cd05f42449
commit 34799f80fb
278 changed files with 63751 additions and 823 deletions

Binary file not shown.

View File

@ -156,6 +156,12 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Forms\Atuador\frmAtuConfig.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\Atuador\frmAtuConfig.Designer.cs">
<DependentUpon>frmAtuConfig.cs</DependentUpon>
</Compile>
<Compile Include="Forms\Direcional\frmDirConfig.cs">
<SubType>Form</SubType>
</Compile>
@ -174,11 +180,11 @@
<Compile Include="Forms\frmAcompanhamento.Designer.cs">
<DependentUpon>frmAcompanhamento.cs</DependentUpon>
</Compile>
<Compile Include="Forms\frmCamera.cs">
<Compile Include="Forms\Atuador\frmAtuCamera.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\frmCamera.Designer.cs">
<DependentUpon>frmCamera.cs</DependentUpon>
<Compile Include="Forms\Atuador\frmAtuCamera.Designer.cs">
<DependentUpon>frmAtuCamera.cs</DependentUpon>
</Compile>
<Compile Include="Forms\frmMapa.cs">
<SubType>Form</SubType>
@ -216,6 +222,18 @@
<Compile Include="Forms\Movimentacao\frmMovPlot.Designer.cs">
<DependentUpon>frmMovPlot.cs</DependentUpon>
</Compile>
<Compile Include="Forms\Operacoes\frmOperacaoSeguidorLinha.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\Operacoes\frmOperacaoSeguidorLinha.Designer.cs">
<DependentUpon>frmOperacaoSeguidorLinha.cs</DependentUpon>
</Compile>
<Compile Include="Forms\Sensoriamento\frmSenCamera.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\Sensoriamento\frmSenCamera.Designer.cs">
<DependentUpon>frmSenCamera.cs</DependentUpon>
</Compile>
<Compile Include="Forms\Sensoriamento\frmSenConfig.cs">
<SubType>Form</SubType>
</Compile>
@ -224,14 +242,17 @@
</Compile>
<Compile Include="Models\CameraModel.cs" />
<Compile Include="Models\MapasModel.cs" />
<Compile Include="Models\Modules\AtuadorModel.cs" />
<Compile Include="Models\Modules\DirecionalModel.cs" />
<Compile Include="Models\Modules\DispositivosBaseModel.cs" />
<Compile Include="Models\Modules\DispositivoBaseModel.cs" />
<Compile Include="Models\Enuns.cs" />
<Compile Include="Models\GeneralJoystick.cs" />
<Compile Include="Models\Modules\MovimentacaoModel.cs" />
<Compile Include="Models\Modules\PinoutModel.cs" />
<Compile Include="Models\Modules\SensoriamentoModel.cs" />
<Compile Include="Models\MotorComum.cs" />
<Compile Include="Models\Operacoes\OperacaoModel.cs" />
<Compile Include="Models\Variaveis.cs" />
<Compile Include="Services\CameraService.cs" />
<Compile Include="Services\DispositivosService.cs" />
<Compile Include="Forms\frmPrincipal.cs">
@ -242,9 +263,15 @@
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Services\DispositivosServiceFactory.cs" />
<Compile Include="Services\IDispositivosService.cs" />
<Compile Include="Services\MapasService.cs" />
<Compile Include="Services\PythonService.cs" />
<Compile Include="Services\SerialService.cs" />
<Compile Include="Services\SocketService.cs" />
<EmbeddedResource Include="Forms\Atuador\frmAtuConfig.resx">
<DependentUpon>frmAtuConfig.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\Direcional\frmDirConfig.resx">
<DependentUpon>frmDirConfig.cs</DependentUpon>
</EmbeddedResource>
@ -254,8 +281,8 @@
<EmbeddedResource Include="Forms\frmAcompanhamento.resx">
<DependentUpon>frmAcompanhamento.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\frmCamera.resx">
<DependentUpon>frmCamera.cs</DependentUpon>
<EmbeddedResource Include="Forms\Atuador\frmAtuCamera.resx">
<DependentUpon>frmAtuCamera.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\frmMapa.resx">
<DependentUpon>frmMapa.cs</DependentUpon>
@ -278,6 +305,12 @@
<EmbeddedResource Include="Forms\frmJoystick.resx">
<DependentUpon>frmJoystick.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\Operacoes\frmOperacaoSeguidorLinha.resx">
<DependentUpon>frmOperacaoSeguidorLinha.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\Sensoriamento\frmSenCamera.resx">
<DependentUpon>frmSenCamera.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\Sensoriamento\frmSenConfig.resx">
<DependentUpon>frmSenConfig.cs</DependentUpon>
</EmbeddedResource>
@ -349,6 +382,12 @@
<Content Include="Python\Scripts\green-detector.py">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Python\Scripts\line-angle.py">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Python\Scripts\line-angle2.py">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Python\Scripts\map-load.py">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>

View File

@ -1,7 +1,7 @@

namespace AgroBase.Forms
{
partial class frmCamera
partial class frmAtuCamera
{
/// <summary>
/// Required designer variable.
@ -114,7 +114,7 @@ namespace AgroBase.Forms
this.cmbCameras.Size = new System.Drawing.Size(176, 24);
this.cmbCameras.TabIndex = 0;
//
// frmCamera
// frmAtuCamera
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
@ -122,9 +122,9 @@ namespace AgroBase.Forms
this.Controls.Add(this.gpbCameras);
this.Controls.Add(this.pnlLeituras);
this.Controls.Add(this.pnlCamera);
this.Name = "frmCamera";
this.Name = "frmAtuCamera";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Câmera";
this.Text = "Identificação do solo";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.frmCamera_FormClosing);
this.Load += new System.EventHandler(this.frmCamera_Load);
this.gpbCameras.ResumeLayout(false);

View File

@ -0,0 +1,209 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Management;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using AgroBase.Models;
using AgroBase.Services;
using CefSharp.WinForms;
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using Newtonsoft.Json;
namespace AgroBase.Forms
{
public partial class frmAtuCamera : Form
{
private CameraService<CameraCoordenadasFrameModel> cameraService = new CameraService<CameraCoordenadasFrameModel>();
private ChromiumWebBrowser chromiumWebBrowser = null;
private Timer tmrLeitura;
private int MaxLeituras = 10;
private string VideoPorta = "8080";
private string VideoUrl = "green_objects";
private string SocketPorta = "6536";
private string ArquivoLeitura = "objetos.json";
public frmAtuCamera()
{
InitializeComponent();
}
private void frmCamera_Load(object sender, EventArgs e)
{
AtualizaListaCameras();
}
private void frmCamera_FormClosing(object sender, FormClosingEventArgs e)
{
try
{
cameraService.socket.Disconnect();
cameraService.pythonProcess.Kill();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private void TmrLeitura_Tick(object sender, EventArgs e)
{
ListarObjetosDetectados();
}
private void btnAtualizar_Click(object sender, EventArgs e)
{
AtualizaListaCameras();
}
private void btnSalvar_Click(object sender, EventArgs e)
{
if (btnSalvar.Text == "Editar")
{
btnSalvar.Text = "Salvar";
}
else
{
btnSalvar.Text = "Editar";
cameraService.selectedCamera = cmbCameras.SelectedIndex;
}
btnIniciar.Enabled = btnSalvar.Text == "Editar" && cmbCameras.SelectedIndex > 0;
cmbCameras.Enabled = btnSalvar.Text == "Salvar";
}
private void btnIniciar_Click(object sender, EventArgs e)
{
cameraService.ArquivoLeitura = ArquivoLeitura;
cameraService.IniciarCamera(
PythonService.ScriptGreenDetector,
new string[] { MaxLeituras.ToString(), VideoPorta, VideoUrl, ArquivoLeitura, "1", SocketPorta },
VideoPorta,
VideoUrl,
SocketPorta
);
tmrLeitura = new Timer() { Interval = 200 };
tmrLeitura.Tick += TmrLeitura_Tick;
tmrLeitura.Start();
}
private void AtualizaListaCameras()
{
cameraService.selectedCamera = cmbCameras.SelectedIndex > 0 ? cmbCameras.SelectedIndex : 0;
cmbCameras.Items.Clear();
cmbCameras.Items.AddRange(cameraService.AtualizaListaCameras().ToArray());
if (cmbCameras.Items.Count == 1)
{
cameraService.selectedCamera = 0;
}
cmbCameras.SelectedIndex = cameraService.selectedCamera;
}
private void ListarObjetosDetectados()
{
if (chromiumWebBrowser == null)
{
chromiumWebBrowser = new ChromiumWebBrowser(cameraService.URLcamera);
this.pnlCamera.Controls.Add(chromiumWebBrowser);
chromiumWebBrowser.Dock = DockStyle.Fill;
}
this.pnlLeituras.Controls.Clear();
int i = 0;
//var coordenadas = cameraService.AferirDadosCamera<CameraCoordenadasModel>();
var leituras = cameraService.socket.DadosRecebidos.ToList().OrderByDescending(x => x.timestamp).Take(MaxLeituras).ToList();
if (!leituras.Any())
{
return;
}
foreach (var objeto in leituras.FirstOrDefault().objetos)
{
GroupBox gpb = new GroupBox()
{
Name = "gpbLeitura" + i,
Size = new Size(120, 170),
Text = "Leitura " + (i + 1),
Location = new Point(3, 3 + (i * 190))
};
Label _lblID = new Label()
{
Name = "lblLeitura" + i + "ID",
Size = new Size(100, 20),
Text = "ID: " + objeto.id,
Location = new Point(6, 20)
};
Label _lblDescricao = new Label()
{
Name = "lblLeitura" + i + "Descricao",
Size = new Size(100, 20),
Text = "Descrição: " + objeto.descricao,
Location = new Point(6, 40)
};
Label _lblConfianca = new Label()
{
Name = "lblLeitura" + i + "Confianca",
Size = new Size(100, 20),
Text = "Confiança: " + (objeto.confianca * 100).ToString("0.00") + "%",
Location = new Point(6, 60)
};
Label _lblX = new Label()
{
Name = "lblLeitura" + i + "X",
Size = new Size(100, 20),
Text = "X: " + objeto.x,
Location = new Point(6, 80)
};
Label _lblY = new Label()
{
Name = "lblLeitura" + i + "Y",
Size = new Size(100, 20),
Text = "Y: " + objeto.y,
Location = new Point(6, 100)
};
Label _lblAltura = new Label()
{
Name = "lblLeitura" + i + "Altura",
Size = new Size(100, 20),
Text = "Altura: " + objeto.altura,
Location = new Point(6, 120)
};
Label _lblLargura = new Label()
{
Name = "lblLeitura" + i + "Largura",
Size = new Size(100, 20),
Text = "Largura: " + objeto.largura,
Location = new Point(6, 140)
};
gpb.Controls.Add(_lblID);
gpb.Controls.Add(_lblDescricao);
gpb.Controls.Add(_lblConfianca);
gpb.Controls.Add(_lblX);
gpb.Controls.Add(_lblY);
gpb.Controls.Add(_lblAltura);
gpb.Controls.Add(_lblLargura);
pnlLeituras.Controls.Add(gpb);
i++;
}
}
}
}

View File

@ -0,0 +1,588 @@

namespace AgroBase.Forms.Atuador
{
partial class frmAtuConfig
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(frmAtuConfig));
this.cmbGND1 = new System.Windows.Forms.ComboBox();
this.cmb5V = new System.Windows.Forms.ComboBox();
this.cmbGPIO14 = new System.Windows.Forms.ComboBox();
this.cmbGND2 = new System.Windows.Forms.ComboBox();
this.cmbGND3 = new System.Windows.Forms.ComboBox();
this.cmbGPIO19 = new System.Windows.Forms.ComboBox();
this.btnSalvar = new System.Windows.Forms.Button();
this.cmbGPIO20 = new System.Windows.Forms.ComboBox();
this.cmbGPIO21 = new System.Windows.Forms.ComboBox();
this.cmbGPIO47 = new System.Windows.Forms.ComboBox();
this.cmbGPIO48 = new System.Windows.Forms.ComboBox();
this.cmbGPIO45 = new System.Windows.Forms.ComboBox();
this.cmbGPIO0 = new System.Windows.Forms.ComboBox();
this.cmbGPIO35 = new System.Windows.Forms.ComboBox();
this.cmbGPIO36 = new System.Windows.Forms.ComboBox();
this.cmbGPIO37 = new System.Windows.Forms.ComboBox();
this.cmbGPIO38 = new System.Windows.Forms.ComboBox();
this.cmbGPIO39 = new System.Windows.Forms.ComboBox();
this.cmbGPIO40 = new System.Windows.Forms.ComboBox();
this.cmbGPIO41 = new System.Windows.Forms.ComboBox();
this.cmbGPIO42 = new System.Windows.Forms.ComboBox();
this.cmbGPIO2 = new System.Windows.Forms.ComboBox();
this.cmbGPIO1 = new System.Windows.Forms.ComboBox();
this.cmbRX = new System.Windows.Forms.ComboBox();
this.cmbTX = new System.Windows.Forms.ComboBox();
this.cmbGND4 = new System.Windows.Forms.ComboBox();
this.cmbGPIO13 = new System.Windows.Forms.ComboBox();
this.cmbGPIO12 = new System.Windows.Forms.ComboBox();
this.cmbGPIO11 = new System.Windows.Forms.ComboBox();
this.cmbGPIO10 = new System.Windows.Forms.ComboBox();
this.cmbGPIO9 = new System.Windows.Forms.ComboBox();
this.cmbGPIO46 = new System.Windows.Forms.ComboBox();
this.cmbGPIO3 = new System.Windows.Forms.ComboBox();
this.cmbGPIO8 = new System.Windows.Forms.ComboBox();
this.cmbGPIO18 = new System.Windows.Forms.ComboBox();
this.cmbGPIO17 = new System.Windows.Forms.ComboBox();
this.cmbGPIO16 = new System.Windows.Forms.ComboBox();
this.cmbGPIO15 = new System.Windows.Forms.ComboBox();
this.cmbGPIO7 = new System.Windows.Forms.ComboBox();
this.cmbGPIO6 = new System.Windows.Forms.ComboBox();
this.cmbGPIO5 = new System.Windows.Forms.ComboBox();
this.cmbGPIO4 = new System.Windows.Forms.ComboBox();
this.cmbRst = new System.Windows.Forms.ComboBox();
this.cmb3v3_2 = new System.Windows.Forms.ComboBox();
this.cmb3v3_1 = new System.Windows.Forms.ComboBox();
this.imgESP32 = new System.Windows.Forms.PictureBox();
this.lblPinout = new System.Windows.Forms.Label();
((System.ComponentModel.ISupportInitialize)(this.imgESP32)).BeginInit();
this.SuspendLayout();
//
// cmbGND1
//
this.cmbGND1.Enabled = false;
this.cmbGND1.FormattingEnabled = true;
this.cmbGND1.Location = new System.Drawing.Point(18, 719);
this.cmbGND1.Name = "cmbGND1";
this.cmbGND1.Size = new System.Drawing.Size(148, 24);
this.cmbGND1.TabIndex = 179;
//
// cmb5V
//
this.cmb5V.Enabled = false;
this.cmb5V.FormattingEnabled = true;
this.cmb5V.Location = new System.Drawing.Point(18, 689);
this.cmb5V.Name = "cmb5V";
this.cmb5V.Size = new System.Drawing.Size(148, 24);
this.cmb5V.TabIndex = 178;
//
// cmbGPIO14
//
this.cmbGPIO14.FormattingEnabled = true;
this.cmbGPIO14.Location = new System.Drawing.Point(18, 659);
this.cmbGPIO14.Name = "cmbGPIO14";
this.cmbGPIO14.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO14.TabIndex = 177;
//
// cmbGND2
//
this.cmbGND2.Enabled = false;
this.cmbGND2.FormattingEnabled = true;
this.cmbGND2.Location = new System.Drawing.Point(584, 719);
this.cmbGND2.Name = "cmbGND2";
this.cmbGND2.Size = new System.Drawing.Size(148, 24);
this.cmbGND2.TabIndex = 176;
//
// cmbGND3
//
this.cmbGND3.Enabled = false;
this.cmbGND3.FormattingEnabled = true;
this.cmbGND3.Location = new System.Drawing.Point(584, 689);
this.cmbGND3.Name = "cmbGND3";
this.cmbGND3.Size = new System.Drawing.Size(148, 24);
this.cmbGND3.TabIndex = 175;
//
// cmbGPIO19
//
this.cmbGPIO19.FormattingEnabled = true;
this.cmbGPIO19.Location = new System.Drawing.Point(584, 659);
this.cmbGPIO19.Name = "cmbGPIO19";
this.cmbGPIO19.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO19.TabIndex = 174;
//
// btnSalvar
//
this.btnSalvar.Location = new System.Drawing.Point(584, 786);
this.btnSalvar.Name = "btnSalvar";
this.btnSalvar.Size = new System.Drawing.Size(148, 40);
this.btnSalvar.TabIndex = 173;
this.btnSalvar.Text = "Salvar";
this.btnSalvar.UseVisualStyleBackColor = true;
this.btnSalvar.Click += new System.EventHandler(this.btnSalvar_Click);
//
// cmbGPIO20
//
this.cmbGPIO20.FormattingEnabled = true;
this.cmbGPIO20.Location = new System.Drawing.Point(584, 629);
this.cmbGPIO20.Name = "cmbGPIO20";
this.cmbGPIO20.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO20.TabIndex = 172;
//
// cmbGPIO21
//
this.cmbGPIO21.FormattingEnabled = true;
this.cmbGPIO21.Location = new System.Drawing.Point(584, 599);
this.cmbGPIO21.Name = "cmbGPIO21";
this.cmbGPIO21.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO21.TabIndex = 171;
//
// cmbGPIO47
//
this.cmbGPIO47.FormattingEnabled = true;
this.cmbGPIO47.Location = new System.Drawing.Point(584, 569);
this.cmbGPIO47.Name = "cmbGPIO47";
this.cmbGPIO47.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO47.TabIndex = 170;
//
// cmbGPIO48
//
this.cmbGPIO48.FormattingEnabled = true;
this.cmbGPIO48.Location = new System.Drawing.Point(584, 539);
this.cmbGPIO48.Name = "cmbGPIO48";
this.cmbGPIO48.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO48.TabIndex = 169;
//
// cmbGPIO45
//
this.cmbGPIO45.FormattingEnabled = true;
this.cmbGPIO45.Location = new System.Drawing.Point(584, 509);
this.cmbGPIO45.Name = "cmbGPIO45";
this.cmbGPIO45.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO45.TabIndex = 168;
//
// cmbGPIO0
//
this.cmbGPIO0.FormattingEnabled = true;
this.cmbGPIO0.Location = new System.Drawing.Point(584, 479);
this.cmbGPIO0.Name = "cmbGPIO0";
this.cmbGPIO0.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO0.TabIndex = 167;
//
// cmbGPIO35
//
this.cmbGPIO35.FormattingEnabled = true;
this.cmbGPIO35.Location = new System.Drawing.Point(584, 449);
this.cmbGPIO35.Name = "cmbGPIO35";
this.cmbGPIO35.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO35.TabIndex = 166;
//
// cmbGPIO36
//
this.cmbGPIO36.FormattingEnabled = true;
this.cmbGPIO36.Location = new System.Drawing.Point(584, 419);
this.cmbGPIO36.Name = "cmbGPIO36";
this.cmbGPIO36.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO36.TabIndex = 165;
//
// cmbGPIO37
//
this.cmbGPIO37.FormattingEnabled = true;
this.cmbGPIO37.Location = new System.Drawing.Point(584, 389);
this.cmbGPIO37.Name = "cmbGPIO37";
this.cmbGPIO37.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO37.TabIndex = 164;
//
// cmbGPIO38
//
this.cmbGPIO38.FormattingEnabled = true;
this.cmbGPIO38.Location = new System.Drawing.Point(584, 359);
this.cmbGPIO38.Name = "cmbGPIO38";
this.cmbGPIO38.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO38.TabIndex = 163;
//
// cmbGPIO39
//
this.cmbGPIO39.FormattingEnabled = true;
this.cmbGPIO39.Location = new System.Drawing.Point(584, 329);
this.cmbGPIO39.Name = "cmbGPIO39";
this.cmbGPIO39.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO39.TabIndex = 162;
//
// cmbGPIO40
//
this.cmbGPIO40.FormattingEnabled = true;
this.cmbGPIO40.Location = new System.Drawing.Point(584, 299);
this.cmbGPIO40.Name = "cmbGPIO40";
this.cmbGPIO40.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO40.TabIndex = 161;
//
// cmbGPIO41
//
this.cmbGPIO41.FormattingEnabled = true;
this.cmbGPIO41.Location = new System.Drawing.Point(584, 269);
this.cmbGPIO41.Name = "cmbGPIO41";
this.cmbGPIO41.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO41.TabIndex = 160;
//
// cmbGPIO42
//
this.cmbGPIO42.FormattingEnabled = true;
this.cmbGPIO42.Location = new System.Drawing.Point(584, 239);
this.cmbGPIO42.Name = "cmbGPIO42";
this.cmbGPIO42.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO42.TabIndex = 159;
//
// cmbGPIO2
//
this.cmbGPIO2.FormattingEnabled = true;
this.cmbGPIO2.Location = new System.Drawing.Point(584, 209);
this.cmbGPIO2.Name = "cmbGPIO2";
this.cmbGPIO2.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO2.TabIndex = 158;
//
// cmbGPIO1
//
this.cmbGPIO1.FormattingEnabled = true;
this.cmbGPIO1.Location = new System.Drawing.Point(584, 179);
this.cmbGPIO1.Name = "cmbGPIO1";
this.cmbGPIO1.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO1.TabIndex = 157;
//
// cmbRX
//
this.cmbRX.Enabled = false;
this.cmbRX.FormattingEnabled = true;
this.cmbRX.Location = new System.Drawing.Point(584, 149);
this.cmbRX.Name = "cmbRX";
this.cmbRX.Size = new System.Drawing.Size(148, 24);
this.cmbRX.TabIndex = 156;
//
// cmbTX
//
this.cmbTX.Enabled = false;
this.cmbTX.FormattingEnabled = true;
this.cmbTX.Location = new System.Drawing.Point(584, 119);
this.cmbTX.Name = "cmbTX";
this.cmbTX.Size = new System.Drawing.Size(148, 24);
this.cmbTX.TabIndex = 155;
//
// cmbGND4
//
this.cmbGND4.Enabled = false;
this.cmbGND4.FormattingEnabled = true;
this.cmbGND4.Location = new System.Drawing.Point(584, 89);
this.cmbGND4.Name = "cmbGND4";
this.cmbGND4.Size = new System.Drawing.Size(148, 24);
this.cmbGND4.TabIndex = 154;
//
// cmbGPIO13
//
this.cmbGPIO13.FormattingEnabled = true;
this.cmbGPIO13.Location = new System.Drawing.Point(18, 629);
this.cmbGPIO13.Name = "cmbGPIO13";
this.cmbGPIO13.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO13.TabIndex = 153;
//
// cmbGPIO12
//
this.cmbGPIO12.FormattingEnabled = true;
this.cmbGPIO12.Location = new System.Drawing.Point(18, 599);
this.cmbGPIO12.Name = "cmbGPIO12";
this.cmbGPIO12.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO12.TabIndex = 152;
//
// cmbGPIO11
//
this.cmbGPIO11.FormattingEnabled = true;
this.cmbGPIO11.Location = new System.Drawing.Point(18, 569);
this.cmbGPIO11.Name = "cmbGPIO11";
this.cmbGPIO11.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO11.TabIndex = 151;
//
// cmbGPIO10
//
this.cmbGPIO10.FormattingEnabled = true;
this.cmbGPIO10.Location = new System.Drawing.Point(18, 539);
this.cmbGPIO10.Name = "cmbGPIO10";
this.cmbGPIO10.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO10.TabIndex = 150;
//
// cmbGPIO9
//
this.cmbGPIO9.FormattingEnabled = true;
this.cmbGPIO9.Location = new System.Drawing.Point(18, 509);
this.cmbGPIO9.Name = "cmbGPIO9";
this.cmbGPIO9.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO9.TabIndex = 149;
//
// cmbGPIO46
//
this.cmbGPIO46.FormattingEnabled = true;
this.cmbGPIO46.Location = new System.Drawing.Point(18, 479);
this.cmbGPIO46.Name = "cmbGPIO46";
this.cmbGPIO46.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO46.TabIndex = 148;
//
// cmbGPIO3
//
this.cmbGPIO3.FormattingEnabled = true;
this.cmbGPIO3.Location = new System.Drawing.Point(18, 449);
this.cmbGPIO3.Name = "cmbGPIO3";
this.cmbGPIO3.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO3.TabIndex = 147;
//
// cmbGPIO8
//
this.cmbGPIO8.FormattingEnabled = true;
this.cmbGPIO8.Location = new System.Drawing.Point(18, 419);
this.cmbGPIO8.Name = "cmbGPIO8";
this.cmbGPIO8.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO8.TabIndex = 146;
//
// cmbGPIO18
//
this.cmbGPIO18.FormattingEnabled = true;
this.cmbGPIO18.Location = new System.Drawing.Point(18, 389);
this.cmbGPIO18.Name = "cmbGPIO18";
this.cmbGPIO18.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO18.TabIndex = 145;
//
// cmbGPIO17
//
this.cmbGPIO17.FormattingEnabled = true;
this.cmbGPIO17.Location = new System.Drawing.Point(18, 359);
this.cmbGPIO17.Name = "cmbGPIO17";
this.cmbGPIO17.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO17.TabIndex = 144;
//
// cmbGPIO16
//
this.cmbGPIO16.FormattingEnabled = true;
this.cmbGPIO16.Location = new System.Drawing.Point(18, 329);
this.cmbGPIO16.Name = "cmbGPIO16";
this.cmbGPIO16.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO16.TabIndex = 143;
//
// cmbGPIO15
//
this.cmbGPIO15.FormattingEnabled = true;
this.cmbGPIO15.Location = new System.Drawing.Point(18, 299);
this.cmbGPIO15.Name = "cmbGPIO15";
this.cmbGPIO15.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO15.TabIndex = 142;
//
// cmbGPIO7
//
this.cmbGPIO7.FormattingEnabled = true;
this.cmbGPIO7.Location = new System.Drawing.Point(18, 269);
this.cmbGPIO7.Name = "cmbGPIO7";
this.cmbGPIO7.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO7.TabIndex = 141;
//
// cmbGPIO6
//
this.cmbGPIO6.FormattingEnabled = true;
this.cmbGPIO6.Location = new System.Drawing.Point(18, 239);
this.cmbGPIO6.Name = "cmbGPIO6";
this.cmbGPIO6.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO6.TabIndex = 140;
//
// cmbGPIO5
//
this.cmbGPIO5.FormattingEnabled = true;
this.cmbGPIO5.Location = new System.Drawing.Point(18, 209);
this.cmbGPIO5.Name = "cmbGPIO5";
this.cmbGPIO5.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO5.TabIndex = 139;
//
// cmbGPIO4
//
this.cmbGPIO4.FormattingEnabled = true;
this.cmbGPIO4.Location = new System.Drawing.Point(18, 179);
this.cmbGPIO4.Name = "cmbGPIO4";
this.cmbGPIO4.Size = new System.Drawing.Size(148, 24);
this.cmbGPIO4.TabIndex = 138;
//
// cmbRst
//
this.cmbRst.Enabled = false;
this.cmbRst.FormattingEnabled = true;
this.cmbRst.Location = new System.Drawing.Point(18, 149);
this.cmbRst.Name = "cmbRst";
this.cmbRst.Size = new System.Drawing.Size(148, 24);
this.cmbRst.TabIndex = 137;
//
// cmb3v3_2
//
this.cmb3v3_2.Enabled = false;
this.cmb3v3_2.FormattingEnabled = true;
this.cmb3v3_2.Location = new System.Drawing.Point(18, 119);
this.cmb3v3_2.Name = "cmb3v3_2";
this.cmb3v3_2.Size = new System.Drawing.Size(148, 24);
this.cmb3v3_2.TabIndex = 136;
//
// cmb3v3_1
//
this.cmb3v3_1.Enabled = false;
this.cmb3v3_1.FormattingEnabled = true;
this.cmb3v3_1.Location = new System.Drawing.Point(18, 89);
this.cmb3v3_1.Name = "cmb3v3_1";
this.cmb3v3_1.Size = new System.Drawing.Size(148, 24);
this.cmb3v3_1.TabIndex = 135;
//
// imgESP32
//
this.imgESP32.Image = ((System.Drawing.Image)(resources.GetObject("imgESP32.Image")));
this.imgESP32.Location = new System.Drawing.Point(172, -2);
this.imgESP32.Name = "imgESP32";
this.imgESP32.Size = new System.Drawing.Size(406, 847);
this.imgESP32.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
this.imgESP32.TabIndex = 134;
this.imgESP32.TabStop = false;
//
// lblPinout
//
this.lblPinout.AutoSize = true;
this.lblPinout.Location = new System.Drawing.Point(15, 12);
this.lblPinout.Name = "lblPinout";
this.lblPinout.Size = new System.Drawing.Size(48, 17);
this.lblPinout.TabIndex = 180;
this.lblPinout.Text = "Pinout";
//
// frmAtuConfig
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.White;
this.ClientSize = new System.Drawing.Size(1285, 838);
this.Controls.Add(this.lblPinout);
this.Controls.Add(this.cmbGND1);
this.Controls.Add(this.cmb5V);
this.Controls.Add(this.cmbGPIO14);
this.Controls.Add(this.cmbGND2);
this.Controls.Add(this.cmbGND3);
this.Controls.Add(this.cmbGPIO19);
this.Controls.Add(this.btnSalvar);
this.Controls.Add(this.cmbGPIO20);
this.Controls.Add(this.cmbGPIO21);
this.Controls.Add(this.cmbGPIO47);
this.Controls.Add(this.cmbGPIO48);
this.Controls.Add(this.cmbGPIO45);
this.Controls.Add(this.cmbGPIO0);
this.Controls.Add(this.cmbGPIO35);
this.Controls.Add(this.cmbGPIO36);
this.Controls.Add(this.cmbGPIO37);
this.Controls.Add(this.cmbGPIO38);
this.Controls.Add(this.cmbGPIO39);
this.Controls.Add(this.cmbGPIO40);
this.Controls.Add(this.cmbGPIO41);
this.Controls.Add(this.cmbGPIO42);
this.Controls.Add(this.cmbGPIO2);
this.Controls.Add(this.cmbGPIO1);
this.Controls.Add(this.cmbRX);
this.Controls.Add(this.cmbTX);
this.Controls.Add(this.cmbGND4);
this.Controls.Add(this.cmbGPIO13);
this.Controls.Add(this.cmbGPIO12);
this.Controls.Add(this.cmbGPIO11);
this.Controls.Add(this.cmbGPIO10);
this.Controls.Add(this.cmbGPIO9);
this.Controls.Add(this.cmbGPIO46);
this.Controls.Add(this.cmbGPIO3);
this.Controls.Add(this.cmbGPIO8);
this.Controls.Add(this.cmbGPIO18);
this.Controls.Add(this.cmbGPIO17);
this.Controls.Add(this.cmbGPIO16);
this.Controls.Add(this.cmbGPIO15);
this.Controls.Add(this.cmbGPIO7);
this.Controls.Add(this.cmbGPIO6);
this.Controls.Add(this.cmbGPIO5);
this.Controls.Add(this.cmbGPIO4);
this.Controls.Add(this.cmbRst);
this.Controls.Add(this.cmb3v3_2);
this.Controls.Add(this.cmb3v3_1);
this.Controls.Add(this.imgESP32);
this.Name = "frmAtuConfig";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Atuadores - Parametrização";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.frmAtuConfig_FormClosing);
this.Load += new System.EventHandler(this.frmAtuConfig_Load);
((System.ComponentModel.ISupportInitialize)(this.imgESP32)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.ComboBox cmbGND1;
private System.Windows.Forms.ComboBox cmb5V;
private System.Windows.Forms.ComboBox cmbGPIO14;
private System.Windows.Forms.ComboBox cmbGND2;
private System.Windows.Forms.ComboBox cmbGND3;
private System.Windows.Forms.ComboBox cmbGPIO19;
private System.Windows.Forms.Button btnSalvar;
private System.Windows.Forms.ComboBox cmbGPIO20;
private System.Windows.Forms.ComboBox cmbGPIO21;
private System.Windows.Forms.ComboBox cmbGPIO47;
private System.Windows.Forms.ComboBox cmbGPIO48;
private System.Windows.Forms.ComboBox cmbGPIO45;
private System.Windows.Forms.ComboBox cmbGPIO0;
private System.Windows.Forms.ComboBox cmbGPIO35;
private System.Windows.Forms.ComboBox cmbGPIO36;
private System.Windows.Forms.ComboBox cmbGPIO37;
private System.Windows.Forms.ComboBox cmbGPIO38;
private System.Windows.Forms.ComboBox cmbGPIO39;
private System.Windows.Forms.ComboBox cmbGPIO40;
private System.Windows.Forms.ComboBox cmbGPIO41;
private System.Windows.Forms.ComboBox cmbGPIO42;
private System.Windows.Forms.ComboBox cmbGPIO2;
private System.Windows.Forms.ComboBox cmbGPIO1;
private System.Windows.Forms.ComboBox cmbRX;
private System.Windows.Forms.ComboBox cmbTX;
private System.Windows.Forms.ComboBox cmbGND4;
private System.Windows.Forms.ComboBox cmbGPIO13;
private System.Windows.Forms.ComboBox cmbGPIO12;
private System.Windows.Forms.ComboBox cmbGPIO11;
private System.Windows.Forms.ComboBox cmbGPIO10;
private System.Windows.Forms.ComboBox cmbGPIO9;
private System.Windows.Forms.ComboBox cmbGPIO46;
private System.Windows.Forms.ComboBox cmbGPIO3;
private System.Windows.Forms.ComboBox cmbGPIO8;
private System.Windows.Forms.ComboBox cmbGPIO18;
private System.Windows.Forms.ComboBox cmbGPIO17;
private System.Windows.Forms.ComboBox cmbGPIO16;
private System.Windows.Forms.ComboBox cmbGPIO15;
private System.Windows.Forms.ComboBox cmbGPIO7;
private System.Windows.Forms.ComboBox cmbGPIO6;
private System.Windows.Forms.ComboBox cmbGPIO5;
private System.Windows.Forms.ComboBox cmbGPIO4;
private System.Windows.Forms.ComboBox cmbRst;
private System.Windows.Forms.ComboBox cmb3v3_2;
private System.Windows.Forms.ComboBox cmb3v3_1;
private System.Windows.Forms.PictureBox imgESP32;
private System.Windows.Forms.Label lblPinout;
}
}

View File

@ -0,0 +1,98 @@
using AgroBase.Comum;
using AgroBase.Models;
using AgroBase.Models.Modules;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static AgroBase.Models.Enuns;
namespace AgroBase.Forms.Atuador
{
public partial class frmAtuConfig : Form
{
DispositivosService<AtuadorModel> Disp = (DispositivosService<AtuadorModel>)Variaveis.DispositivosConectados.FirstOrDefault(x => x.Dispositivo == T_Code.Atu);
public frmAtuConfig()
{
InitializeComponent();
}
private void frmAtuConfig_Load(object sender, EventArgs e)
{
if (Disp == null)
{
return;
}
List<string> Pinos = new List<string>()
{
Enum.GetName(typeof(FuncoesPinout), FuncoesPinout.NaoConectado),
};
AtuadorModel.Funcoes.ForEach(x => Pinos.Add(Enum.GetName(typeof(FuncoesPinout), x)));
foreach (var Sensor in Disp.Dados.BicosPulverizadores)
{
Sensor.Funcoes.ForEach(x => Pinos.Add(Sensor.ID + " " + Enum.GetName(typeof(FuncoesPinout), x)));
}
List<ComboBox> cmbs = this.Controls.OfType<ComboBox>().Where(x => x.Name.Contains("cmbGPIO") && x.Enabled).ToList();
foreach (var cmb in cmbs)
{
cmb.SelectedIndexChanged += Cmb_SelectedIndexChanged;
cmb.Items.Clear();
Pinos.ForEach(x => cmb.Items.Add(x));
int pino = int.Parse(cmb.Name.Replace("cmbGPIO", ""));
cmb.SelectedIndex = 0;
var Selecionado = AtuadorModel.Pinout.FirstOrDefault(x => x.Pino == pino);
if (Selecionado != null) cmb.SelectedItem = (Selecionado.Funcao != FuncoesPinout.Geral ? Selecionado.ComponenteID + " " : "") + Enum.GetName(typeof(FuncoesPinout), Selecionado.Funcao);
}
}
private void frmAtuConfig_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
this.Visible = false;
}
private void Cmb_SelectedIndexChanged(object sender, EventArgs e)
{
var cmb = (ComboBox)sender;
this.Controls.OfType<ComboBox>().Where(x => x.Name != cmb.Name && x.SelectedItem != null && x.SelectedItem.ToString() == cmb.SelectedItem.ToString()).ToList().ForEach(x => x.SelectedIndex = 0);
}
private void btnSalvar_Click(object sender, EventArgs e)
{
if (Disp == null)
{
return;
}
AtuadorModel.Pinout.ForEach(x =>
{
x.ComponenteID = "";
x.Funcao = FuncoesPinout.NaoConectado;
});
List<ComboBox> cmbs = this.Controls.OfType<ComboBox>().Where(x => x.Enabled).ToList();
foreach (var cmb in cmbs)
{
int pino = int.Parse(cmb.Name.Replace("cmbGPIO", ""));
string ComponenteID = cmb.SelectedItem.ToString().Split(' ').Length > 1 ? cmb.SelectedItem.ToString().Split(' ')[0] : "";
FuncoesPinout Funcao = (FuncoesPinout)Enum.Parse(typeof(FuncoesPinout), ComponenteID != "" ? (cmb.SelectedItem.ToString().Split(' ')[1]) : cmb.SelectedItem.ToString());
AtuadorModel.Pinout.FirstOrDefault(x => x.Pino == pino).Funcao = Funcao;
AtuadorModel.Pinout.FirstOrDefault(x => x.Pino == pino).ComponenteID = ComponenteID;
}
Disp.Dados.SalvarPinout(AtuadorModel.Pinout, "pinout" + Enum.GetName(typeof(T_Code), Disp.Dispositivo) + ".pin");
}
}
}

View File

@ -0,0 +1,991 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="imgESP32.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
/9j/4AAQSkZJRgABAQEAeAB4AAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcI
CQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwM
DAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAI+AQ4DASIAAhEBAxEB/8QA
HwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIh
MUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVW
V1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXG
x8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQF
BgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAV
YnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOE
hYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq
8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD9/KKKKACiiigAooooAKbJIsKFmZVVeSScAU6vDf8AgpbqE+k/
sE/Fa5tZpLe4g0Cd45I2KshGOQRyKAPZl8Q6e3S+sz24mX/Gl/t+x/5/bT/v8v8AjX8hEPxi8X317FH/
AMJNr26Yqo/0+Xqfxrul0D4hPDu/4TDUg393+0Jjj9aAP6vf7fsf+f20/wC/y/40f2/Y/wDP7af9/l/x
r+UD+wPiL/0OGpf+B03+NMn0f4iW8MkjeMNSIjRnwL+YZwM9zQB/WF/b9j/z+2n/AH+X/Gj+37H/AJ/b
T/v8v+NfyBD4zeLhkHxPr2VOD/p8n+NA+M3i4kD/AISfXeSBzfycfrQB/X7/AG/Y/wDP7af9/l/xo/t+
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
GygD/9k=
</value>
</data>
</root>

View File

@ -1,4 +1,5 @@
using AgroBase.Comum;
using AgroBase.Models;
using AgroBase.Models.Modules;
using System;
using System.Collections.Generic;
@ -15,7 +16,7 @@ namespace AgroBase.Forms.Direcional
{
public partial class frmDirConfig : Form
{
DispositivosService Disp = frmPrincipal.Dispositivos.FirstOrDefault(x => x.Dispositivo == T_Code.Dir);
DispositivosService<DirecionalModel> Disp = (DispositivosService<DirecionalModel>)Variaveis.DispositivosConectados.FirstOrDefault(x => x.Dispositivo == T_Code.Dir);
public frmDirConfig()
{

View File

@ -1,4 +1,5 @@
using AgroBase.Models.Modules;
using AgroBase.Models;
using AgroBase.Models.Modules;
using System;
using System.Collections.Generic;
using System.ComponentModel;
@ -35,7 +36,7 @@ namespace AgroBase.Forms.Direcional
private void DesenharGraficos(object sender, PaintEventArgs e)
{
PictureBox pic = (PictureBox)sender;
var Motor = ((DirecionalModel)frmPrincipal.Dispositivos.FirstOrDefault(d => d.Dispositivo == T_Code.Dir).Dados).Motores.FirstOrDefault(m => m.ID == pic.Name.Replace("pic", ""));
var Motor = ((DirecionalModel)Variaveis.DispositivosConectados.FirstOrDefault(d => d.Dispositivo == T_Code.Dir).Dados).Motores.FirstOrDefault(m => m.ID == pic.Name.Replace("pic", ""));
Label lbl = Controls.OfType<Label>().FirstOrDefault(ctrl => ctrl.Name == pic.Name.Replace("pic", "lbl"));
lbl.Text = "SP: " + ((Motor.Sentido_SP == Sentido.Antihorario ? -1 : 1) * Motor.Angulo_SP).ToString("00") + "º - Angulo: " + Motor.Angulo.ToString("00") + "º - Sentido: " + Enum.GetName(typeof(Sentido), Motor.Sentido);
@ -188,7 +189,7 @@ namespace AgroBase.Forms.Direcional
private void btnReferenciar_Click(object sender, EventArgs e)
{
string ID = ((Button)sender).Name.Substring(3, 2);
var DispCon = frmPrincipal.Dispositivos.Where(x => x._Porta.IsOpen && x.Dispositivo == T_Code.Dir).ToList();
var DispCon = Variaveis.DispositivosConectados.Where(x => x._Porta.IsOpen && x.Dispositivo == T_Code.Dir).ToList();
foreach (var Dispositivo in DispCon)
{
var Motor = ((DirecionalModel)Dispositivo.Dados).Motores.FirstOrDefault(x => x.ID == ID);

View File

@ -115,12 +115,33 @@ namespace AgroBase.Forms.Movimentacao
this.cmb3v3_2 = new System.Windows.Forms.ComboBox();
this.cmb3v3_1 = new System.Windows.Forms.ComboBox();
this.imgESP32 = new System.Windows.Forms.PictureBox();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.btnSalvarPID = new System.Windows.Forms.Button();
this.lblPPR = new System.Windows.Forms.Label();
this.lblKp = new System.Windows.Forms.Label();
this.nudPPR = new System.Windows.Forms.NumericUpDown();
this.lblRampaMax = new System.Windows.Forms.Label();
this.txtKp = new System.Windows.Forms.TextBox();
this.lblRampaMin = new System.Windows.Forms.Label();
this.lblKi = new System.Windows.Forms.Label();
this.nudRampaMax = new System.Windows.Forms.NumericUpDown();
this.txtKi = new System.Windows.Forms.TextBox();
this.nudRampaMin = new System.Windows.Forms.NumericUpDown();
this.lblKd = new System.Windows.Forms.Label();
this.txtKd = new System.Windows.Forms.TextBox();
this.chbMalhaFechada = new System.Windows.Forms.CheckBox();
this.gpbPID = new System.Windows.Forms.GroupBox();
this.gpbSentido.SuspendLayout();
this.gpbDF.SuspendLayout();
this.gpbEF.SuspendLayout();
this.gpbDT.SuspendLayout();
this.gpbET.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.imgESP32)).BeginInit();
this.groupBox1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.nudPPR)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.nudRampaMax)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.nudRampaMin)).BeginInit();
this.gpbPID.SuspendLayout();
this.SuspendLayout();
//
// gpbSentido
@ -878,12 +899,207 @@ namespace AgroBase.Forms.Movimentacao
this.imgESP32.TabIndex = 88;
this.imgESP32.TabStop = false;
//
// groupBox1
//
this.groupBox1.Controls.Add(this.chbMalhaFechada);
this.groupBox1.Controls.Add(this.gpbPID);
this.groupBox1.Controls.Add(this.btnSalvarPID);
this.groupBox1.Controls.Add(this.lblPPR);
this.groupBox1.Controls.Add(this.nudPPR);
this.groupBox1.Controls.Add(this.lblRampaMax);
this.groupBox1.Controls.Add(this.lblRampaMin);
this.groupBox1.Controls.Add(this.nudRampaMax);
this.groupBox1.Controls.Add(this.nudRampaMin);
this.groupBox1.Location = new System.Drawing.Point(766, 443);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(505, 177);
this.groupBox1.TabIndex = 135;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Ajustes";
//
// btnSalvarPID
//
this.btnSalvarPID.Location = new System.Drawing.Point(369, 115);
this.btnSalvarPID.Name = "btnSalvarPID";
this.btnSalvarPID.Size = new System.Drawing.Size(130, 33);
this.btnSalvarPID.TabIndex = 28;
this.btnSalvarPID.Text = "Salvar";
this.btnSalvarPID.UseVisualStyleBackColor = true;
this.btnSalvarPID.Click += new System.EventHandler(this.btnSalvarPID_Click);
//
// lblPPR
//
this.lblPPR.AutoSize = true;
this.lblPPR.Location = new System.Drawing.Point(244, 28);
this.lblPPR.Name = "lblPPR";
this.lblPPR.Size = new System.Drawing.Size(40, 17);
this.lblPPR.TabIndex = 36;
this.lblPPR.Text = "PPR:";
//
// lblKp
//
this.lblKp.AutoSize = true;
this.lblKp.Location = new System.Drawing.Point(18, 36);
this.lblKp.Name = "lblKp";
this.lblKp.Size = new System.Drawing.Size(25, 17);
this.lblKp.TabIndex = 22;
this.lblKp.Text = "Kp";
//
// nudPPR
//
this.nudPPR.Location = new System.Drawing.Point(247, 48);
this.nudPPR.Maximum = new decimal(new int[] {
999,
0,
0,
0});
this.nudPPR.Minimum = new decimal(new int[] {
1,
0,
0,
0});
this.nudPPR.Name = "nudPPR";
this.nudPPR.Size = new System.Drawing.Size(76, 22);
this.nudPPR.TabIndex = 35;
this.nudPPR.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
this.nudPPR.Value = new decimal(new int[] {
40,
0,
0,
0});
this.nudPPR.ValueChanged += new System.EventHandler(this.nudPPR_ValueChanged);
//
// lblRampaMax
//
this.lblRampaMax.AutoSize = true;
this.lblRampaMax.Location = new System.Drawing.Point(124, 28);
this.lblRampaMax.Name = "lblRampaMax";
this.lblRampaMax.Size = new System.Drawing.Size(86, 17);
this.lblRampaMax.TabIndex = 34;
this.lblRampaMax.Text = "Rampa Max:";
//
// txtKp
//
this.txtKp.Location = new System.Drawing.Point(49, 33);
this.txtKp.Name = "txtKp";
this.txtKp.Size = new System.Drawing.Size(60, 22);
this.txtKp.TabIndex = 23;
this.txtKp.Text = "0,2";
this.txtKp.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// lblRampaMin
//
this.lblRampaMin.AutoSize = true;
this.lblRampaMin.Location = new System.Drawing.Point(15, 28);
this.lblRampaMin.Name = "lblRampaMin";
this.lblRampaMin.Size = new System.Drawing.Size(83, 17);
this.lblRampaMin.TabIndex = 33;
this.lblRampaMin.Text = "Rampa Min:";
//
// lblKi
//
this.lblKi.AutoSize = true;
this.lblKi.Location = new System.Drawing.Point(135, 36);
this.lblKi.Name = "lblKi";
this.lblKi.Size = new System.Drawing.Size(20, 17);
this.lblKi.TabIndex = 24;
this.lblKi.Text = "Ki";
//
// nudRampaMax
//
this.nudRampaMax.Location = new System.Drawing.Point(127, 48);
this.nudRampaMax.Maximum = new decimal(new int[] {
9999,
0,
0,
0});
this.nudRampaMax.Name = "nudRampaMax";
this.nudRampaMax.Size = new System.Drawing.Size(76, 22);
this.nudRampaMax.TabIndex = 32;
this.nudRampaMax.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
this.nudRampaMax.Value = new decimal(new int[] {
1023,
0,
0,
0});
this.nudRampaMax.ValueChanged += new System.EventHandler(this.nudRampaMax_ValueChanged);
//
// txtKi
//
this.txtKi.Location = new System.Drawing.Point(161, 33);
this.txtKi.Name = "txtKi";
this.txtKi.Size = new System.Drawing.Size(60, 22);
this.txtKi.TabIndex = 25;
this.txtKi.Text = "0,2";
this.txtKi.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// nudRampaMin
//
this.nudRampaMin.Location = new System.Drawing.Point(18, 48);
this.nudRampaMin.Maximum = new decimal(new int[] {
9999,
0,
0,
0});
this.nudRampaMin.Name = "nudRampaMin";
this.nudRampaMin.Size = new System.Drawing.Size(76, 22);
this.nudRampaMin.TabIndex = 31;
this.nudRampaMin.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
this.nudRampaMin.ValueChanged += new System.EventHandler(this.nudRampaMin_ValueChanged);
//
// lblKd
//
this.lblKd.AutoSize = true;
this.lblKd.Location = new System.Drawing.Point(245, 36);
this.lblKd.Name = "lblKd";
this.lblKd.Size = new System.Drawing.Size(25, 17);
this.lblKd.TabIndex = 26;
this.lblKd.Text = "Kd";
//
// txtKd
//
this.txtKd.Location = new System.Drawing.Point(276, 33);
this.txtKd.Name = "txtKd";
this.txtKd.Size = new System.Drawing.Size(60, 22);
this.txtKd.TabIndex = 27;
this.txtKd.Text = "0,005";
this.txtKd.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// chbMalhaFechada
//
this.chbMalhaFechada.AutoSize = true;
this.chbMalhaFechada.Checked = true;
this.chbMalhaFechada.CheckState = System.Windows.Forms.CheckState.Checked;
this.chbMalhaFechada.Location = new System.Drawing.Point(349, 49);
this.chbMalhaFechada.Name = "chbMalhaFechada";
this.chbMalhaFechada.Size = new System.Drawing.Size(127, 21);
this.chbMalhaFechada.TabIndex = 30;
this.chbMalhaFechada.Text = "Malha Fechada";
this.chbMalhaFechada.UseVisualStyleBackColor = true;
this.chbMalhaFechada.CheckedChanged += new System.EventHandler(this.chbMalhaFechada_CheckedChanged);
//
// gpbPID
//
this.gpbPID.Controls.Add(this.lblKp);
this.gpbPID.Controls.Add(this.txtKp);
this.gpbPID.Controls.Add(this.lblKi);
this.gpbPID.Controls.Add(this.txtKi);
this.gpbPID.Controls.Add(this.lblKd);
this.gpbPID.Controls.Add(this.txtKd);
this.gpbPID.Location = new System.Drawing.Point(6, 87);
this.gpbPID.Name = "gpbPID";
this.gpbPID.Size = new System.Drawing.Size(357, 75);
this.gpbPID.TabIndex = 37;
this.gpbPID.TabStop = false;
this.gpbPID.Text = "PID";
//
// frmMovConfig
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.White;
this.ClientSize = new System.Drawing.Size(1285, 838);
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.lblPinout);
this.Controls.Add(this.cmbGND1);
this.Controls.Add(this.cmb5V);
@ -948,6 +1164,13 @@ namespace AgroBase.Forms.Movimentacao
this.gpbET.ResumeLayout(false);
this.gpbET.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.imgESP32)).EndInit();
this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.nudPPR)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.nudRampaMax)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.nudRampaMin)).EndInit();
this.gpbPID.ResumeLayout(false);
this.gpbPID.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
@ -1039,5 +1262,21 @@ namespace AgroBase.Forms.Movimentacao
private System.Windows.Forms.ComboBox cmb3v3_2;
private System.Windows.Forms.ComboBox cmb3v3_1;
private System.Windows.Forms.PictureBox imgESP32;
private System.Windows.Forms.GroupBox groupBox1;
public System.Windows.Forms.CheckBox chbMalhaFechada;
private System.Windows.Forms.GroupBox gpbPID;
private System.Windows.Forms.Label lblKp;
private System.Windows.Forms.TextBox txtKp;
private System.Windows.Forms.Label lblKi;
private System.Windows.Forms.TextBox txtKi;
private System.Windows.Forms.Label lblKd;
private System.Windows.Forms.TextBox txtKd;
private System.Windows.Forms.Button btnSalvarPID;
private System.Windows.Forms.Label lblPPR;
private System.Windows.Forms.NumericUpDown nudPPR;
private System.Windows.Forms.Label lblRampaMax;
private System.Windows.Forms.Label lblRampaMin;
private System.Windows.Forms.NumericUpDown nudRampaMax;
private System.Windows.Forms.NumericUpDown nudRampaMin;
}
}

View File

@ -12,7 +12,7 @@ namespace AgroBase.Forms.Movimentacao
{
public partial class frmMovConfig : Form
{
DispositivosService Disp = frmPrincipal.Dispositivos.FirstOrDefault(x => x.Dispositivo == T_Code.Mov);
DispositivosService<MovimentacaoModel> Disp = (DispositivosService<MovimentacaoModel>)Variaveis.DispositivosConectados.FirstOrDefault(x => x.Dispositivo == T_Code.Mov);
public frmMovConfig()
{
@ -21,6 +21,14 @@ namespace AgroBase.Forms.Movimentacao
private void frmMovConfig_Load(object sender, EventArgs e)
{
nudRampaMin.Value = MovimentacaoModel.RampaMin;
nudRampaMax.Value = MovimentacaoModel.RampaMax;
nudPPR.Value = MovimentacaoModel.PulsosPorRevolucao;
chbMalhaFechada.Checked = MovimentacaoModel._FOC;
txtKd.Text = MovimentacaoModel.Kd.ToString();
txtKp.Text = MovimentacaoModel.Kp.ToString();
txtKi.Text = MovimentacaoModel.Ki.ToString();
if (Disp == null)
{
return;
@ -153,5 +161,45 @@ namespace AgroBase.Forms.Movimentacao
e.Cancel = true;
this.Visible = false;
}
private void chbMalhaFechada_CheckedChanged(object sender, EventArgs e)
{
MovimentacaoModel._FOC = chbMalhaFechada.Checked;
txtKp.Enabled = MovimentacaoModel._FOC;
txtKi.Enabled = MovimentacaoModel._FOC;
txtKd.Enabled = MovimentacaoModel._FOC;
btnSalvarPID.Enabled = MovimentacaoModel._FOC;
}
private void btnSalvarPID_Click(object sender, EventArgs e)
{
if (double.TryParse(txtKp.Text, out double kp))
{
MovimentacaoModel.Kp = kp;
}
if (double.TryParse(txtKi.Text, out double ki))
{
MovimentacaoModel.Ki = ki;
}
if (double.TryParse(txtKd.Text, out double kd))
{
MovimentacaoModel.Kd = kd;
}
}
private void nudRampaMin_ValueChanged(object sender, EventArgs e)
{
MovimentacaoModel.RampaMin = Convert.ToInt32(nudRampaMin.Value);
}
private void nudRampaMax_ValueChanged(object sender, EventArgs e)
{
MovimentacaoModel.RampaMax = Convert.ToInt32(nudRampaMax.Value);
}
private void nudPPR_ValueChanged(object sender, EventArgs e)
{
MovimentacaoModel.PulsosPorRevolucao = Convert.ToInt32(nudPPR.Value);
}
}
}

View File

@ -17,7 +17,7 @@ namespace AgroBase.Forms
{
public static Timer tmrLeitura = new Timer() { Enabled = false, Interval = 500 };
public List<DataGridView> Tabelas = new List<DataGridView>();
public static DispositivosService DispMov;
public static DispositivosService<MovimentacaoModel> DispMov;
List<string> ListaPinosDiagnosticar = new List<string>()
{
"DIR",
@ -72,7 +72,7 @@ namespace AgroBase.Forms
private void btnIniciar_Click(object sender, EventArgs e)
{
DispMov = frmPrincipal.Dispositivos.FirstOrDefault(x => x._Porta.IsOpen && x.Dispositivo == T_Code.Mov);
DispMov = (DispositivosService<MovimentacaoModel>)Variaveis.DispositivosConectados.FirstOrDefault(x => x._Porta.IsOpen && x.Dispositivo == T_Code.Mov);
if (DispMov == null)
{
return;

View File

@ -16,7 +16,7 @@ namespace AgroBase.Forms
{
public partial class frmMovPlot : Form
{
private DispositivosService DispMov;
private DispositivosService<MovimentacaoModel> DispMov;
public frmMovPlot()
{
@ -31,7 +31,7 @@ namespace AgroBase.Forms
public void AtualizaGrafico()
{
DispMov = frmPrincipal.Dispositivos.FirstOrDefault(x => x._Porta.IsOpen && x.Dispositivo == T_Code.Mov);
DispMov = (DispositivosService<MovimentacaoModel>)Variaveis.DispositivosConectados.FirstOrDefault(x => x._Porta.IsOpen && x.Dispositivo == T_Code.Mov);
if (chartEF.InvokeRequired)
{
chartEF.Invoke(new Action(AtualizaGrafico));

View File

@ -0,0 +1,523 @@

namespace AgroBase.Forms.Operacoes
{
partial class frmOperacaoSeguidorLinha
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
System.Windows.Forms.DataVisualization.Charting.Legend legend1 = new System.Windows.Forms.DataVisualization.Charting.Legend();
System.Windows.Forms.DataVisualization.Charting.Series series1 = new System.Windows.Forms.DataVisualization.Charting.Series();
this.pnlCameraSolo = new System.Windows.Forms.Panel();
this.pnlCameraCaminho = new System.Windows.Forms.Panel();
this.pnlAtuadores = new System.Windows.Forms.Panel();
this.pnlMapa = new System.Windows.Forms.Panel();
this.pnlGraficos = new System.Windows.Forms.Panel();
this.chartGraficos = new System.Windows.Forms.DataVisualization.Charting.Chart();
this.pnlNiveis = new System.Windows.Forms.Panel();
this.lblPorcentagemProgresso = new System.Windows.Forms.Label();
this.pgbProgresso = new System.Windows.Forms.ProgressBar();
this.lblPorcentagemBateria = new System.Windows.Forms.Label();
this.pgbBateria = new System.Windows.Forms.ProgressBar();
this.lblPorcentagemReservatorio = new System.Windows.Forms.Label();
this.pgbReservatorio = new System.Windows.Forms.ProgressBar();
this.gpbOpcoes = new System.Windows.Forms.GroupBox();
this.btnIniciarOperacao = new System.Windows.Forms.Button();
this.btnCarregarMapa = new System.Windows.Forms.Button();
this.lblMapa = new System.Windows.Forms.Label();
this.cmbCameraCaminho = new System.Windows.Forms.ComboBox();
this.lblCameraCaminho = new System.Windows.Forms.Label();
this.cmbCameraSolo = new System.Windows.Forms.ComboBox();
this.lblCameraSolo = new System.Windows.Forms.Label();
this.lblMapaCarregado = new System.Windows.Forms.Label();
this.gpbInformacoesGerais = new System.Windows.Forms.GroupBox();
this.lblBateriaConsumida = new System.Windows.Forms.Label();
this.lblHerbicidaPorErva = new System.Windows.Forms.Label();
this.lblHerbicidaAplicado = new System.Windows.Forms.Label();
this.lblErvasIdentificadas = new System.Windows.Forms.Label();
this.lblVelocidadeMedia = new System.Windows.Forms.Label();
this.lblTempoOperacao = new System.Windows.Forms.Label();
this.lblDistanciaPercorrida = new System.Windows.Forms.Label();
this.pnlInclinacao = new System.Windows.Forms.Panel();
this.lblDistanciaEsquerda = new System.Windows.Forms.Label();
this.lblDistanciaDireita = new System.Windows.Forms.Label();
this.pnlInferior = new System.Windows.Forms.Panel();
this.lblUltimaLeituraRua = new System.Windows.Forms.Label();
this.lblUltimaLeituraSolo = new System.Windows.Forms.Label();
this.btnDesenharMapa = new System.Windows.Forms.Button();
this.pnlGraficos.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.chartGraficos)).BeginInit();
this.pnlNiveis.SuspendLayout();
this.gpbOpcoes.SuspendLayout();
this.gpbInformacoesGerais.SuspendLayout();
this.pnlInferior.SuspendLayout();
this.SuspendLayout();
//
// pnlCameraSolo
//
this.pnlCameraSolo.BackColor = System.Drawing.SystemColors.ControlDark;
this.pnlCameraSolo.Location = new System.Drawing.Point(12, 40);
this.pnlCameraSolo.Name = "pnlCameraSolo";
this.pnlCameraSolo.Size = new System.Drawing.Size(790, 558);
this.pnlCameraSolo.TabIndex = 0;
//
// pnlCameraCaminho
//
this.pnlCameraCaminho.BackColor = System.Drawing.SystemColors.ControlDarkDark;
this.pnlCameraCaminho.Location = new System.Drawing.Point(481, 12);
this.pnlCameraCaminho.Name = "pnlCameraCaminho";
this.pnlCameraCaminho.Size = new System.Drawing.Size(349, 250);
this.pnlCameraCaminho.TabIndex = 1;
//
// pnlAtuadores
//
this.pnlAtuadores.BackColor = System.Drawing.SystemColors.Control;
this.pnlAtuadores.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
this.pnlAtuadores.Location = new System.Drawing.Point(12, 604);
this.pnlAtuadores.Name = "pnlAtuadores";
this.pnlAtuadores.Size = new System.Drawing.Size(790, 86);
this.pnlAtuadores.TabIndex = 2;
this.pnlAtuadores.Paint += new System.Windows.Forms.PaintEventHandler(this.pnlAtuadores_Paint);
//
// pnlMapa
//
this.pnlMapa.BackColor = System.Drawing.Color.White;
this.pnlMapa.Location = new System.Drawing.Point(836, 12);
this.pnlMapa.Name = "pnlMapa";
this.pnlMapa.Size = new System.Drawing.Size(512, 343);
this.pnlMapa.TabIndex = 3;
this.pnlMapa.Paint += new System.Windows.Forms.PaintEventHandler(this.pnlMapa_Paint);
//
// pnlGraficos
//
this.pnlGraficos.Controls.Add(this.chartGraficos);
this.pnlGraficos.Location = new System.Drawing.Point(808, 378);
this.pnlGraficos.Name = "pnlGraficos";
this.pnlGraficos.Size = new System.Drawing.Size(540, 312);
this.pnlGraficos.TabIndex = 4;
//
// chartGraficos
//
chartArea1.Name = "ChartArea1";
this.chartGraficos.ChartAreas.Add(chartArea1);
this.chartGraficos.Dock = System.Windows.Forms.DockStyle.Fill;
legend1.Name = "Legend1";
this.chartGraficos.Legends.Add(legend1);
this.chartGraficos.Location = new System.Drawing.Point(0, 0);
this.chartGraficos.Name = "chartGraficos";
series1.ChartArea = "ChartArea1";
series1.Legend = "Legend1";
series1.Name = "Series1";
this.chartGraficos.Series.Add(series1);
this.chartGraficos.Size = new System.Drawing.Size(540, 312);
this.chartGraficos.TabIndex = 0;
this.chartGraficos.Text = "chart1";
//
// pnlNiveis
//
this.pnlNiveis.BackColor = System.Drawing.SystemColors.Control;
this.pnlNiveis.Controls.Add(this.lblPorcentagemProgresso);
this.pnlNiveis.Controls.Add(this.pgbProgresso);
this.pnlNiveis.Controls.Add(this.lblPorcentagemBateria);
this.pnlNiveis.Controls.Add(this.pgbBateria);
this.pnlNiveis.Controls.Add(this.lblPorcentagemReservatorio);
this.pnlNiveis.Controls.Add(this.pgbReservatorio);
this.pnlNiveis.Font = new System.Drawing.Font("Mongolian Baiti", 9F, System.Drawing.FontStyle.Bold);
this.pnlNiveis.Location = new System.Drawing.Point(12, 702);
this.pnlNiveis.Name = "pnlNiveis";
this.pnlNiveis.Size = new System.Drawing.Size(790, 85);
this.pnlNiveis.TabIndex = 6;
//
// lblPorcentagemProgresso
//
this.lblPorcentagemProgresso.AutoSize = true;
this.lblPorcentagemProgresso.Location = new System.Drawing.Point(522, 13);
this.lblPorcentagemProgresso.Name = "lblPorcentagemProgresso";
this.lblPorcentagemProgresso.Size = new System.Drawing.Size(134, 16);
this.lblPorcentagemProgresso.TabIndex = 5;
this.lblPorcentagemProgresso.Text = "Progresso: 0,00%";
//
// pgbProgresso
//
this.pgbProgresso.Location = new System.Drawing.Point(525, 33);
this.pgbProgresso.Name = "pgbProgresso";
this.pgbProgresso.Size = new System.Drawing.Size(255, 49);
this.pgbProgresso.TabIndex = 4;
//
// lblPorcentagemBateria
//
this.lblPorcentagemBateria.AutoSize = true;
this.lblPorcentagemBateria.Location = new System.Drawing.Point(264, 13);
this.lblPorcentagemBateria.Name = "lblPorcentagemBateria";
this.lblPorcentagemBateria.Size = new System.Drawing.Size(115, 16);
this.lblPorcentagemBateria.TabIndex = 3;
this.lblPorcentagemBateria.Text = "Bateria: 0,00%";
//
// pgbBateria
//
this.pgbBateria.Location = new System.Drawing.Point(264, 33);
this.pgbBateria.Name = "pgbBateria";
this.pgbBateria.Size = new System.Drawing.Size(255, 49);
this.pgbBateria.TabIndex = 2;
//
// lblPorcentagemReservatorio
//
this.lblPorcentagemReservatorio.AutoSize = true;
this.lblPorcentagemReservatorio.Location = new System.Drawing.Point(3, 13);
this.lblPorcentagemReservatorio.Name = "lblPorcentagemReservatorio";
this.lblPorcentagemReservatorio.Size = new System.Drawing.Size(155, 16);
this.lblPorcentagemReservatorio.TabIndex = 1;
this.lblPorcentagemReservatorio.Text = "Reservatório: 0,00%";
//
// pgbReservatorio
//
this.pgbReservatorio.Location = new System.Drawing.Point(3, 33);
this.pgbReservatorio.Name = "pgbReservatorio";
this.pgbReservatorio.Size = new System.Drawing.Size(255, 49);
this.pgbReservatorio.TabIndex = 0;
//
// gpbOpcoes
//
this.gpbOpcoes.Controls.Add(this.btnIniciarOperacao);
this.gpbOpcoes.Controls.Add(this.btnCarregarMapa);
this.gpbOpcoes.Controls.Add(this.lblMapa);
this.gpbOpcoes.Controls.Add(this.cmbCameraCaminho);
this.gpbOpcoes.Controls.Add(this.lblCameraCaminho);
this.gpbOpcoes.Controls.Add(this.cmbCameraSolo);
this.gpbOpcoes.Controls.Add(this.lblCameraSolo);
this.gpbOpcoes.Font = new System.Drawing.Font("Mongolian Baiti", 9F, System.Drawing.FontStyle.Bold);
this.gpbOpcoes.Location = new System.Drawing.Point(1084, 696);
this.gpbOpcoes.Name = "gpbOpcoes";
this.gpbOpcoes.Size = new System.Drawing.Size(264, 147);
this.gpbOpcoes.TabIndex = 7;
this.gpbOpcoes.TabStop = false;
this.gpbOpcoes.Text = "Opções";
//
// btnIniciarOperacao
//
this.btnIniciarOperacao.Location = new System.Drawing.Point(9, 115);
this.btnIniciarOperacao.Name = "btnIniciarOperacao";
this.btnIniciarOperacao.Size = new System.Drawing.Size(249, 26);
this.btnIniciarOperacao.TabIndex = 6;
this.btnIniciarOperacao.Text = "Iniciar Operação";
this.btnIniciarOperacao.UseVisualStyleBackColor = true;
this.btnIniciarOperacao.Click += new System.EventHandler(this.btnIniciarOperacao_Click);
//
// btnCarregarMapa
//
this.btnCarregarMapa.Location = new System.Drawing.Point(111, 81);
this.btnCarregarMapa.Name = "btnCarregarMapa";
this.btnCarregarMapa.Size = new System.Drawing.Size(147, 26);
this.btnCarregarMapa.TabIndex = 5;
this.btnCarregarMapa.Text = "Carregar...";
this.btnCarregarMapa.UseVisualStyleBackColor = true;
this.btnCarregarMapa.Click += new System.EventHandler(this.btnCarregarMapa_Click);
//
// lblMapa
//
this.lblMapa.AutoSize = true;
this.lblMapa.Location = new System.Drawing.Point(6, 86);
this.lblMapa.Name = "lblMapa";
this.lblMapa.Size = new System.Drawing.Size(47, 16);
this.lblMapa.TabIndex = 4;
this.lblMapa.Text = "Mapa";
//
// cmbCameraCaminho
//
this.cmbCameraCaminho.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cmbCameraCaminho.FormattingEnabled = true;
this.cmbCameraCaminho.Location = new System.Drawing.Point(111, 51);
this.cmbCameraCaminho.Name = "cmbCameraCaminho";
this.cmbCameraCaminho.Size = new System.Drawing.Size(147, 24);
this.cmbCameraCaminho.TabIndex = 3;
this.cmbCameraCaminho.SelectedIndexChanged += new System.EventHandler(this.cmbCameraCaminho_SelectedIndexChanged);
//
// lblCameraCaminho
//
this.lblCameraCaminho.AutoSize = true;
this.lblCameraCaminho.Location = new System.Drawing.Point(6, 54);
this.lblCameraCaminho.Name = "lblCameraCaminho";
this.lblCameraCaminho.Size = new System.Drawing.Size(95, 16);
this.lblCameraCaminho.TabIndex = 2;
this.lblCameraCaminho.Text = "Camera Rua";
//
// cmbCameraSolo
//
this.cmbCameraSolo.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cmbCameraSolo.FormattingEnabled = true;
this.cmbCameraSolo.Location = new System.Drawing.Point(111, 21);
this.cmbCameraSolo.Name = "cmbCameraSolo";
this.cmbCameraSolo.Size = new System.Drawing.Size(147, 24);
this.cmbCameraSolo.TabIndex = 1;
this.cmbCameraSolo.SelectedIndexChanged += new System.EventHandler(this.cmbCameraSolo_SelectedIndexChanged);
//
// lblCameraSolo
//
this.lblCameraSolo.AutoSize = true;
this.lblCameraSolo.Location = new System.Drawing.Point(6, 24);
this.lblCameraSolo.Name = "lblCameraSolo";
this.lblCameraSolo.Size = new System.Drawing.Size(99, 16);
this.lblCameraSolo.TabIndex = 0;
this.lblCameraSolo.Text = "Camera Solo";
//
// lblMapaCarregado
//
this.lblMapaCarregado.AutoSize = true;
this.lblMapaCarregado.Font = new System.Drawing.Font("Mongolian Baiti", 9F, System.Drawing.FontStyle.Bold);
this.lblMapaCarregado.Location = new System.Drawing.Point(918, 358);
this.lblMapaCarregado.Name = "lblMapaCarregado";
this.lblMapaCarregado.Size = new System.Drawing.Size(162, 16);
this.lblMapaCarregado.TabIndex = 8;
this.lblMapaCarregado.Text = "Mapa carregado: N/A";
//
// gpbInformacoesGerais
//
this.gpbInformacoesGerais.Controls.Add(this.lblBateriaConsumida);
this.gpbInformacoesGerais.Controls.Add(this.lblHerbicidaPorErva);
this.gpbInformacoesGerais.Controls.Add(this.lblHerbicidaAplicado);
this.gpbInformacoesGerais.Controls.Add(this.lblErvasIdentificadas);
this.gpbInformacoesGerais.Controls.Add(this.lblVelocidadeMedia);
this.gpbInformacoesGerais.Controls.Add(this.lblTempoOperacao);
this.gpbInformacoesGerais.Controls.Add(this.lblDistanciaPercorrida);
this.gpbInformacoesGerais.Font = new System.Drawing.Font("Mongolian Baiti", 9F, System.Drawing.FontStyle.Bold);
this.gpbInformacoesGerais.Location = new System.Drawing.Point(808, 696);
this.gpbInformacoesGerais.Name = "gpbInformacoesGerais";
this.gpbInformacoesGerais.Size = new System.Drawing.Size(270, 147);
this.gpbInformacoesGerais.TabIndex = 9;
this.gpbInformacoesGerais.TabStop = false;
this.gpbInformacoesGerais.Text = "Informações Gerais";
//
// lblBateriaConsumida
//
this.lblBateriaConsumida.AutoSize = true;
this.lblBateriaConsumida.Location = new System.Drawing.Point(11, 123);
this.lblBateriaConsumida.Name = "lblBateriaConsumida";
this.lblBateriaConsumida.Size = new System.Drawing.Size(200, 16);
this.lblBateriaConsumida.TabIndex = 6;
this.lblBateriaConsumida.Text = "Bateria Consumida: 0,00%";
//
// lblHerbicidaPorErva
//
this.lblHerbicidaPorErva.AutoSize = true;
this.lblHerbicidaPorErva.Location = new System.Drawing.Point(11, 107);
this.lblHerbicidaPorErva.Name = "lblHerbicidaPorErva";
this.lblHerbicidaPorErva.Size = new System.Drawing.Size(224, 16);
this.lblHerbicidaPorErva.TabIndex = 5;
this.lblHerbicidaPorErva.Text = "Herbicida por Erva: 0,000 mL";
//
// lblHerbicidaAplicado
//
this.lblHerbicidaAplicado.AutoSize = true;
this.lblHerbicidaAplicado.Location = new System.Drawing.Point(11, 91);
this.lblHerbicidaAplicado.Name = "lblHerbicidaAplicado";
this.lblHerbicidaAplicado.Size = new System.Drawing.Size(205, 16);
this.lblHerbicidaAplicado.TabIndex = 4;
this.lblHerbicidaAplicado.Text = "Herbicida Aplicado: 0,00 L";
//
// lblErvasIdentificadas
//
this.lblErvasIdentificadas.AutoSize = true;
this.lblErvasIdentificadas.Location = new System.Drawing.Point(11, 75);
this.lblErvasIdentificadas.Name = "lblErvasIdentificadas";
this.lblErvasIdentificadas.Size = new System.Drawing.Size(183, 16);
this.lblErvasIdentificadas.TabIndex = 3;
this.lblErvasIdentificadas.Text = "Ervas Identificadas: 000";
//
// lblVelocidadeMedia
//
this.lblVelocidadeMedia.AutoSize = true;
this.lblVelocidadeMedia.Location = new System.Drawing.Point(11, 59);
this.lblVelocidadeMedia.Name = "lblVelocidadeMedia";
this.lblVelocidadeMedia.Size = new System.Drawing.Size(221, 16);
this.lblVelocidadeMedia.TabIndex = 2;
this.lblVelocidadeMedia.Text = "Velocidade Média: 0,00 km/h";
//
// lblTempoOperacao
//
this.lblTempoOperacao.AutoSize = true;
this.lblTempoOperacao.Location = new System.Drawing.Point(11, 43);
this.lblTempoOperacao.Name = "lblTempoOperacao";
this.lblTempoOperacao.Size = new System.Drawing.Size(226, 16);
this.lblTempoOperacao.TabIndex = 1;
this.lblTempoOperacao.Text = "Tempo de Operação: 00:00:00";
//
// lblDistanciaPercorrida
//
this.lblDistanciaPercorrida.AutoSize = true;
this.lblDistanciaPercorrida.Location = new System.Drawing.Point(11, 27);
this.lblDistanciaPercorrida.Name = "lblDistanciaPercorrida";
this.lblDistanciaPercorrida.Size = new System.Drawing.Size(214, 16);
this.lblDistanciaPercorrida.TabIndex = 0;
this.lblDistanciaPercorrida.Text = "Distancia Percorrida: 0,00 m";
//
// pnlInclinacao
//
this.pnlInclinacao.BackColor = System.Drawing.Color.White;
this.pnlInclinacao.Location = new System.Drawing.Point(808, 268);
this.pnlInclinacao.Name = "pnlInclinacao";
this.pnlInclinacao.Size = new System.Drawing.Size(104, 104);
this.pnlInclinacao.TabIndex = 10;
this.pnlInclinacao.Paint += new System.Windows.Forms.PaintEventHandler(this.pnlInclinacao_Paint);
//
// lblDistanciaEsquerda
//
this.lblDistanciaEsquerda.AutoSize = true;
this.lblDistanciaEsquerda.Font = new System.Drawing.Font("Mongolian Baiti", 9F, System.Drawing.FontStyle.Bold);
this.lblDistanciaEsquerda.Location = new System.Drawing.Point(12, 20);
this.lblDistanciaEsquerda.Name = "lblDistanciaEsquerda";
this.lblDistanciaEsquerda.Size = new System.Drawing.Size(228, 16);
this.lblDistanciaEsquerda.TabIndex = 11;
this.lblDistanciaEsquerda.Text = "Distancia da Esquerda: 000 px";
//
// lblDistanciaDireita
//
this.lblDistanciaDireita.AutoSize = true;
this.lblDistanciaDireita.Font = new System.Drawing.Font("Mongolian Baiti", 9F, System.Drawing.FontStyle.Bold);
this.lblDistanciaDireita.Location = new System.Drawing.Point(253, 20);
this.lblDistanciaDireita.Name = "lblDistanciaDireita";
this.lblDistanciaDireita.Size = new System.Drawing.Size(211, 16);
this.lblDistanciaDireita.TabIndex = 12;
this.lblDistanciaDireita.Text = "Distancia da Direita: 000 px";
//
// pnlInferior
//
this.pnlInferior.Controls.Add(this.lblUltimaLeituraRua);
this.pnlInferior.Controls.Add(this.lblUltimaLeituraSolo);
this.pnlInferior.Font = new System.Drawing.Font("Mongolian Baiti", 9F, System.Drawing.FontStyle.Bold);
this.pnlInferior.Location = new System.Drawing.Point(12, 793);
this.pnlInferior.Name = "pnlInferior";
this.pnlInferior.Size = new System.Drawing.Size(790, 50);
this.pnlInferior.TabIndex = 13;
//
// lblUltimaLeituraRua
//
this.lblUltimaLeituraRua.AutoSize = true;
this.lblUltimaLeituraRua.Location = new System.Drawing.Point(3, 5);
this.lblUltimaLeituraRua.Name = "lblUltimaLeituraRua";
this.lblUltimaLeituraRua.Size = new System.Drawing.Size(251, 16);
this.lblUltimaLeituraRua.TabIndex = 5;
this.lblUltimaLeituraRua.Text = "Ultima Leitura Rua: 00:00:00.000";
//
// lblUltimaLeituraSolo
//
this.lblUltimaLeituraSolo.AutoSize = true;
this.lblUltimaLeituraSolo.Location = new System.Drawing.Point(3, 30);
this.lblUltimaLeituraSolo.Name = "lblUltimaLeituraSolo";
this.lblUltimaLeituraSolo.Size = new System.Drawing.Size(255, 16);
this.lblUltimaLeituraSolo.TabIndex = 4;
this.lblUltimaLeituraSolo.Text = "Ultima Leitura Solo: 00:00:00.000";
//
// btnDesenharMapa
//
this.btnDesenharMapa.Location = new System.Drawing.Point(1241, 358);
this.btnDesenharMapa.Name = "btnDesenharMapa";
this.btnDesenharMapa.Size = new System.Drawing.Size(101, 23);
this.btnDesenharMapa.TabIndex = 14;
this.btnDesenharMapa.Text = "Desenhar";
this.btnDesenharMapa.UseVisualStyleBackColor = true;
this.btnDesenharMapa.Click += new System.EventHandler(this.btnDesenharMapa_Click);
//
// frmOperacaoSeguidorLinha
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(1360, 855);
this.Controls.Add(this.btnDesenharMapa);
this.Controls.Add(this.pnlInferior);
this.Controls.Add(this.lblDistanciaDireita);
this.Controls.Add(this.lblDistanciaEsquerda);
this.Controls.Add(this.pnlInclinacao);
this.Controls.Add(this.gpbInformacoesGerais);
this.Controls.Add(this.lblMapaCarregado);
this.Controls.Add(this.gpbOpcoes);
this.Controls.Add(this.pnlNiveis);
this.Controls.Add(this.pnlGraficos);
this.Controls.Add(this.pnlMapa);
this.Controls.Add(this.pnlAtuadores);
this.Controls.Add(this.pnlCameraCaminho);
this.Controls.Add(this.pnlCameraSolo);
this.Name = "frmOperacaoSeguidorLinha";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Operação Seguidor de Linha";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.frmOperacaoSeguidorLinha_FormClosing);
this.Load += new System.EventHandler(this.frmOperacaoSeguidorLinha_Load);
this.pnlGraficos.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.chartGraficos)).EndInit();
this.pnlNiveis.ResumeLayout(false);
this.pnlNiveis.PerformLayout();
this.gpbOpcoes.ResumeLayout(false);
this.gpbOpcoes.PerformLayout();
this.gpbInformacoesGerais.ResumeLayout(false);
this.gpbInformacoesGerais.PerformLayout();
this.pnlInferior.ResumeLayout(false);
this.pnlInferior.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Panel pnlCameraSolo;
private System.Windows.Forms.Panel pnlCameraCaminho;
private System.Windows.Forms.Panel pnlAtuadores;
private System.Windows.Forms.Panel pnlMapa;
private System.Windows.Forms.Panel pnlGraficos;
private System.Windows.Forms.DataVisualization.Charting.Chart chartGraficos;
private System.Windows.Forms.Panel pnlNiveis;
private System.Windows.Forms.Label lblPorcentagemBateria;
private System.Windows.Forms.ProgressBar pgbBateria;
private System.Windows.Forms.Label lblPorcentagemReservatorio;
private System.Windows.Forms.ProgressBar pgbReservatorio;
private System.Windows.Forms.GroupBox gpbOpcoes;
private System.Windows.Forms.Label lblPorcentagemProgresso;
private System.Windows.Forms.ProgressBar pgbProgresso;
private System.Windows.Forms.Button btnIniciarOperacao;
private System.Windows.Forms.Button btnCarregarMapa;
private System.Windows.Forms.Label lblMapa;
private System.Windows.Forms.ComboBox cmbCameraCaminho;
private System.Windows.Forms.Label lblCameraCaminho;
private System.Windows.Forms.ComboBox cmbCameraSolo;
private System.Windows.Forms.Label lblCameraSolo;
private System.Windows.Forms.Label lblMapaCarregado;
private System.Windows.Forms.GroupBox gpbInformacoesGerais;
private System.Windows.Forms.Label lblBateriaConsumida;
private System.Windows.Forms.Label lblHerbicidaPorErva;
private System.Windows.Forms.Label lblHerbicidaAplicado;
private System.Windows.Forms.Label lblErvasIdentificadas;
private System.Windows.Forms.Label lblVelocidadeMedia;
private System.Windows.Forms.Label lblTempoOperacao;
private System.Windows.Forms.Label lblDistanciaPercorrida;
private System.Windows.Forms.Panel pnlInclinacao;
private System.Windows.Forms.Label lblDistanciaEsquerda;
private System.Windows.Forms.Label lblDistanciaDireita;
private System.Windows.Forms.Panel pnlInferior;
private System.Windows.Forms.Label lblUltimaLeituraRua;
private System.Windows.Forms.Label lblUltimaLeituraSolo;
private System.Windows.Forms.Button btnDesenharMapa;
}
}

View File

@ -0,0 +1,645 @@
using AgroBase.Comum;
using AgroBase.Models;
using AgroBase.Models.Modules;
using AgroBase.Services;
using CefSharp.WinForms;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
namespace AgroBase.Forms.Operacoes
{
public partial class frmOperacaoSeguidorLinha : Form
{
private CameraService<CameraCoordenadasFrameModel> cameraSolo = new CameraService<CameraCoordenadasFrameModel>();
private ChromiumWebBrowser webSolo = null;
private string cameraSoloSelecionada = "";
private CameraService<CameraAnguloModel> cameraCaminho = new CameraService<CameraAnguloModel>();
private ChromiumWebBrowser webCaminho = null;
private string cameraCaminhoSelecionada = "";
private ChromiumWebBrowser webMapa = null;
private Timer tmrLeituras = new Timer() { Interval = 200 };
DispositivosService<MovimentacaoModel> Movimentacao;
DispositivosService<DirecionalModel> Direcional;
DispositivosService<AtuadorModel> Atuador;
private List<PointF> pathPoints = new List<PointF>();
private PointF currentPosition = new PointF(0, 0);
public frmOperacaoSeguidorLinha()
{
InitializeComponent();
}
private void frmOperacaoSeguidorLinha_Load(object sender, EventArgs e)
{
AtualizarDispositivos();
AtualizaListaCameras();
Variaveis.OperacaoEmAndamento = new OperacaoModel(Enuns.ModoOperacao.SeguidorDeLinha, Movimentacao, Direcional, Atuador);
}
private void frmOperacaoSeguidorLinha_FormClosing(object sender, FormClosingEventArgs e)
{
tmrLeituras.Stop();
DesligarCameraSolo();
DesligarCameraCaminho();
Variaveis.OperacaoEmAndamento.FinalizarOperacao();
}
private void AtualizarDispositivos()
{
Movimentacao = (DispositivosService<MovimentacaoModel>)Variaveis.DispositivosConectados.FirstOrDefault(x => x.Dispositivo == Enuns.T_Code.Mov);
Direcional = (DispositivosService<DirecionalModel>)Variaveis.DispositivosConectados.FirstOrDefault(x => x.Dispositivo == Enuns.T_Code.Dir);
Atuador = (DispositivosService<AtuadorModel>)Variaveis.DispositivosConectados.FirstOrDefault(x => x.Dispositivo == Enuns.T_Code.Atu);
AtualizarGrafico();
}
private void DesligarCameraSolo()
{
try
{
pnlCameraSolo.Controls.Remove(webSolo);
webSolo = null;
if (cameraSolo.socket != null)
{
cameraSolo.socket.Disconnect();
}
if (cameraSolo.pythonProcess != null)
{
cameraSolo.pythonProcess.Kill();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private void DesligarCameraCaminho()
{
try
{
pnlCameraCaminho.Controls.Remove(webCaminho);
webCaminho = null;
if (cameraCaminho.socket != null)
{
cameraCaminho.socket.Disconnect();
}
if (cameraCaminho.pythonProcess != null)
{
cameraCaminho.pythonProcess.Kill();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private void AtualizaListaCameras()
{
cameraSolo.selectedCamera = cmbCameraSolo.SelectedIndex > 0 ? cmbCameraSolo.SelectedIndex : 0;
cmbCameraSolo.Items.Clear();
cmbCameraSolo.Items.AddRange(cameraSolo.AtualizaListaCameras().ToArray());
if (cmbCameraSolo.Items.Count == 1)
{
cameraSolo.selectedCamera = 0;
}
cmbCameraSolo.SelectedIndex = cameraSolo.selectedCamera;
cameraCaminho.selectedCamera = cmbCameraCaminho.SelectedIndex > 0 ? cmbCameraCaminho.SelectedIndex : 0;
cmbCameraCaminho.Items.Clear();
cmbCameraCaminho.Items.AddRange(cameraCaminho.AtualizaListaCameras().ToArray());
if (cmbCameraCaminho.Items.Count == 1)
{
cameraCaminho.selectedCamera = 0;
}
cmbCameraCaminho.SelectedIndex = cameraCaminho.selectedCamera;
}
private void cmbCameraSolo_SelectedIndexChanged(object sender, EventArgs e)
{
if (cameraSoloSelecionada != "Sem vídeo" && cameraSoloSelecionada != "")
{
cmbCameraCaminho.Items.Add(cameraSoloSelecionada);
}
cameraSolo.selectedCamera = cmbCameraSolo.SelectedIndex;
if (cameraSolo.selectedCamera > 0)
{
DesligarCameraSolo();
IniciarCameraSolo();
}
else
{
DesligarCameraSolo();
}
cameraSoloSelecionada = cmbCameraSolo.Text;
//btnIniciarOperacao.Enabled = cmbCameraSolo.SelectedIndex > 0 && cmbCameraCaminho.SelectedIndex > 0;
if (cameraSoloSelecionada != "Sem vídeo" && cameraSoloSelecionada != "")
{
cmbCameraCaminho.Items.Remove(cameraSoloSelecionada);
}
}
private void cmbCameraCaminho_SelectedIndexChanged(object sender, EventArgs e)
{
if (cameraCaminhoSelecionada != "Sem vídeo" && cameraCaminhoSelecionada != "")
{
cmbCameraSolo.Items.Add(cameraCaminhoSelecionada);
}
cameraCaminho.selectedCamera = cmbCameraCaminho.SelectedIndex;
if (cameraCaminho.selectedCamera > 0)
{
DesligarCameraCaminho();
IniciarCameraCaminho();
}
else
{
DesligarCameraCaminho();
}
cameraCaminhoSelecionada = cmbCameraCaminho.Text;
//btnIniciarOperacao.Enabled = cmbCameraSolo.SelectedIndex > 0 && cmbCameraCaminho.SelectedIndex > 0;
if (cameraCaminhoSelecionada != "Sem vídeo" && cameraCaminhoSelecionada != "" )
{
cmbCameraSolo.Items.Remove(cameraCaminhoSelecionada);
}
}
private void IniciarCameraSolo()
{
string ArquivoLeitura = "verdes.json";
int MaxLeituras = 10;
string VideoPorta = "8080";
string VideoUrl = "green_objects";
string SocketPorta = "6535";
cameraSolo.ArquivoLeitura = ArquivoLeitura;
cameraSolo.IniciarCamera(
PythonService.ScriptGreenDetector,
new string[] { MaxLeituras.ToString(), VideoPorta, VideoUrl, ArquivoLeitura, "1", SocketPorta },
VideoPorta,
VideoUrl,
SocketPorta
);
if (webSolo == null)
{
webSolo = new ChromiumWebBrowser(cameraSolo.URLcamera);
pnlCameraSolo.Controls.Add(webSolo);
webSolo.Dock = DockStyle.Fill;
}
}
private void IniciarCameraCaminho()
{
string ArquivoLeitura = "angulos.json";
int MaxLeituras = 10;
string VideoPorta = "8081";
string VideoUrl = "line_angles";
string SocketPorta = "6536";
cameraCaminho.ArquivoLeitura = ArquivoLeitura;
cameraCaminho.IniciarCamera(
PythonService.ScriptLineAngle,
new string[] { MaxLeituras.ToString(), VideoPorta, VideoUrl, ArquivoLeitura, "1", SocketPorta },
VideoPorta,
VideoUrl,
SocketPorta
);
if (webCaminho == null)
{
webCaminho = new ChromiumWebBrowser(cameraCaminho.URLcamera);
pnlCameraCaminho.Controls.Add(webCaminho);
webCaminho.Dock = DockStyle.Fill;
}
}
private void btnCarregarMapa_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "Arquivos de Imagem|*.jpg;*.jpeg;*.png;*.gif;*.bmp";
if (ofd.ShowDialog() == DialogResult.OK)
{
string imagemPath = ofd.FileName;
// Cria um arquivo HTML temporário
string tempHtmlPath = Path.Combine(Path.GetTempPath(), "tempImage.html");
string htmlContent = $"<html><body style='margin:0;'><img src='file:///{imagemPath}' style='width:100%; height:100%;'></body></html>";
File.WriteAllText(tempHtmlPath, htmlContent);
if (webMapa == null)
{
webMapa = new ChromiumWebBrowser();
webMapa.Dock = DockStyle.Fill;
pnlMapa.Controls.Add(webMapa);
}
// Carrega o arquivo HTML no ChromiumWebBrowser
webMapa.Load(tempHtmlPath);
lblMapaCarregado.Text = "Mapa carregado: " + ofd.FileName.Split('\\')[ofd.FileName.Split('\\').Length - 1];
}
}
private void btnIniciarOperacao_Click(object sender, EventArgs e)
{
if (tmrLeituras.Enabled == true)
{
btnIniciarOperacao.Text = "Iniciar Operação";
cmbCameraSolo.Enabled = true;
cmbCameraCaminho.Enabled = true;
Variaveis.OperacaoEmAndamento.FinalizarOperacao();
tmrLeituras.Tick -= TmrLeituras_Tick;
tmrLeituras.Stop();
}
else
{
btnIniciarOperacao.Text = "Finalizar Operação";
cmbCameraSolo.Enabled = false;
cmbCameraCaminho.Enabled = false;
Variaveis.OperacaoEmAndamento.IniciarOperacao();
tmrLeituras.Tick += TmrLeituras_Tick;
tmrLeituras.Start();
}
}
private void TmrLeituras_Tick(object sender, EventArgs e)
{
if (cameraSolo.socket != null && cameraSolo.socket.DadosRecebidos.Any())
{
var leitura = cameraSolo.socket.DadosRecebidos.Last();
var Verdes = leitura.objetos.ToList();
int intervaloPorBico = Convert.ToInt32(cameraSolo.socket.DadosRecebidos.First().x_max) / Atuador.Dados.QuantidadeBicos;
int inicioBarraPulverizadora = Convert.ToInt32(cameraSolo.socket.DadosRecebidos.First().y_max * (1 - Atuador.Dados.PercentualInicioPulverizacao));
List<bool> BicosAnteriores = new List<bool>();
// Inicialize todos os bicos como inativos antes de verificar os objetos verdes
for (int i = 0; i < Atuador.Dados.QuantidadeBicos; i++)
{
BicosAnteriores.Add(Atuador.Dados.BicosPulverizadores[i].Atuado);
Atuador.Dados.BicosPulverizadores[i].Atuado = false;
}
foreach (var verde in Verdes)
{
// Calcule a posição final (y + altura) do objeto verde
int posicaoFinalVerdeY = verde.y + verde.altura;
if (posicaoFinalVerdeY > inicioBarraPulverizadora)
{
// Calcule a posição final (x + largura) do objeto verde
int posicaoFinalVerdeX = verde.x + verde.largura;
// Para cada objeto verde, verifique se ele está dentro do intervalo de algum bico e atue-o
for (int i = 0; i < Atuador.Dados.QuantidadeBicos; i++)
{
// Determina o intervalo no eixo x para o bico atual
int limiteInferior = intervaloPorBico * i;
int limiteSuperior = limiteInferior + intervaloPorBico;
// Verifica se o objeto 'verde' está dentro do intervalo deste bico
// A condição foi ajustada para verificar se qualquer parte do objeto verde cruza com o intervalo do bico
if (verde.x < limiteSuperior && posicaoFinalVerdeX > limiteInferior)
{
Atuador.Dados.BicosPulverizadores[i].Atuado = true;
}
}
}
}
for (int i = 0; i < Atuador.Dados.QuantidadeBicos; i++)
{
if (Atuador.Dados.BicosPulverizadores[i].Atuado && BicosAnteriores[i] != Atuador.Dados.BicosPulverizadores[i].Atuado)
{
Variaveis.OperacaoEmAndamento.AtuacoesPorBico[i]++;
}
}
lblUltimaLeituraSolo.Text = "Ultima Leitura Solo: " + FuncoesGlobais.TimestampToDate(leitura.timestamp);
pnlAtuadores.Invalidate();
Variaveis.OperacaoEmAndamento.Controle.BicosAtuados = Atuador.Dados.BicosPulverizadores;
Variaveis.OperacaoEmAndamento.Controle.RPM = !Verdes.Any() ?
Variaveis.OperacaoEmAndamento.Controle.RPM_Max :
Variaveis.OperacaoEmAndamento.Controle.RPM_Min;
}
if (cameraCaminho.socket != null && cameraCaminho.socket.DadosRecebidos.Any())
{
var leitura = cameraCaminho.socket != null && cameraCaminho.socket.DadosRecebidos.Any() ?
cameraCaminho.socket.DadosRecebidos.Last() :
new CameraAnguloModel() { angulo = 0, distancia_direita = 0, distancia_esquerda = 0 };
lblDistanciaEsquerda.Text = "Distancia da Esquerda: " + leitura.distancia_esquerda.ToString("000") + " px";
lblDistanciaDireita.Text = "Distancia da Direita: " + leitura.distancia_direita.ToString("000") + " px";
lblUltimaLeituraRua.Text = "Ultima Leitura Rua: " + FuncoesGlobais.TimestampToDate(leitura.timestamp);
pnlInclinacao.Invalidate();
Variaveis.OperacaoEmAndamento.Controle.Angulo = leitura.angulo;
}
AtualizarGrafico();
Variaveis.OperacaoEmAndamento.AtualizarDadosControle();
AtualizarInformacoesGerais();
}
private void pnlAtuadores_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
Panel myPanel = (Panel)sender;
int panelWidth = myPanel.Width;
int circleDiameter = 40; // Diâmetro dos círculos grandes
int smallCircleDiameter = circleDiameter / 2; // Diâmetro dos círculos pequenos
int spaceBetweenCircles = (panelWidth - (circleDiameter * Atuador.Dados.QuantidadeBicos)) / (Atuador.Dados.QuantidadeBicos + 1);
int yPosition = (myPanel.Height - circleDiameter) / 3; // Centralizado verticalmente
for (int i = 0; i < Atuador.Dados.QuantidadeBicos; i++)
{
// Calcula a posição x do círculo
int xPosition = spaceBetweenCircles + (i * (circleDiameter + spaceBetweenCircles));
// Desenha o contorno do círculo
g.DrawEllipse(Pens.Red, xPosition, yPosition, circleDiameter, circleDiameter);
// Se o bico estiver aceso, preenche o círculo
if (Atuador.Dados.BicosPulverizadores[i].Atuado)
{
g.FillEllipse(Brushes.Red, xPosition, yPosition, circleDiameter, circleDiameter);
}
// Define a string que representa o número do bico
string bicoNumero = Atuador.Dados.BicosPulverizadores[i].ID;
// Define a fonte para o texto
Font font = new Font("Arial", 10, FontStyle.Bold);
// Mede o tamanho do texto
SizeF stringSize = g.MeasureString(bicoNumero, font);
// Calcula as posições x e y para centralizar o texto no círculo
float textXPosition = xPosition + (circleDiameter - stringSize.Width) / 2;
float textYPosition = yPosition + (circleDiameter - stringSize.Height) / 2;
// Desenha o número do bico
g.DrawString(bicoNumero, font, Brushes.Black, textXPosition, textYPosition);
// Define a string que representa a atuacao do bico
string bicoAtuacao = Variaveis.OperacaoEmAndamento.AtuacoesPorBico[i].ToString("000");
// Define a fonte para o texto
Font fontA = new Font("Arial", 8, FontStyle.Bold);
// Mede o tamanho do texto
SizeF stringSizeA = g.MeasureString(bicoAtuacao, fontA);
// Calcula as posições x e y para centralizar o texto no círculo
float textXPositionA = xPosition + (circleDiameter - stringSizeA.Width) / 2;
float textYPositionA = circleDiameter + yPosition + 5;
// Desenha as atuacoes do bico
g.DrawString(bicoAtuacao, fontA, Brushes.Black, textXPositionA, textYPositionA);
// Calcula a posição x e y do círculo pequeno
int smallCircleXPosition = Convert.ToInt32(xPosition + circleDiameter - smallCircleDiameter / 1.3);
int smallCircleYPosition = Convert.ToInt32(yPosition + circleDiameter - smallCircleDiameter / 1.3);
// Define a cor de contorno e preenchimento para o círculo pequeno
Pen smallCirclePen = Pens.Blue; // Cor do contorno
Brush smallCircleBrush = Brushes.Transparent; // Cor de preenchimento padrão
// Se o status do bico for true, altera a cor de preenchimento para azul
if (Atuador.Dados.BicosPulverizadores[i].StatusBico)
{
smallCircleBrush = Brushes.Blue;
}
// Desenha o contorno do círculo pequeno
g.DrawEllipse(smallCirclePen, smallCircleXPosition, smallCircleYPosition, smallCircleDiameter, smallCircleDiameter);
// Preenche o círculo pequeno se o status do bico for true
g.FillEllipse(smallCircleBrush, smallCircleXPosition, smallCircleYPosition, smallCircleDiameter, smallCircleDiameter);
}
}
private void AtualizarGrafico()
{
MovSensorimanetoGrafico Log = null;
var Motor = Movimentacao.Dados.Motores.FirstOrDefault(x => x.LogGrafico.Any());
if (Motor.LogGrafico.Count > 0)
{
Log = Motor.LogGrafico.Last();
}
double Minimo = 0;
double Maximo = 0;
Chart chart = chartGraficos;
chart.Titles.Clear();
chart.Titles.Add("Acompanhamento");
var Logs = (Motor.LogGrafico.Count > MovimentacaoModel.LogsManter ? Motor.LogGrafico.Skip(Math.Max(0, Motor.LogGrafico.Count - MovimentacaoModel.LogsManter)).Take(MovimentacaoModel.LogsManter).ToList() : Motor.LogGrafico).Where(log => log.ComponenteID == Motor.ID).ToList();
chart.Series.Clear();
List<string> Momentos = Logs.Select(x => x.Momento.ToString("mm:ss:fff")).ToList();
var serieRPMsp = new Series("Velocidade: " + (Log != null ? Log.Velocidade : 0));
serieRPMsp.Points.DataBindXY(Momentos, Logs.Select(x => x.Velocidade).ToList());
serieRPMsp.ChartType = SeriesChartType.Line;
chart.Series.Add(serieRPMsp);
Minimo = Logs.Min(x => x.Velocidade) < Minimo ? Logs.Min(x => x.Velocidade) : Minimo;
Maximo = Logs.Min(x => x.Velocidade) > Maximo ? Logs.Min(x => x.Velocidade) : Maximo;
var serieRPM = new Series("RPM: " + (Log != null ? Log.RPM : 0));
serieRPM.Points.DataBindXY(Momentos, Logs.Select(x => x.RPM).ToList());
serieRPM.ChartType = SeriesChartType.Spline;
chart.Series.Add(serieRPM);
Minimo = Logs.Min(x => x.RPM) < Minimo ? Logs.Min(x => x.RPM) : Minimo;
Maximo = Logs.Max(x => x.RPM) > Maximo ? Logs.Max(x => x.RPM) : Maximo;
var seriePotencia = new Series("Potencia: " + (Log != null ? Log.Potencia : 0));
seriePotencia.Points.DataBindXY(Momentos, Logs.Select(x => x.Potencia).ToList());
seriePotencia.ChartType = SeriesChartType.Line;
chart.Series.Add(seriePotencia);
Minimo = Logs.Min(x => x.Potencia) < Minimo ? Logs.Min(x => x.Potencia) : Minimo;
Maximo = Logs.Max(x => x.Potencia) > Maximo ? Logs.Max(x => x.Potencia) : Maximo;
var serieTemperatura = new Series("Temperatura: " + (Log != null ? Log.Temperatura : 0));
serieTemperatura.Points.DataBindXY(Momentos, Logs.Select(x => x.Temperatura).ToList());
serieTemperatura.ChartType = SeriesChartType.Line;
chart.Series.Add(serieTemperatura);
Minimo = Logs.Min(x => x.Temperatura) < Minimo ? Logs.Min(x => x.Temperatura) : Minimo;
Maximo = Logs.Max(x => x.Temperatura) > Maximo ? Logs.Max(x => x.Temperatura) : Maximo;
foreach (var legend in chart.Legends)
{
legend.Docking = Docking.Bottom;
}
chart.ChartAreas[0].AxisY.Minimum = Minimo - 5;
chart.ChartAreas[0].AxisY.Maximum = Maximo + 5;
}
private void AtualizarInformacoesGerais()
{
lblDistanciaPercorrida.Text = "Distancia Percorrida: " + Variaveis.OperacaoEmAndamento.DistanciaPercorrida + " m";
TimeSpan tempo = TimeSpan.FromTicks(Variaveis.OperacaoEmAndamento.TimestampInicio - (Variaveis.OperacaoEmAndamento.TimestampFim > 0 ? Variaveis.OperacaoEmAndamento.TimestampFim : DateTime.Now.Ticks));
lblTempoOperacao.Text = "Tempo de Operação: " + tempo.Hours + ":" + tempo.Minutes + ":" + tempo.Seconds;
lblVelocidadeMedia.Text = "Velocidade Média: " + Variaveis.OperacaoEmAndamento.VelocidadeMedia.ToString("0.00") + " km/h";
lblErvasIdentificadas.Text = "Ervas Identificadas: " + Variaveis.OperacaoEmAndamento.ErvasIdentificadas.ToString("000");
lblErvasIdentificadas.Text = "Herbicida Aplicado: " + Variaveis.OperacaoEmAndamento.HerbicidaConsumido.ToString("0.000") + " L";
lblHerbicidaPorErva.Text = "Herbicida por Erva: " + Variaveis.OperacaoEmAndamento.HerbicidaPorErva.ToString("0.000") + " mL";
lblBateriaConsumida.Text = "Bateria Consumida: " + Variaveis.OperacaoEmAndamento.BateriaConsumida.ToString("0.00") + "%";
pgbReservatorio.Value = Convert.ToInt32(Atuador.Dados.PercentualReservatorio);
lblPorcentagemReservatorio.Text = "Reservatório: " + Atuador.Dados.PercentualReservatorio.ToString("0.00") + "%";
pgbProgresso.Value = Convert.ToInt32(Variaveis.OperacaoEmAndamento.ProgressoPercurso);
lblPorcentagemProgresso.Text = "Progresso: " + Variaveis.OperacaoEmAndamento.ProgressoPercurso.ToString("0.00") + "%";
}
private void pnlInclinacao_Paint(object sender, PaintEventArgs e)
{
DesenharInclinacao((Panel)sender, e);
}
private void DesenharInclinacao(Panel pnlBussola, PaintEventArgs e)
{
// Ângulo de inclinação em graus.
// Suponha que você tenha uma variável que armazene essa informação.
// Por exemplo, o ângulo de 0 graus pode ser diretamente para cima,
// e os ângulos aumentam no sentido horário.
float anguloInclinacao = cameraCaminho.socket != null && cameraCaminho.socket.DadosRecebidos.Any() ? (float)cameraCaminho.socket.DadosRecebidos.Last().angulo : 0;
Graphics g = e.Graphics;
// Desenha o círculo da bússola
int diameter = Math.Min(pnlBussola.Width - 1, pnlBussola.Height - 1);
Point centro = new Point((pnlBussola.Width - 1) / 2, (pnlBussola.Height - 1) / 2);
g.DrawEllipse(Pens.Black, centro.X - diameter / 2, centro.Y - diameter / 2, diameter, diameter);
// Escreve o ângulo no centro do círculo
string anguloTexto = $"{anguloInclinacao.ToString("0.00")}°";
Font fonteAngulo = new Font("Arial", 10); // Ajuste o tamanho da fonte conforme necessário
SizeF textSize = e.Graphics.MeasureString(anguloTexto, fonteAngulo);
// Calcula a posição para o texto ser centralizado no círculo
float textX = centro.X - (textSize.Width / 2);
float textY = centro.Y - (textSize.Height / 2) + (centro.Y / 2);
// Define a cor do texto
Brush textBrush = Brushes.Black;
// Desenha o texto no Graphics do painel
g.DrawString(anguloTexto, fonteAngulo, textBrush, textX, textY);
// A linha será desenhada do centro do círculo
PointF pontoCentral = new PointF(centro.X, centro.Y);
// O comprimento da linha será metade do diâmetro do círculo (raio)
float comprimentoLinha = diameter / 2;
// Ajustar o ângulo para que 0 graus esteja para cima e aumente no sentido horário
float anguloRadianos = (anguloInclinacao - 90) * (float)(Math.PI / 180.0);
// Calcular o ponto final da linha baseado no ângulo de inclinação
PointF pontoFinal = new PointF(
pontoCentral.X + comprimentoLinha * (float)Math.Cos(anguloRadianos),
pontoCentral.Y + comprimentoLinha * (float)Math.Sin(anguloRadianos)
);
// Desenhar a linha de inclinação
g.DrawLine(Pens.Red, pontoCentral, pontoFinal);
// Opcional: Desenhar uma ponta de seta na linha para indicar direção
using (AdjustableArrowCap bigArrow = new AdjustableArrowCap(4, 4))
{
using (Pen pen = new Pen(Color.Red, 2))
{
pen.CustomEndCap = bigArrow;
g.DrawLine(pen, pontoCentral, pontoFinal);
}
}
}
private void UpdatePath(float angle, float distance)
{
// Atualiza o ângulo atual com base na nova leitura
float currentAngle = angle;
// Converte o ângulo em radianos para calcular a nova posição
float angleRadians = currentAngle * (float)Math.PI / 180.0f;
// Calcula a nova posição com base no ângulo e na distância
currentPosition = new PointF(
currentPosition.X + distance * (float)Math.Cos(angleRadians),
currentPosition.Y + distance * (float)Math.Sin(angleRadians)
);
// Adiciona a nova posição na lista de pontos
pathPoints.Add(currentPosition);
// Redesenha o painel
pnlMapa.Invalidate();
}
private void pnlMapa_Paint(object sender, PaintEventArgs e)
{
if (pathPoints.Count < 2) return; // Necessário pelo menos 2 pontos para desenhar um caminho
Graphics g = e.Graphics;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
// Desenha o caminho
for (int i = 1; i < pathPoints.Count; i++)
{
g.DrawLine(Pens.Black, pathPoints[i - 1], pathPoints[i]);
}
}
private void btnDesenharMapa_Click(object sender, EventArgs e)
{
if (tmrMapa.Enabled)
{
btnDesenharMapa.Text = "Desenhar";
tmrMapa.Stop();
}
else
{
btnDesenharMapa.Text = "Parar";
currentPosition = new PointF(pnlMapa.Width / 2, pnlMapa.Height / 2);
tmrMapa = new Timer() { Interval = 1000 };
tmrMapa.Tick -= TmrMapa_Tick;
tmrMapa.Tick += TmrMapa_Tick;
tmrMapa.Start();
}
}
Timer tmrMapa = new Timer();
float distance = 0;
private void TmrMapa_Tick(object sender, EventArgs e)
{
distance = 5;
float angle = new Random().Next(-200, 200);
//distance = (float)Variaveis.OperacaoEmAndamento.DistanciaPercorrida - distance;
//angle = cameraCaminho.socket != null && cameraCaminho.socket.DadosRecebidos.Any() ? (float)cameraCaminho.socket.DadosRecebidos.Last().angulo : 0;
UpdatePath(angle, distance);
}
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,145 @@

namespace AgroBase.Forms.Sensoriamento
{
partial class frmSenCamera
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.gpbCameras = new System.Windows.Forms.GroupBox();
this.btnIniciar = new System.Windows.Forms.Button();
this.btnAtualizar = new System.Windows.Forms.Button();
this.btnSalvar = new System.Windows.Forms.Button();
this.cmbCameras = new System.Windows.Forms.ComboBox();
this.pnlLeituras = new System.Windows.Forms.Panel();
this.pnlCamera = new System.Windows.Forms.Panel();
this.gpbCameras.SuspendLayout();
this.SuspendLayout();
//
// gpbCameras
//
this.gpbCameras.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.gpbCameras.Controls.Add(this.btnIniciar);
this.gpbCameras.Controls.Add(this.btnAtualizar);
this.gpbCameras.Controls.Add(this.btnSalvar);
this.gpbCameras.Controls.Add(this.cmbCameras);
this.gpbCameras.Location = new System.Drawing.Point(618, 12);
this.gpbCameras.Name = "gpbCameras";
this.gpbCameras.Size = new System.Drawing.Size(188, 129);
this.gpbCameras.TabIndex = 10;
this.gpbCameras.TabStop = false;
this.gpbCameras.Text = "Cameras";
//
// btnIniciar
//
this.btnIniciar.Enabled = false;
this.btnIniciar.Location = new System.Drawing.Point(6, 89);
this.btnIniciar.Name = "btnIniciar";
this.btnIniciar.Size = new System.Drawing.Size(176, 28);
this.btnIniciar.TabIndex = 3;
this.btnIniciar.Text = "Iniciar";
this.btnIniciar.UseVisualStyleBackColor = true;
this.btnIniciar.Click += new System.EventHandler(this.btnIniciar_Click);
//
// btnAtualizar
//
this.btnAtualizar.Location = new System.Drawing.Point(6, 55);
this.btnAtualizar.Name = "btnAtualizar";
this.btnAtualizar.Size = new System.Drawing.Size(85, 28);
this.btnAtualizar.TabIndex = 2;
this.btnAtualizar.Text = "Atualizar";
this.btnAtualizar.UseVisualStyleBackColor = true;
this.btnAtualizar.Click += new System.EventHandler(this.btnAtualizar_Click);
//
// btnSalvar
//
this.btnSalvar.Location = new System.Drawing.Point(97, 55);
this.btnSalvar.Name = "btnSalvar";
this.btnSalvar.Size = new System.Drawing.Size(85, 28);
this.btnSalvar.TabIndex = 1;
this.btnSalvar.Text = "Editar";
this.btnSalvar.UseVisualStyleBackColor = true;
this.btnSalvar.Click += new System.EventHandler(this.btnSalvar_Click);
//
// cmbCameras
//
this.cmbCameras.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cmbCameras.Enabled = false;
this.cmbCameras.FormattingEnabled = true;
this.cmbCameras.Location = new System.Drawing.Point(6, 25);
this.cmbCameras.Name = "cmbCameras";
this.cmbCameras.Size = new System.Drawing.Size(176, 24);
this.cmbCameras.TabIndex = 0;
//
// pnlLeituras
//
this.pnlLeituras.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Right)));
this.pnlLeituras.AutoScroll = true;
this.pnlLeituras.Location = new System.Drawing.Point(618, 147);
this.pnlLeituras.Name = "pnlLeituras";
this.pnlLeituras.Size = new System.Drawing.Size(188, 465);
this.pnlLeituras.TabIndex = 9;
//
// pnlCamera
//
this.pnlCamera.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.pnlCamera.Location = new System.Drawing.Point(12, 12);
this.pnlCamera.Name = "pnlCamera";
this.pnlCamera.Size = new System.Drawing.Size(600, 600);
this.pnlCamera.TabIndex = 8;
//
// frmSenCamera
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(818, 625);
this.Controls.Add(this.gpbCameras);
this.Controls.Add(this.pnlLeituras);
this.Controls.Add(this.pnlCamera);
this.Name = "frmSenCamera";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Identificação do caminho";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.frmSenCamera_FormClosing);
this.Load += new System.EventHandler(this.frmSenCamera_Load);
this.gpbCameras.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.GroupBox gpbCameras;
private System.Windows.Forms.Button btnIniciar;
private System.Windows.Forms.Button btnAtualizar;
private System.Windows.Forms.Button btnSalvar;
private System.Windows.Forms.ComboBox cmbCameras;
private System.Windows.Forms.Panel pnlLeituras;
private System.Windows.Forms.Panel pnlCamera;
}
}

View File

@ -0,0 +1,172 @@
using AgroBase.Models;
using AgroBase.Services;
using CefSharp.WinForms;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AgroBase.Forms.Sensoriamento
{
public partial class frmSenCamera : Form
{
private CameraService<CameraAnguloModel> cameraService = new CameraService<CameraAnguloModel>();
private ChromiumWebBrowser chromiumWebBrowser = null;
private Timer tmrLeitura;
private int MaxLeituras = 10;
private string VideoPorta = "8081";
private string VideoUrl = "line_angle";
private string SocketPorta = "6535";
private bool MostrarDebug = true;
private string ArquivoLeitura = "leitura_angulo.json";
public frmSenCamera()
{
InitializeComponent();
}
private void frmSenCamera_Load(object sender, EventArgs e)
{
AtualizaListaCameras();
}
private void frmSenCamera_FormClosing(object sender, FormClosingEventArgs e)
{
try
{
cameraService.socket.Disconnect();
cameraService.pythonProcess.Kill();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private void TmrLeitura_Tick(object sender, EventArgs e)
{
ListarObjetosDetectados();
}
private void btnAtualizar_Click(object sender, EventArgs e)
{
AtualizaListaCameras();
}
private void btnSalvar_Click(object sender, EventArgs e)
{
if (btnSalvar.Text == "Editar")
{
btnSalvar.Text = "Salvar";
}
else
{
btnSalvar.Text = "Editar";
cameraService.selectedCamera = cmbCameras.SelectedIndex;
}
btnIniciar.Enabled = btnSalvar.Text == "Editar" && cmbCameras.SelectedIndex > 0;
cmbCameras.Enabled = btnSalvar.Text == "Salvar";
}
private void btnIniciar_Click(object sender, EventArgs e)
{
cameraService.ArquivoLeitura = ArquivoLeitura;
cameraService.IniciarCamera(
PythonService.ScriptLineAngle,
new string[] { MaxLeituras.ToString(), VideoPorta, VideoUrl, ArquivoLeitura, MostrarDebug ? "1" : "0", SocketPorta },
VideoPorta,
VideoUrl
);
tmrLeitura = new Timer() { Interval = 200 };
tmrLeitura.Tick += TmrLeitura_Tick;
tmrLeitura.Start();
}
private void AtualizaListaCameras()
{
cameraService.selectedCamera = cmbCameras.SelectedIndex > 0 ? cmbCameras.SelectedIndex : 0;
cmbCameras.Items.Clear();
cmbCameras.Items.AddRange(cameraService.AtualizaListaCameras().ToArray());
if (cmbCameras.Items.Count == 1)
{
cameraService.selectedCamera = 0;
}
cmbCameras.SelectedIndex = cameraService.selectedCamera;
}
private void ListarObjetosDetectados()
{
if (chromiumWebBrowser == null)
{
chromiumWebBrowser = new ChromiumWebBrowser(cameraService.URLcamera);
this.pnlCamera.Controls.Add(chromiumWebBrowser);
chromiumWebBrowser.Dock = DockStyle.Fill;
}
this.pnlLeituras.Controls.Clear();
int i = 0;
var leituras = cameraService.socket.DadosRecebidos.ToList().OrderByDescending(x => x.timestamp).Take(MaxLeituras).ToList();
foreach (var leitura in leituras)
{
GroupBox gpb = new GroupBox()
{
Name = "gpbLeitura" + i,
Size = new Size(120, 170),
Text = "Leitura " + (i + 1),
Location = new Point(3, 3 + (i * 190))
};
Label _lblMomento = new Label()
{
Name = "lblLeitura" + i + "Momento",
Size = new Size(100, 20),
Text = "Momento: " + leitura.timestamp,
Location = new Point(6, 20)
};
Label _lblAngulo = new Label()
{
Name = "lblLeitura" + i + "Angulo",
Size = new Size(100, 20),
Text = "Angulo: " + leitura.angulo.ToString("0.00") + "º",
Location = new Point(6, 40)
};
Label _lblEsquerda = new Label()
{
Name = "lblLeitura" + i + "Esquerda",
Size = new Size(100, 20),
Text = "Esquerda: " + leitura.distancia_esquerda,
Location = new Point(6, 60)
};
Label _lblDireita = new Label()
{
Name = "lblLeitura" + i + "Direita",
Size = new Size(100, 20),
Text = "Direita: " + leitura.distancia_direita,
Location = new Point(6, 80)
};
gpb.Controls.Add(_lblMomento);
gpb.Controls.Add(_lblAngulo);
gpb.Controls.Add(_lblEsquerda);
gpb.Controls.Add(_lblDireita);
pnlLeituras.Controls.Add(gpb);
i++;
}
}
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -1,4 +1,5 @@
using AgroBase.Comum;
using AgroBase.Models;
using AgroBase.Models.Modules;
using System;
using System.Collections.Generic;
@ -15,7 +16,7 @@ namespace AgroBase.Forms.Sensoriamento
{
public partial class frmSenConfig : Form
{
DispositivosService Disp = frmPrincipal.Dispositivos.FirstOrDefault(x => x.Dispositivo == T_Code.Sen);
DispositivosService<SensoriamentoModel> Disp = (DispositivosService<SensoriamentoModel>)Variaveis.DispositivosConectados.FirstOrDefault(x => x.Dispositivo == T_Code.Sen);
public frmSenConfig()
{
@ -36,7 +37,7 @@ namespace AgroBase.Forms.Sensoriamento
SensoriamentoModel.Funcoes.ForEach(x => Pinos.Add(Enum.GetName(typeof(FuncoesPinout), x)));
foreach (var Sensor in ((SensoriamentoModel)(Disp.Dados)).Sensores)
foreach (var Sensor in Disp.Dados.Sensores)
{
Sensor.Funcoes.ForEach(x => Pinos.Add(Sensor.ID + " " + Enum.GetName(typeof(FuncoesPinout), x)));
}
@ -91,7 +92,7 @@ namespace AgroBase.Forms.Sensoriamento
SensoriamentoModel.Pinout.FirstOrDefault(x => x.Pino == pino).ComponenteID = ComponenteID;
}
((SensoriamentoModel)(Disp.Dados)).SalvarPinout(SensoriamentoModel.Pinout, "pinout" + Enum.GetName(typeof(T_Code), Disp.Dispositivo) + ".pin");
Disp.Dados.SalvarPinout(SensoriamentoModel.Pinout, "pinout" + Enum.GetName(typeof(T_Code), Disp.Dispositivo) + ".pin");
}
}

View File

@ -29,20 +29,24 @@ namespace AgroBase.Forms
/// </summary>
private void InitializeComponent()
{
System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea5 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
System.Windows.Forms.DataVisualization.Charting.Legend legend5 = new System.Windows.Forms.DataVisualization.Charting.Legend();
System.Windows.Forms.DataVisualization.Charting.Series series5 = new System.Windows.Forms.DataVisualization.Charting.Series();
System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea6 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
System.Windows.Forms.DataVisualization.Charting.Legend legend6 = new System.Windows.Forms.DataVisualization.Charting.Legend();
System.Windows.Forms.DataVisualization.Charting.Series series6 = new System.Windows.Forms.DataVisualization.Charting.Series();
System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea7 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
System.Windows.Forms.DataVisualization.Charting.Legend legend7 = new System.Windows.Forms.DataVisualization.Charting.Legend();
System.Windows.Forms.DataVisualization.Charting.Series series7 = new System.Windows.Forms.DataVisualization.Charting.Series();
System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea8 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
System.Windows.Forms.DataVisualization.Charting.Legend legend8 = new System.Windows.Forms.DataVisualization.Charting.Legend();
System.Windows.Forms.DataVisualization.Charting.Series series8 = new System.Windows.Forms.DataVisualization.Charting.Series();
System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
System.Windows.Forms.DataVisualization.Charting.Legend legend1 = new System.Windows.Forms.DataVisualization.Charting.Legend();
System.Windows.Forms.DataVisualization.Charting.Series series1 = new System.Windows.Forms.DataVisualization.Charting.Series();
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();
System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea3 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
System.Windows.Forms.DataVisualization.Charting.Legend legend3 = new System.Windows.Forms.DataVisualization.Charting.Legend();
System.Windows.Forms.DataVisualization.Charting.Series series3 = new System.Windows.Forms.DataVisualization.Charting.Series();
System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea4 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
System.Windows.Forms.DataVisualization.Charting.Legend legend4 = new System.Windows.Forms.DataVisualization.Charting.Legend();
System.Windows.Forms.DataVisualization.Charting.Series series4 = new System.Windows.Forms.DataVisualization.Charting.Series();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(frmAcompanhamento));
this.pnlFundo = new System.Windows.Forms.Panel();
this.lblDistanciaParcial = new System.Windows.Forms.Label();
this.lblDistanciaTotal = new System.Windows.Forms.Label();
this.lblTempoEmMovimento = new System.Windows.Forms.Label();
this.lblTempoConectado = new System.Windows.Forms.Label();
this.chbDTLivre = new System.Windows.Forms.CheckBox();
this.chbDTControlar = new System.Windows.Forms.CheckBox();
this.chbETLivre = new System.Windows.Forms.CheckBox();
@ -120,10 +124,6 @@ namespace AgroBase.Forms
this.btnEFReferenciar = new System.Windows.Forms.Button();
this.lblM1 = new System.Windows.Forms.Label();
this.picEF = new System.Windows.Forms.PictureBox();
this.lblTempoConectado = new System.Windows.Forms.Label();
this.lblTempoEmMovimento = new System.Windows.Forms.Label();
this.lblDistanciaTotal = new System.Windows.Forms.Label();
this.lblDistanciaParcial = new System.Windows.Forms.Label();
this.pnlFundo.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.chartET)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.chartDT)).BeginInit();
@ -227,6 +227,42 @@ namespace AgroBase.Forms
this.pnlFundo.Size = new System.Drawing.Size(1924, 994);
this.pnlFundo.TabIndex = 0;
//
// lblDistanciaParcial
//
this.lblDistanciaParcial.AutoSize = true;
this.lblDistanciaParcial.Location = new System.Drawing.Point(852, 233);
this.lblDistanciaParcial.Name = "lblDistanciaParcial";
this.lblDistanciaParcial.Size = new System.Drawing.Size(212, 17);
this.lblDistanciaParcial.TabIndex = 170;
this.lblDistanciaParcial.Text = "Distância percorrida parcial: 0 m";
//
// lblDistanciaTotal
//
this.lblDistanciaTotal.AutoSize = true;
this.lblDistanciaTotal.Location = new System.Drawing.Point(852, 216);
this.lblDistanciaTotal.Name = "lblDistanciaTotal";
this.lblDistanciaTotal.Size = new System.Drawing.Size(197, 17);
this.lblDistanciaTotal.TabIndex = 169;
this.lblDistanciaTotal.Text = "Distância percorrida total: 0 m";
//
// lblTempoEmMovimento
//
this.lblTempoEmMovimento.AutoSize = true;
this.lblTempoEmMovimento.Location = new System.Drawing.Point(852, 199);
this.lblTempoEmMovimento.Name = "lblTempoEmMovimento";
this.lblTempoEmMovimento.Size = new System.Drawing.Size(235, 17);
this.lblTempoEmMovimento.TabIndex = 168;
this.lblTempoEmMovimento.Text = "Tempo em movimento: 00:00:00 hrs";
//
// lblTempoConectado
//
this.lblTempoConectado.AutoSize = true;
this.lblTempoConectado.Location = new System.Drawing.Point(852, 182);
this.lblTempoConectado.Name = "lblTempoConectado";
this.lblTempoConectado.Size = new System.Drawing.Size(210, 17);
this.lblTempoConectado.TabIndex = 167;
this.lblTempoConectado.Text = "Tempo conectado: 00:00:00 hrs";
//
// chbDTLivre
//
this.chbDTLivre.AutoSize = true;
@ -309,64 +345,64 @@ namespace AgroBase.Forms
//
// chartET
//
chartArea5.Name = "ChartArea1";
this.chartET.ChartAreas.Add(chartArea5);
legend5.Name = "Legend1";
this.chartET.Legends.Add(legend5);
chartArea1.Name = "ChartArea1";
this.chartET.ChartAreas.Add(chartArea1);
legend1.Name = "Legend1";
this.chartET.Legends.Add(legend1);
this.chartET.Location = new System.Drawing.Point(268, 504);
this.chartET.Name = "chartET";
series5.ChartArea = "ChartArea1";
series5.Legend = "Legend1";
series5.Name = "Series1";
this.chartET.Series.Add(series5);
series1.ChartArea = "ChartArea1";
series1.Legend = "Legend1";
series1.Name = "Series1";
this.chartET.Series.Add(series1);
this.chartET.Size = new System.Drawing.Size(578, 480);
this.chartET.TabIndex = 94;
this.chartET.Text = "chart1";
//
// chartDT
//
chartArea6.Name = "ChartArea1";
this.chartDT.ChartAreas.Add(chartArea6);
legend6.Name = "Legend1";
this.chartDT.Legends.Add(legend6);
chartArea2.Name = "ChartArea1";
this.chartDT.ChartAreas.Add(chartArea2);
legend2.Name = "Legend1";
this.chartDT.Legends.Add(legend2);
this.chartDT.Location = new System.Drawing.Point(1112, 504);
this.chartDT.Name = "chartDT";
series6.ChartArea = "ChartArea1";
series6.Legend = "Legend1";
series6.Name = "Series1";
this.chartDT.Series.Add(series6);
series2.ChartArea = "ChartArea1";
series2.Legend = "Legend1";
series2.Name = "Series1";
this.chartDT.Series.Add(series2);
this.chartDT.Size = new System.Drawing.Size(577, 480);
this.chartDT.TabIndex = 110;
this.chartDT.Text = "chart1";
//
// chartDF
//
chartArea7.Name = "ChartArea1";
this.chartDF.ChartAreas.Add(chartArea7);
legend7.Name = "Legend1";
this.chartDF.Legends.Add(legend7);
chartArea3.Name = "ChartArea1";
this.chartDF.ChartAreas.Add(chartArea3);
legend3.Name = "Legend1";
this.chartDF.Legends.Add(legend3);
this.chartDF.Location = new System.Drawing.Point(1112, 5);
this.chartDF.Name = "chartDF";
series7.ChartArea = "ChartArea1";
series7.Legend = "Legend1";
series7.Name = "Series1";
this.chartDF.Series.Add(series7);
series3.ChartArea = "ChartArea1";
series3.Legend = "Legend1";
series3.Name = "Series1";
this.chartDF.Series.Add(series3);
this.chartDF.Size = new System.Drawing.Size(577, 480);
this.chartDF.TabIndex = 109;
this.chartDF.Text = "chart1";
//
// chartEF
//
chartArea8.Name = "ChartArea1";
this.chartEF.ChartAreas.Add(chartArea8);
legend8.Name = "Legend1";
this.chartEF.Legends.Add(legend8);
chartArea4.Name = "ChartArea1";
this.chartEF.ChartAreas.Add(chartArea4);
legend4.Name = "Legend1";
this.chartEF.Legends.Add(legend4);
this.chartEF.Location = new System.Drawing.Point(268, 5);
this.chartEF.Name = "chartEF";
series8.ChartArea = "ChartArea1";
series8.Legend = "Legend1";
series8.Name = "Series1";
this.chartEF.Series.Add(series8);
series4.ChartArea = "ChartArea1";
series4.Legend = "Legend1";
series4.Name = "Series1";
this.chartEF.Series.Add(series4);
this.chartEF.Size = new System.Drawing.Size(578, 480);
this.chartEF.TabIndex = 93;
this.chartEF.Text = "chart1";
@ -957,42 +993,6 @@ namespace AgroBase.Forms
this.picEF.TabIndex = 90;
this.picEF.TabStop = false;
//
// lblTempoConectado
//
this.lblTempoConectado.AutoSize = true;
this.lblTempoConectado.Location = new System.Drawing.Point(852, 182);
this.lblTempoConectado.Name = "lblTempoConectado";
this.lblTempoConectado.Size = new System.Drawing.Size(210, 17);
this.lblTempoConectado.TabIndex = 167;
this.lblTempoConectado.Text = "Tempo conectado: 00:00:00 hrs";
//
// lblTempoEmMovimento
//
this.lblTempoEmMovimento.AutoSize = true;
this.lblTempoEmMovimento.Location = new System.Drawing.Point(852, 199);
this.lblTempoEmMovimento.Name = "lblTempoEmMovimento";
this.lblTempoEmMovimento.Size = new System.Drawing.Size(235, 17);
this.lblTempoEmMovimento.TabIndex = 168;
this.lblTempoEmMovimento.Text = "Tempo em movimento: 00:00:00 hrs";
//
// lblDistanciaTotal
//
this.lblDistanciaTotal.AutoSize = true;
this.lblDistanciaTotal.Location = new System.Drawing.Point(852, 216);
this.lblDistanciaTotal.Name = "lblDistanciaTotal";
this.lblDistanciaTotal.Size = new System.Drawing.Size(197, 17);
this.lblDistanciaTotal.TabIndex = 169;
this.lblDistanciaTotal.Text = "Distância percorrida total: 0 m";
//
// lblDistanciaParcial
//
this.lblDistanciaParcial.AutoSize = true;
this.lblDistanciaParcial.Location = new System.Drawing.Point(852, 233);
this.lblDistanciaParcial.Name = "lblDistanciaParcial";
this.lblDistanciaParcial.Size = new System.Drawing.Size(212, 17);
this.lblDistanciaParcial.TabIndex = 170;
this.lblDistanciaParcial.Text = "Distância percorrida parcial: 0 m";
//
// frmAcompanhamento
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
@ -1001,7 +1001,7 @@ namespace AgroBase.Forms
this.Controls.Add(this.pnlFundo);
this.Name = "frmAcompanhamento";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "frmAcompanhamento";
this.Text = "Acompanhamento";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.frmAcompanhamento_FormClosing);
this.Load += new System.EventHandler(this.frmAcompanhamento_Load);
this.Shown += new System.EventHandler(this.frmAcompanhamento_Shown);

View File

@ -1,4 +1,5 @@
using AgroBase.Models;
using AgroBase.Comum;
using AgroBase.Models;
using AgroBase.Models.Modules;
using System;
using System.Collections.Generic;
@ -59,7 +60,7 @@ namespace AgroBase.Forms
private void PreencherOpcoes()
{
var DispCon = frmPrincipal.Dispositivos.Where(x => x.Dispositivo == T_Code.Dir).ToList();
var DispCon = Variaveis.DispositivosConectados.Where(x => x.Dispositivo == T_Code.Dir).ToList();
foreach (var Dispositivo in DispCon)
{
foreach (var Motor in ((DirecionalModel)Dispositivo.Dados).Motores)
@ -93,7 +94,7 @@ namespace AgroBase.Forms
private void AtualzarDadosMovimentacao()
{
var DispMov = frmPrincipal.Dispositivos.FirstOrDefault(x => x._Porta.IsOpen && x.Dispositivo == T_Code.Mov);
var DispMov = (DispositivosService<MovimentacaoModel>)Variaveis.DispositivosConectados.FirstOrDefault(x => x._Porta.IsOpen && x.Dispositivo == T_Code.Mov);
if (DispMov == null)
{
return;
@ -106,11 +107,11 @@ namespace AgroBase.Forms
else
{
lblTempoConectado.Text = "Tempo conectado: " + TimeSpan.FromSeconds(DispMov.TempoConectado).ToString(@"hh\:mm\:ss") + " hrs";
lblTempoEmMovimento.Text = "Tempo em movimento: " + TimeSpan.FromSeconds(((MovimentacaoModel)DispMov.Dados).TempoEmAtividade).ToString(@"hh\:mm\:ss") + " hrs";
lblDistanciaTotal.Text = "Distancia percorrida total: " + ((MovimentacaoModel)DispMov.Dados).DistanciaPercorridaTotal.ToString("0.00") + " m";
lblDistanciaParcial.Text = "Distancia percorrida parcial: " + ((MovimentacaoModel)DispMov.Dados).DistanciaPercorridaParcial.ToString("0.00") + " m";
lblTempoEmMovimento.Text = "Tempo em movimento: " + TimeSpan.FromSeconds(DispMov.Dados.TempoEmAtividade).ToString(@"hh\:mm\:ss") + " hrs";
lblDistanciaTotal.Text = "Distancia percorrida total: " + DispMov.Dados.DistanciaPercorridaTotal.ToString("0.00") + " m";
lblDistanciaParcial.Text = "Distancia percorrida parcial: " + DispMov.Dados.DistanciaPercorridaParcial.ToString("0.00") + " m";
foreach (var Motor in ((MovimentacaoModel)DispMov.Dados).Motores.Where(x => x.Comandar))
foreach (var Motor in DispMov.Dados.Motores.Where(x => x.Comandar))
{
Label lblM_RPMSP = pnlFundo.Controls.OfType<Label>().FirstOrDefault(ctrl => ctrl.Name == "lbl" + Motor.ID + "M_RPMSP");
lblM_RPMSP.Text = "RPM SP: " + Motor.RPM_SP.ToString("0.00");
@ -192,7 +193,7 @@ namespace AgroBase.Forms
private void DesenharGraficos(object sender, PaintEventArgs e)
{
if (!frmPrincipal.Dispositivos.Any(d => d.Dispositivo == T_Code.Dir))
if (!Variaveis.DispositivosConectados.Any(d => d.Dispositivo == T_Code.Dir))
{
return;
}
@ -200,7 +201,7 @@ namespace AgroBase.Forms
PictureBox pic = (PictureBox)sender;
string ID = pic.Name.Replace("pic", "");
var Motor = ((DirecionalModel)frmPrincipal.Dispositivos.FirstOrDefault(d => d.Dispositivo == T_Code.Dir).Dados).Motores.FirstOrDefault(m => m.ID == ID);
var Motor = ((DirecionalModel)Variaveis.DispositivosConectados.FirstOrDefault(d => d.Dispositivo == T_Code.Dir).Dados).Motores.FirstOrDefault(m => m.ID == ID);
Label lblA_SP = pnlFundo.Controls.OfType<Label>().FirstOrDefault(ctrl => ctrl.Name == "lbl" + ID + "A_SP");
lblA_SP.Text = "Angulo SP: " + ((Motor.Sentido_SP == Sentido.Antihorario ? -1 : 1) * Motor.Angulo_SP).ToString("000") + "º";
Label lblA = pnlFundo.Controls.OfType<Label>().FirstOrDefault(ctrl => ctrl.Name == "lbl" + ID + "A");
@ -352,7 +353,7 @@ namespace AgroBase.Forms
private void btnReferenciar_Click(object sender, EventArgs e)
{
string ID = ((Button)sender).Name.Substring(3, 2);
var DispCon = frmPrincipal.Dispositivos.Where(x => x._Porta.IsOpen && x.Dispositivo == T_Code.Dir).ToList();
var DispCon = Variaveis.DispositivosConectados.Where(x => x._Porta.IsOpen && x.Dispositivo == T_Code.Dir).ToList();
foreach (var Dispositivo in DispCon)
{
var Motor = ((DirecionalModel)Dispositivo.Dados).Motores.FirstOrDefault(x => x.ID == ID);
@ -364,7 +365,7 @@ namespace AgroBase.Forms
private void btnReverter_Click(object sender, EventArgs e)
{
string ID = ((Button)sender).Name.Substring(3, 2);
var DispCon = frmPrincipal.Dispositivos.Where(x => x._Porta.IsOpen && x.Dispositivo == T_Code.Mov).ToList();
var DispCon = Variaveis.DispositivosConectados.Where(x => x._Porta.IsOpen && x.Dispositivo == T_Code.Mov).ToList();
foreach (var Dispositivo in DispCon)
{
var Motor = ((MovimentacaoModel)Dispositivo.Dados).Motores.FirstOrDefault(x => x.ID == ID);
@ -376,7 +377,7 @@ namespace AgroBase.Forms
private void ChbLivre_CheckedChanged(object sender, EventArgs e)
{
string ID = ((CheckBox)sender).Name.Substring(3, 2);
var DispCon = frmPrincipal.Dispositivos.Where(x => x._Porta.IsOpen && x.Dispositivo == T_Code.Dir).ToList();
var DispCon = Variaveis.DispositivosConectados.Where(x => x._Porta.IsOpen && x.Dispositivo == T_Code.Dir).ToList();
foreach (var Dispositivo in DispCon)
{
var Motor = ((DirecionalModel)Dispositivo.Dados).Motores.FirstOrDefault(x => x.ID == ID);
@ -387,7 +388,7 @@ namespace AgroBase.Forms
private void ChbControlar_CheckedChanged(object sender, EventArgs e)
{
string ID = ((CheckBox)sender).Name.Substring(3, 2);
var DispCon = frmPrincipal.Dispositivos.Where(x => x._Porta.IsOpen && x.Dispositivo == T_Code.Dir).ToList();
var DispCon = Variaveis.DispositivosConectados.Where(x => x._Porta.IsOpen && x.Dispositivo == T_Code.Dir).ToList();
foreach (var Dispositivo in DispCon)
{
var Motor = ((DirecionalModel)Dispositivo.Dados).Motores.FirstOrDefault(x => x.ID == ID);

View File

@ -1,188 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Management;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using AgroBase.Services;
using CefSharp.WinForms;
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using Newtonsoft.Json;
namespace AgroBase.Forms
{
public partial class frmCamera : Form
{
private CameraService cameraService = new CameraService();
private ChromiumWebBrowser chromiumWebBrowser = null;
private Timer tmrLeitura;
public frmCamera()
{
InitializeComponent();
}
private void frmCamera_Load(object sender, EventArgs e)
{
AtualizaListaCameras();
}
private void TmrLeitura_Tick(object sender, EventArgs e)
{
ListarObjetosDetectados();
}
private void frmCamera_FormClosing(object sender, FormClosingEventArgs e)
{
try
{
cameraService.pythonProcess.Kill();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private void btnIniciar_Click(object sender, EventArgs e)
{
cameraService.IniciarCamera(PythonService.ScriptGreenDetector);
tmrLeitura = new Timer() { Interval = 500 };
tmrLeitura.Tick += TmrLeitura_Tick;
tmrLeitura.Start();
}
private void btnAtualizar_Click(object sender, EventArgs e)
{
AtualizaListaCameras();
}
private void btnSalvar_Click(object sender, EventArgs e)
{
if (btnSalvar.Text == "Editar")
{
btnSalvar.Text = "Salvar";
}
else
{
btnSalvar.Text = "Editar";
cameraService.selectedCamera = cmbCameras.SelectedIndex;
}
btnIniciar.Enabled = btnSalvar.Text == "Editar" && cmbCameras.SelectedIndex > 0;
cmbCameras.Enabled = btnSalvar.Text == "Salvar";
}
private void AtualizaListaCameras()
{
cameraService.selectedCamera = cmbCameras.SelectedIndex > 0 ? cmbCameras.SelectedIndex : 0;
cmbCameras.Items.Clear();
cmbCameras.Items.AddRange(cameraService.AtualizaListaCameras().ToArray());
if (cmbCameras.Items.Count == 1)
{
cameraService.selectedCamera = 0;
}
cmbCameras.SelectedIndex = cameraService.selectedCamera;
}
private void ListarObjetosDetectados()
{
if (chromiumWebBrowser == null)
{
chromiumWebBrowser = new ChromiumWebBrowser(cameraService.URLcamera);
this.pnlCamera.Controls.Add(chromiumWebBrowser);
chromiumWebBrowser.Dock = DockStyle.Fill;
}
var coordenadas = cameraService.AferirDadosCamera();
if (coordenadas != null && coordenadas.frames.Any(x => x.objetos.Any()))
{
this.pnlLeituras.Controls.Clear();
int i = 0;
foreach (var objeto in coordenadas.frames.Last().objetos)
{
GroupBox gpb = new GroupBox()
{
Name = "gpbLeitura" + i,
Size = new Size(120, 170),
Text = "Leitura " + (i + 1),
Location = new Point(3, 3 + (i * 190))
};
Label _lblID = new Label()
{
Name = "lblLeitura" + i + "ID",
Size = new Size(100, 20),
Text = "ID: " + objeto.id,
Location = new Point(6, 20)
};
Label _lblDescricao = new Label()
{
Name = "lblLeitura" + i + "Descricao",
Size = new Size(100, 20),
Text = "Descrição: " + objeto.descricao,
Location = new Point(6, 40)
};
Label _lblConfianca = new Label()
{
Name = "lblLeitura" + i + "Confianca",
Size = new Size(100, 20),
Text = "Confiança: " + (objeto.confianca * 100).ToString("0.00") + "%",
Location = new Point(6, 60)
};
Label _lblX = new Label()
{
Name = "lblLeitura" + i + "X",
Size = new Size(100, 20),
Text = "X: " + objeto.x,
Location = new Point(6, 80)
};
Label _lblY = new Label()
{
Name = "lblLeitura" + i + "Y",
Size = new Size(100, 20),
Text = "Y: " + objeto.y,
Location = new Point(6, 100)
};
Label _lblAltura = new Label()
{
Name = "lblLeitura" + i + "Altura",
Size = new Size(100, 20),
Text = "Altura: " + objeto.altura,
Location = new Point(6, 120)
};
Label _lblLargura = new Label()
{
Name = "lblLeitura" + i + "Largura",
Size = new Size(100, 20),
Text = "Largura: " + objeto.largura,
Location = new Point(6, 140)
};
gpb.Controls.Add(_lblID);
gpb.Controls.Add(_lblDescricao);
gpb.Controls.Add(_lblConfianca);
gpb.Controls.Add(_lblX);
gpb.Controls.Add(_lblY);
gpb.Controls.Add(_lblAltura);
gpb.Controls.Add(_lblLargura);
pnlLeituras.Controls.Add(gpb);
i++;
}
}
}
}
}

View File

@ -29,11 +29,15 @@ namespace AgroBase.Forms
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(frmMapa));
this.pnlMapa = new System.Windows.Forms.Panel();
this.pnlBotoes = new System.Windows.Forms.Panel();
this.btnCarregar = new System.Windows.Forms.Button();
this.lblMapa = new System.Windows.Forms.Label();
this.btnCarregar = new System.Windows.Forms.Button();
this.picLoading = new System.Windows.Forms.PictureBox();
this.pnlMapa.SuspendLayout();
this.pnlBotoes.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.picLoading)).BeginInit();
this.SuspendLayout();
//
// pnlMapa
@ -41,6 +45,7 @@ namespace AgroBase.Forms
this.pnlMapa.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.pnlMapa.Controls.Add(this.picLoading);
this.pnlMapa.Location = new System.Drawing.Point(12, 12);
this.pnlMapa.Name = "pnlMapa";
this.pnlMapa.Size = new System.Drawing.Size(1030, 571);
@ -56,6 +61,15 @@ namespace AgroBase.Forms
this.pnlBotoes.Size = new System.Drawing.Size(1054, 57);
this.pnlBotoes.TabIndex = 2;
//
// lblMapa
//
this.lblMapa.AutoSize = true;
this.lblMapa.Location = new System.Drawing.Point(12, 21);
this.lblMapa.Name = "lblMapa";
this.lblMapa.Size = new System.Drawing.Size(120, 17);
this.lblMapa.TabIndex = 1;
this.lblMapa.Text = "Mapa carregado: ";
//
// btnCarregar
//
this.btnCarregar.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
@ -67,14 +81,20 @@ namespace AgroBase.Forms
this.btnCarregar.UseVisualStyleBackColor = true;
this.btnCarregar.Click += new System.EventHandler(this.btnCarregar_Click);
//
// lblMapa
// picLoading
//
this.lblMapa.AutoSize = true;
this.lblMapa.Location = new System.Drawing.Point(12, 21);
this.lblMapa.Name = "lblMapa";
this.lblMapa.Size = new System.Drawing.Size(120, 17);
this.lblMapa.TabIndex = 1;
this.lblMapa.Text = "Mapa carregado: ";
this.picLoading.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.picLoading.BackColor = System.Drawing.Color.Transparent;
this.picLoading.Image = ((System.Drawing.Image)(resources.GetObject("picLoading.Image")));
this.picLoading.Location = new System.Drawing.Point(259, 29);
this.picLoading.Name = "picLoading";
this.picLoading.Size = new System.Drawing.Size(512, 512);
this.picLoading.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage;
this.picLoading.TabIndex = 2;
this.picLoading.TabStop = false;
this.picLoading.Visible = false;
//
// frmMapa
//
@ -86,8 +106,10 @@ namespace AgroBase.Forms
this.Name = "frmMapa";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Mapas";
this.pnlMapa.ResumeLayout(false);
this.pnlBotoes.ResumeLayout(false);
this.pnlBotoes.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.picLoading)).EndInit();
this.ResumeLayout(false);
}
@ -98,5 +120,6 @@ namespace AgroBase.Forms
private System.Windows.Forms.Panel pnlBotoes;
private System.Windows.Forms.Label lblMapa;
private System.Windows.Forms.Button btnCarregar;
private System.Windows.Forms.PictureBox picLoading;
}
}

View File

@ -30,6 +30,7 @@ namespace AgroBase.Forms
private void btnCarregar_Click(object sender, EventArgs e)
{
mapaService.CarregarMapa();
picLoading.Visible = true;
Timer tmr = new Timer() { Interval = 500 };
tmr.Tick += Tmr_Tick;
tmr.Start();
@ -40,6 +41,7 @@ namespace AgroBase.Forms
if (mapaService.pythonProcess.HasExited)
{
((Timer)sender).Stop();
picLoading.Visible = false;
mapaService.CarregarDadosMapa();

File diff suppressed because it is too large Load Diff

View File

@ -46,27 +46,14 @@ namespace AgroBase
this.lblDescricao = new System.Windows.Forms.Label();
this.lblTipo = new System.Windows.Forms.Label();
this.btnNovoDispositivo = new System.Windows.Forms.Button();
this.joystickStrip = new System.Windows.Forms.StatusStrip();
this.generalStrip = new System.Windows.Forms.StatusStrip();
this.lblStripJoystick = new System.Windows.Forms.ToolStripStatusLabel();
this.lblStripJoystickComando = new System.Windows.Forms.ToolStripStatusLabel();
this.gpbJoysticks = new System.Windows.Forms.GroupBox();
this.lblPPR = new System.Windows.Forms.Label();
this.nudPPR = new System.Windows.Forms.NumericUpDown();
this.lblRampaMax = new System.Windows.Forms.Label();
this.lblRampaMin = new System.Windows.Forms.Label();
this.nudRampaMax = new System.Windows.Forms.NumericUpDown();
this.nudRampaMin = new System.Windows.Forms.NumericUpDown();
this.chbMalhaFechada = new System.Windows.Forms.CheckBox();
this.lblPID = new System.Windows.Forms.Label();
this.btnSalvarPID = new System.Windows.Forms.Button();
this.txtKd = new System.Windows.Forms.TextBox();
this.lblKd = new System.Windows.Forms.Label();
this.txtKi = new System.Windows.Forms.TextBox();
this.lblKi = new System.Windows.Forms.Label();
this.txtKp = new System.Windows.Forms.TextBox();
this.lblKp = new System.Windows.Forms.Label();
this.lblRPM = new System.Windows.Forms.Label();
this.gpbMovimentacao = new System.Windows.Forms.GroupBox();
this.lblKmh = new System.Windows.Forms.Label();
this.trkKmh = new System.Windows.Forms.TrackBar();
this.trkRPM = new System.Windows.Forms.TrackBar();
this.lblRPM = new System.Windows.Forms.Label();
this.tkbAngulo = new System.Windows.Forms.TrackBar();
this.lblAngulo = new System.Windows.Forms.Label();
this.lblVelocidade = new System.Windows.Forms.Label();
@ -81,23 +68,36 @@ namespace AgroBase
this.gridSenMotores = new System.Windows.Forms.DataGridView();
this.btnDiagnosticos = new System.Windows.Forms.Button();
this.btnAcompanhamento = new System.Windows.Forms.Button();
this.btnCamera = new System.Windows.Forms.Button();
this.btnAtuCamera = new System.Windows.Forms.Button();
this.btnMapas = new System.Windows.Forms.Button();
this.btnSenCamera = new System.Windows.Forms.Button();
this.gpbJoystick = new System.Windows.Forms.GroupBox();
this.groupBox2 = new System.Windows.Forms.GroupBox();
this.gpbAtalhos = new System.Windows.Forms.GroupBox();
this.gpbOperacao = new System.Windows.Forms.GroupBox();
this.chbDebugMode = new System.Windows.Forms.CheckBox();
this.btnIniciarOperacao = new System.Windows.Forms.Button();
this.lblModoOperacao = new System.Windows.Forms.Label();
this.cmbModoOperacao = new System.Windows.Forms.ComboBox();
this.lblStripOperacao = new System.Windows.Forms.ToolStripStatusLabel();
this.lblStripOperacaoStatus = new System.Windows.Forms.ToolStripStatusLabel();
this.gpbAcoes.SuspendLayout();
this.erroStrip.SuspendLayout();
this.pnlLateral.SuspendLayout();
this.gpbDispositivos.SuspendLayout();
this.gpbNovoDispositivo.SuspendLayout();
this.joystickStrip.SuspendLayout();
this.gpbJoysticks.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.nudPPR)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.nudRampaMax)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.nudRampaMin)).BeginInit();
this.generalStrip.SuspendLayout();
this.gpbMovimentacao.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.trkKmh)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.trkRPM)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.tkbAngulo)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.tkbVelocidade)).BeginInit();
this.gpbSensoriamento.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.gridSenMotores)).BeginInit();
this.gpbJoystick.SuspendLayout();
this.groupBox2.SuspendLayout();
this.gpbAtalhos.SuspendLayout();
this.gpbOperacao.SuspendLayout();
this.SuspendLayout();
//
// gpbAcoes
@ -105,9 +105,9 @@ namespace AgroBase
this.gpbAcoes.Controls.Add(this.erroStrip);
this.gpbAcoes.Controls.Add(this.pnlLateral);
this.gpbAcoes.Dock = System.Windows.Forms.DockStyle.Right;
this.gpbAcoes.Location = new System.Drawing.Point(582, 0);
this.gpbAcoes.Location = new System.Drawing.Point(588, 0);
this.gpbAcoes.Name = "gpbAcoes";
this.gpbAcoes.Size = new System.Drawing.Size(829, 763);
this.gpbAcoes.Size = new System.Drawing.Size(823, 763);
this.gpbAcoes.TabIndex = 0;
this.gpbAcoes.TabStop = false;
this.gpbAcoes.Text = "Conexão";
@ -119,7 +119,7 @@ namespace AgroBase
this.lblStripErro});
this.erroStrip.Location = new System.Drawing.Point(3, 734);
this.erroStrip.Name = "erroStrip";
this.erroStrip.Size = new System.Drawing.Size(823, 26);
this.erroStrip.Size = new System.Drawing.Size(817, 26);
this.erroStrip.TabIndex = 1;
this.erroStrip.Text = "statusStrip1";
//
@ -141,7 +141,7 @@ namespace AgroBase
this.pnlLateral.Dock = System.Windows.Forms.DockStyle.Fill;
this.pnlLateral.Location = new System.Drawing.Point(3, 18);
this.pnlLateral.Name = "pnlLateral";
this.pnlLateral.Size = new System.Drawing.Size(823, 742);
this.pnlLateral.Size = new System.Drawing.Size(817, 742);
this.pnlLateral.TabIndex = 0;
//
// gpbDispositivos
@ -262,17 +262,19 @@ namespace AgroBase
this.btnNovoDispositivo.UseVisualStyleBackColor = true;
this.btnNovoDispositivo.Click += new System.EventHandler(this.btnNovoDispositivo_Click);
//
// joystickStrip
// generalStrip
//
this.joystickStrip.ImageScalingSize = new System.Drawing.Size(20, 20);
this.joystickStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.generalStrip.ImageScalingSize = new System.Drawing.Size(20, 20);
this.generalStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.lblStripJoystick,
this.lblStripJoystickComando});
this.joystickStrip.Location = new System.Drawing.Point(0, 737);
this.joystickStrip.Name = "joystickStrip";
this.joystickStrip.Size = new System.Drawing.Size(582, 26);
this.joystickStrip.TabIndex = 1;
this.joystickStrip.Text = "statusStrip1";
this.lblStripJoystickComando,
this.lblStripOperacao,
this.lblStripOperacaoStatus});
this.generalStrip.Location = new System.Drawing.Point(0, 737);
this.generalStrip.Name = "generalStrip";
this.generalStrip.Size = new System.Drawing.Size(588, 26);
this.generalStrip.TabIndex = 1;
this.generalStrip.Text = "statusStrip1";
//
// lblStripJoystick
//
@ -286,234 +288,63 @@ namespace AgroBase
this.lblStripJoystickComando.Size = new System.Drawing.Size(18, 20);
this.lblStripJoystickComando.Text = "...";
//
// gpbJoysticks
// gpbMovimentacao
//
this.gpbJoysticks.Controls.Add(this.lblPPR);
this.gpbJoysticks.Controls.Add(this.nudPPR);
this.gpbJoysticks.Controls.Add(this.lblRampaMax);
this.gpbJoysticks.Controls.Add(this.lblRampaMin);
this.gpbJoysticks.Controls.Add(this.nudRampaMax);
this.gpbJoysticks.Controls.Add(this.nudRampaMin);
this.gpbJoysticks.Controls.Add(this.chbMalhaFechada);
this.gpbJoysticks.Controls.Add(this.lblPID);
this.gpbJoysticks.Controls.Add(this.btnSalvarPID);
this.gpbJoysticks.Controls.Add(this.txtKd);
this.gpbJoysticks.Controls.Add(this.lblKd);
this.gpbJoysticks.Controls.Add(this.txtKi);
this.gpbJoysticks.Controls.Add(this.lblKi);
this.gpbJoysticks.Controls.Add(this.txtKp);
this.gpbJoysticks.Controls.Add(this.lblKp);
this.gpbJoysticks.Controls.Add(this.lblRPM);
this.gpbJoysticks.Controls.Add(this.trkRPM);
this.gpbJoysticks.Controls.Add(this.tkbAngulo);
this.gpbJoysticks.Controls.Add(this.lblAngulo);
this.gpbJoysticks.Controls.Add(this.lblVelocidade);
this.gpbJoysticks.Controls.Add(this.tkbVelocidade);
this.gpbJoysticks.Controls.Add(this.btnVer);
this.gpbJoysticks.Controls.Add(this.btnJoyAtt);
this.gpbJoysticks.Controls.Add(this.btnJoyEdt);
this.gpbJoysticks.Controls.Add(this.cmbJoysticks);
this.gpbJoysticks.Location = new System.Drawing.Point(12, 12);
this.gpbJoysticks.Name = "gpbJoysticks";
this.gpbJoysticks.Size = new System.Drawing.Size(440, 490);
this.gpbJoysticks.TabIndex = 2;
this.gpbJoysticks.TabStop = false;
this.gpbJoysticks.Text = "Controle";
this.gpbMovimentacao.Controls.Add(this.lblKmh);
this.gpbMovimentacao.Controls.Add(this.trkKmh);
this.gpbMovimentacao.Controls.Add(this.trkRPM);
this.gpbMovimentacao.Controls.Add(this.lblRPM);
this.gpbMovimentacao.Location = new System.Drawing.Point(12, 78);
this.gpbMovimentacao.Name = "gpbMovimentacao";
this.gpbMovimentacao.Size = new System.Drawing.Size(440, 105);
this.gpbMovimentacao.TabIndex = 2;
this.gpbMovimentacao.TabStop = false;
this.gpbMovimentacao.Text = "Controle Movimentação";
//
// lblPPR
// lblKmh
//
this.lblPPR.AutoSize = true;
this.lblPPR.Location = new System.Drawing.Point(336, 70);
this.lblPPR.Name = "lblPPR";
this.lblPPR.Size = new System.Drawing.Size(40, 17);
this.lblPPR.TabIndex = 36;
this.lblPPR.Text = "PPR:";
this.lblKmh.AutoSize = true;
this.lblKmh.Location = new System.Drawing.Point(221, 25);
this.lblKmh.Name = "lblKmh";
this.lblKmh.Size = new System.Drawing.Size(128, 17);
this.lblKmh.TabIndex = 23;
this.lblKmh.Text = "Velocidade: 3 km/h";
//
// nudPPR
// trkKmh
//
this.nudPPR.Location = new System.Drawing.Point(379, 67);
this.nudPPR.Maximum = new decimal(new int[] {
999,
0,
0,
0});
this.nudPPR.Minimum = new decimal(new int[] {
1,
0,
0,
0});
this.nudPPR.Name = "nudPPR";
this.nudPPR.Size = new System.Drawing.Size(55, 22);
this.nudPPR.TabIndex = 35;
this.nudPPR.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
this.nudPPR.Value = new decimal(new int[] {
40,
0,
0,
0});
this.nudPPR.ValueChanged += new System.EventHandler(this.nudPPR_ValueChanged);
this.trkKmh.Location = new System.Drawing.Point(224, 45);
this.trkKmh.Maximum = 34;
this.trkKmh.Name = "trkKmh";
this.trkKmh.Size = new System.Drawing.Size(210, 56);
this.trkKmh.TabIndex = 22;
this.trkKmh.TickFrequency = 2;
this.trkKmh.Value = 3;
this.trkKmh.ValueChanged += new System.EventHandler(this.trkKmh_ValueChanged);
//
// lblRampaMax
// trkRPM
//
this.lblRampaMax.AutoSize = true;
this.lblRampaMax.Location = new System.Drawing.Point(171, 70);
this.lblRampaMax.Name = "lblRampaMax";
this.lblRampaMax.Size = new System.Drawing.Size(86, 17);
this.lblRampaMax.TabIndex = 34;
this.lblRampaMax.Text = "Rampa Max:";
//
// lblRampaMin
//
this.lblRampaMin.AutoSize = true;
this.lblRampaMin.Location = new System.Drawing.Point(11, 70);
this.lblRampaMin.Name = "lblRampaMin";
this.lblRampaMin.Size = new System.Drawing.Size(83, 17);
this.lblRampaMin.TabIndex = 33;
this.lblRampaMin.Text = "Rampa Min:";
//
// nudRampaMax
//
this.nudRampaMax.Location = new System.Drawing.Point(260, 67);
this.nudRampaMax.Maximum = new decimal(new int[] {
9999,
0,
0,
0});
this.nudRampaMax.Name = "nudRampaMax";
this.nudRampaMax.Size = new System.Drawing.Size(66, 22);
this.nudRampaMax.TabIndex = 32;
this.nudRampaMax.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
this.nudRampaMax.Value = new decimal(new int[] {
1023,
0,
0,
0});
this.nudRampaMax.ValueChanged += new System.EventHandler(this.nudRampaMax_ValueChanged);
//
// nudRampaMin
//
this.nudRampaMin.Location = new System.Drawing.Point(97, 67);
this.nudRampaMin.Maximum = new decimal(new int[] {
9999,
0,
0,
0});
this.nudRampaMin.Name = "nudRampaMin";
this.nudRampaMin.Size = new System.Drawing.Size(66, 22);
this.nudRampaMin.TabIndex = 31;
this.nudRampaMin.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
this.nudRampaMin.ValueChanged += new System.EventHandler(this.nudRampaMin_ValueChanged);
//
// chbMalhaFechada
//
this.chbMalhaFechada.AutoSize = true;
this.chbMalhaFechada.Checked = true;
this.chbMalhaFechada.CheckState = System.Windows.Forms.CheckState.Checked;
this.chbMalhaFechada.Location = new System.Drawing.Point(307, 406);
this.chbMalhaFechada.Name = "chbMalhaFechada";
this.chbMalhaFechada.Size = new System.Drawing.Size(127, 21);
this.chbMalhaFechada.TabIndex = 30;
this.chbMalhaFechada.Text = "Malha Fechada";
this.chbMalhaFechada.UseVisualStyleBackColor = true;
this.chbMalhaFechada.CheckedChanged += new System.EventHandler(this.chbMalhaFechada_CheckedChanged);
//
// lblPID
//
this.lblPID.AutoSize = true;
this.lblPID.Location = new System.Drawing.Point(12, 407);
this.lblPID.Name = "lblPID";
this.lblPID.Size = new System.Drawing.Size(116, 17);
this.lblPID.TabIndex = 29;
this.lblPID.Text = "PID - Parâmetros";
//
// btnSalvarPID
//
this.btnSalvarPID.Location = new System.Drawing.Point(350, 453);
this.btnSalvarPID.Name = "btnSalvarPID";
this.btnSalvarPID.Size = new System.Drawing.Size(84, 25);
this.btnSalvarPID.TabIndex = 28;
this.btnSalvarPID.Text = "Salvar";
this.btnSalvarPID.UseVisualStyleBackColor = true;
this.btnSalvarPID.Click += new System.EventHandler(this.btnSalvarPID_Click);
//
// txtKd
//
this.txtKd.Location = new System.Drawing.Point(182, 454);
this.txtKd.Name = "txtKd";
this.txtKd.Size = new System.Drawing.Size(60, 22);
this.txtKd.TabIndex = 27;
this.txtKd.Text = "0,005";
this.txtKd.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// lblKd
//
this.lblKd.AutoSize = true;
this.lblKd.Location = new System.Drawing.Point(179, 434);
this.lblKd.Name = "lblKd";
this.lblKd.Size = new System.Drawing.Size(25, 17);
this.lblKd.TabIndex = 26;
this.lblKd.Text = "Kd";
//
// txtKi
//
this.txtKi.Location = new System.Drawing.Point(98, 454);
this.txtKi.Name = "txtKi";
this.txtKi.Size = new System.Drawing.Size(60, 22);
this.txtKi.TabIndex = 25;
this.txtKi.Text = "0,2";
this.txtKi.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// lblKi
//
this.lblKi.AutoSize = true;
this.lblKi.Location = new System.Drawing.Point(95, 434);
this.lblKi.Name = "lblKi";
this.lblKi.Size = new System.Drawing.Size(20, 17);
this.lblKi.TabIndex = 24;
this.lblKi.Text = "Ki";
//
// txtKp
//
this.txtKp.Location = new System.Drawing.Point(15, 454);
this.txtKp.Name = "txtKp";
this.txtKp.Size = new System.Drawing.Size(60, 22);
this.txtKp.TabIndex = 23;
this.txtKp.Text = "0,2";
this.txtKp.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// lblKp
//
this.lblKp.AutoSize = true;
this.lblKp.Location = new System.Drawing.Point(12, 434);
this.lblKp.Name = "lblKp";
this.lblKp.Size = new System.Drawing.Size(25, 17);
this.lblKp.TabIndex = 22;
this.lblKp.Text = "Kp";
this.trkRPM.Location = new System.Drawing.Point(6, 45);
this.trkRPM.Maximum = 500;
this.trkRPM.Minimum = 5;
this.trkRPM.Name = "trkRPM";
this.trkRPM.Size = new System.Drawing.Size(210, 56);
this.trkRPM.TabIndex = 20;
this.trkRPM.TickFrequency = 20;
this.trkRPM.Value = 5;
this.trkRPM.ValueChanged += new System.EventHandler(this.trkRPM_ValueChanged);
//
// lblRPM
//
this.lblRPM.AutoSize = true;
this.lblRPM.Location = new System.Drawing.Point(12, 328);
this.lblRPM.Location = new System.Drawing.Point(3, 25);
this.lblRPM.Name = "lblRPM";
this.lblRPM.Size = new System.Drawing.Size(54, 17);
this.lblRPM.TabIndex = 21;
this.lblRPM.Text = "RPM: 5";
//
// trkRPM
//
this.trkRPM.Location = new System.Drawing.Point(15, 348);
this.trkRPM.Maximum = 500;
this.trkRPM.Minimum = 5;
this.trkRPM.Name = "trkRPM";
this.trkRPM.Size = new System.Drawing.Size(419, 56);
this.trkRPM.TabIndex = 20;
this.trkRPM.TickFrequency = 10;
this.trkRPM.Value = 5;
this.trkRPM.ValueChanged += new System.EventHandler(this.trkRPM_ValueChanged);
//
// tkbAngulo
//
this.tkbAngulo.Location = new System.Drawing.Point(15, 196);
this.tkbAngulo.Location = new System.Drawing.Point(6, 117);
this.tkbAngulo.Maximum = 180;
this.tkbAngulo.Name = "tkbAngulo";
this.tkbAngulo.Size = new System.Drawing.Size(419, 56);
@ -524,7 +355,7 @@ namespace AgroBase
// lblAngulo
//
this.lblAngulo.AutoSize = true;
this.lblAngulo.Location = new System.Drawing.Point(12, 176);
this.lblAngulo.Location = new System.Drawing.Point(3, 97);
this.lblAngulo.Name = "lblAngulo";
this.lblAngulo.Size = new System.Drawing.Size(73, 17);
this.lblAngulo.TabIndex = 16;
@ -533,7 +364,7 @@ namespace AgroBase
// lblVelocidade
//
this.lblVelocidade.AutoSize = true;
this.lblVelocidade.Location = new System.Drawing.Point(12, 102);
this.lblVelocidade.Location = new System.Drawing.Point(3, 23);
this.lblVelocidade.Name = "lblVelocidade";
this.lblVelocidade.Size = new System.Drawing.Size(106, 17);
this.lblVelocidade.TabIndex = 15;
@ -541,7 +372,7 @@ namespace AgroBase
//
// tkbVelocidade
//
this.tkbVelocidade.Location = new System.Drawing.Point(15, 122);
this.tkbVelocidade.Location = new System.Drawing.Point(6, 43);
this.tkbVelocidade.Maximum = 100;
this.tkbVelocidade.Minimum = 1;
this.tkbVelocidade.Name = "tkbVelocidade";
@ -553,7 +384,7 @@ namespace AgroBase
//
// btnVer
//
this.btnVer.Location = new System.Drawing.Point(350, 29);
this.btnVer.Location = new System.Drawing.Point(341, 25);
this.btnVer.Name = "btnVer";
this.btnVer.Size = new System.Drawing.Size(84, 25);
this.btnVer.TabIndex = 13;
@ -563,7 +394,7 @@ namespace AgroBase
//
// btnJoyAtt
//
this.btnJoyAtt.Location = new System.Drawing.Point(170, 29);
this.btnJoyAtt.Location = new System.Drawing.Point(161, 25);
this.btnJoyAtt.Name = "btnJoyAtt";
this.btnJoyAtt.Size = new System.Drawing.Size(84, 25);
this.btnJoyAtt.TabIndex = 12;
@ -573,7 +404,7 @@ namespace AgroBase
//
// btnJoyEdt
//
this.btnJoyEdt.Location = new System.Drawing.Point(260, 29);
this.btnJoyEdt.Location = new System.Drawing.Point(251, 25);
this.btnJoyEdt.Name = "btnJoyEdt";
this.btnJoyEdt.Size = new System.Drawing.Size(84, 25);
this.btnJoyEdt.TabIndex = 11;
@ -585,7 +416,7 @@ namespace AgroBase
//
this.cmbJoysticks.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cmbJoysticks.FormattingEnabled = true;
this.cmbJoysticks.Location = new System.Drawing.Point(15, 30);
this.cmbJoysticks.Location = new System.Drawing.Point(6, 26);
this.cmbJoysticks.Name = "cmbJoysticks";
this.cmbJoysticks.Size = new System.Drawing.Size(148, 24);
this.cmbJoysticks.TabIndex = 3;
@ -633,7 +464,7 @@ namespace AgroBase
//
// btnDiagnosticos
//
this.btnDiagnosticos.Location = new System.Drawing.Point(458, 41);
this.btnDiagnosticos.Location = new System.Drawing.Point(6, 21);
this.btnDiagnosticos.Name = "btnDiagnosticos";
this.btnDiagnosticos.Size = new System.Drawing.Size(112, 25);
this.btnDiagnosticos.TabIndex = 14;
@ -643,7 +474,7 @@ namespace AgroBase
//
// btnAcompanhamento
//
this.btnAcompanhamento.Location = new System.Drawing.Point(458, 72);
this.btnAcompanhamento.Location = new System.Drawing.Point(6, 52);
this.btnAcompanhamento.Name = "btnAcompanhamento";
this.btnAcompanhamento.Size = new System.Drawing.Size(112, 25);
this.btnAcompanhamento.TabIndex = 15;
@ -651,19 +482,19 @@ namespace AgroBase
this.btnAcompanhamento.UseVisualStyleBackColor = true;
this.btnAcompanhamento.Click += new System.EventHandler(this.btnAcompanhamento_Click);
//
// btnCamera
// btnAtuCamera
//
this.btnCamera.Location = new System.Drawing.Point(458, 103);
this.btnCamera.Name = "btnCamera";
this.btnCamera.Size = new System.Drawing.Size(112, 25);
this.btnCamera.TabIndex = 16;
this.btnCamera.Text = "Câmeras";
this.btnCamera.UseVisualStyleBackColor = true;
this.btnCamera.Click += new System.EventHandler(this.btnCamera_Click);
this.btnAtuCamera.Location = new System.Drawing.Point(6, 83);
this.btnAtuCamera.Name = "btnAtuCamera";
this.btnAtuCamera.Size = new System.Drawing.Size(112, 25);
this.btnAtuCamera.TabIndex = 16;
this.btnAtuCamera.Text = "Ver solo";
this.btnAtuCamera.UseVisualStyleBackColor = true;
this.btnAtuCamera.Click += new System.EventHandler(this.btnCamera_Click);
//
// btnMapas
//
this.btnMapas.Location = new System.Drawing.Point(458, 134);
this.btnMapas.Location = new System.Drawing.Point(6, 145);
this.btnMapas.Name = "btnMapas";
this.btnMapas.Size = new System.Drawing.Size(112, 25);
this.btnMapas.TabIndex = 17;
@ -671,18 +502,132 @@ namespace AgroBase
this.btnMapas.UseVisualStyleBackColor = true;
this.btnMapas.Click += new System.EventHandler(this.btnMapas_Click);
//
// btnSenCamera
//
this.btnSenCamera.Location = new System.Drawing.Point(6, 114);
this.btnSenCamera.Name = "btnSenCamera";
this.btnSenCamera.Size = new System.Drawing.Size(112, 25);
this.btnSenCamera.TabIndex = 18;
this.btnSenCamera.Text = "Ver caminho";
this.btnSenCamera.UseVisualStyleBackColor = true;
this.btnSenCamera.Click += new System.EventHandler(this.btnSenCamera_Click);
//
// gpbJoystick
//
this.gpbJoystick.Controls.Add(this.cmbJoysticks);
this.gpbJoystick.Controls.Add(this.btnJoyEdt);
this.gpbJoystick.Controls.Add(this.btnJoyAtt);
this.gpbJoystick.Controls.Add(this.btnVer);
this.gpbJoystick.Location = new System.Drawing.Point(12, 12);
this.gpbJoystick.Name = "gpbJoystick";
this.gpbJoystick.Size = new System.Drawing.Size(440, 60);
this.gpbJoystick.TabIndex = 18;
this.gpbJoystick.TabStop = false;
this.gpbJoystick.Text = "Joystick";
//
// groupBox2
//
this.groupBox2.Controls.Add(this.tkbVelocidade);
this.groupBox2.Controls.Add(this.tkbAngulo);
this.groupBox2.Controls.Add(this.lblAngulo);
this.groupBox2.Controls.Add(this.lblVelocidade);
this.groupBox2.Location = new System.Drawing.Point(12, 189);
this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(440, 183);
this.groupBox2.TabIndex = 19;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "Controle Direcional";
//
// gpbAtalhos
//
this.gpbAtalhos.Controls.Add(this.btnDiagnosticos);
this.gpbAtalhos.Controls.Add(this.btnAcompanhamento);
this.gpbAtalhos.Controls.Add(this.btnSenCamera);
this.gpbAtalhos.Controls.Add(this.btnAtuCamera);
this.gpbAtalhos.Controls.Add(this.btnMapas);
this.gpbAtalhos.Location = new System.Drawing.Point(458, 12);
this.gpbAtalhos.Name = "gpbAtalhos";
this.gpbAtalhos.Size = new System.Drawing.Size(124, 360);
this.gpbAtalhos.TabIndex = 20;
this.gpbAtalhos.TabStop = false;
this.gpbAtalhos.Text = "Atalhos";
//
// gpbOperacao
//
this.gpbOperacao.Controls.Add(this.chbDebugMode);
this.gpbOperacao.Controls.Add(this.btnIniciarOperacao);
this.gpbOperacao.Controls.Add(this.lblModoOperacao);
this.gpbOperacao.Controls.Add(this.cmbModoOperacao);
this.gpbOperacao.Location = new System.Drawing.Point(12, 378);
this.gpbOperacao.Name = "gpbOperacao";
this.gpbOperacao.Size = new System.Drawing.Size(570, 124);
this.gpbOperacao.TabIndex = 21;
this.gpbOperacao.TabStop = false;
this.gpbOperacao.Text = "Operação";
//
// chbDebugMode
//
this.chbDebugMode.AutoSize = true;
this.chbDebugMode.Location = new System.Drawing.Point(179, 49);
this.chbDebugMode.Name = "chbDebugMode";
this.chbDebugMode.Size = new System.Drawing.Size(139, 21);
this.chbDebugMode.TabIndex = 14;
this.chbDebugMode.Text = "Modo Depuração";
this.chbDebugMode.UseVisualStyleBackColor = true;
//
// btnIniciarOperacao
//
this.btnIniciarOperacao.Location = new System.Drawing.Point(9, 77);
this.btnIniciarOperacao.Name = "btnIniciarOperacao";
this.btnIniciarOperacao.Size = new System.Drawing.Size(145, 41);
this.btnIniciarOperacao.TabIndex = 13;
this.btnIniciarOperacao.Text = "Iniciar Operação";
this.btnIniciarOperacao.UseVisualStyleBackColor = true;
this.btnIniciarOperacao.Click += new System.EventHandler(this.btnIniciarOperacao_Click);
//
// lblModoOperacao
//
this.lblModoOperacao.AutoSize = true;
this.lblModoOperacao.Location = new System.Drawing.Point(6, 27);
this.lblModoOperacao.Name = "lblModoOperacao";
this.lblModoOperacao.Size = new System.Drawing.Size(43, 17);
this.lblModoOperacao.TabIndex = 13;
this.lblModoOperacao.Text = "Modo";
//
// cmbModoOperacao
//
this.cmbModoOperacao.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cmbModoOperacao.FormattingEnabled = true;
this.cmbModoOperacao.Location = new System.Drawing.Point(9, 47);
this.cmbModoOperacao.Name = "cmbModoOperacao";
this.cmbModoOperacao.Size = new System.Drawing.Size(145, 24);
this.cmbModoOperacao.TabIndex = 13;
this.cmbModoOperacao.SelectedIndexChanged += new System.EventHandler(this.cmbModoOperacao_SelectedIndexChanged);
//
// lblStripOperacao
//
this.lblStripOperacao.Name = "lblStripOperacao";
this.lblStripOperacao.Size = new System.Drawing.Size(130, 20);
this.lblStripOperacao.Text = "Operação: Manual";
//
// lblStripOperacaoStatus
//
this.lblStripOperacaoStatus.Name = "lblStripOperacaoStatus";
this.lblStripOperacaoStatus.Size = new System.Drawing.Size(94, 20);
this.lblStripOperacaoStatus.Text = "Não iniciado";
//
// frmPrincipal
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(1411, 763);
this.Controls.Add(this.btnMapas);
this.Controls.Add(this.btnCamera);
this.Controls.Add(this.btnAcompanhamento);
this.Controls.Add(this.btnDiagnosticos);
this.Controls.Add(this.gpbJoysticks);
this.Controls.Add(this.gpbOperacao);
this.Controls.Add(this.gpbAtalhos);
this.Controls.Add(this.groupBox2);
this.Controls.Add(this.gpbJoystick);
this.Controls.Add(this.gpbMovimentacao);
this.Controls.Add(this.gpbSensoriamento);
this.Controls.Add(this.joystickStrip);
this.Controls.Add(this.generalStrip);
this.Controls.Add(this.gpbAcoes);
this.Name = "frmPrincipal";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
@ -699,19 +644,23 @@ namespace AgroBase
this.gpbDispositivos.ResumeLayout(false);
this.gpbNovoDispositivo.ResumeLayout(false);
this.gpbNovoDispositivo.PerformLayout();
this.joystickStrip.ResumeLayout(false);
this.joystickStrip.PerformLayout();
this.gpbJoysticks.ResumeLayout(false);
this.gpbJoysticks.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.nudPPR)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.nudRampaMax)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.nudRampaMin)).EndInit();
this.generalStrip.ResumeLayout(false);
this.generalStrip.PerformLayout();
this.gpbMovimentacao.ResumeLayout(false);
this.gpbMovimentacao.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.trkKmh)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.trkRPM)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.tkbAngulo)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.tkbVelocidade)).EndInit();
this.gpbSensoriamento.ResumeLayout(false);
this.gpbSensoriamento.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.gridSenMotores)).EndInit();
this.gpbJoystick.ResumeLayout(false);
this.groupBox2.ResumeLayout(false);
this.groupBox2.PerformLayout();
this.gpbAtalhos.ResumeLayout(false);
this.gpbOperacao.ResumeLayout(false);
this.gpbOperacao.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
@ -730,8 +679,8 @@ namespace AgroBase
private System.Windows.Forms.Button btnRemover;
private System.Windows.Forms.Label lblDispositivos;
private System.Windows.Forms.StatusStrip erroStrip;
private System.Windows.Forms.StatusStrip joystickStrip;
private System.Windows.Forms.GroupBox gpbJoysticks;
private System.Windows.Forms.StatusStrip generalStrip;
private System.Windows.Forms.GroupBox gpbMovimentacao;
private System.Windows.Forms.Button btnJoyEdt;
public System.Windows.Forms.ToolStripStatusLabel lblStripErro;
public System.Windows.Forms.ToolStripStatusLabel lblStripJoystick;
@ -746,32 +695,30 @@ namespace AgroBase
private System.Windows.Forms.TrackBar tkbAngulo;
private System.Windows.Forms.Label lblAngulo;
private System.Windows.Forms.GroupBox gpbSensoriamento;
private System.Windows.Forms.Label lblSenMotores;
public System.Windows.Forms.DataGridView gridSenMotores;
private System.Windows.Forms.Label lblRPM;
private System.Windows.Forms.Button btnDiagnosticos;
public System.Windows.Forms.TrackBar trkRPM;
private System.Windows.Forms.ToolStripStatusLabel lblStripJoystickComando;
private System.Windows.Forms.Label lblPID;
private System.Windows.Forms.Button btnSalvarPID;
private System.Windows.Forms.TextBox txtKd;
private System.Windows.Forms.Label lblKd;
private System.Windows.Forms.TextBox txtKi;
private System.Windows.Forms.Label lblKi;
private System.Windows.Forms.TextBox txtKp;
private System.Windows.Forms.Label lblKp;
public System.Windows.Forms.CheckBox chbMalhaFechada;
private System.Windows.Forms.Label lblRampaMax;
private System.Windows.Forms.Label lblRampaMin;
private System.Windows.Forms.NumericUpDown nudRampaMax;
private System.Windows.Forms.NumericUpDown nudRampaMin;
private System.Windows.Forms.Label lblPPR;
private System.Windows.Forms.NumericUpDown nudPPR;
public System.Windows.Forms.ComboBox cmbJoysticks;
public System.Windows.Forms.ComboBox cmbDispositivos;
private System.Windows.Forms.Button btnAcompanhamento;
private System.Windows.Forms.Button btnCamera;
private System.Windows.Forms.Button btnAtuCamera;
private System.Windows.Forms.Button btnMapas;
private System.Windows.Forms.Button btnSenCamera;
private System.Windows.Forms.GroupBox gpbJoystick;
private System.Windows.Forms.Label lblSenMotores;
public System.Windows.Forms.DataGridView gridSenMotores;
private System.Windows.Forms.GroupBox groupBox2;
private System.Windows.Forms.GroupBox gpbAtalhos;
private System.Windows.Forms.GroupBox gpbOperacao;
private System.Windows.Forms.Label lblModoOperacao;
private System.Windows.Forms.ComboBox cmbModoOperacao;
private System.Windows.Forms.Button btnIniciarOperacao;
private System.Windows.Forms.CheckBox chbDebugMode;
private System.Windows.Forms.Label lblKmh;
public System.Windows.Forms.TrackBar trkKmh;
private System.Windows.Forms.ToolStripStatusLabel lblStripOperacao;
private System.Windows.Forms.ToolStripStatusLabel lblStripOperacaoStatus;
}
}

View File

@ -1,6 +1,8 @@
using AgroBase.Comum;
using AgroBase.Forms;
using AgroBase.Forms.Movimentacao;
using AgroBase.Forms.Operacoes;
using AgroBase.Forms.Sensoriamento;
using AgroBase.Models;
using AgroBase.Models.Modules;
using AgroBase.Services;
@ -17,7 +19,6 @@ namespace AgroBase
{
public partial class frmPrincipal : Form
{
public static List<DispositivosService> Dispositivos = new List<DispositivosService>();
public frmPrincipal()
{
@ -28,24 +29,27 @@ namespace AgroBase
{
timerDispositivos.Enabled = true;
AtualizaDadosGerais();
}
//InstanciaJoystick();
private void frmPrincipal_FormClosing(object sender, FormClosingEventArgs e)
{
foreach (var Disp in Variaveis.DispositivosConectados)
{
Disp.SalvarParametros(Disp.Dados);
}
}
public void AtualizaDadosGerais()
{
btnJoyAtt_Click(new object(), new EventArgs());
nudRampaMin.Value = MovimentacaoModel.RampaMin;
nudRampaMax.Value = MovimentacaoModel.RampaMax;
nudPPR.Value = MovimentacaoModel.PulsosPorRevolucao;
tkbVelocidade.Value = GeneralJoystick.Velocidade;
tkbAngulo.Value = Convert.ToInt32(GeneralJoystick.Angulo);
trkRPM.Value = GeneralJoystick.RPM;
chbMalhaFechada.Checked = MovimentacaoModel._FOC;
txtKd.Text = MovimentacaoModel.Kd.ToString();
txtKp.Text = MovimentacaoModel.Kp.ToString();
txtKi.Text = MovimentacaoModel.Ki.ToString();
cmbModoOperacao.Items.Clear();
cmbModoOperacao.Items.AddRange(Enum.GetNames(typeof(ModoOperacao)));
cmbModoOperacao.SelectedIndex = (int)Variaveis.OperacaoEmAndamento.Modo;
}
private void btnNovoDispositivo_Click(object sender, EventArgs e)
@ -59,33 +63,35 @@ namespace AgroBase
private void btnSalvar_Click(object sender, EventArgs e)
{
Dispositivos.Add(new DispositivosService()
{
Dispositivo = (T_Code)Enum.Parse(typeof(T_Code), cmbTipos.Text),
_Nome = cmbTipos.Text,
_Descricao = txtDescricao.Text,
_Porta = new SerialPort(),
});
T_Code tipoDispositivo = (T_Code)Enum.Parse(typeof(T_Code), cmbTipos.Text);
IDispositivosService dispositivoService = DispositivosServiceFactory.CreateDispositivoService(
tipoDispositivo,
cmbTipos.Text,
txtDescricao.Text,
new SerialPort()
);
Control controle = Dispositivos[Dispositivos.Count - 1].InstanciarDispositivo(Dispositivos.Count - 1);
Variaveis.DispositivosConectados.Add(dispositivoService);
Control controle = dispositivoService.InstanciarDispositivo(Variaveis.DispositivosConectados.Count - 1);
controle.Location = new System.Drawing.Point(controle.Location.X, controle.Location.Y + (cmbDispositivos.Items.Count * 50));
pnlLateral.Controls.Add(controle);
cmbDispositivos.Items.Add(Dispositivos[Dispositivos.Count - 1]._Descricao);
cmbDispositivos.Items.Add(dispositivoService._Descricao);
gpbNovoDispositivo.Enabled = false;
cmbDispositivos.SelectedIndex = Dispositivos.Count - 1;
cmbDispositivos.SelectedIndex = Variaveis.DispositivosConectados.Count - 1;
}
private void btnRemover_Click(object sender, EventArgs e)
{
if (cmbDispositivos.Items.Count > 0)
{
pnlLateral.Controls.Remove(Dispositivos[cmbDispositivos.SelectedIndex].gpbItem);
Dispositivos.RemoveAt(cmbDispositivos.SelectedIndex);
pnlLateral.Controls.Remove(Variaveis.DispositivosConectados[cmbDispositivos.SelectedIndex].gpbItem);
Variaveis.DispositivosConectados.RemoveAt(cmbDispositivos.SelectedIndex);
cmbDispositivos.Items.RemoveAt(cmbDispositivos.SelectedIndex);
cmbDispositivos.SelectedIndex = Dispositivos.Count - 1;
cmbDispositivos.SelectedIndex = Variaveis.DispositivosConectados.Count - 1;
int idx = 0;
Dispositivos.ForEach(Dispositivo =>
Variaveis.DispositivosConectados.ForEach(Dispositivo =>
{
Dispositivo.AtualizaIndex(idx);
idx++;
@ -117,19 +123,26 @@ namespace AgroBase
SerialService.DispositivosConectados
.Select(x => new ListViewItem()
{
Text = x.PortaCOM + " - " + Enum.GetName(typeof(T_Code), x.Dispositivo) + " - " + (Dispositivos.FirstOrDefault(y => y.PortaCOM() == x.PortaCOM)?.StatusPorta() ?? "Desconectado")
Text = x.PortaCOM + " - " + Enum.GetName(typeof(T_Code), x.Dispositivo) + " - " + (Variaveis.DispositivosConectados.FirstOrDefault(y => y.PortaCOM() == x.PortaCOM)?.StatusPorta() ?? "Desconectado")
}).ToArray()
);
if (SerialService.DispositivosConectados.Count == 0)
{
Dispositivos.Where(x => x.Dados.GetStatusConexao()).ToList().ForEach(x => x.AcaoDesconectar());
Variaveis.DispositivosConectados.Where(x => x.Dados.GetStatusConexao()).ToList().ForEach(x => x.AcaoDesconectar());
}
SerialService.AtualizarDispositivos();
}
private void frmPrincipal_FormClosed(object sender, FormClosedEventArgs e)
{
Environment.Exit(0);
try
{
Environment.Exit(0);
}
catch
{
}
}
private void btnDiagnosticos_Click(object sender, EventArgs e)
@ -142,58 +155,23 @@ namespace AgroBase
{
if (valor >= trkRPM.Minimum && valor <= trkRPM.Maximum)
{
double Velocidade = MovimentacaoModel.CalculaVelocidadeRPM(valor);
trkRPM.Value = valor;
trkKmh.Value = Convert.ToInt32(Velocidade);
GeneralJoystick.RPM = trkRPM.Value;
lblRPM.Text = "RPM: " + GeneralJoystick.RPM;
lblKmh.Text = "Velocidade: " + Velocidade.ToString("0.00") + " km/h";
}
}
private void btnSalvarPID_Click(object sender, EventArgs e)
{
if (double.TryParse(txtKp.Text, out double kp))
{
MovimentacaoModel.Kp = kp;
}
if (double.TryParse(txtKi.Text, out double ki))
{
MovimentacaoModel.Ki = ki;
}
if (double.TryParse(txtKd.Text, out double kd))
{
MovimentacaoModel.Kd = kd;
}
}
private void chbMalhaFechada_CheckedChanged(object sender, EventArgs e)
{
MovimentacaoModel._FOC = chbMalhaFechada.Checked;
txtKp.Enabled = MovimentacaoModel._FOC;
txtKi.Enabled = MovimentacaoModel._FOC;
txtKd.Enabled = MovimentacaoModel._FOC;
btnSalvarPID.Enabled = MovimentacaoModel._FOC;
}
private void btnMovConfig_Click(object sender, EventArgs e)
{
frmMovConfig frm = new frmMovConfig();
frm.ShowDialog();
}
private void nudRampaMin_ValueChanged(object sender, EventArgs e)
{
MovimentacaoModel.RampaMin = Convert.ToInt32(nudRampaMin.Value);
}
private void nudRampaMax_ValueChanged(object sender, EventArgs e)
{
MovimentacaoModel.RampaMax = Convert.ToInt32(nudRampaMax.Value);
}
private void nudPPR_ValueChanged(object sender, EventArgs e)
{
MovimentacaoModel.PulsosPorRevolucao = Convert.ToInt32(nudPPR.Value);
}
private void cmbDispositivos_SelectedIndexChanged(object sender, EventArgs e)
{
@ -215,17 +193,17 @@ namespace AgroBase
private void trkRPM_ValueChanged(object sender, EventArgs e)
{
AtualizaRPM(((TrackBar)sender).Value);
int RPM = ((TrackBar)sender).Value;
AtualizaRPM(RPM);
}
private void frmPrincipal_FormClosing(object sender, FormClosingEventArgs e)
private void trkKmh_ValueChanged(object sender, EventArgs e)
{
foreach (var Disp in Dispositivos)
{
Disp.SalvarParametros(Disp.Dados);
}
int RPM = Convert.ToInt32(MovimentacaoModel.CalculaRPMVelocidade(((TrackBar)sender).Value));
AtualizaRPM(RPM);
}
private void btnAcompanhamento_Click(object sender, EventArgs e)
{
frmInstancial.frmAcompanhamento.Show();
@ -233,7 +211,7 @@ namespace AgroBase
private void btnCamera_Click(object sender, EventArgs e)
{
frmCamera frmCamera = new frmCamera();
frmAtuCamera frmCamera = new frmAtuCamera();
frmCamera.Show();
}
@ -242,5 +220,85 @@ namespace AgroBase
frmMapa frmMapa = new frmMapa();
frmMapa.Show();
}
private void btnSenCamera_Click(object sender, EventArgs e)
{
frmSenCamera frmCamera = new frmSenCamera();
frmCamera.Show();
}
private void cmbModoOperacao_SelectedIndexChanged(object sender, EventArgs e)
{
Variaveis.OperacaoEmAndamento.Modo = (ModoOperacao)cmbModoOperacao.SelectedIndex;
}
private void btnIniciarOperacao_Click(object sender, EventArgs e)
{
bool DebugMode = chbDebugMode.Checked;
string MensagemErro = "";
bool MovConectado = Variaveis.DispositivosConectados.Any(x => x.Dispositivo == T_Code.Mov && (x._Porta.IsOpen || DebugMode));
bool DirConectado = Variaveis.DispositivosConectados.Any(x => x.Dispositivo == T_Code.Dir && (x._Porta.IsOpen || DebugMode));
bool AtuConectado = Variaveis.DispositivosConectados.Any(x => x.Dispositivo == T_Code.Atu && (x._Porta.IsOpen || DebugMode));
if (Variaveis.OperacaoEmAndamento.Iniciado)
{
Variaveis.OperacaoEmAndamento.FinalizarOperacao();
btnIniciarOperacao.Text = "Iniciar Operação";
cmbModoOperacao.Enabled = true;
}
else
{
if (Variaveis.OperacaoEmAndamento.Modo == ModoOperacao.Manual)
{
if (MovConectado || DirConectado || AtuConectado)
{
Variaveis.OperacaoEmAndamento.IniciarOperacao();
cmbModoOperacao.Enabled = false;
}
else
{
MensagemErro = "Para iniciar a operação " + Enum.GetName(typeof(ModoOperacao), Variaveis.OperacaoEmAndamento.Modo) +
", é necessário que ao menos um dos seguintes módulos estejam devidamente conectados ao equipamento:\r\n" +
"Movimentação: ( " + (MovConectado ? "OK" : " ") + " )\r\n" +
"Direcional: ( " + (DirConectado ? "OK" : " ") + " )\r\n" +
"Atuador: ( " + (AtuConectado ? "OK" : " ") + " )";
}
}
else if (Variaveis.OperacaoEmAndamento.Modo == ModoOperacao.SeguidorDeLinha)
{
if (MovConectado && DirConectado && AtuConectado)
{
frmOperacaoSeguidorLinha frmSeguidorLinha = new frmOperacaoSeguidorLinha();
frmSeguidorLinha.Show();
}
else
{
MensagemErro = "Para iniciar a operação " + Enum.GetName(typeof(ModoOperacao), Variaveis.OperacaoEmAndamento.Modo) +
", é necessário que os seguintes módulos estejam devidamente conectados ao equipamento:\r\n" +
"Movimentação: ( " + (MovConectado ? "OK" : " ") + " )\r\n" +
"Direcional: ( " + (DirConectado ? "OK" : " ") + " )\r\n" +
"Atuador: ( " + (AtuConectado ? "OK" : " ") + " )";
}
}
if (MensagemErro != "")
{
MessageBox.Show(MensagemErro, "Conexão de módulos pendentes", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
btnIniciarOperacao.Text = "Finalizar Operação";
}
lblStripOperacao.Text = "Operação: " + Enum.GetName(typeof(ModoOperacao), Variaveis.OperacaoEmAndamento.Modo);
lblStripOperacaoStatus.Text = Variaveis.OperacaoEmAndamento.Iniciado ? "Iniciado" : "Não iniciado";
}
}
}

View File

@ -120,14 +120,11 @@
<metadata name="erroStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>11, 10</value>
</metadata>
<metadata name="erroStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>11, 10</value>
</metadata>
<metadata name="joystickStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>93, 10</value>
<metadata name="generalStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>133, 16</value>
</metadata>
<metadata name="timerDispositivos.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>227, 12</value>
<value>266, 15</value>
</metadata>
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>59</value>

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

View File

@ -17,8 +17,10 @@ namespace AgroBase.Models
public class CameraCoordenadasFrameModel
{
public long timestamp { get; set; }
public List<CameraCoordenadasObjetoModel> objetos { get; set; }
public double timestamp { get; set; }
public double x_max { get; set; }
public double y_max { get; set; }
public CameraCoordenadasObjetoModel[] objetos { get; set; }
}
public class CameraCoordenadasObjetoModel
@ -32,4 +34,12 @@ namespace AgroBase.Models
public double confianca { get; set; }
}
public class CameraAnguloModel
{
public double timestamp { get; set; }
public double angulo { get; set; }
public int distancia_esquerda { get; set; }
public int distancia_direita { get; set; }
}
}

View File

@ -71,6 +71,7 @@ namespace AgroBase.Models
sENC,
sCOR,
sTEN,
sFLX,
}
public enum BotoesJoystick
@ -102,5 +103,13 @@ namespace AgroBase.Models
Vazio
}
public enum ModoOperacao
{
Manual,
SeguidorDeLinha,
MapaGPS,
Remoto
}
}
}

View File

@ -11,6 +11,7 @@ using System.Threading.Tasks;
using Windows.Gaming.Input;
using AgroBase.Models.Modules;
using SharpDX.DirectInput;
using AgroBase.Services;
namespace AgroBase
{
@ -36,19 +37,18 @@ namespace AgroBase
public static Direcao UltimaDirecao = Direcao.Parado;
public static bool Pressionado = false;
public static List<DispositivosService> DispCon;
public static List<IDispositivosService> DispCon;
public static int RPM { get; set; } = 15;
public static int RPM { get; set; } = 30;
public static double Angulo { get; set; } = 20;
public static int Velocidade { get; set; } = 15;
public static int Velocidade { get; set; } = 50;
public static Timer tmrJoystick = new Timer() { Interval = 100, Enabled = false };
public static void AtualizaDispositivo()
{
DispCon = frmPrincipal.Dispositivos.Where(x => x._Porta.IsOpen).ToList();
DispCon = Variaveis.DispositivosConectados.Where(x => x._Porta.IsOpen).ToList();
frmInstancial.frmJoystick.lblDispositivo.Text = "Dispositivos: " + (DispCon.Count == 0 ? "N/A" : string.Join(", ", DispCon.Select(x => x._Descricao + " (" + Enum.GetName(typeof(T_Code), x.Dispositivo) + ")").ToArray()));
frmInstancial.frmPrincipal.cmbJoysticks.Items.Clear();
@ -458,7 +458,7 @@ namespace AgroBase
public static void EnviaComandoMotor(Keys Tecla, T_Code? Disp = null)
{
if (DispCon.Count == 0)
if (DispCon.Count == 0 || Variaveis.OperacaoEmAndamento.Modo != ModoOperacao.Manual || !Variaveis.OperacaoEmAndamento.Iniciado)
{
return;
}
@ -540,7 +540,7 @@ namespace AgroBase
for (int i = 0; i < 1; i++)
{
DispositivosService Dispositivo = DispCon.FirstOrDefault(x => x.Dispositivo == Comando.Dispositivo);
var Dispositivo = DispCon.FirstOrDefault(x => x.Dispositivo == Comando.Dispositivo);
if (Dispositivo != null)
{
var Protocolos =

View File

@ -0,0 +1,214 @@
using AgroBase.Services;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static AgroBase.Models.Enuns;
namespace AgroBase.Models.Modules
{
public class AtuadorModel : DispositivoBaseModel
{
public static int _TaxaAmostragem { get; set; } = 500;
public bool Conectado { get; set; } = false;
public static List<PinoutModel> Pinout { get; set; }
public static List<FuncoesPinout> Funcoes { get; set; } = new List<FuncoesPinout>() { FuncoesPinout.Geral };
public int QuantidadeBicos { get; set; } = 10;
public List<AtuadorBicoModel> BicosPulverizadores { get; set; } = new List<AtuadorBicoModel>();
public double PercentualInicioPulverizacao { get; set; } = 0.3;
public double PercentualReservatorio { get; set; } = 0;
public static AtuadorModel CarregarParametrosIniciais()
{
AtuadorModel Atuador = new AtuadorModel()
{
QuantidadeBicos = 10,
Conectado = false,
BicosPulverizadores = new List<AtuadorBicoModel>()
};
for (int i = 0; i < Atuador.QuantidadeBicos; i++)
{
Atuador.BicosPulverizadores.Add(new AtuadorBicoModel()
{
ID = "B" + (i + 1).ToString("00"),
Posicao = i + 1,
Comandar = false,
Atuado = false,
Funcoes = new List<FuncoesPinout>()
{
FuncoesPinout.Solenoide,
FuncoesPinout.Fluxo
},
StatusBico = false,
NivelFluxo = 0
});
}
return Atuador;
}
public List<string> ProtocoloConfiguracao(bool Conectar)
{
List<string> Config = BicosPulverizadores.Select(x => x.ProtocoloConfiguracaoBico(Conectar)).ToList();
string ProtocoloMOD = ((int)F_Code.Cfg).ToString() +
"MD " + ";" + // 0 ~ 2
(Conectar ? "1" : "0") + ";" + // 4
_TaxaAmostragem.ToString("00000") + ";" + // 6 ~ 10
(Pinout.Any(x => x.Funcao == FuncoesPinout.Geral) ? Pinout.FirstOrDefault(x => x.Funcao == FuncoesPinout.Geral).Pino.ToString("00") : "-1"); // 12 ~ 13
Config.Add(ProtocoloMOD);
return Config;
}
public void RecebeProtocoloSerial(string Protocolo)
{
// #ET;00000;00000;00000;000
if (!string.IsNullOrEmpty(Protocolo) && Protocolo[0].ToString() == SerialService.BeginSensor)
{
string[] Dados = Protocolo.Replace(SerialService.BeginSensor, "").Split(SerialService.EndLine[0])[0].Split(';');
S_Code TipoSensor = (S_Code)(int.Parse(Dados[0]));
AtuadorBicoModel Bico = BicosPulverizadores.FirstOrDefault(x => x.ID == Dados[1]);
if (Bico == null)
{
if (Dados[1] == "MD ")
{
Conectado = Dados[2] == "1";
}
return;
}
try
{
switch (TipoSensor)
{
case S_Code.sFLX:
{
Bico.StatusBico = Dados[2] == "1";
double nivelFluxo = 0;
double.TryParse(Dados[3].Replace(".", ","), out nivelFluxo);
Bico.NivelFluxo = nivelFluxo;
break;
}
case S_Code.sTST:
{
bool testando = Dados[1] == "1";
Bico.Testando = testando;
break;
}
case S_Code.sCFG:
{
Bico.Inicializado = Dados[2] == "1";
break;
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
public string GetTaxaAmostragem()
{
return _TaxaAmostragem.ToString("00000");
}
public void SetTaxaAmostragem(int TaxaAmostragem)
{
_TaxaAmostragem = TaxaAmostragem;
}
public bool GetStatusConexao()
{
return Conectado;
}
public void PopulaGridSensoriamento()
{
}
public void AtualizaGridSensoriamento()
{
}
public List<PinoutModel> CarregarPinout(string nomeArquivo)
{
if (!File.Exists(nomeArquivo))
{
var newPinout = PinoutModel.CarregarPinoutPadrao();
File.WriteAllText(nomeArquivo, JsonConvert.SerializeObject(newPinout));
}
var pinoutText = File.ReadAllText(nomeArquivo);
Pinout = JsonConvert.DeserializeObject<PinoutModel[]>(pinoutText).ToList();
return Pinout;
}
public void SalvarPinout(List<PinoutModel> newPinout, string nomeArquivo)
{
File.WriteAllText(nomeArquivo, JsonConvert.SerializeObject(newPinout));
}
public void IniciarRegistrador()
{
}
}
public class AtuadorBicoModel
{
public string ID { get; set; }
public int Posicao { get; set; }
public bool Atuado { get; set; }
public bool Comandar { get; set; }
public bool Inicializado { get; set; }
public bool Testando { get; set; }
public List<FuncoesPinout> Funcoes { get; set; }
public bool StatusBico { get; set; }
public double NivelFluxo { get; set; }
public string ProtocoloConfiguracaoBico(bool Conectar)
{
var _pinout = AtuadorModel.Pinout.Where(x => x.ComponenteID == ID).ToList();
return ((int)F_Code.Cfg).ToString() +
ID + ";" + // 0 ~ 2
(Conectar ? "1" : "0") + ";" + // 4
(Comandar ? "1" : "0") + ";" + // 6
Posicao.ToString("00") + ";" + // 8 ~ 9
(_pinout.Any(x => x.Funcao == FuncoesPinout.Solenoide) ? _pinout.FirstOrDefault(x => x.Funcao == FuncoesPinout.Solenoide).Pino.ToString("00") : "-1") + "," + // 11 ~ 12
(_pinout.Any(x => x.Funcao == FuncoesPinout.Fluxo) ? _pinout.FirstOrDefault(x => x.Funcao == FuncoesPinout.Fluxo).Pino.ToString("00") : "-1"); // 14 ~ 15
}
public string ProtocoloComando()
{
if (Comandar)
{
string ProtocoloBico =
((int)F_Code.Cmd).ToString() +
ID + ";" + // 0 ~ 2
(Atuado ? "1" : "0"); // 4
return ProtocoloBico;
}
return "";
}
public string ProtocoloTeste()
{
if (Comandar)
{
string ProtocoloBico =
((int)F_Code.Tst).ToString() +
ID; // 0 ~ 2;
return ProtocoloBico;
}
return "";
}
}
}

View File

@ -13,7 +13,7 @@ using static AgroBase.Models.Enuns;
namespace AgroBase.Models.Modules
{
class DirecionalModel : DispositivosBaseModel
public class DirecionalModel : DispositivoBaseModel
{
public static int _TaxaAmostragem { get; set; } = 500;
public bool Conectado { get; set; } = false;
@ -232,7 +232,7 @@ namespace AgroBase.Models.Modules
Motor.LogGrafico.RemoveAt(0);
}
if (frmPrincipal.Dispositivos.Any(x => x.Dispositivo == T_Code.Dir))
if (Variaveis.DispositivosConectados.Any(x => x.Dispositivo == T_Code.Dir))
{
//((frmDirPlot)(frmPrincipal.Dispositivos.First(x => x.Dispositivo == T_Code.Dir).frmPlot)).AtualizaGrafico();
frmInstancial.frmAcompanhamento.AtualizaGrafico();
@ -292,9 +292,13 @@ namespace AgroBase.Models.Modules
File.WriteAllText(nomeArquivo, JsonConvert.SerializeObject(newPinout));
}
public void IniciarRegistrador()
{
}
}
class DirSensoriamentoMotor
public class DirSensoriamentoMotor
{
public int Canal { get; set; }
public string ID { get; set; }

View File

@ -8,7 +8,7 @@ using static AgroBase.Models.Enuns;
namespace AgroBase.Models
{
public interface DispositivosBaseModel
public interface DispositivoBaseModel
{
void RecebeProtocoloSerial(string Protocolo);
string GetTaxaAmostragem();
@ -19,6 +19,7 @@ namespace AgroBase.Models
void AtualizaGridSensoriamento();
List<PinoutModel> CarregarPinout(string nomeArquivo);
void SalvarPinout(List<PinoutModel> newPinout, string nomeArquivo);
void IniciarRegistrador();
}
}

View File

@ -13,7 +13,7 @@ using static AgroBase.Models.Enuns;
namespace AgroBase.Models
{
public class MovimentacaoModel : DispositivosBaseModel
public class MovimentacaoModel : DispositivoBaseModel
{
public static int _TaxaAmostragem { get; set; } = 500;
public static int RampaMin { get; set; } = 220;
@ -23,7 +23,7 @@ namespace AgroBase.Models
public static double Kp { get; set; } = 1.85;
public static double Ki { get; set; } = 2.1;
public static double Kd { get; set; } = 0.08;
public double DiametroRoda { get; set; } = 0.3556;
public static double DiametroRoda { get; set; } = 0.3556;
public bool Conectado { get; set; } = false;
public static int LogsManter { get; set; } = 60;
public static List<PinoutModel> Pinout { get; set; }
@ -256,6 +256,7 @@ namespace AgroBase.Models
Umidade = Motor.Umidade,
IndiceCalor = Motor.IndiceCalor,
Sentido = Motor.Sentido,
Velocidade = Motor.VelocidadeInstantanea,
});
if (Motor.LogGrafico.Count() > LogsManter)
@ -330,7 +331,7 @@ namespace AgroBase.Models
{
foreach (var Motor in Motores)
{
Motor.CalculaVelocidadeInstantanea(DiametroRoda);
Motor.VelocidadeInstantanea = CalculaVelocidadeRPM(Motor.RPM);
frmInstancial.frmPrincipal.gridSenMotores.Rows[Motor.Canal].Cells[1].Value = Motor.Inicializado ? "Sim" : "Não";
frmInstancial.frmPrincipal.gridSenMotores.Rows[Motor.Canal].Cells[2].Value = Enum.GetName(typeof(Sentido), Motor.Sentido_SP);
frmInstancial.frmPrincipal.gridSenMotores.Rows[Motor.Canal].Cells[3].Value = Enum.GetName(typeof(Sentido), Motor.Sentido);
@ -382,6 +383,17 @@ namespace AgroBase.Models
}
}
public static double CalculaVelocidadeRPM(double RPM)
{
double VelocidadeInstantanea = Math.Round((Math.PI * DiametroRoda * 60 * RPM) / 1000, 2); // Km/h
return VelocidadeInstantanea;
}
public static double CalculaRPMVelocidade(double Velocidade)
{
double RPM = Math.Round((Velocidade * 1000) / (Math.PI * DiametroRoda * 60), 2);
return RPM;
}
}
public class MovSensoriamentoMotor
@ -499,12 +511,6 @@ namespace AgroBase.Models
return "";
}
public void CalculaVelocidadeInstantanea(double Diametro)
{
VelocidadeInstantanea = Math.Round((Math.PI * Diametro * 60 * RPM) / 1000, 2); // Km/h
}
}
public class SensoriamentoMotorTestes
@ -533,6 +539,7 @@ namespace AgroBase.Models
public double Umidade { get; set; }
public double IndiceCalor { get; set; }
public Sentido Sentido { get; set; }
public double Velocidade { get; set; }
}

View File

@ -91,6 +91,8 @@ namespace AgroBase.Models.Modules
REF090,
REF180,
REF270,
Solenoide,
Fluxo,
Leitura1,
Leitura2,
Leitura3,

View File

@ -11,7 +11,7 @@ using static AgroBase.Models.Enuns;
namespace AgroBase.Models.Modules
{
class SensoriamentoModel : DispositivosBaseModel
class SensoriamentoModel : DispositivoBaseModel
{
public static int _TaxaAmostragem { get; set; } = 500;
public bool Conectado { get; set; } = false;
@ -145,7 +145,7 @@ namespace AgroBase.Models.Modules
Sensor.LogGrafico.RemoveAt(0);
}
if (frmPrincipal.Dispositivos.Any(x => x.Dispositivo == T_Code.Dir))
if (Variaveis.DispositivosConectados.Any(x => x.Dispositivo == T_Code.Dir))
{
//((frmDirPlot)(frmPrincipal.Dispositivos.First(x => x.Dispositivo == T_Code.Dir).frmPlot)).AtualizaGrafico();
}
@ -205,6 +205,10 @@ namespace AgroBase.Models.Modules
File.WriteAllText(nomeArquivo, JsonConvert.SerializeObject(newPinout));
}
public void IniciarRegistrador()
{
}
}
public class SensorModel

View File

@ -0,0 +1,178 @@
using AgroBase.Comum;
using AgroBase.Models.Modules;
using AgroBase.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using static AgroBase.Models.Enuns;
namespace AgroBase.Models
{
public class OperacaoModel
{
public OperacaoModel(ModoOperacao Modo, DispositivosService<MovimentacaoModel> Mov = null, DispositivosService<DirecionalModel> Dir = null, DispositivosService<AtuadorModel> Atu = null)
{
this.Modo = Modo;
this.Controle = new OperacaoControleModel();
this.ControleAnterior = new OperacaoControleModel();
this.DispMov = Mov;
this.DispDir = Dir;
this.DispAtu = Atu;
AtuacoesPorBico = new List<int>();
if (DispAtu != null)
{
for (int i = 0; i < DispAtu.Dados.QuantidadeBicos; i++)
{
AtuacoesPorBico.Add(0);
}
}
}
public ModoOperacao Modo { get; set; }
public DispositivosService<MovimentacaoModel> DispMov { get; set; }
public DispositivosService<DirecionalModel> DispDir { get; set; }
public DispositivosService<AtuadorModel> DispAtu { get; set; }
public bool Iniciado { get; set; }
public long TimestampInicio { get; set; }
public long TimestampFim { get; set; }
public OperacaoControleModel Controle { get; set; }
public OperacaoControleModel ControleAnterior { get; set; }
public int ErvasNoRadar { get; set; } = 0;
public double VelocidadeMedia { get; set; } = 0;
public double HerbicidaConsumido { get; set; } = 0;
public double HerbicidaPorErva { get; set; } = 0;
public double BateriaConsumida { get; set; } = 0;
public int ErvasIdentificadas { get; set; } = 0;
public List<int> AtuacoesPorBico { get; set; } = new List<int>();
public double DistanciaPercorrida { get; set; } = 0;
public double ProgressoPercurso { get; set; } = 0;
public void IniciarOperacao(OperacaoControleModel controle = null)
{
Iniciado = true;
TimestampInicio = DateTime.Now.Ticks;
TimestampFim = 0;
if (controle != null)
{
Controle = controle;
}
}
public void FinalizarOperacao()
{
Controle.Angulo = 0;
Controle.RPM = 0;
AtualizarDadosControle();
Iniciado = false;
TimestampFim = DateTime.Now.Ticks;
}
public void AtualizarDadosControle()
{
if (Controle.RPM != ControleAnterior.RPM)
{
// Enviar comando MOV
EnviarProtocoloComando(DispMov);
}
if (Controle.Angulo != ControleAnterior.Angulo)
{
// Enviar comando
EnviarProtocoloComando(DispDir);
}
if (Controle.BicosAtuados.Select(x => x.Atuado).ToList() != ControleAnterior.BicosAtuados.Select(x => x.Atuado).ToList())
{
// Enviar comando ATU
EnviarProtocoloComando(DispAtu);
}
ControleAnterior = Controle;
AtualizarDadosOperacao();
}
private void AtualizarDadosOperacao()
{
if (DispMov == null)
{
return;
}
VelocidadeMedia = DispMov.Dados.Motores.Average(x => x.VelocidadeInstantanea);
DistanciaPercorrida = DispMov.Dados.DistanciaPercorridaTotal;
}
public void EnviarProtocoloComando(IDispositivosService Dispositivo)
{
if (Dispositivo == null)
{
return;
}
Direcao DirecaoAtual = Direcao.Parado;
if (Dispositivo.Dispositivo == T_Code.Mov)
{
if (Controle.RPM == 0)
{
DirecaoAtual = Direcao.Parado;
}
else
{
GeneralJoystick.RPM = Controle.RPM;
}
}
else if (Dispositivo.Dispositivo == T_Code.Dir)
{
GeneralJoystick.Angulo = Controle.Angulo;
if (Controle.Angulo < 0)
{
GeneralJoystick.Angulo *= -1;
DirecaoAtual = Direcao.Baixo;
}
else
{
DirecaoAtual = Direcao.Cima;
}
}
var Protocolos =
Dispositivo.Dados is MovimentacaoModel ? ((MovimentacaoModel)Dispositivo.Dados).Motores.Select(x => x.ProtocoloComando(DirecaoAtual)) :
Dispositivo.Dados is DirecionalModel ? ((DirecionalModel)Dispositivo.Dados).Motores.Select(x => x.ProtocoloComando(DirecaoAtual)) :
Dispositivo.Dados is AtuadorModel ? ((AtuadorModel)Dispositivo.Dados).BicosPulverizadores.Select(x => x.ProtocoloComando()) :
null;
foreach (var ProtocoloMotor in Protocolos)
{
Dispositivo.EnviarDadosSerial(ProtocoloMotor);
Task.Delay(10);
}
}
}
public class OperacaoControleModel
{
public int RPM_Max { get; set; } = 45;
public int RPM_Min { get; set; } = 15;
public double Angulo_Max { get; set; } = 30;
public double Angulo_Min { get; set; } = -30;
public double Angulo { get; set; } = 0;
public int RPM { get; set; } = 0;
public Direcao Direcao { get; set; } = Direcao.Parado;
public double VelocidadeMP { get; set; } = 50;
public List<AtuadorBicoModel> BicosAtuados { get; set; } = new List<AtuadorBicoModel>();
}
public class OperacaoGraficoModel
{
public double Velocidade { get; set; }
public double Temperatura { get; set; }
}
}

View File

@ -0,0 +1,37 @@
using AgroBase.Comum;
using AgroBase.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static AgroBase.Models.Enuns;
namespace AgroBase.Models
{
public class Variaveis
{
public static string CaminhoSistema { get; set; } = AppDomain.CurrentDomain.BaseDirectory;
public static List<IDispositivosService> DispositivosConectados { get; set; } = new List<IDispositivosService>();
public static OperacaoModel OperacaoEmAndamento { get; set; } = new OperacaoModel(ModoOperacao.Manual);
}
public static class FuncoesGlobais
{
public static string TimestampToDate(double timestamp, string Formatacao = "HH:mm:ss.fff")
{
// Converta o timestamp Unix para DateTime
// A época Unix começa em 1 de janeiro de 1970
DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
DateTime date = epoch.AddSeconds(timestamp);
// Converter a data UTC para a data no fuso horário local do sistema
DateTime localDate = date.ToLocalTime();
// Formate a data para hh:mm:ss.fff (note a correção de MM para mm)
string formattedDate = localDate.ToString(Formatacao, System.Globalization.CultureInfo.InvariantCulture);
return formattedDate;
}
}
}

View File

@ -3,6 +3,8 @@ import numpy as np
from flask import Flask, Response, request
import json
import time
import socket
import threading
import sys
import os
@ -11,8 +13,14 @@ max_readings = int(sys.argv[1])
porta = sys.argv[2]
url = sys.argv[3]
arquivoSaida = sys.argv[4]
mostrar_linhas = sys.argv[5] == "1"
socket_porta = int(sys.argv[6])
app = Flask(__name__)
json_data = None
output_folder = 'Python/Output/'
# Função para detecção de objetos usando YOLO e salvar as coordenadas em um arquivo JSON
def detect_objects(conf_threshold, nms_threshold, _camera_index):
# Definir intervalos de cor verde no espaço HSV
@ -20,6 +28,8 @@ def detect_objects(conf_threshold, nms_threshold, _camera_index):
upper_green = np.array([90, 255, 255]) # Valores de limite superior (Hue, Saturation, Value)
cap = cv2.VideoCapture(_camera_index, cv2.CAP_DSHOW)
width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
readings = []
while True:
@ -43,7 +53,7 @@ def detect_objects(conf_threshold, nms_threshold, _camera_index):
if area > 1000: # Filtrar áreas menores que um valor específico (ajuste conforme necessário)
x, y, w, h = cv2.boundingRect(contour)
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.putText(frame, f'Green {idx}', (x, y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
cv2.putText(frame, f'Verde {idx}', (x, y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
# Salvar as informações da detecção
detection_info = {
@ -58,29 +68,23 @@ def detect_objects(conf_threshold, nms_threshold, _camera_index):
current_readings.append(detection_info)
idx += 1
global json_data
# Atualizar os resultados
timestamp = time.time()
readings.append({'timestamp': timestamp, 'objetos': current_readings})
json_data = {'timestamp': timestamp, 'x_max': width, 'y_max': height, 'objetos': current_readings}
readings.append(json_data)
# Salvar as detecções em um arquivo JSON
if len(readings) > max_readings:
readings.pop(0)
output_folder = 'Python/Output/'
if not os.path.exists(output_folder):
os.makedirs(output_folder)
if len(readings) > max_readings:
readings.pop(0)
with open(output_folder + arquivoSaida, 'w') as file:
json.dump(readings, file, indent=4)
if len(readings) == max_readings:
try:
with open(output_folder + arquivoSaida, 'w') as file:
json.dump({'frames': readings}, file)
except Exception as e:
print(f"Erro ao escrever no arquivo: {e}")
cv2.imshow('Deteccao de Objetos YOLO', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# Convertendo frame para JPEG e enviando via Flask
ret, buffer = cv2.imencode('.jpg', frame)
@ -88,6 +92,48 @@ def detect_objects(conf_threshold, nms_threshold, _camera_index):
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
# Função para lidar com a conexão de cada cliente
def handle_client_connection(client_socket):
try:
while True:
# Enviar o dicionário serializado em JSON
client_socket.send(json.dumps(json_data).encode('utf-8'))
# Aguardar um pouco antes de enviar os próximos dados
time.sleep(0.2)
except socket.error:
print(f"Cliente desconectado.")
finally:
# Fechar a conexão do socket ao sair do loop
client_socket.close()
# Configuração inicial do servidor de socket
def start_server(address='localhost', port=socket_porta):
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((address, port))
server.listen()
print(f"Servidor iniciado. Aguardando conexões em {address}:{port}...")
try:
while True:
client_sock, address = server.accept()
print(f"Aceitando conexão de {address[0]}:{address[1]}")
client_handler = threading.Thread(
target=handle_client_connection,
args=(client_sock,)
)
client_handler.start()
finally:
server.close()
# Esta função é para iniciar o servidor de socket em uma thread separada
def run_socket_server():
start_server()
# Iniciar o servidor Flask em uma thread separada
def run_flask_server():
app.run(host='0.0.0.0', port=porta, threaded=True, debug=False)
@app.route('/' + url, methods=['GET'])
def video_feed():
@ -96,5 +142,12 @@ def video_feed():
camera_index = int(request.args.get('camera_index'))
return Response(detect_objects(conf_threshold, nms_threshold, camera_index), mimetype='multipart/x-mixed-replace; boundary=frame')
if __name__ == "__main__":
app.run(host='0.0.0.0', port=porta)
# Iniciar o servidor
if __name__ == '__main__':
# Inicia o servidor de socket em uma thread separada
socket_server_thread = threading.Thread(target=run_socket_server)
socket_server_thread.start()
# Inicia o servidor Flask na thread principal
run_flask_server()

View File

@ -0,0 +1,94 @@
import cv2
import numpy as np
from flask import Flask, Response, request
import json
import time
import sys
import os
max_readings = int(sys.argv[1])
porta = sys.argv[2]
url = sys.argv[3]
arquivoSaida = sys.argv[4]
app = Flask(__name__)
def calculate_angle(reference_line, width):
[vx, vy, _, _] = cv2.fitLine(reference_line, cv2.DIST_L2, 0, 0.01, 0.01)
slope_reference = vy / vx
vertical_line = np.array([[width // 2, 0], [width // 2, 100]], dtype=np.float32)
[vx, vy, _, _] = cv2.fitLine(vertical_line, cv2.DIST_L2, 0, 0.01, 0.01)
slope_vertical = vy / vx
angle_radians = np.arctan((slope_reference - slope_vertical) / (1 + slope_reference * slope_vertical))
angle_degrees = np.degrees(angle_radians)
return angle_degrees
def detect_lines(_camera_index):
cap = cv2.VideoCapture(_camera_index)
readings = []
output_folder = 'Python/Output/'
while True:
ret, frame = cap.read()
if not ret:
break
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# Defina o limite de intensidade desejado
_, thresh = cv2.threshold(gray, 50, 255, cv2.THRESH_BINARY) # Ajuste o valor do limite conforme necessário
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
if contours:
reference_line = max(contours, key=cv2.contourArea)
angle = calculate_angle(reference_line.squeeze(), frame.shape[1])[0]
#print(angle)
# Adicionando o ângulo atual à lista de dados
timestamp = time.time()
readings.append({"timestamp": timestamp, "angle": float(angle)})
# Mantendo apenas as últimas 10 leituras
if len(readings) > max_readings:
readings.pop(0)
# Salvando os dados em formato JSON no arquivo
if not os.path.exists(output_folder):
os.makedirs(output_folder)
if len(readings) == max_readings:
try:
with open(output_folder + arquivoSaida, 'w') as file:
json.dump({'frames': readings}, file)
except Exception as e:
print(f"Erro ao escrever no arquivo: {e}")
cv2.drawContours(frame, [reference_line], -1, (0, 255, 0), 2)
cv2.line(frame, (frame.shape[1] // 2, 0), (frame.shape[1] // 2, 100), (255, 0, 0), 2)
cv2.imshow('Video', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# Convertendo frame para JPEG e enviando via Flask
ret, buffer = cv2.imencode('.jpg', frame)
frame = buffer.tobytes()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
@app.route('/' + url, methods=['GET'])
def video_feed():
camera_index = int(request.args.get('camera_index'))
return Response(detect_lines(camera_index), mimetype='multipart/x-mixed-replace; boundary=frame')
if __name__ == "__main__":
app.run(host='0.0.0.0', port=porta)

View File

@ -0,0 +1,218 @@
import cv2
import numpy as np
from flask import Flask, Response, request
import json
import time
import socket
import threading
import sys
import os
import math
# Variável para mostrar as linhas (True = mostrar, False = não mostrar)
max_readings = int(sys.argv[1])
porta = sys.argv[2]
url = sys.argv[3]
arquivoSaida = sys.argv[4]
mostrar_linhas = sys.argv[5] == "1"
socket_porta = int(sys.argv[6])
app = Flask(__name__)
# Função para calcular o ângulo entre duas linhas
def calcular_angulo(linha1, linha2):
# Extraia os elementos individuais dos arrays NumPy
try:
angulo1 = math.atan2(float(linha1[1]) - float(linha1[3]), float(linha1[0]) - float(linha1[2]))
except:
angulo1 = math.atan2(float(linha1[1][0]) - float(linha1[3][0]), float(linha1[0][0]) - float(linha1[2][0]))
try:
angulo2 = math.atan2(float(linha2[1]) - float(linha2[3]), float(linha2[0]) - float(linha2[2]))
except:
angulo2 = math.atan2(float(linha2[1][0]) - float(linha2[3][0]), float(linha2[0][0]) - float(linha2[2][0]))
angulo = math.degrees(angulo1 - angulo2)
angulo = (angulo + 360) % 360
if angulo > 180:
angulo -= 360
return angulo
# Função para desenhar as linhas na imagem
def desenhar_linhas(frame, altura, largura, esquerda_x, direita_x, mostrar_linhas):
if mostrar_linhas:
meio = largura // 2
cv2.line(frame, (meio, 0), (meio, altura), (255, 0, 0), 2)
cv2.line(frame, (int(esquerda_x), 0), (int(direita_x), altura), (0, 255, 0), 2)
cv2.line(frame, (int(esquerda_x), 0), (int(esquerda_x), altura), (0, 255, 255), 2)
cv2.line(frame, (int(direita_x), 0), (int(direita_x), altura), (0, 255, 255), 2)
# Função para processar cada frame do vídeo e calcular as distâncias
def processar_frame(frame, largura, altura):
# Convertendo para escala de cinza
cinza = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# Limiarização para criar uma imagem binária
_, binarizada = cv2.threshold(cinza, 128, 255, cv2.THRESH_BINARY_INV)
# Encontrar os contornos
contornos, _ = cv2.findContours(binarizada, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# Se houver contornos, assumir que o maior é a linha preta
if contornos:
maior_contorno = max(contornos, key=cv2.contourArea)
# Ajustar uma linha ao maior contorno (linha preta)
[vx, vy, x0, y0] = cv2.fitLine(maior_contorno, cv2.DIST_L2, 0, 0.01, 0.01)
# Verificar se vy é zero para evitar divisão por zero
if vy == 0:
esquerda_x = x0
direita_x = x0
else:
# Determinar os pontos extremos da linha preta
esquerda_x = int(x0 + (-y0 * vx / vy))
direita_x = int(x0 + ((altura - y0) * vx / vy))
# Calcular distâncias das bordas
distancia_esquerda = max(0, esquerda_x)
distancia_direita = max(0, largura - direita_x)
# Calcular o ângulo entre a linha central e a linha ajustada
linha_central = [largura // 2, 0, largura // 2, altura]
linha_ajustada = [esquerda_x, 0, direita_x, altura]
angulo = calcular_angulo(linha_central, linha_ajustada)
# Desenhar linhas, se necessário
desenhar_linhas(frame, altura, largura, esquerda_x, direita_x, mostrar_linhas)
return (angulo, distancia_esquerda, distancia_direita, frame)
return (None, None, None, frame)
# Caminho do arquivo JSON para salvar os dados
output_folder = 'Python/Output/'
json_path = arquivoSaida
json_data = None
# Função para salvar os dados em formato JSON
def salvar_json(leituras, angulo, distancia_esquerda, distancia_direita, timestamp, json_path):
global json_data # Indica que queremos usar a variável global json_data
# Assegure-se que todos os dados são tipos primitivos antes de salvar em JSON
json_data = {
'timestamp': timestamp,
'angulo': angulo,
'distancia_esquerda': distancia_esquerda,
'distancia_direita': distancia_direita
}
if not os.path.exists(output_folder):
os.makedirs(output_folder)
leituras.append(json_data)
if len(leituras) > max_readings:
leituras.pop(0)
with open(output_folder + json_path, 'w') as file:
json.dump(leituras, file, indent=4)
def detect_lines(camera_index):
# Inicializando a captura de vídeo
cap = cv2.VideoCapture(camera_index)
if not cap.isOpened():
print("Erro: A câmera não pôde ser aberta.")
return
altura, largura = None, None
leituras = []
try:
while True:
ret, frame = cap.read()
if not ret:
print("Falha ao capturar imagem da câmera.")
break
if altura is None or largura is None:
altura, largura = frame.shape[:2]
# Processar o frame atual
angulo, distancia_esquerda, distancia_direita, frame_processado = processar_frame(frame, largura, altura)
if angulo is not None and distancia_esquerda is not None and distancia_direita is not None:
timestamp = time.time()
salvar_json(leituras, angulo, distancia_esquerda, distancia_direita, timestamp, json_path)
# Codificar o frame processado para JPEG
ret, buffer = cv2.imencode('.jpg', frame_processado)
if not ret:
continue
frame_bytes = buffer.tobytes()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame_bytes + b'\r\n')
finally:
# Quando tudo estiver feito, liberar a captura
cap.release()
# Função para lidar com a conexão de cada cliente
def handle_client_connection(client_socket):
try:
while True:
# Tente enviar o dicionário serializado em JSON
try:
client_socket.send(json.dumps(json_data).encode('utf-8'))
except TypeError as e:
print(f"Erro ao enviar dados: {e}")
# Aguardar um pouco antes de enviar os próximos dados
time.sleep(0.2)
except socket.error as e:
print(f"Cliente desconectado com erro: {e}")
finally:
# Fechar a conexão do socket ao sair do loop
client_socket.close()
# Configuração inicial do servidor de socket
def start_server(address='localhost', port=socket_porta):
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((address, port))
server.listen()
print(f"Servidor iniciado. Aguardando conexões em {address}:{port}...")
try:
while True:
client_sock, address = server.accept()
print(f"Aceitando conexão de {address[0]}:{address[1]}")
client_handler = threading.Thread(
target=handle_client_connection,
args=(client_sock,)
)
client_handler.start()
finally:
server.close()
# Esta função é para iniciar o servidor de socket em uma thread separada
def run_socket_server():
start_server()
# Iniciar o servidor Flask em uma thread separada
def run_flask_server():
app.run(host='0.0.0.0', port=porta, threaded=True, debug=False)
@app.route('/' + url, methods=['GET'])
def video_feed():
camera_index = int(request.args.get('camera_index'))
return Response(detect_lines(camera_index), mimetype='multipart/x-mixed-replace; boundary=frame')
# Iniciar o servidor
if __name__ == '__main__':
# Inicia o servidor de socket em uma thread separada
socket_server_thread = threading.Thread(target=run_socket_server)
socket_server_thread.start()
# Inicia o servidor Flask na thread principal
run_flask_server()

View File

@ -6,6 +6,7 @@ import folium
pathFiles = sys.argv[1]
fileName = sys.argv[2]
outputName = sys.argv[3]
outputMapName = sys.argv[4]
pastaSaida = 'Python/Output/'
@ -68,4 +69,4 @@ geojson_data = data_geometry.to_json()
folium.GeoJson(geojson_data).add_to(m)
# Salvar o mapa interativo em um arquivo HTML
m.save(pastaSaida + 'mapa_interativo.html')
m.save(pastaSaida + outputMapName)

View File

@ -13,35 +13,35 @@ using System.Windows.Forms;
namespace AgroBase.Services
{
public class CameraService
public class CameraService<T>
{
public Process pythonProcess;
public SocketService<T> socket;
private string Endereco = "localhost";
private string Porta = "8080";
private string Url = "video_feed";
private string ArquivoLeitura = "objetos.json";
private int Leituras = 10;
public string ArquivoLeitura = "leitura.json";
public int selectedCamera = 0;
private double conf_threshold = 0.5;
private double nms_threshold = 0.4;
public string URLcamera = "";
public void IniciarCamera(string Script)
public void IniciarCamera(string Script, string[] Argumentos, string FlaskPorta = "8080", string FlaskUrl = "video_feed", string SocketPorta = "6535")
{
string Argumentos = Leituras + " " + Porta + " " + Url + " " + ArquivoLeitura;
pythonProcess = PythonService.RunScript(Script, Argumentos);
URLcamera = "http://" + Endereco + ":" + Porta + "/" + Url +
URLcamera = "http://" + Endereco + ":" + FlaskPorta + "/" + FlaskUrl +
"?conf_threshold=" + conf_threshold.ToString().Replace(",", ".") +
"&nms_threshold=" + nms_threshold.ToString().Replace(",", ".") +
"&camera_index=" + (selectedCamera - 1);
socket = new SocketService<T>();
socket.Connect(Endereco, Convert.ToInt32(SocketPorta));
}
public CameraCoordenadasModel AferirDadosCamera()
public T AferirDadosJson()
{
CameraCoordenadasModel Coordenadas = null;
T Coordenadas = default(T);
if (File.Exists(PythonService.CaminhoGeral + PythonService.CaminhoLeitura + ArquivoLeitura))
{
@ -54,7 +54,7 @@ namespace AgroBase.Services
}
File.Copy(PythonService.CaminhoGeral + PythonService.CaminhoLeitura + ArquivoLeitura, tempFile);
var linhas = File.ReadAllText(tempFile);
Coordenadas = JsonConvert.DeserializeObject<CameraCoordenadasModel>(linhas);
Coordenadas = JsonConvert.DeserializeObject<T>(linhas);
}
catch (Exception ex)
{

View File

@ -1,4 +1,5 @@
using AgroBase.Forms;
using AgroBase.Forms.Atuador;
using AgroBase.Forms.Direcional;
using AgroBase.Forms.Movimentacao;
using AgroBase.Forms.Sensoriamento;
@ -18,7 +19,7 @@ using static AgroBase.Models.Enuns;
namespace AgroBase.Comum
{
public class DispositivosService
public class DispositivosService<T> : IDispositivosService where T : DispositivoBaseModel, new()
{
public T_Code Dispositivo { get; set; } = T_Code.Vzo;
public string _Nome { get; set; }
@ -37,7 +38,12 @@ namespace AgroBase.Comum
public int _index { get; set; }
public List<string> DadosEnviados { get; set; } = new List<string>();
public List<string> DadosRecebidos { get; set; } = new List<string>();
public DispositivosBaseModel Dados { get; set; } = default(DispositivosBaseModel);
public T Dados { get; set; } = new T();
DispositivoBaseModel IDispositivosService.Dados
{
get { return this.Dados; }
set { this.Dados = (T)value; } // Isso pode lançar uma exceção se o valor não for do tipo T
}
public Form frmConfig { get; set; }
public Form frmPlot { get; set; }
@ -47,8 +53,6 @@ namespace AgroBase.Comum
public int TempoConectado { get; set; } = 0;
public int BaudRate()
{
if (cmbBaudRate.SelectedIndex < 0)
@ -81,7 +85,7 @@ namespace AgroBase.Comum
var DispositivosTipo = SerialService.DispositivosConectados.Where(x => x.Dispositivo == Dispositivo).ToList();
for (int i = 0; i < DispositivosTipo.Count(); i++)
{
String PortaCom = DispositivosTipo[i].PortaCOM;
string PortaCom = DispositivosTipo[i].PortaCOM;
SerialPort _Porta = new SerialPort() { PortName = PortaCom };
try
{
@ -184,26 +188,30 @@ namespace AgroBase.Comum
switch (Dispositivo)
{
case T_Code.Mov:
Dados = CarregarParametros<MovimentacaoModel>(MovimentacaoModel.CarregarParametrosIniciais());
Dados = CarregarParametros(MovimentacaoModel.CarregarParametrosIniciais());
frmPlot = new frmMovPlot();
frmConfig = new frmMovConfig();
((MovimentacaoModel)Dados).IniciarRegistrador();
Dados.IniciarRegistrador();
break;
case T_Code.Dir:
Dados = CarregarParametros<DirecionalModel>(DirecionalModel.CarregarParametrosIniciais());
Dados = CarregarParametros(DirecionalModel.CarregarParametrosIniciais());
frmPlot = new frmDirPlot();
frmConfig = new frmDirConfig();
break;
case T_Code.Sen:
Dados = CarregarParametros<SensoriamentoModel>(SensoriamentoModel.CarregarParametrosIniciais());
Dados = CarregarParametros(SensoriamentoModel.CarregarParametrosIniciais());
frmConfig = new frmSenConfig();
break;
case T_Code.Atu:
Dados = CarregarParametros(AtuadorModel.CarregarParametrosIniciais());
frmConfig = new frmAtuConfig();
break;
default:
Dados = default(DispositivosBaseModel);
Dados = default(T);
break;
}
if (Dados != default(DispositivosBaseModel))
if (!EqualityComparer<T>.Default.Equals(Dados, default(T)))
{
Dados.PopulaGridSensoriamento();
Dados.CarregarPinout("pinout" + Enum.GetName(typeof(T_Code), Dispositivo) + ".pin");
@ -317,30 +325,42 @@ namespace AgroBase.Comum
{
clbDispositivos.Items.Clear();
Models.MovSensoriamentoMotor[] Motores = { };
if (Dispositivo == T_Code.Mov)
if (Dados is MovimentacaoModel movModel && Dispositivo == T_Code.Mov)
{
Motores = ((MovimentacaoModel)Dados).Motores.Select(x => new Models.MovSensoriamentoMotor { ID = x.ID, Comandar = x.Comandar }).ToArray();
Motores = movModel.Motores.Select(x => new Models.MovSensoriamentoMotor { ID = x.ID, Comandar = x.Comandar }).ToArray();
}
else if (Dispositivo == T_Code.Dir)
else if (Dados is DirecionalModel dirModel && Dispositivo == T_Code.Dir)
{
Motores = ((DirecionalModel)Dados).Motores.Select(x => new Models.MovSensoriamentoMotor { ID = x.ID, Comandar = x.Comandar }).ToArray();
Motores = dirModel.Motores.Select(x => new Models.MovSensoriamentoMotor { ID = x.ID, Comandar = x.Comandar }).ToArray();
}
foreach (var Motor in Motores) {
foreach (var Motor in Motores)
{
clbDispositivos.Items.Add(Motor.ID);
clbDispositivos.SetItemChecked(clbDispositivos.Items.Count - 1, Motor.Comandar);
}
}
else if (Dispositivo == T_Code.Sen)
else if (Dados is SensoriamentoModel senModel && Dispositivo == T_Code.Sen)
{
clbDispositivos.Items.Clear();
var Sensores = ((SensoriamentoModel)Dados).Sensores;
var Sensores = senModel.Sensores;
foreach (var Sensor in Sensores)
{
clbDispositivos.Items.Add(Sensor.ID);
clbDispositivos.SetItemChecked(clbDispositivos.Items.Count - 1, Sensor.Aferir);
}
}
else if (Dados is AtuadorModel atuModel && Dispositivo == T_Code.Atu)
{
clbDispositivos.Items.Clear();
var Bicos = atuModel.BicosPulverizadores;
foreach (var Bico in Bicos)
{
clbDispositivos.Items.Add(Bico.ID.ToString());
clbDispositivos.SetItemChecked(clbDispositivos.Items.Count - 1, Bico.Comandar);
}
}
clbDispositivos.ItemCheck -= clbDispositivos_ItemCheck;
clbDispositivos.ItemCheck += clbDispositivos_ItemCheck;
@ -485,24 +505,43 @@ namespace AgroBase.Comum
switch (Dispositivo)
{
case T_Code.Mov:
((MovimentacaoModel)Dados).Motores.ForEach(x => x.Comandar = false);
foreach (var Item in ((CheckedListBox)sender).CheckedItems)
if (Dados is MovimentacaoModel movModel)
{
((MovimentacaoModel)Dados).Motores.First(x => x.ID == Item.ToString()).Comandar = true;
movModel.Motores.ForEach(x => x.Comandar = false);
foreach (var Item in ((CheckedListBox)sender).CheckedItems)
{
movModel.Motores.First(x => x.ID == Item.ToString()).Comandar = true;
}
}
break;
case T_Code.Dir:
((DirecionalModel)Dados).Motores.ForEach(x => x.Comandar = false);
foreach (var Item in ((CheckedListBox)sender).CheckedItems)
if (Dados is DirecionalModel dirModel)
{
((DirecionalModel)Dados).Motores.First(x => x.ID == Item.ToString()).Comandar = true;
dirModel.Motores.ForEach(x => x.Comandar = false);
foreach (var Item in ((CheckedListBox)sender).CheckedItems)
{
dirModel.Motores.First(x => x.ID == Item.ToString()).Comandar = true;
}
}
break;
case T_Code.Sen:
((SensoriamentoModel)Dados).Sensores.ForEach(x => x.Aferir = false);
foreach (var Item in ((CheckedListBox)sender).CheckedItems)
if (Dados is SensoriamentoModel senModel)
{
((SensoriamentoModel)Dados).Sensores.First(x => x.ID == Item.ToString()).Aferir = true;
senModel.Sensores.ForEach(x => x.Aferir = false);
foreach (var Item in ((CheckedListBox)sender).CheckedItems)
{
senModel.Sensores.First(x => x.ID == Item.ToString()).Aferir = true;
}
}
break;
case T_Code.Atu:
if (Dados is AtuadorModel atuModel)
{
atuModel.BicosPulverizadores.ForEach(x => x.Comandar = false);
foreach (var Item in ((CheckedListBox)sender).CheckedItems)
{
atuModel.BicosPulverizadores.First(x => x.ID == Item.ToString()).Comandar = true;
}
}
break;
}
@ -575,7 +614,7 @@ namespace AgroBase.Comum
DadosRecebidos.Add("< " + DateTime.Now.ToString("HH:mm:ss:fff") + " - " + Recebido);
AtualizarConsole(DadosRecebidos[DadosRecebidos.Count - 1]);
if (Recebido[0].ToString() == SerialService.BeginSensor && Dados != default(DispositivosBaseModel))
if (Recebido[0].ToString() == SerialService.BeginSensor && !EqualityComparer<T>.Default.Equals(Dados, default(T)))
{
Dados.RecebeProtocoloSerial(Recebido);
Dados.AtualizaGridSensoriamento();
@ -683,7 +722,7 @@ namespace AgroBase.Comum
}
public T CarregarParametros<T>(object empty)
public T CarregarParametros(object empty)
{
string nomeArquivo = "parameters" + Enum.GetName(typeof(T_Code), Dispositivo) + ".par";
if (!File.Exists(nomeArquivo))
@ -696,7 +735,7 @@ namespace AgroBase.Comum
return Parametros;
}
public void SalvarParametros<T>(T newConfig)
public void SalvarParametros(DispositivoBaseModel newConfig)
{
File.WriteAllText("parameters" + Enum.GetName(typeof(T_Code), Dispositivo) + ".par", JsonConvert.SerializeObject(newConfig));
}

View File

@ -0,0 +1,57 @@
using AgroBase.Comum;
using AgroBase.Models;
using AgroBase.Models.Modules;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static AgroBase.Models.Enuns;
namespace AgroBase.Services
{
public static class DispositivosServiceFactory
{
public static IDispositivosService CreateDispositivoService(T_Code tipoDispositivo, string nome, string descricao, SerialPort porta)
{
switch (tipoDispositivo)
{
case T_Code.Mov:
return new DispositivosService<MovimentacaoModel>
{
Dispositivo = tipoDispositivo,
_Nome = nome,
_Descricao = descricao,
_Porta = porta,
};
case T_Code.Dir:
return new DispositivosService<DirecionalModel>
{
Dispositivo = tipoDispositivo,
_Nome = nome,
_Descricao = descricao,
_Porta = porta,
};
case T_Code.Sen:
return new DispositivosService<SensoriamentoModel>
{
Dispositivo = tipoDispositivo,
_Nome = nome,
_Descricao = descricao,
_Porta = porta,
};
case T_Code.Atu:
return new DispositivosService<AtuadorModel>
{
Dispositivo = tipoDispositivo,
_Nome = nome,
_Descricao = descricao,
_Porta = porta,
};
default:
throw new ArgumentException("Tipo de dispositivo não reconhecido.");
}
}
}
}

View File

@ -0,0 +1,32 @@
using AgroBase.Models;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static AgroBase.Models.Enuns;
namespace AgroBase.Services
{
public interface IDispositivosService
{
T_Code Dispositivo { get; set; }
string _Nome { get; set; }
string _Descricao { get; set; }
SerialPort _Porta { get; set; }
DispositivoBaseModel Dados { get; set; }
int TempoConectado { get; set; }
GroupBox gpbItem { get; set; }
string PortaCOM();
string StatusPorta();
Control InstanciarDispositivo(int index);
void AtualizaIndex(int index);
void AcaoDesconectar();
void SalvarParametros(DispositivoBaseModel dados);
void LimparBufferSerial(bool LimparConsole);
void EnviarDadosSerial(string Protocolo);
}
}

View File

@ -15,7 +15,7 @@ namespace AgroBase.Services
{
OpenFileDialog opfMapa;
public Process pythonProcess;
private string CaminhoSaida = AppDomain.CurrentDomain.BaseDirectory + PythonService.CaminhoGeral + PythonService.CaminhoLeitura;
private string CaminhoSaida = Variaveis.CaminhoSistema + PythonService.CaminhoGeral + PythonService.CaminhoLeitura;
private string NomeArquivoMapa = "mapa_interativo.html";
public string NomeArquivos = "";
public string CaminhoMapa = "";
@ -39,8 +39,7 @@ namespace AgroBase.Services
NomeArquivos = opfMapa.FileName.Split('\\')[opfMapa.FileName.Split('\\').Length - 1].Split('.')[0];
CaminhoMapa = opfMapa.FileName.Substring(0, opfMapa.FileName.Length - NomeArquivos.Length - 4).Replace("\\", "/");
string Argumentos = '"' + CaminhoMapa + '"' + ' ' + '"' + NomeArquivos + '"' + ' ' + '"' + ArquivoSaida + '"';
pythonProcess = PythonService.RunScript(PythonService.ScriptMapConverter, Argumentos);
pythonProcess = PythonService.RunScript(PythonService.ScriptMapConverter, new string[] { CaminhoMapa, NomeArquivos, ArquivoSaida, NomeArquivoMapa });
MapaUrl = new Uri(CaminhoSaida + NomeArquivoMapa).AbsoluteUri;
CaminhoDadosMapa = CaminhoSaida + ArquivoSaida;

View File

@ -15,13 +15,19 @@ namespace AgroBase.Services
public static string ScriptGreenDetector = "green-detector.py";
public static string ScriptMapConverter = "map-load.py";
public static string ScriptLineAngle = "line-angle2.py";
public static Process RunScript(string Script, string Argumentos)
public static Process RunScript(string Script, string[] Argumentos)
{
string ScriptPath = CaminhoGeral + CaminhoScripts + Script;
string Args = "";
foreach (var arg in Argumentos)
{
Args += ' '.ToString() + '"'.ToString() + arg + '"'.ToString();
}
Process pythonProcess = new Process();
pythonProcess.StartInfo.FileName = "python";
pythonProcess.StartInfo.Arguments = ScriptPath + " " + Argumentos;
pythonProcess.StartInfo.Arguments = ScriptPath + Args;
pythonProcess.StartInfo.UseShellExecute = false;
pythonProcess.StartInfo.RedirectStandardOutput = true;
pythonProcess.StartInfo.CreateNoWindow = true;

View File

@ -0,0 +1,89 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace AgroBase.Services
{
public class SocketService<T>
{
private int DadosRegistrar;
private TcpClient client;
private NetworkStream stream;
private byte[] buffer = new byte[1024];
public List<T> DadosRecebidos = new List<T>();
public void Connect(string host, int port, int _Registrar = 50)
{
DadosRegistrar = _Registrar;
client = new TcpClient(host, port);
stream = client.GetStream();
stream.BeginRead(buffer, 0, buffer.Length, OnRead, null);
}
private void OnRead(IAsyncResult ar)
{
string dado = "";
try
{
int bytesRead = stream.EndRead(ar);
if (bytesRead > 0)
{
string result = Encoding.UTF8.GetString(buffer, 0, bytesRead);
// Aqui você processaria a mensagem recebida
//Console.WriteLine(result);
if (result != "" && result != null && !result.Contains("null"))
{
var dados = result.Replace("}{", "}¬{").Split('¬');
for (int i = 0; i < (dados.Length > 1 ? dados.Length - 1 : dados.Length); i++)
{
dado = dados[i];
if (dado != "")
{
var _Dados = JsonConvert.DeserializeObject<T>(dado);
if (_Dados != null)
{
DadosRecebidos.Add(_Dados);
if (DadosRecebidos.Count() > DadosRegistrar)
{
DadosRecebidos.RemoveAt(0);
}
}
}
}
}
}
// Continue lendo do stream
stream.BeginRead(buffer, 0, buffer.Length, OnRead, null);
}
catch (Exception ex)
{
Console.WriteLine(dado + " - " + ex.Message);
try
{
stream.BeginRead(buffer, 0, buffer.Length, OnRead, null);
}
catch
{
}
}
}
public void Disconnect()
{
if (client != null)
{
client.Close();
}
}
}
}

View File

@ -0,0 +1,62 @@
[
{
"timestamp": 1703261258.146047,
"angulo": 70.83386634512402,
"distancia_esquerda": 0,
"distancia_direita": 0
},
{
"timestamp": 1703261258.1779122,
"angulo": 71.62454833068,
"distancia_esquerda": 0,
"distancia_direita": 0
},
{
"timestamp": 1703261258.2098758,
"angulo": 71.21250362005355,
"distancia_esquerda": 0,
"distancia_direita": 0
},
{
"timestamp": 1703261258.2414749,
"angulo": 71.29878626894322,
"distancia_esquerda": 0,
"distancia_direita": 0
},
{
"timestamp": 1703261258.2731776,
"angulo": 71.37213682354496,
"distancia_esquerda": 0,
"distancia_direita": 0
},
{
"timestamp": 1703261258.305718,
"angulo": 70.71739479109578,
"distancia_esquerda": 0,
"distancia_direita": 0
},
{
"timestamp": 1703261258.3383834,
"angulo": 71.01237591212987,
"distancia_esquerda": 0,
"distancia_direita": 0
},
{
"timestamp": 1703261258.3862917,
"angulo": 70.9617007750378,
"distancia_esquerda": 0,
"distancia_direita": 0
},
{
"timestamp": 1703261258.4176264,
"angulo": 70.98707086102593,
"distancia_esquerda": 0,
"distancia_direita": 0
},
{
"timestamp": 1703261258.4505165,
"angulo": 71.13793400214888,
"distancia_esquerda": 0,
"distancia_direita": 0
}
]

View File

@ -0,0 +1 @@
{"frames": [{"timestamp": 1702480400.7133753, "angle": 36.13109588623047}, {"timestamp": 1702480400.745675, "angle": 33.215476989746094}, {"timestamp": 1702480400.7778916, "angle": 39.78017807006836}, {"timestamp": 1702480400.8581421, "angle": 31.20282554626465}, {"timestamp": 1702480400.8901947, "angle": 38.749080657958984}, {"timestamp": 1702480400.9048932, "angle": 38.749080657958984}, {"timestamp": 1702480400.9250338, "angle": 46.84868621826172}, {"timestamp": 1702480400.9539185, "angle": 49.89439392089844}, {"timestamp": 1702480400.9851637, "angle": 44.38512420654297}, {"timestamp": 1702480401.0168378, "angle": 36.830345153808594}]}

View File

@ -1 +1 @@
{"frames": [{"timestamp": 1701867548.053637, "objetos": [{"id": 0, "descricao": "Green", "x": 278, "y": 197, "largura": 272, "altura": 242, "confianca": 1.0}]}, {"timestamp": 1701867548.0857556, "objetos": [{"id": 0, "descricao": "Green", "x": 276, "y": 197, "largura": 273, "altura": 243, "confianca": 1.0}]}, {"timestamp": 1701867548.1179557, "objetos": [{"id": 0, "descricao": "Green", "x": 276, "y": 198, "largura": 279, "altura": 243, "confianca": 1.0}]}, {"timestamp": 1701867548.148815, "objetos": [{"id": 0, "descricao": "Green", "x": 276, "y": 197, "largura": 274, "altura": 243, "confianca": 1.0}]}, {"timestamp": 1701867548.1815276, "objetos": [{"id": 0, "descricao": "Green", "x": 276, "y": 196, "largura": 274, "altura": 243, "confianca": 1.0}]}, {"timestamp": 1701867548.2139637, "objetos": [{"id": 0, "descricao": "Green", "x": 276, "y": 197, "largura": 275, "altura": 243, "confianca": 1.0}]}, {"timestamp": 1701867548.2448485, "objetos": [{"id": 0, "descricao": "Green", "x": 278, "y": 197, "largura": 277, "altura": 243, "confianca": 1.0}]}, {"timestamp": 1701867548.277702, "objetos": [{"id": 0, "descricao": "Green", "x": 276, "y": 197, "largura": 274, "altura": 241, "confianca": 1.0}]}, {"timestamp": 1701867548.325753, "objetos": [{"id": 0, "descricao": "Green", "x": 276, "y": 197, "largura": 274, "altura": 243, "confianca": 1.0}]}, {"timestamp": 1701867548.357562, "objetos": [{"id": 0, "descricao": "Green", "x": 276, "y": 197, "largura": 274, "altura": 243, "confianca": 1.0}]}]}
{"frames": [{"timestamp": 1702044717.2849479, "objetos": []}, {"timestamp": 1702044717.3335934, "objetos": []}, {"timestamp": 1702044717.3977585, "objetos": []}, {"timestamp": 1702044717.4447577, "objetos": []}, {"timestamp": 1702044717.4936533, "objetos": []}, {"timestamp": 1702044717.5410244, "objetos": []}, {"timestamp": 1702044717.5886612, "objetos": []}, {"timestamp": 1702044717.6369445, "objetos": []}, {"timestamp": 1702044717.6846058, "objetos": []}, {"timestamp": 1702044717.7331538, "objetos": []}]}

View File

@ -0,0 +1,62 @@
[
{
"timestamp": 1703093033,
"angulo": -40.98247895634074,
"distancia_esquerda": 323,
"distancia_direita": 734
},
{
"timestamp": 1703093033,
"angulo": -42.704431859458225,
"distancia_esquerda": 292,
"distancia_direita": 791
},
{
"timestamp": 1703093033,
"angulo": -36.71680307495137,
"distancia_esquerda": 174,
"distancia_direita": 824
},
{
"timestamp": 1703093033,
"angulo": -36.563095868594075,
"distancia_esquerda": 75,
"distancia_direita": 921
},
{
"timestamp": 1703093034,
"angulo": 60.13716564372487,
"distancia_esquerda": 0,
"distancia_direita": 120
},
{
"timestamp": 1703093034,
"angulo": -70.12782418075608,
"distancia_esquerda": 1449,
"distancia_direita": 519
},
{
"timestamp": 1703093034,
"angulo": -75.04477159018887,
"distancia_esquerda": 1196,
"distancia_direita": 1241
},
{
"timestamp": 1703093034,
"angulo": -76.74694477253388,
"distancia_esquerda": 713,
"distancia_direita": 1965
},
{
"timestamp": 1703093034,
"angulo": -87.56119229669366,
"distancia_esquerda": 1191,
"distancia_direita": 10719
},
{
"timestamp": 1703093034,
"angulo": 60.97352342910659,
"distancia_esquerda": 22,
"distancia_direita": 0
}
]

File diff suppressed because one or more lines are too long

View File

@ -1 +1,42 @@
{"frames": [{"timestamp": 1701867548.053637, "objetos": [{"id": 0, "descricao": "Green", "x": 278, "y": 197, "largura": 272, "altura": 242, "confianca": 1.0}]}, {"timestamp": 1701867548.0857556, "objetos": [{"id": 0, "descricao": "Green", "x": 276, "y": 197, "largura": 273, "altura": 243, "confianca": 1.0}]}, {"timestamp": 1701867548.1179557, "objetos": [{"id": 0, "descricao": "Green", "x": 276, "y": 198, "largura": 279, "altura": 243, "confianca": 1.0}]}, {"timestamp": 1701867548.148815, "objetos": [{"id": 0, "descricao": "Green", "x": 276, "y": 197, "largura": 274, "altura": 243, "confianca": 1.0}]}, {"timestamp": 1701867548.1815276, "objetos": [{"id": 0, "descricao": "Green", "x": 276, "y": 196, "largura": 274, "altura": 243, "confianca": 1.0}]}, {"timestamp": 1701867548.2139637, "objetos": [{"id": 0, "descricao": "Green", "x": 276, "y": 197, "largura": 275, "altura": 243, "confianca": 1.0}]}, {"timestamp": 1701867548.2448485, "objetos": [{"id": 0, "descricao": "Green", "x": 278, "y": 197, "largura": 277, "altura": 243, "confianca": 1.0}]}, {"timestamp": 1701867548.277702, "objetos": [{"id": 0, "descricao": "Green", "x": 276, "y": 197, "largura": 274, "altura": 241, "confianca": 1.0}]}, {"timestamp": 1701867548.325753, "objetos": [{"id": 0, "descricao": "Green", "x": 276, "y": 197, "largura": 274, "altura": 243, "confianca": 1.0}]}, {"timestamp": 1701867548.357562, "objetos": [{"id": 0, "descricao": "Green", "x": 276, "y": 197, "largura": 274, "altura": 243, "confianca": 1.0}]}]}
[
{
"timestamp": 1702497316.221366,
"objetos": []
},
{
"timestamp": 1702497316.2529476,
"objetos": []
},
{
"timestamp": 1702497316.2853158,
"objetos": []
},
{
"timestamp": 1702497316.3178427,
"objetos": []
},
{
"timestamp": 1702497316.3489544,
"objetos": []
},
{
"timestamp": 1702497316.3819983,
"objetos": []
},
{
"timestamp": 1702497316.4131682,
"objetos": []
},
{
"timestamp": 1702497316.4452527,
"objetos": []
},
{
"timestamp": 1702497316.4783282,
"objetos": []
},
{
"timestamp": 1702497316.5099552,
"objetos": []
}
]

View File

@ -0,0 +1,72 @@
[
{
"timestamp": 1703261249.8491328,
"x_max": 640.0,
"y_max": 480.0,
"objetos": []
},
{
"timestamp": 1703261250.8542001,
"x_max": 640.0,
"y_max": 480.0,
"objetos": []
},
{
"timestamp": 1703261251.858236,
"x_max": 640.0,
"y_max": 480.0,
"objetos": []
},
{
"timestamp": 1703261252.8649428,
"x_max": 640.0,
"y_max": 480.0,
"objetos": []
},
{
"timestamp": 1703261253.8680236,
"x_max": 640.0,
"y_max": 480.0,
"objetos": []
},
{
"timestamp": 1703261254.8731163,
"x_max": 640.0,
"y_max": 480.0,
"objetos": []
},
{
"timestamp": 1703261255.8774235,
"x_max": 640.0,
"y_max": 480.0,
"objetos": []
},
{
"timestamp": 1703261256.88373,
"x_max": 640.0,
"y_max": 480.0,
"objetos": []
},
{
"timestamp": 1703261257.8879297,
"x_max": 640.0,
"y_max": 480.0,
"objetos": []
},
{
"timestamp": 1703261258.7623699,
"x_max": 640.0,
"y_max": 480.0,
"objetos": [
{
"id": 0,
"descricao": "Green",
"x": 86,
"y": 341,
"largura": 49,
"altura": 58,
"confianca": 1.0
}
]
}
]

View File

@ -3,6 +3,8 @@ import numpy as np
from flask import Flask, Response, request
import json
import time
import socket
import threading
import sys
import os
@ -11,8 +13,14 @@ max_readings = int(sys.argv[1])
porta = sys.argv[2]
url = sys.argv[3]
arquivoSaida = sys.argv[4]
mostrar_linhas = sys.argv[5] == "1"
socket_porta = int(sys.argv[6])
app = Flask(__name__)
json_data = None
output_folder = 'Python/Output/'
# Função para detecção de objetos usando YOLO e salvar as coordenadas em um arquivo JSON
def detect_objects(conf_threshold, nms_threshold, _camera_index):
# Definir intervalos de cor verde no espaço HSV
@ -20,6 +28,8 @@ def detect_objects(conf_threshold, nms_threshold, _camera_index):
upper_green = np.array([90, 255, 255]) # Valores de limite superior (Hue, Saturation, Value)
cap = cv2.VideoCapture(_camera_index, cv2.CAP_DSHOW)
width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
readings = []
while True:
@ -43,7 +53,7 @@ def detect_objects(conf_threshold, nms_threshold, _camera_index):
if area > 1000: # Filtrar áreas menores que um valor específico (ajuste conforme necessário)
x, y, w, h = cv2.boundingRect(contour)
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.putText(frame, f'Green {idx}', (x, y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
cv2.putText(frame, f'Verde {idx}', (x, y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
# Salvar as informações da detecção
detection_info = {
@ -58,29 +68,23 @@ def detect_objects(conf_threshold, nms_threshold, _camera_index):
current_readings.append(detection_info)
idx += 1
global json_data
# Atualizar os resultados
timestamp = time.time()
readings.append({'timestamp': timestamp, 'objetos': current_readings})
json_data = {'timestamp': timestamp, 'x_max': width, 'y_max': height, 'objetos': current_readings}
readings.append(json_data)
# Salvar as detecções em um arquivo JSON
if len(readings) > max_readings:
readings.pop(0)
output_folder = 'Python/Output/'
if not os.path.exists(output_folder):
os.makedirs(output_folder)
if len(readings) > max_readings:
readings.pop(0)
with open(output_folder + arquivoSaida, 'w') as file:
json.dump(readings, file, indent=4)
if len(readings) == max_readings:
try:
with open(output_folder + arquivoSaida, 'w') as file:
json.dump({'frames': readings}, file)
except Exception as e:
print(f"Erro ao escrever no arquivo: {e}")
cv2.imshow('Deteccao de Objetos YOLO', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# Convertendo frame para JPEG e enviando via Flask
ret, buffer = cv2.imencode('.jpg', frame)
@ -88,6 +92,48 @@ def detect_objects(conf_threshold, nms_threshold, _camera_index):
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
# Função para lidar com a conexão de cada cliente
def handle_client_connection(client_socket):
try:
while True:
# Enviar o dicionário serializado em JSON
client_socket.send(json.dumps(json_data).encode('utf-8'))
# Aguardar um pouco antes de enviar os próximos dados
time.sleep(0.2)
except socket.error:
print(f"Cliente desconectado.")
finally:
# Fechar a conexão do socket ao sair do loop
client_socket.close()
# Configuração inicial do servidor de socket
def start_server(address='localhost', port=socket_porta):
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((address, port))
server.listen()
print(f"Servidor iniciado. Aguardando conexões em {address}:{port}...")
try:
while True:
client_sock, address = server.accept()
print(f"Aceitando conexão de {address[0]}:{address[1]}")
client_handler = threading.Thread(
target=handle_client_connection,
args=(client_sock,)
)
client_handler.start()
finally:
server.close()
# Esta função é para iniciar o servidor de socket em uma thread separada
def run_socket_server():
start_server()
# Iniciar o servidor Flask em uma thread separada
def run_flask_server():
app.run(host='0.0.0.0', port=porta, threaded=True, debug=False)
@app.route('/' + url, methods=['GET'])
def video_feed():
@ -96,5 +142,12 @@ def video_feed():
camera_index = int(request.args.get('camera_index'))
return Response(detect_objects(conf_threshold, nms_threshold, camera_index), mimetype='multipart/x-mixed-replace; boundary=frame')
if __name__ == "__main__":
app.run(host='0.0.0.0', port=porta)
# Iniciar o servidor
if __name__ == '__main__':
# Inicia o servidor de socket em uma thread separada
socket_server_thread = threading.Thread(target=run_socket_server)
socket_server_thread.start()
# Inicia o servidor Flask na thread principal
run_flask_server()

View File

@ -0,0 +1,94 @@
import cv2
import numpy as np
from flask import Flask, Response, request
import json
import time
import sys
import os
max_readings = int(sys.argv[1])
porta = sys.argv[2]
url = sys.argv[3]
arquivoSaida = sys.argv[4]
app = Flask(__name__)
def calculate_angle(reference_line, width):
[vx, vy, _, _] = cv2.fitLine(reference_line, cv2.DIST_L2, 0, 0.01, 0.01)
slope_reference = vy / vx
vertical_line = np.array([[width // 2, 0], [width // 2, 100]], dtype=np.float32)
[vx, vy, _, _] = cv2.fitLine(vertical_line, cv2.DIST_L2, 0, 0.01, 0.01)
slope_vertical = vy / vx
angle_radians = np.arctan((slope_reference - slope_vertical) / (1 + slope_reference * slope_vertical))
angle_degrees = np.degrees(angle_radians)
return angle_degrees
def detect_lines(_camera_index):
cap = cv2.VideoCapture(_camera_index)
readings = []
output_folder = 'Python/Output/'
while True:
ret, frame = cap.read()
if not ret:
break
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# Defina o limite de intensidade desejado
_, thresh = cv2.threshold(gray, 50, 255, cv2.THRESH_BINARY) # Ajuste o valor do limite conforme necessário
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
if contours:
reference_line = max(contours, key=cv2.contourArea)
angle = calculate_angle(reference_line.squeeze(), frame.shape[1])[0]
#print(angle)
# Adicionando o ângulo atual à lista de dados
timestamp = time.time()
readings.append({"timestamp": timestamp, "angle": float(angle)})
# Mantendo apenas as últimas 10 leituras
if len(readings) > max_readings:
readings.pop(0)
# Salvando os dados em formato JSON no arquivo
if not os.path.exists(output_folder):
os.makedirs(output_folder)
if len(readings) == max_readings:
try:
with open(output_folder + arquivoSaida, 'w') as file:
json.dump({'frames': readings}, file)
except Exception as e:
print(f"Erro ao escrever no arquivo: {e}")
cv2.drawContours(frame, [reference_line], -1, (0, 255, 0), 2)
cv2.line(frame, (frame.shape[1] // 2, 0), (frame.shape[1] // 2, 100), (255, 0, 0), 2)
cv2.imshow('Video', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# Convertendo frame para JPEG e enviando via Flask
ret, buffer = cv2.imencode('.jpg', frame)
frame = buffer.tobytes()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
@app.route('/' + url, methods=['GET'])
def video_feed():
camera_index = int(request.args.get('camera_index'))
return Response(detect_lines(camera_index), mimetype='multipart/x-mixed-replace; boundary=frame')
if __name__ == "__main__":
app.run(host='0.0.0.0', port=porta)

View File

@ -0,0 +1,218 @@
import cv2
import numpy as np
from flask import Flask, Response, request
import json
import time
import socket
import threading
import sys
import os
import math
# Variável para mostrar as linhas (True = mostrar, False = não mostrar)
max_readings = int(sys.argv[1])
porta = sys.argv[2]
url = sys.argv[3]
arquivoSaida = sys.argv[4]
mostrar_linhas = sys.argv[5] == "1"
socket_porta = int(sys.argv[6])
app = Flask(__name__)
# Função para calcular o ângulo entre duas linhas
def calcular_angulo(linha1, linha2):
# Extraia os elementos individuais dos arrays NumPy
try:
angulo1 = math.atan2(float(linha1[1]) - float(linha1[3]), float(linha1[0]) - float(linha1[2]))
except:
angulo1 = math.atan2(float(linha1[1][0]) - float(linha1[3][0]), float(linha1[0][0]) - float(linha1[2][0]))
try:
angulo2 = math.atan2(float(linha2[1]) - float(linha2[3]), float(linha2[0]) - float(linha2[2]))
except:
angulo2 = math.atan2(float(linha2[1][0]) - float(linha2[3][0]), float(linha2[0][0]) - float(linha2[2][0]))
angulo = math.degrees(angulo1 - angulo2)
angulo = (angulo + 360) % 360
if angulo > 180:
angulo -= 360
return angulo
# Função para desenhar as linhas na imagem
def desenhar_linhas(frame, altura, largura, esquerda_x, direita_x, mostrar_linhas):
if mostrar_linhas:
meio = largura // 2
cv2.line(frame, (meio, 0), (meio, altura), (255, 0, 0), 2)
cv2.line(frame, (int(esquerda_x), 0), (int(direita_x), altura), (0, 255, 0), 2)
cv2.line(frame, (int(esquerda_x), 0), (int(esquerda_x), altura), (0, 255, 255), 2)
cv2.line(frame, (int(direita_x), 0), (int(direita_x), altura), (0, 255, 255), 2)
# Função para processar cada frame do vídeo e calcular as distâncias
def processar_frame(frame, largura, altura):
# Convertendo para escala de cinza
cinza = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# Limiarização para criar uma imagem binária
_, binarizada = cv2.threshold(cinza, 128, 255, cv2.THRESH_BINARY_INV)
# Encontrar os contornos
contornos, _ = cv2.findContours(binarizada, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# Se houver contornos, assumir que o maior é a linha preta
if contornos:
maior_contorno = max(contornos, key=cv2.contourArea)
# Ajustar uma linha ao maior contorno (linha preta)
[vx, vy, x0, y0] = cv2.fitLine(maior_contorno, cv2.DIST_L2, 0, 0.01, 0.01)
# Verificar se vy é zero para evitar divisão por zero
if vy == 0:
esquerda_x = x0
direita_x = x0
else:
# Determinar os pontos extremos da linha preta
esquerda_x = int(x0 + (-y0 * vx / vy))
direita_x = int(x0 + ((altura - y0) * vx / vy))
# Calcular distâncias das bordas
distancia_esquerda = max(0, esquerda_x)
distancia_direita = max(0, largura - direita_x)
# Calcular o ângulo entre a linha central e a linha ajustada
linha_central = [largura // 2, 0, largura // 2, altura]
linha_ajustada = [esquerda_x, 0, direita_x, altura]
angulo = calcular_angulo(linha_central, linha_ajustada)
# Desenhar linhas, se necessário
desenhar_linhas(frame, altura, largura, esquerda_x, direita_x, mostrar_linhas)
return (angulo, distancia_esquerda, distancia_direita, frame)
return (None, None, None, frame)
# Caminho do arquivo JSON para salvar os dados
output_folder = 'Python/Output/'
json_path = arquivoSaida
json_data = None
# Função para salvar os dados em formato JSON
def salvar_json(leituras, angulo, distancia_esquerda, distancia_direita, timestamp, json_path):
global json_data # Indica que queremos usar a variável global json_data
# Assegure-se que todos os dados são tipos primitivos antes de salvar em JSON
json_data = {
'timestamp': timestamp,
'angulo': angulo,
'distancia_esquerda': distancia_esquerda,
'distancia_direita': distancia_direita
}
if not os.path.exists(output_folder):
os.makedirs(output_folder)
leituras.append(json_data)
if len(leituras) > max_readings:
leituras.pop(0)
with open(output_folder + json_path, 'w') as file:
json.dump(leituras, file, indent=4)
def detect_lines(camera_index):
# Inicializando a captura de vídeo
cap = cv2.VideoCapture(camera_index)
if not cap.isOpened():
print("Erro: A câmera não pôde ser aberta.")
return
altura, largura = None, None
leituras = []
try:
while True:
ret, frame = cap.read()
if not ret:
print("Falha ao capturar imagem da câmera.")
break
if altura is None or largura is None:
altura, largura = frame.shape[:2]
# Processar o frame atual
angulo, distancia_esquerda, distancia_direita, frame_processado = processar_frame(frame, largura, altura)
if angulo is not None and distancia_esquerda is not None and distancia_direita is not None:
timestamp = time.time()
salvar_json(leituras, angulo, distancia_esquerda, distancia_direita, timestamp, json_path)
# Codificar o frame processado para JPEG
ret, buffer = cv2.imencode('.jpg', frame_processado)
if not ret:
continue
frame_bytes = buffer.tobytes()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame_bytes + b'\r\n')
finally:
# Quando tudo estiver feito, liberar a captura
cap.release()
# Função para lidar com a conexão de cada cliente
def handle_client_connection(client_socket):
try:
while True:
# Tente enviar o dicionário serializado em JSON
try:
client_socket.send(json.dumps(json_data).encode('utf-8'))
except TypeError as e:
print(f"Erro ao enviar dados: {e}")
# Aguardar um pouco antes de enviar os próximos dados
time.sleep(0.2)
except socket.error as e:
print(f"Cliente desconectado com erro: {e}")
finally:
# Fechar a conexão do socket ao sair do loop
client_socket.close()
# Configuração inicial do servidor de socket
def start_server(address='localhost', port=socket_porta):
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((address, port))
server.listen()
print(f"Servidor iniciado. Aguardando conexões em {address}:{port}...")
try:
while True:
client_sock, address = server.accept()
print(f"Aceitando conexão de {address[0]}:{address[1]}")
client_handler = threading.Thread(
target=handle_client_connection,
args=(client_sock,)
)
client_handler.start()
finally:
server.close()
# Esta função é para iniciar o servidor de socket em uma thread separada
def run_socket_server():
start_server()
# Iniciar o servidor Flask em uma thread separada
def run_flask_server():
app.run(host='0.0.0.0', port=porta, threaded=True, debug=False)
@app.route('/' + url, methods=['GET'])
def video_feed():
camera_index = int(request.args.get('camera_index'))
return Response(detect_lines(camera_index), mimetype='multipart/x-mixed-replace; boundary=frame')
# Iniciar o servidor
if __name__ == '__main__':
# Inicia o servidor de socket em uma thread separada
socket_server_thread = threading.Thread(target=run_socket_server)
socket_server_thread.start()
# Inicia o servidor Flask na thread principal
run_flask_server()

View File

@ -6,6 +6,7 @@ import folium
pathFiles = sys.argv[1]
fileName = sys.argv[2]
outputName = sys.argv[3]
outputMapName = sys.argv[4]
pastaSaida = 'Python/Output/'
@ -68,4 +69,4 @@ geojson_data = data_geometry.to_json()
folium.GeoJson(geojson_data).add_to(m)
# Salvar o mapa interativo em um arquivo HTML
m.save(pastaSaida + 'mapa_interativo.html')
m.save(pastaSaida + outputMapName)

View File

@ -0,0 +1 @@
{"Conectado":false,"QuantidadeBicos":10,"BicosPulverizadores":[{"ID":"B01","Posicao":1,"Atuado":true,"Comandar":true,"Inicializado":false,"Testando":false,"Funcoes":[21,22],"StatusBico":false,"NivelFluxo":0.0},{"ID":"B02","Posicao":2,"Atuado":true,"Comandar":true,"Inicializado":false,"Testando":false,"Funcoes":[21,22],"StatusBico":false,"NivelFluxo":0.0},{"ID":"B03","Posicao":3,"Atuado":true,"Comandar":true,"Inicializado":false,"Testando":false,"Funcoes":[21,22],"StatusBico":false,"NivelFluxo":0.0},{"ID":"B04","Posicao":4,"Atuado":false,"Comandar":false,"Inicializado":false,"Testando":false,"Funcoes":[21,22],"StatusBico":false,"NivelFluxo":0.0},{"ID":"B05","Posicao":5,"Atuado":false,"Comandar":false,"Inicializado":false,"Testando":false,"Funcoes":[21,22],"StatusBico":false,"NivelFluxo":0.0},{"ID":"B06","Posicao":6,"Atuado":false,"Comandar":false,"Inicializado":false,"Testando":false,"Funcoes":[21,22],"StatusBico":false,"NivelFluxo":0.0},{"ID":"B07","Posicao":7,"Atuado":false,"Comandar":false,"Inicializado":false,"Testando":false,"Funcoes":[21,22],"StatusBico":false,"NivelFluxo":0.0},{"ID":"B08","Posicao":8,"Atuado":false,"Comandar":false,"Inicializado":false,"Testando":false,"Funcoes":[21,22],"StatusBico":false,"NivelFluxo":0.0},{"ID":"B09","Posicao":9,"Atuado":false,"Comandar":false,"Inicializado":false,"Testando":false,"Funcoes":[21,22],"StatusBico":false,"NivelFluxo":0.0},{"ID":"B10","Posicao":10,"Atuado":false,"Comandar":false,"Inicializado":false,"Testando":false,"Funcoes":[21,22],"StatusBico":false,"NivelFluxo":0.0}],"PercentualInicioPulverizacao":0.3,"PercentualReservatorio":0.0}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
{"Conectado":false,"Sensores":[{"ID":"VBAT","Descricao":"Tensão da bateria","Componente":6,"Aferir":true,"Inicializado":false,"Testando":false,"Funcoes":[21]},{"ID":"ABAT","Descricao":"Corrente da bateria","Componente":5,"Aferir":true,"Inicializado":false,"Testando":false,"Funcoes":[21]}]}
{"Conectado":false,"Sensores":[{"LogGrafico":[],"ID":"VBAT","Prioridade":0,"Descricao":"Tensão da bateria","Componente":6,"Aferir":true,"DelayAmostragem":500,"Inicializado":false,"Testando":false,"Funcoes":[21],"UnidadeMedida":null,"Leituras":null,"ValorMinimo":0.0,"ValorMaximo":0.0},{"LogGrafico":[],"ID":"ABAT","Prioridade":0,"Descricao":"Corrente da bateria","Componente":5,"Aferir":true,"DelayAmostragem":500,"Inicializado":false,"Testando":false,"Funcoes":[21],"UnidadeMedida":null,"Leituras":null,"ValorMinimo":0.0,"ValorMaximo":0.0}]}

View File

@ -0,0 +1 @@
[{"Pino":99,"Descricao":"3V3_1","Funcao":0,"Habilitado":false,"ComponenteID":""},{"Pino":98,"Descricao":"3V3_2","Funcao":0,"Habilitado":false,"ComponenteID":""},{"Pino":97,"Descricao":"RST","Funcao":0,"Habilitado":false,"ComponenteID":""},{"Pino":4,"Descricao":"GPIO4","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Pino":5,"Descricao":"GPIO5","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Pino":6,"Descricao":"GPIO6","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Pino":7,"Descricao":"GPIO7","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Pino":15,"Descricao":"GPIO15","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Pino":16,"Descricao":"GPIO16","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Pino":17,"Descricao":"GPIO17","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Pino":18,"Descricao":"GPIO18","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Pino":8,"Descricao":"GPIO8","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Pino":3,"Descricao":"GPIO3","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Pino":46,"Descricao":"GPIO46","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Pino":9,"Descricao":"GPIO9","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Pino":10,"Descricao":"GPIO10","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Pino":11,"Descricao":"GPIO11","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Pino":12,"Descricao":"GPIO12","Funcao":21,"Habilitado":true,"ComponenteID":"B03"},{"Pino":13,"Descricao":"GPIO13","Funcao":21,"Habilitado":true,"ComponenteID":"B02"},{"Pino":14,"Descricao":"GPIO14","Funcao":21,"Habilitado":true,"ComponenteID":"B01"},{"Pino":96,"Descricao":"5V","Funcao":0,"Habilitado":false,"ComponenteID":""},{"Pino":95,"Descricao":"GND_1","Funcao":0,"Habilitado":false,"ComponenteID":""},{"Pino":94,"Descricao":"GND_2","Funcao":0,"Habilitado":false,"ComponenteID":""},{"Pino":93,"Descricao":"GND_3","Funcao":0,"Habilitado":false,"ComponenteID":""},{"Pino":19,"Descricao":"GPIO19","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Pino":20,"Descricao":"GPIO20","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Pino":21,"Descricao":"GPIO21","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Pino":47,"Descricao":"GPIO47","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Pino":48,"Descricao":"GPIO48","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Pino":45,"Descricao":"GPIO45","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Pino":0,"Descricao":"GPIO0","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Pino":35,"Descricao":"GPIO35","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Pino":36,"Descricao":"GPIO36","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Pino":37,"Descricao":"GPIO37","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Pino":38,"Descricao":"GPIO38","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Pino":39,"Descricao":"GPIO39","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Pino":40,"Descricao":"GPIO40","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Pino":41,"Descricao":"GPIO41","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Pino":42,"Descricao":"GPIO42","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Pino":2,"Descricao":"GPIO2","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Pino":1,"Descricao":"GPIO1","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Pino":44,"Descricao":"RX","Funcao":0,"Habilitado":false,"ComponenteID":""},{"Pino":43,"Descricao":"TX","Funcao":0,"Habilitado":false,"ComponenteID":""},{"Pino":92,"Descricao":"GND_4","Funcao":0,"Habilitado":false,"ComponenteID":""}]

View File

@ -1 +1 @@
ac61833169a5368b815cb3f22b161e5a300cdf03
908a685e8becb0dd9bec840937514641f5a9adbd

View File

@ -80,7 +80,6 @@ C:\Zendion Inc\agrobot_base\AgroBase\AgroBase\bin\Debug\sv\ZedGraph.resources.dl
C:\Zendion Inc\agrobot_base\AgroBase\AgroBase\bin\Debug\tr\ZedGraph.resources.dll
C:\Zendion Inc\agrobot_base\AgroBase\AgroBase\bin\Debug\zh-cn\ZedGraph.resources.dll
C:\Zendion Inc\agrobot_base\AgroBase\AgroBase\bin\Debug\zh-tw\ZedGraph.resources.dll
C:\Zendion Inc\agrobot_base\AgroBase\AgroBase\obj\Debug\AgroBase.Forms.frmCamera.resources
C:\Zendion Inc\agrobot_base\AgroBase\AgroBase\bin\Debug\CefSharp.Core.Runtime.dll
C:\Zendion Inc\agrobot_base\AgroBase\AgroBase\bin\Debug\CefSharp.Core.Runtime.pdb
C:\Zendion Inc\agrobot_base\AgroBase\AgroBase\bin\Debug\CefSharp.Core.Runtime.xml
@ -183,3 +182,9 @@ C:\Zendion Inc\agrobot_base\AgroBase\AgroBase\bin\Debug\Python\Models\yolo\crop_
C:\Zendion Inc\agrobot_base\AgroBase\AgroBase\bin\Debug\Python\Scripts\green-detector.py
C:\Zendion Inc\agrobot_base\AgroBase\AgroBase\obj\Debug\AgroBase.Forms.frmMapa.resources
C:\Zendion Inc\agrobot_base\AgroBase\AgroBase\bin\Debug\Python\Scripts\map-load.py
C:\Zendion Inc\agrobot_base\AgroBase\AgroBase\obj\Debug\AgroBase.Forms.frmAtuCamera.resources
C:\Zendion Inc\agrobot_base\AgroBase\AgroBase\obj\Debug\AgroBase.Forms.Sensoriamento.frmSenCamera.resources
C:\Zendion Inc\agrobot_base\AgroBase\AgroBase\bin\Debug\Python\Scripts\line-angle.py
C:\Zendion Inc\agrobot_base\AgroBase\AgroBase\bin\Debug\Python\Scripts\line-angle2.py
C:\Zendion Inc\agrobot_base\AgroBase\AgroBase\obj\Debug\AgroBase.Forms.Operacoes.frmOperacaoSeguidorLinha.resources
C:\Zendion Inc\agrobot_base\AgroBase\AgroBase\obj\Debug\AgroBase.Forms.Atuador.frmAtuConfig.resources

BIN
Documentos/Cabeamento.xlsx Normal file

Binary file not shown.

View File

@ -0,0 +1,249 @@
// Dispositivo: Atuador
// Versão Firmware: 1
// Ultima atualização: 22/12/2023
#include "C:\Zendion Inc\agrobot_base\Firmware\Modulos\SerialService.h"
#define D_Code Atu
#define _pinoLED RGB_BUILTIN
int _pinoReleGeral = -1;
long _baudRate = 115200;
bool Conectado = false;
int _TaxaAmostragem = 500;
int BicosAtivos = 10;
class BicoPulverizador {
public:
// Construtor
BicoPulverizador(String desc) {
_ID = desc;
}
// Definições
String _ID;
int _posicao;
int _pinoSolenoide;
int _pinoSensor;
bool Iniciado = false;
bool Testando = false;
// Consumo
double NivelFluxo;
bool StatusBico;
// Entrada de dados
bool _BicoAtuado = false;
void Inicializar() {
if (Iniciado) {
EnviarDadosSerial(_ID + " ja inicializado");
EnviarDadosSerial(MontarProtocoloSensor(sCFG, _ID, Iniciado ? "1" : "0"));
return;
}
if (_pinoSolenoide > -1) {
pinMode(_pinoSolenoide, OUTPUT);
digitalWrite(_pinoSolenoide, LOW);
_BicoAtuado = false;
StatusBico = digitalRead(_pinoSolenoide) == 1;
}
if (_pinoSensor > -1) {
pinMode(_pinoSensor, INPUT);
NivelFluxo = 0;
}
xTaskCreatePinnedToCore(&BicoPulverizador::SensorTaskWrapper, "SensorTask", 5000, this, 25 - _posicao, &SensorTaskHandle, tskNO_AFFINITY);
EnviarDadosSerial(_ID + " Iniciado");
Iniciado = true;
EnviarDadosSerial(MontarProtocoloSensor(sCFG, _ID, Iniciado ? "1" : "0"));
}
void Desligar() {
if (!Iniciado) {
EnviarDadosSerial(_ID + " nao esta inicializado");
EnviarDadosSerial(MontarProtocoloSensor(sCFG, _ID, Iniciado ? "1" : "0"));
return;
}
// Parar a execução das tarefas
vTaskDelete(SensorTaskHandle);
// Redefinir as configurações para os valores iniciais
pinMode(_pinoSolenoide, INPUT);
pinMode(_pinoSensor, INPUT);
EnviarDadosSerial(_ID + " Desligado");
Iniciado = false;
EnviarDadosSerial(MontarProtocoloSensor(sCFG, _ID, Iniciado ? "1" : "0"));
}
void AlterarStatusBico() {
digitalWrite(_pinoSolenoide, _BicoAtuado);
StatusBico = digitalRead(_pinoSolenoide) == 1;
}
private:
TaskHandle_t SensorTaskHandle = NULL;
static void SensorTaskWrapper(void *pvParameters) {
BicoPulverizador *bico = static_cast<BicoPulverizador*>(pvParameters);
bico->SensorTask();
}
void SensorTask() {
unsigned long previousMillisLeitura = millis();
while (1)
{
if (!Conectado) {
// Caso não esteja conectado, aguarda 1 segundo até a próxima verificação, liberando uso de CPU
vTaskDelay(1000);
continue;
}
unsigned long currentMillis = millis();
if ((currentMillis - previousMillisLeitura) >= _TaxaAmostragem) {
previousMillisLeitura = currentMillis;
EnviarDadosSerial(MontarProtocoloSensor(sFLX, _ID, MontarDadosProtocoloBicoPulverizador(StatusBico, NivelFluxo)));
}
vTaskDelay(1);
}
}
};
BicoPulverizador B_01("B01");
BicoPulverizador B_02("B02");
BicoPulverizador B_03("B03");
BicoPulverizador B_04("B04");
BicoPulverizador B_05("B05");
BicoPulverizador B_06("B06");
BicoPulverizador B_07("B07");
BicoPulverizador B_08("B08");
BicoPulverizador B_09("B09");
BicoPulverizador B_10("B10");
BicoPulverizador* BicoPorID(String ID) {
BicoPulverizador* _bico =
ID == "B01" ? &B_01 :
ID == "B02" ? &B_02 :
ID == "B03" ? &B_03 :
ID == "B04" ? &B_04 :
ID == "B05" ? &B_05 :
ID == "B06" ? &B_06 :
ID == "B07" ? &B_07 :
ID == "B08" ? &B_08 :
ID == "B09" ? &B_09 :
&B_10;
return _bico;
}
void setup() {
Serial.begin(_baudRate);
if (_pinoReleGeral > -1) {
pinMode(_pinoReleGeral, OUTPUT);
digitalWrite(_pinoReleGeral, LOW);
}
}
void loop() {
if (Serial.available() > 3) {
String Protocolo = "";
F_Code _funcao = Nda;
while (Serial.available()) {
char Entrada = (char)Serial.read();
if (Entrada == EndLine) {
break;
}
Protocolo += Entrada;
if (Protocolo.length() == 3) {
if (_funcao == Nda) {
_funcao = (F_Code)((String)Protocolo[0] + (String)Protocolo[1] + (String)Protocolo[2]).toInt();
Protocolo = "";
}
}
}
EnviarDadosSerial("OK");
if (_funcao == Chk) {
EnviarDadosSerial(MontarProtocoloVerificacao(D_Code));
}
else if (_funcao == Cfg) {
String ID = ((String)Protocolo[0] + (String)Protocolo[1] + (String)Protocolo[2]);
bool Conectar = (String)Protocolo[4] == "1";
if (ID == "MD ") {
_TaxaAmostragem = ((String)Protocolo[6] + (String)Protocolo[7] + (String)Protocolo[8] + (String)Protocolo[9] + (String)Protocolo[10]).toInt();
int pinoReleGeral = ((String)Protocolo[12] + (String)Protocolo[13]).toInt();
if (pinoReleGeral > -1) {
pinMode(_pinoReleGeral, INPUT);
_pinoReleGeral = pinoReleGeral;
pinMode(_pinoReleGeral, OUTPUT);
digitalWrite(_pinoReleGeral, Conectar);
}
vTaskDelay(pdMS_TO_TICKS(100));
Conectado = Conectar;
EnviarDadosSerial(MontarProtocoloSensor(sCFG, "MD ", Conectado ? "1" : "0"));
}
else {
bool bico_ativado = (String)Protocolo[6] == "1";
int posicao = ((String)Protocolo[8] + (String)Protocolo[9]).toInt();
int solenoide = ((String)Protocolo[11] + (String)Protocolo[12]).toInt();
int sensor = ((String)Protocolo[14] + (String)Protocolo[15]).toInt();
BicoPulverizador* _bico = BicoPorID(ID);
if (bico_ativado) {
if (Conectar) {
_bico->_posicao = posicao;
_bico->_pinoSolenoide = solenoide;
_bico->_pinoSensor = sensor;
_bico->Inicializar();
}
else {
_bico->Desligar();
}
vTaskDelay(pdMS_TO_TICKS(500));
}
}
}
else if (_funcao == Cmd) {
//canal;potencia;sentido;rampa;precisao;rpm
//0;000;0;000;000;000
String ID = ((String)Protocolo[0] + (String)Protocolo[1] + (String)Protocolo[2]);
BicoPulverizador* _bico = BicoPorID(ID);
_bico->_BicoAtuado = (String)Protocolo[4] == "1";
_bico->AlterarStatusBico();
}
else if (_funcao == Tst) {
String ID = ((String)Protocolo[0] + (String)Protocolo[1] + (String)Protocolo[2]);
BicoPulverizador* _bico = BicoPorID(ID);
bool EmTeste = _bico->Testando;
if (!EmTeste) {
//_motor->Testar();
}
}
}
}

Binary file not shown.

View File

@ -0,0 +1,28 @@
name: Check Arduino
# See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows
on:
push:
pull_request:
schedule:
# Run every Tuesday at 8 AM UTC to catch breakage caused by new rules added to Arduino Lint.
- cron: "0 8 * * TUE"
workflow_dispatch:
repository_dispatch:
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Arduino Lint
uses: arduino/arduino-lint-action@v1
with:
compliance: specification
library-manager: update
# Always use this setting for official repositories. Remove for 3rd party projects.
official: false
project-type: library

View File

@ -0,0 +1,62 @@
name: Compile Examples
# See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows
on:
push:
paths:
- ".github/workflows/compile-examples.yml"
- "examples/**"
- "src/**"
pull_request:
paths:
- ".github/workflows/compile-examples.yml"
- "examples/**"
- "src/**"
schedule:
# Run every Tuesday at 8 AM UTC to catch breakage caused by changes to external resources (libraries, platforms).
- cron: "0 8 * * TUE"
workflow_dispatch:
repository_dispatch:
jobs:
build:
name: ${{ matrix.board.fqbn }}
runs-on: ubuntu-latest
env:
SKETCHES_REPORTS_PATH: sketches-reports
strategy:
fail-fast: false
matrix:
board:
- fqbn: arduino:avr:mega
platforms: |
- name: arduino:avr
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Compile examples
uses: arduino/compile-sketches@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
fqbn: ${{ matrix.board.fqbn }}
platforms: ${{ matrix.board.platforms }}
libraries: |
# Install the library from the local path.
- source-path: ./
- name: I2C_Functions
- name: Statistical
sketch-paths: |
- examples
enable-deltas-report: true
sketches-report-path: ${{ env.SKETCHES_REPORTS_PATH }}
- name: Save sketches report as workflow artifact
uses: actions/upload-artifact@v2
with:
if-no-files-found: error
path: ${{ env.SKETCHES_REPORTS_PATH }}
name: ${{ env.SKETCHES_REPORTS_PATH }}

View File

@ -0,0 +1,24 @@
name: Report Size Deltas
# See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows
on:
push:
paths:
- ".github/workflows/report-size-deltas.yml"
schedule:
# Run at the minimum interval allowed by GitHub Actions.
# Note: GitHub Actions periodically has outages which result in workflow failures.
# In this event, the workflows will start passing again once the service recovers.
- cron: "*/5 * * * *"
workflow_dispatch:
repository_dispatch:
jobs:
report:
runs-on: ubuntu-latest
steps:
- name: Comment size deltas reports to PRs
uses: arduino/report-size-deltas@v1
with:
# The name of the workflow artifact created by the sketch compilation workflow
sketches-reports-source: sketches-reports

View File

@ -0,0 +1,22 @@
name: Spell Check
# See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows
on:
push:
pull_request:
schedule:
# Run every Tuesday at 8 AM UTC to catch new misspelling detections resulting from dictionary updates.
- cron: "0 8 * * TUE"
workflow_dispatch:
repository_dispatch:
jobs:
spellcheck:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Spell check
uses: codespell-project/actions-codespell@master

View File

@ -0,0 +1,133 @@
# Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/sync-labels.md
name: Sync Labels
# See: https://docs.github.com/en/actions/reference/events-that-trigger-workflows
on:
push:
paths:
- ".github/workflows/sync-labels.ya?ml"
- ".github/label-configuration-files/*.ya?ml"
pull_request:
paths:
- ".github/workflows/sync-labels.ya?ml"
- ".github/label-configuration-files/*.ya?ml"
schedule:
# Run daily at 8 AM UTC to sync with changes to shared label configurations.
- cron: "0 8 * * *"
workflow_dispatch:
repository_dispatch:
env:
CONFIGURATIONS_FOLDER: .github/label-configuration-files
CONFIGURATIONS_ARTIFACT: label-configuration-files
jobs:
check:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Download JSON schema for labels configuration file
id: download-schema
uses: carlosperate/download-file-action@v1
with:
file-url: https://raw.githubusercontent.com/arduino/tooling-project-assets/main/workflow-templates/assets/sync-labels/arduino-tooling-gh-label-configuration-schema.json
location: ${{ runner.temp }}/label-configuration-schema
- name: Install JSON schema validator
run: |
sudo npm install \
--global \
ajv-cli \
ajv-formats
- name: Validate local labels configuration
run: |
# See: https://github.com/ajv-validator/ajv-cli#readme
ajv validate \
--all-errors \
-c ajv-formats \
-s "${{ steps.download-schema.outputs.file-path }}" \
-d "${{ env.CONFIGURATIONS_FOLDER }}/*.{yml,yaml}"
download:
needs: check
runs-on: ubuntu-latest
strategy:
matrix:
filename:
# Filenames of the shared configurations to apply to the repository in addition to the local configuration.
# https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/sync-labels
- universal.yml
steps:
- name: Download
uses: carlosperate/download-file-action@v1
with:
file-url: https://raw.githubusercontent.com/arduino/tooling-project-assets/main/workflow-templates/assets/sync-labels/${{ matrix.filename }}
- name: Pass configuration files to next job via workflow artifact
uses: actions/upload-artifact@v2
with:
path: |
*.yaml
*.yml
if-no-files-found: error
name: ${{ env.CONFIGURATIONS_ARTIFACT }}
sync:
needs: download
runs-on: ubuntu-latest
steps:
- name: Set environment variables
run: |
# See: https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-environment-variable
echo "MERGED_CONFIGURATION_PATH=${{ runner.temp }}/labels.yml" >> "$GITHUB_ENV"
- name: Determine whether to dry run
id: dry-run
if: >
github.event_name == 'pull_request' ||
(
(
github.event_name == 'push' ||
github.event_name == 'workflow_dispatch'
) &&
github.ref != format('refs/heads/{0}', github.event.repository.default_branch)
)
run: |
# Use of this flag in the github-label-sync command will cause it to only check the validity of the
# configuration.
echo "::set-output name=flag::--dry-run"
- name: Checkout repository
uses: actions/checkout@v3
- name: Download configuration files artifact
uses: actions/download-artifact@v2
with:
name: ${{ env.CONFIGURATIONS_ARTIFACT }}
path: ${{ env.CONFIGURATIONS_FOLDER }}
- name: Remove unneeded artifact
uses: geekyeggo/delete-artifact@v1
with:
name: ${{ env.CONFIGURATIONS_ARTIFACT }}
- name: Merge label configuration files
run: |
# Merge all configuration files
shopt -s extglob
cat "${{ env.CONFIGURATIONS_FOLDER }}"/*.@(yml|yaml) > "${{ env.MERGED_CONFIGURATION_PATH }}"
- name: Install github-label-sync
run: sudo npm install --global github-label-sync
- name: Sync labels
env:
GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# See: https://github.com/Financial-Times/github-label-sync
github-label-sync \
--labels "${{ env.MERGED_CONFIGURATION_PATH }}" \
${{ steps.dry-run.outputs.flag }} \
${{ github.repository }}

View File

@ -0,0 +1,41 @@
{
"configurations": [
{
"name": "PlatformIO",
"includePath": [
"~/Documents/Arduino/**",
"~/Documents/Arduino/Libraries/**",
"~/Documents/Arduino/Hardware/**",
"~/Applications/Arduino.app/**",
"~/Documents/Arduino/hardware/MegaCore-2.1.3/avr/cores/**",
"~/Documents/Arduino/hardware/MegaCore-2.1.3/avr/libraries/**"
],
"browse": {
"limitSymbolsToIncludedHeaders": true,
"path": [
"~/Documents/Arduino/**",
"~/Documents/Arduino/Libraries/**",
"~/Documents/Arduino/Hardware/**",
"~/Applications/Arduino.app/**",
"~/Documents/Arduino/hardware/MegaCore-2.1.3/avr/cores/**",
"~/Documents/Arduino/hardware/MegaCore-2.1.3/avr/libraries/**"
]
},
"defines": [
"PLATFORMIO=50203",
"ARDUINO_AVR_MEGA2560",
"F_CPU=7372800L",
"ARDUINO_ARCH_AVR",
"ARDUINO=10808",
"__AVR_ATmega2560__"
],
"cStandard": "c11",
"cppStandard": "c++11",
"compilerPath": "~/.platformio/packages/toolchain-atmelavr/bin/avr-gcc",
"compilerArgs": [
"-mmcu=atmega2560"
]
}
],
"version": 4
}

View File

@ -0,0 +1 @@
* @akkoyun

View File

@ -0,0 +1,22 @@
MIT License
Copyright (c) 2022 Mehmet Günce Akkoyun
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,79 @@
# MAX17055 Library <sup>V2.2</sup>
![GitHub release (latest by date)](https://img.shields.io/github/v/release/akkoyun/MAX17055) ![arduino-library-badge](https://www.ardu-badge.com/badge/MAX17055.svg?) ![Visits Badge](https://badges.pufler.dev/visits/akkoyun/MAX17055) ![GitHub stars](https://img.shields.io/github/stars/akkoyun/MAX17055?style=flat&logo=github) ![Updated Badge](https://badges.pufler.dev/updated/akkoyun/MAX17055) [![PlatformIO Registry](https://badges.registry.platformio.org/packages/akkoyun/library/MAX17055.svg)](https://registry.platformio.org/libraries/akkoyun/MAX17055)
[![Check Arduino](https://github.com/akkoyun/MAX17055/actions/workflows/check-arduino.yml/badge.svg)](https://github.com/akkoyun/MAX17055/actions/workflows/check-arduino.yml) [![Compile Examples](https://github.com/akkoyun/MAX17055/actions/workflows/compile-examples.yml/badge.svg)](https://github.com/akkoyun/MAX17055/actions/workflows/compile-examples.yml) [![Spell Check](https://github.com/akkoyun/MAX17055/actions/workflows/spell-check.yml/badge.svg)](https://github.com/akkoyun/MAX17055/actions/workflows/spell-check.yml)
Battery Gauge Sensor - 02.02.00
---
**General Description**
The MAX17055 is a low 7μA operating current fuel gauge that implements Maxim ModelGaugeTM m5 EZ algorithm. ModelGauge m5 EZ makes fuel gauge implementation easy by eliminating battery characterization requirements and simplifying host software interaction. The ModelGauge m5 EZ robust algorithm provides tolerance against battery diversity for most lithium batteries and applications.
ModelGauge m5 EZ algorithm combines the short-term accuracy and linearity of a coulomb counter with the longterm stability of a voltage-based fuel gauge, along with temperature compensation to provide industry-leading fuel gauge accuracy. The MAX17055 automatically compensates for cell aging, temperature, and discharge rate, and provides accurate state of charge (SOC in %) and remaining capacity in milliampere-hours (mAh). As the battery approaches the critical region near empty, the ModelGauge m5 algorithm invokes a special compensa- tion that eliminates any error. It also provides three methods for reporting the age of the battery: reduction in capacity, increase in battery resistance, and cycle odometer.
The MAX17055 provides precision measurements of current, voltage, and temperature. Temperature of the battery pack is measured using an internal temperature measurement or external thermistor. A 2-wire I2C interface provides access to data and control registers.
The MAX17055 is available in a tiny, lead-free 0.4mm pitch 1.4mm x 1.5mm, 9-pin WLP package, and a 2mm x 2.5mm, 10-pin TDFN package.
**Benefits and Features**
* ModelGauge m5 EZ
* No Characterization Required for EZ Performance
* Robust Against Battery Variation
* Eliminates Error Near Empty Voltage
* Eliminates Coulomb Counter Drift
* Current, Temperature, and Age Compensated
* Does Not Require Empty, Full, or Idle States
* Low 7μA Operating Current
* Wide Sense Resistor Range
* 1mΩ to 1000mΩ
* PCB Metal Sensing + Temperature Compensation
* Supports Li+ and Variants Including LiFePO4
* ±1°C Internal Temperature or Thermistor
* Dynamic Power Estimates Power Capability During Discharge
* Time-to-Empty and Time-to-Full Estimation
* Constant Power or Constant Current
* Predicts Remaining Capacity Under Theoretical Load
* Precision Measurement System
* No Calibration Required
* Alert Indicator for Voltage, SOC, Temperature, Current and 1% SOC Change
**Measured Parameters**
* Gauge Serial ID
* Instant Voltage
* Average Voltage
* Empty Voltage
* Charge Recovery Voltage
* Instant Current
* Average Current
* Charge Termination Current
* State Of Charge
* Average State Of Charge
* Instant Capacity
* Design Capacity
* Full Capacity
* Temperature
* Time To Empty
* Time To Full
* Battery Age
* Charge Cycle
* Control for Power on Reset
* Control for Min Current
* Control for Max Current
* Control for Min Voltage
* Control for Max Voltage
* Control for Min Temperature
* Control for Max Temperature
* Control for Min SOC
* Control for Max SOC
* Control for Battery Present
* Control for SOC Change
* Control for Battery Insertion
* Control for Battery Removal
---
[![Support me](https://img.shields.io/badge/Support-PATREON-GREEN.svg)](https://www.patreon.com/bePatron?u=62967889) ![Twitter Follow](https://img.shields.io/twitter/follow/gunceakkoyun?style=social) ![YouTube Channel Views](https://img.shields.io/youtube/channel/views/UCIguQGdaBT1GnnVMz5qAZ2Q?style=social) ![Repos Badge](https://badges.pufler.dev/repos/akkoyun) [![E-Mail](https://img.shields.io/badge/E_Mail-Mehmet_Gunce_Akkoyun-blue.svg)](mailto:akkoyun@me.com) ![GitHub](https://img.shields.io/github/license/akkoyun/Statistical)

View File

@ -0,0 +1,54 @@
// İnclude Library
#include "MAX17055.h"
// Create Charger Object
MAX17055 Battery(true, 8);
// Setup Function
void setup() {
// Serial Communication Start
Serial.begin(115200);
// Begin Sensor
Battery.Begin();
// Header
Serial.println(" Battery Abstract ");
Serial.println("--------------------------");
}
void loop() {
// Set Start Time
uint32_t Time = millis();
// Serial Print Data
Serial.print("Temperature : "); Serial.print(Battery.Temperature()); Serial.println(" C");
Serial.print("Instant Voltage : "); Serial.print(Battery.Instant_Voltage()); Serial.println(" V");
Serial.print("Average Voltage : "); Serial.print(Battery.Average_Voltage()); Serial.println(" V");
Serial.print("Empty Voltage : "); Serial.print(Battery.Empty_Voltage()); Serial.println(" V");
Serial.print("Recovery Voltage : "); Serial.print(Battery.Recovery_Voltage()); Serial.println(" V");
Serial.print("Instant Current : "); Serial.print(Battery.Instant_Current()); Serial.println(" mA");
Serial.print("Average Current : "); Serial.print(Battery.Average_Current()); Serial.println(" mA");
Serial.print("State of Charge : "); Serial.print(Battery.State_Of_Charge(), 2); Serial.println(" %");
Serial.print("Instant Capacity : "); Serial.print(Battery.Instant_Capacity()); Serial.println(" mAh");
Serial.print("Full Capacity : "); Serial.print(Battery.Full_Capacity()); Serial.println(" mAh");
Serial.print("Design Capacity : "); Serial.print(Battery.Design_Capacity()); Serial.println(" mAh");
Serial.print("Time to Empty : "); Serial.print(Battery.Time_To_Empty()); Serial.println(" h");
Serial.print("Time to Full : "); Serial.print(Battery.Time_To_Full()); Serial.println(" h");
Serial.print("Battery Age : "); Serial.print(Battery.Battery_Age()); Serial.println(" ");
Serial.println(" ");
// Calculate Delta Time
uint32_t _DT = millis() - Time;
// Serial Print Divider
Serial.println("--------------------------------");
// Loop Delay
delay(5000);
}

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