implementado protocolo CAN para o modulo MKS

This commit is contained in:
Diego Freitas 2025-04-04 15:58:30 -03:00
parent 8c87105398
commit 9fbcbeb621
34 changed files with 1100 additions and 140 deletions

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -485,6 +485,7 @@
<Compile Include="Services\APIService.cs" />
<Compile Include="Services\BLD300RService.cs" />
<Compile Include="Services\CameraService.cs" />
<Compile Include="Services\CANService.cs" />
<Compile Include="Services\CoulombCounterService.cs" />
<Compile Include="Services\DispositivosService.cs" />
<Compile Include="Forms\frmPrincipal.cs">
@ -504,6 +505,7 @@
<Compile Include="Services\LoRaSerializer.cs" />
<Compile Include="Services\LoRaService.cs" />
<Compile Include="Services\MapasService.cs" />
<Compile Include="Services\MKS057DCanService.cs" />
<Compile Include="Services\MKS057DService.cs" />
<Compile Include="Services\ModbusService.cs" />
<Compile Include="Services\MqttService.cs" />

View File

@ -98,6 +98,9 @@
this.cmbModoLimite = new System.Windows.Forms.ComboBox();
this.label17 = new System.Windows.Forms.Label();
this.groupBox5 = new System.Windows.Forms.GroupBox();
this.btnEntradas = new System.Windows.Forms.Button();
this.chbIN2 = new System.Windows.Forms.CheckBox();
this.chbIN1 = new System.Windows.Forms.CheckBox();
this.btnSobre = new System.Windows.Forms.Button();
this.btnDesbloquear = new System.Windows.Forms.Button();
this.btnBloqueado = new System.Windows.Forms.Button();
@ -126,17 +129,18 @@
this.label23 = new System.Windows.Forms.Label();
this.txtDirecao = new System.Windows.Forms.TextBox();
this.label22 = new System.Windows.Forms.Label();
this.chbIN1 = new System.Windows.Forms.CheckBox();
this.chbIN2 = new System.Windows.Forms.CheckBox();
this.btnEntradas = new System.Windows.Forms.Button();
this.groupBox7 = new System.Windows.Forms.GroupBox();
this.txtAnguloSP = new System.Windows.Forms.TextBox();
this.label26 = new System.Windows.Forms.Label();
this.label27 = new System.Windows.Forms.Label();
this.txtAnguloAtual = new System.Windows.Forms.TextBox();
this.btnCANtest = new System.Windows.Forms.Button();
this.btnIniciarRef = new System.Windows.Forms.Button();
this.label28 = new System.Windows.Forms.Label();
this.txtSensor = new System.Windows.Forms.TextBox();
this.btnIniciarRef = new System.Windows.Forms.Button();
this.label27 = new System.Windows.Forms.Label();
this.txtAnguloAtual = new System.Windows.Forms.TextBox();
this.label26 = new System.Windows.Forms.Label();
this.txtAnguloSP = new System.Windows.Forms.TextBox();
this.btnSetZeroCAN = new System.Windows.Forms.Button();
this.btnMovimentoCAN = new System.Windows.Forms.Button();
this.lblLeituraMksCan = new System.Windows.Forms.Label();
this.groupBox1.SuspendLayout();
this.groupBox2.SuspendLayout();
this.groupBox3.SuspendLayout();
@ -870,6 +874,38 @@
this.groupBox5.TabStop = false;
this.groupBox5.Text = "Leitura Dados";
//
// btnEntradas
//
this.btnEntradas.Location = new System.Drawing.Point(112, 238);
this.btnEntradas.Name = "btnEntradas";
this.btnEntradas.Size = new System.Drawing.Size(102, 23);
this.btnEntradas.TabIndex = 22;
this.btnEntradas.Text = "Entradas";
this.btnEntradas.UseVisualStyleBackColor = true;
this.btnEntradas.Click += new System.EventHandler(this.btnEntradas_Click);
//
// chbIN2
//
this.chbIN2.AutoSize = true;
this.chbIN2.Enabled = false;
this.chbIN2.Location = new System.Drawing.Point(63, 242);
this.chbIN2.Name = "chbIN2";
this.chbIN2.Size = new System.Drawing.Size(43, 17);
this.chbIN2.TabIndex = 21;
this.chbIN2.Text = "IN2";
this.chbIN2.UseVisualStyleBackColor = true;
//
// chbIN1
//
this.chbIN1.AutoSize = true;
this.chbIN1.Enabled = false;
this.chbIN1.Location = new System.Drawing.Point(6, 242);
this.chbIN1.Name = "chbIN1";
this.chbIN1.Size = new System.Drawing.Size(43, 17);
this.chbIN1.TabIndex = 20;
this.chbIN1.Text = "IN1";
this.chbIN1.UseVisualStyleBackColor = true;
//
// btnSobre
//
this.btnSobre.Location = new System.Drawing.Point(220, 238);
@ -1130,40 +1166,11 @@
this.label22.TabIndex = 10;
this.label22.Text = "Direção";
//
// chbIN1
//
this.chbIN1.AutoSize = true;
this.chbIN1.Enabled = false;
this.chbIN1.Location = new System.Drawing.Point(6, 242);
this.chbIN1.Name = "chbIN1";
this.chbIN1.Size = new System.Drawing.Size(43, 17);
this.chbIN1.TabIndex = 20;
this.chbIN1.Text = "IN1";
this.chbIN1.UseVisualStyleBackColor = true;
//
// chbIN2
//
this.chbIN2.AutoSize = true;
this.chbIN2.Enabled = false;
this.chbIN2.Location = new System.Drawing.Point(63, 242);
this.chbIN2.Name = "chbIN2";
this.chbIN2.Size = new System.Drawing.Size(43, 17);
this.chbIN2.TabIndex = 21;
this.chbIN2.Text = "IN2";
this.chbIN2.UseVisualStyleBackColor = true;
//
// btnEntradas
//
this.btnEntradas.Location = new System.Drawing.Point(112, 238);
this.btnEntradas.Name = "btnEntradas";
this.btnEntradas.Size = new System.Drawing.Size(102, 23);
this.btnEntradas.TabIndex = 22;
this.btnEntradas.Text = "Entradas";
this.btnEntradas.UseVisualStyleBackColor = true;
this.btnEntradas.Click += new System.EventHandler(this.btnEntradas_Click);
//
// groupBox7
//
this.groupBox7.Controls.Add(this.btnMovimentoCAN);
this.groupBox7.Controls.Add(this.btnSetZeroCAN);
this.groupBox7.Controls.Add(this.btnCANtest);
this.groupBox7.Controls.Add(this.btnIniciarRef);
this.groupBox7.Controls.Add(this.label28);
this.groupBox7.Controls.Add(this.txtSensor);
@ -1178,39 +1185,25 @@
this.groupBox7.TabStop = false;
this.groupBox7.Text = "Referenciamento";
//
// txtAnguloSP
// btnCANtest
//
this.txtAnguloSP.Location = new System.Drawing.Point(87, 19);
this.txtAnguloSP.Name = "txtAnguloSP";
this.txtAnguloSP.ReadOnly = true;
this.txtAnguloSP.Size = new System.Drawing.Size(100, 20);
this.txtAnguloSP.TabIndex = 0;
this.btnCANtest.Location = new System.Drawing.Point(9, 304);
this.btnCANtest.Name = "btnCANtest";
this.btnCANtest.Size = new System.Drawing.Size(178, 23);
this.btnCANtest.TabIndex = 24;
this.btnCANtest.Text = "Requisitar Dados CAN";
this.btnCANtest.UseVisualStyleBackColor = true;
this.btnCANtest.Click += new System.EventHandler(this.btnCANtest_Click);
//
// label26
// btnIniciarRef
//
this.label26.AutoSize = true;
this.label26.Location = new System.Drawing.Point(6, 22);
this.label26.Name = "label26";
this.label26.Size = new System.Drawing.Size(57, 13);
this.label26.TabIndex = 18;
this.label26.Text = "Angulo SP";
//
// label27
//
this.label27.AutoSize = true;
this.label27.Location = new System.Drawing.Point(6, 48);
this.label27.Name = "label27";
this.label27.Size = new System.Drawing.Size(67, 13);
this.label27.TabIndex = 20;
this.label27.Text = "Angulo Atual";
//
// txtAnguloAtual
//
this.txtAnguloAtual.Location = new System.Drawing.Point(87, 45);
this.txtAnguloAtual.Name = "txtAnguloAtual";
this.txtAnguloAtual.ReadOnly = true;
this.txtAnguloAtual.Size = new System.Drawing.Size(100, 20);
this.txtAnguloAtual.TabIndex = 19;
this.btnIniciarRef.Location = new System.Drawing.Point(9, 376);
this.btnIniciarRef.Name = "btnIniciarRef";
this.btnIniciarRef.Size = new System.Drawing.Size(178, 23);
this.btnIniciarRef.TabIndex = 23;
this.btnIniciarRef.Text = "Iniciar Referenciamento";
this.btnIniciarRef.UseVisualStyleBackColor = true;
this.btnIniciarRef.Click += new System.EventHandler(this.btnIniciarRef_Click);
//
// label28
//
@ -1229,21 +1222,75 @@
this.txtSensor.Size = new System.Drawing.Size(100, 20);
this.txtSensor.TabIndex = 21;
//
// btnIniciarRef
// label27
//
this.btnIniciarRef.Location = new System.Drawing.Point(9, 376);
this.btnIniciarRef.Name = "btnIniciarRef";
this.btnIniciarRef.Size = new System.Drawing.Size(178, 23);
this.btnIniciarRef.TabIndex = 23;
this.btnIniciarRef.Text = "Iniciar Referenciamento";
this.btnIniciarRef.UseVisualStyleBackColor = true;
this.btnIniciarRef.Click += new System.EventHandler(this.btnIniciarRef_Click);
this.label27.AutoSize = true;
this.label27.Location = new System.Drawing.Point(6, 48);
this.label27.Name = "label27";
this.label27.Size = new System.Drawing.Size(67, 13);
this.label27.TabIndex = 20;
this.label27.Text = "Angulo Atual";
//
// txtAnguloAtual
//
this.txtAnguloAtual.Location = new System.Drawing.Point(87, 45);
this.txtAnguloAtual.Name = "txtAnguloAtual";
this.txtAnguloAtual.ReadOnly = true;
this.txtAnguloAtual.Size = new System.Drawing.Size(100, 20);
this.txtAnguloAtual.TabIndex = 19;
//
// label26
//
this.label26.AutoSize = true;
this.label26.Location = new System.Drawing.Point(6, 22);
this.label26.Name = "label26";
this.label26.Size = new System.Drawing.Size(57, 13);
this.label26.TabIndex = 18;
this.label26.Text = "Angulo SP";
//
// txtAnguloSP
//
this.txtAnguloSP.Location = new System.Drawing.Point(87, 19);
this.txtAnguloSP.Name = "txtAnguloSP";
this.txtAnguloSP.ReadOnly = true;
this.txtAnguloSP.Size = new System.Drawing.Size(100, 20);
this.txtAnguloSP.TabIndex = 0;
//
// btnSetZeroCAN
//
this.btnSetZeroCAN.Location = new System.Drawing.Point(9, 246);
this.btnSetZeroCAN.Name = "btnSetZeroCAN";
this.btnSetZeroCAN.Size = new System.Drawing.Size(178, 23);
this.btnSetZeroCAN.TabIndex = 25;
this.btnSetZeroCAN.Text = "Set Zero CAN";
this.btnSetZeroCAN.UseVisualStyleBackColor = true;
this.btnSetZeroCAN.Click += new System.EventHandler(this.btnSetZeroCAN_Click);
//
// btnMovimentoCAN
//
this.btnMovimentoCAN.Location = new System.Drawing.Point(9, 275);
this.btnMovimentoCAN.Name = "btnMovimentoCAN";
this.btnMovimentoCAN.Size = new System.Drawing.Size(178, 23);
this.btnMovimentoCAN.TabIndex = 26;
this.btnMovimentoCAN.Text = "Executar Movimento CAN";
this.btnMovimentoCAN.UseVisualStyleBackColor = true;
this.btnMovimentoCAN.Click += new System.EventHandler(this.btnMovimentoCAN_Click);
//
// lblLeituraMksCan
//
this.lblLeituraMksCan.AutoSize = true;
this.lblLeituraMksCan.Location = new System.Drawing.Point(12, 425);
this.lblLeituraMksCan.Name = "lblLeituraMksCan";
this.lblLeituraMksCan.Size = new System.Drawing.Size(39, 13);
this.lblLeituraMksCan.TabIndex = 15;
this.lblLeituraMksCan.Text = "Leitura";
//
// frmMKS
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(1051, 432);
this.ClientSize = new System.Drawing.Size(1051, 447);
this.Controls.Add(this.lblLeituraMksCan);
this.Controls.Add(this.groupBox7);
this.Controls.Add(this.groupBox6);
this.Controls.Add(this.groupBox5);
@ -1269,6 +1316,7 @@
this.groupBox7.ResumeLayout(false);
this.groupBox7.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
@ -1383,5 +1431,9 @@
private System.Windows.Forms.Label label28;
private System.Windows.Forms.TextBox txtSensor;
private System.Windows.Forms.Button btnIniciarRef;
private System.Windows.Forms.Button btnCANtest;
private System.Windows.Forms.Button btnSetZeroCAN;
private System.Windows.Forms.Button btnMovimentoCAN;
private System.Windows.Forms.Label lblLeituraMksCan;
}
}

View File

@ -2,6 +2,7 @@
using AgroBase.Services;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Threading.Tasks;
@ -329,7 +330,7 @@ namespace AgroBase.Forms
DataSended = Convert.ToByte(MyButton.Tag);
//SendRelevantData(QueryCommand[DataSended]);
MKS057DService.AdicionarComandoNaFila(MKS057DService.MontarComandoSetZero(Convert.ToByte(cmbEndereco.Text.Replace("0x", ""), 16)));
MKS057DRs485Service.AdicionarComandoNaFila(MKS057DRs485Service.MontarComandoSetZero(Convert.ToByte(cmbEndereco.Text.Replace("0x", ""), 16)));
}
private void btnIrParaZero_Click(object sender, EventArgs e)
@ -347,7 +348,7 @@ namespace AgroBase.Forms
DataSended = Convert.ToByte(MyButton.Tag);
//SendRelevantData(QueryCommand[DataSended]);
MKS057DService.AdicionarComandoNaFila(MKS057DService.MontarComandoMovimento(Convert.ToByte(cmbEndereco.Text.Replace("0x", ""), 16), Convert.ToDouble(txtValor.Text), Convert.ToInt32(cmbVelocidadePosicao.Text), rdbHorarioPosicao.Checked ? Sentido.Horario : Sentido.Antihorario));
MKS057DRs485Service.AdicionarComandoNaFila(MKS057DRs485Service.MontarComandoMovimento(Convert.ToByte(cmbEndereco.Text.Replace("0x", ""), 16), Convert.ToDouble(txtValor.Text), Convert.ToInt32(cmbVelocidadePosicao.Text), rdbHorarioPosicao.Checked ? Sentido.Horario : Sentido.Antihorario));
}
@ -377,8 +378,8 @@ namespace AgroBase.Forms
DataSended = Convert.ToByte(MyButton.Tag);
//SendRelevantData(QueryCommand[DataSended]);
MKS057DService.AddrRef = 0x00;
MKS057DService.AdicionarComandoNaFila(MKS057DService.MontarComandoParada(Convert.ToByte(cmbEndereco.Text.Replace("0x", ""), 16)));
MKS057DRs485Service.AddrRef = 0x00;
MKS057DRs485Service.AdicionarComandoNaFila(MKS057DRs485Service.MontarComandoParada(Convert.ToByte(cmbEndereco.Text.Replace("0x", ""), 16)));
}
private void btnModoControle_Click(object sender, EventArgs e)
@ -536,7 +537,7 @@ namespace AgroBase.Forms
await SendRelevantData(QueryCommand[DataSended]);
await Task.Delay(100);*/
MKS057DService.AdicionarComandoNaFila(new Models.MKS057ComandoModel()
MKS057DRs485Service.AdicionarComandoNaFila(new Models.MKS057ComandoModel()
{
Comando = data,
Endereco = Convert.ToByte(addr, 16),
@ -1575,7 +1576,7 @@ namespace AgroBase.Forms
DataSended = Convert.ToByte(MyButton.Tag);
//SendRelevantData(QueryCommand[DataSended]);
MKS057DService.AdicionarComandoNaFila(MKS057DService.MontarComandoRequisicaoIO(Convert.ToByte(cmbEndereco.Text.Replace("0x", ""), 16)));
MKS057DRs485Service.AdicionarComandoNaFila(MKS057DRs485Service.MontarComandoRequisicaoIO(Convert.ToByte(cmbEndereco.Text.Replace("0x", ""), 16)));
}
private void Text_display()
@ -1660,7 +1661,7 @@ namespace AgroBase.Forms
str = Convert.ToString(data32, 10);
txtNumeroPulsos.AppendText(str);
txtAnguloAtual.Text = Math.Round(MKS057DService.PulsosParaAngulo(Convert.ToInt32(txtNumeroPulsos.Text)), 2).ToString();
txtAnguloAtual.Text = Math.Round(MKS057DRs485Service.PulsosParaAngulo(Convert.ToInt32(txtNumeroPulsos.Text)), 2).ToString();
}
else
{
@ -2372,6 +2373,95 @@ namespace AgroBase.Forms
}
private bool MKSIniciado()
{
if (!CanService.IsConnected)
{
CanService.AbrirComunicacao(new SerialPort(cmbPorta.Text, Convert.ToInt32(cmbBaud.Text)));
}
if (CanService.IsConnected)
{
MKS057DCanService.RequisitarDado(Convert.ToByte(cmbEndereco.Text), MKS057DCanService.MksHandler.MksFuncCode.Versao);
}
return CanService.IsConnected;
}
private void btnMovimentoCAN_Click(object sender, EventArgs e)
{
if (MKSIniciado())
{
double.TryParse(txtValor.Text, out double angulo);
double.TryParse(cmbVelocidadePosicao.Text, out double velocidade);
Sentido sentido = rdbHorarioPosicao.Checked ? Sentido.Horario : Sentido.Antihorario;
ModosControle modo = (ModosControle)(cmbModo.SelectedIndex + 1);
MKS057DCanService.Movimento(Convert.ToByte(cmbEndereco.Text), angulo, (int)velocidade, sentido, modo);
}
}
private void btnSetZeroCAN_Click(object sender, EventArgs e)
{
if (MKSIniciado())
{
MKS057DCanService.SetZero(Convert.ToByte(cmbEndereco.Text));
}
}
AsyncTaskTimerModel tmrReq;
MKS057DModel dadosLeitura;
private void btnCANtest_Click(object sender, EventArgs e)
{
if (tmrReq == null)
{
tmrReq = new AsyncTaskTimerModel("tmrReqMksCan", tmrReq_Tick, 1000, this);
tmrReq.Start();
}
else if (tmrReq.IsRunning)
{
tmrReq.Stop();
}
else
{
tmrReq.Start();
}
}
private async Task tmrReq_Tick()
{
tmrReq.SetInterval(200);
if (MKSIniciado())
{
MKS057DCanService.RequisitarDado(Convert.ToByte(cmbEndereco.Text), MKS057DCanService.MksHandler.MksFuncCode.PulsosRecebidos);
//mks.RequisitarDado(endereco, MKS057DCanService.MksHandler.MksFuncCode.EncoderCarregado);
//mks.RequisitarDado(endereco, MKS057DCanService.MksHandler.MksFuncCode.EncoderAcumulado);
MKS057DCanService.RequisitarDado(Convert.ToByte(cmbEndereco.Text), MKS057DCanService.MksHandler.MksFuncCode.IO);
//mks.RequisitarDado(endereco, MKS057DCanService.MksHandler.MksFuncCode.RPM);
dadosLeitura = MKS057DCanService.DadosLeitura.FirstOrDefault(x => x.Endereco == Convert.ToByte(cmbEndereco.Text));
if (dadosLeitura != null)
{
string a =
$"Versão: {dadosLeitura.FV}, " +
$"RPM: {dadosLeitura.Velocidade}, " +
$"Pulsos: {dadosLeitura.NumeroPulsos}, " +
$"Angulo: {dadosLeitura.AnguloPulsos}, " +
$"Pulsos Relativo: {dadosLeitura.NumeroPulsosRelativo}, " +
$"Angulo Relativo: {dadosLeitura.AnguloPulsosRelativo}, " +
$"Pulsos Absoluto: {dadosLeitura.NumeroPulsosAbsoluto}, " +
$"Angulo Absoluto: {dadosLeitura.AnguloPulsosAbsoluto}, " +
$"Entradas: {string.Join(",", (dadosLeitura.Entradas ?? new List<bool>()).Select(x => x ? "1" : "0"))}," +
$"Saidas: {string.Join(",", (dadosLeitura.Saidas ?? new List<bool>()).Select(x => x ? "1" : "0"))},";
lblLeituraMksCan.Text = a;
}
}
}
}
}

View File

@ -481,7 +481,7 @@ namespace AgroBase
!frmDiagnosticos.Diagnosticando && !ForcarComando &&
(
Variaveis.OperacaoEmAndamento.Modo == ModoOperacao.Manual && (
MKS057DService.Referenciando ||
MKS057DCanService.Referenciando ||
!Variaveis.OperacaoEmAndamento.OperacaoLiberada ||
!Variaveis.OperacaoEmAndamento.Iniciado ||
!VerificaComandoValidoSonar(Tecla)

View File

@ -13,7 +13,7 @@ namespace AgroBase.Models
get
{
// Houve comandos recebidos do driver dentro dos ultimos 10 segundos
int tempo = MKS057DService.UltimoReferenciamento.AddSeconds(10) > DateTime.Now || MKS057DService.Referenciando ? 120 : 10;
int tempo = MKS057DCanService.UltimoReferenciamento.AddSeconds(10) > DateTime.Now || MKS057DCanService.Referenciando ? 120 : 10;
return UltimoComandoRecebido.AddSeconds(tempo) > DateTime.Now;
}
}
@ -25,7 +25,12 @@ namespace AgroBase.Models
public double RPM { get; set; }
public string RPM_Hex { get; set; }
public int NumeroPulsos { get; set; }
public double AnguloPulsos { get; set; }
public string NumeroPulsos_Hex { get; set; }
public int NumeroPulsosAbsoluto { get; set; }
public double AnguloPulsosAbsoluto { get; set; }
public int NumeroPulsosRelativo { get; set; }
public double AnguloPulsosRelativo { get; set; }
public double ErroAngulo { get; set; }
public string ErroAngulo_Hex { get; set; }
public Estado StatusDriver { get; set; }

View File

@ -2,7 +2,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static AgroBase.Models.Enums;
@ -62,7 +61,7 @@ namespace AgroBase.Models.Modules
{
get
{
return MKS057DService.PulsosParaAngulo(Leitura?.NumeroPulsos ?? 0);
return Leitura?.AnguloPulsos ?? 0;
}
}
public double RPM
@ -101,7 +100,7 @@ namespace AgroBase.Models.Modules
{
get
{
_leitura = MKS057DService.DadosLeitura?.FirstOrDefault(x => x.Endereco == EnderecoByte);
_leitura = MKS057DCanService.DadosLeitura?.FirstOrDefault(x => x.Endereco == EnderecoByte);
return _leitura;
}
set
@ -313,7 +312,8 @@ namespace AgroBase.Models.Modules
return;
}
MKS057DService.AdicionarComandoNaFila(MKS057DService.MontarComandoMovimento(EnderecoByte, Angulo_SP, Velocidade, Sentido_SP));
//MKS057DService.AdicionarComandoNaFila(MKS057DService.MontarComandoMovimento(EnderecoByte, Angulo_SP, Velocidade, Sentido_SP));
MKS057DCanService.Movimento(EnderecoByte, Angulo_SP, Velocidade, Sentido_SP);
UltimoComandoEnviado = DateTime.Now;
}
@ -323,12 +323,13 @@ namespace AgroBase.Models.Modules
{
byte Addr = EnderecoByte;
MKS057DService.AddrRef = Addr;
MKS057DService.UltimoReferenciamento = DateTime.Now;
MKS057DCanService.AddrRef = Addr;
MKS057DCanService.UltimoReferenciamento = DateTime.Now;
await Task.Delay(2000);
await MKS057DService.EnviarComandoControle(MKS057DService.MontarComandoSetZero(Addr));
//await MKS057DService.EnviarComandoControle(MKS057DService.MontarComandoSetZero(Addr));
MKS057DCanService.SetZero(Addr);
await Task.Delay(500);
@ -359,16 +360,17 @@ namespace AgroBase.Models.Modules
if (!Sucesso)
{
while (!Sucesso && tentativas < MaxTentativas && DateTime.Now < TimeoutGeral && MKS057DService.Referenciando)
while (!Sucesso && tentativas < MaxTentativas && DateTime.Now < TimeoutGeral && MKS057DCanService.Referenciando)
{
// Se o angulo ja foi visitado, entao pode se mover mais rapido, senao, se move mais devagar
int VelocidadeGiro = DefineVelocidadeReferenciamento(EstadoInicial, anguloMaxVisitado, anguloMinVisitado);
await MKS057DService.EnviarComandoControle(MKS057DService.MontarComandoMovimento(Addr, _angulo, VelocidadeGiro, _sentido));
//await MKS057DService.EnviarComandoControle(MKS057DService.MontarComandoMovimento(Addr, _angulo, VelocidadeGiro, _sentido));
MKS057DCanService.Movimento(Addr, _angulo, VelocidadeGiro, _sentido);
DateTime Inicio = DateTime.Now;
bool inverterGiro = false;
while (!Sucesso && !inverterGiro && Inicio.AddSeconds(120) > DateTime.Now && MKS057DService.Referenciando)
while (!Sucesso && !inverterGiro && Inicio.AddSeconds(120) > DateTime.Now && MKS057DCanService.Referenciando)
{
bool _ref = IN1_Atuado;
@ -425,14 +427,17 @@ namespace AgroBase.Models.Modules
if (Sucesso)
{
await MKS057DService.EnviarComandoControle(MKS057DService.MontarComandoParada(Addr));
//await MKS057DService.EnviarComandoControle(MKS057DService.MontarComandoParada(Addr));
MKS057DCanService.Parar(Addr);
await Task.Delay(1500);
int _centro = Convert.ToInt32((_anguloEntrada + _anguloSaida) / 2.0);
await MKS057DService.EnviarComandoControle(MKS057DService.MontarComandoMovimento(Addr, _centro, 36, Sentido.Horario));
//await MKS057DService.EnviarComandoControle(MKS057DService.MontarComandoMovimento(Addr, _centro, 36, Sentido.Horario));
MKS057DCanService.Movimento(Addr, _centro, 36, Sentido.Horario);
await Task.Delay(2500);
await MKS057DService.EnviarComandoControle(MKS057DService.MontarComandoSetZero(Addr));
//await MKS057DService.EnviarComandoControle(MKS057DService.MontarComandoSetZero(Addr));
MKS057DCanService.SetZero(Addr);
await Task.Delay(1000);
break;
}
@ -446,7 +451,8 @@ namespace AgroBase.Models.Modules
(_velocidadeAnterior != VelocidadeGiro) // Verifica se mudou a velocidade de giro do motor de acordo com o angulo atual
)
{
await MKS057DService.EnviarComandoControle(MKS057DService.MontarComandoMovimento(Addr, _angulo, VelocidadeGiro, _sentido));
//await MKS057DService.EnviarComandoControle(MKS057DService.MontarComandoMovimento(Addr, _angulo, VelocidadeGiro, _sentido));
MKS057DCanService.Movimento(Addr, _angulo, VelocidadeGiro, _sentido);
}
_anguloAnterior = Angulo;
@ -463,7 +469,8 @@ namespace AgroBase.Models.Modules
if (!Sucesso && inverterGiro)
{
await MKS057DService.EnviarComandoControle(MKS057DService.MontarComandoParada(Addr));
//await MKS057DService.EnviarComandoControle(MKS057DService.MontarComandoParada(Addr));
MKS057DCanService.Parar(Addr);
await Task.Delay(500);
_sentido = _sentido == Sentido.Horario ? Sentido.Antihorario : Sentido.Horario;
@ -477,11 +484,12 @@ namespace AgroBase.Models.Modules
if (!Sucesso)
{
await MKS057DService.EnviarComandoControle(MKS057DService.MontarComandoParada(Addr));
//await MKS057DService.EnviarComandoControle(MKS057DService.MontarComandoParada(Addr));
MKS057DCanService.Parar(Addr);
}
MKS057DService.AddrRef = 0x00;
MKS057DService.UltimoReferenciamento = DateTime.Now;
MKS057DCanService.AddrRef = 0x00;
MKS057DCanService.UltimoReferenciamento = DateTime.Now;
}
private int DefineVelocidadeReferenciamento(bool EstadoInicial, double anguloMaxVisitado, double anguloMinVisitado)

View File

@ -235,7 +235,7 @@ namespace AgroBase.Models.Modules
tmrRegistradorMOV = new AsyncTaskTimerModel("tmrRegistrador_" + T_Code.Mov.ToString(), tmrRegistradorMOV_Tick, OIDService.TaxaAmostragem);
tmrRegistradorMOV.Start();
tmrRegistradorDIR = new AsyncTaskTimerModel("tmrRegistrador_" + T_Code.Dir.ToString(), tmrRegistradorDIR_Tick, MKS057DService.TaxaAmostragem);
tmrRegistradorDIR = new AsyncTaskTimerModel("tmrRegistrador_" + T_Code.Dir.ToString(), tmrRegistradorDIR_Tick, MKS057DCanService.TaxaAmostragem);
tmrRegistradorDIR.Start();
}
}
@ -328,13 +328,14 @@ namespace AgroBase.Models.Modules
return;
}
if (!MKS057DService.Iniciado && SerialService.DispositivosMapeados.Any(x => x.Dispositivo == T_Code.Mks))
if (!MKS057DCanService.Iniciado && SerialService.DispositivosMapeados.Any(x => x.Dispositivo == T_Code.Mks))
{
await MKS057DService.InicializarEthernetService();
//await MKS057DService.InicializarEthernetService();
foreach (var Leitura in MKS057DService.DadosLeitura.Where(x => x.UltimoComandoRecebido.AddSeconds(10) < DateTime.Now))
foreach (var Leitura in MKS057DCanService.DadosLeitura.Where(x => x.UltimoComandoRecebido.AddSeconds(10) < DateTime.Now))
{
MKS057DService.AdicionarComandoNaFila(MKS057DService.MontarComandoRequisicaoPulsos(Leitura.Endereco));
//MKS057DService.AdicionarComandoNaFila(MKS057DService.MontarComandoRequisicaoPulsos(Leitura.Endereco));
MKS057DCanService.RequisitarDado(Leitura.Endereco, MKS057DCanService.MksHandler.MksFuncCode.PulsosRecebidos);
}
tmrRegistradorDIR.SetInterval(3000);
@ -344,13 +345,15 @@ namespace AgroBase.Models.Modules
foreach (var Modulo in Modulos.Where(x => x.DirMotor.Inicializado))
{
byte modAddr = Modulo.DirMotor.EnderecoByte;
if (!MKS057DService.Referenciando || (MKS057DService.Referenciando && MKS057DService.AddrRef == modAddr))
if (!MKS057DCanService.Referenciando || (MKS057DCanService.Referenciando && MKS057DCanService.AddrRef == modAddr))
{
MKS057DService.AdicionarComandoNaFila(MKS057DService.MontarComandoRequisicaoPulsos(modAddr));
MKS057DService.AdicionarComandoNaFila(MKS057DService.MontarComandoRequisicaoIO(modAddr));
//MKS057DService.AdicionarComandoNaFila(MKS057DService.MontarComandoRequisicaoPulsos(modAddr));
MKS057DCanService.RequisitarDado(modAddr, MKS057DCanService.MksHandler.MksFuncCode.PulsosRecebidos);
//MKS057DService.AdicionarComandoNaFila(MKS057DService.MontarComandoRequisicaoIO(modAddr));
MKS057DCanService.RequisitarDado(modAddr, MKS057DCanService.MksHandler.MksFuncCode.IO);
// Verifica se o angulo de set point do motor em questao e diferente do angulo atual, e se for, reenvia o comando para garantir que o motor esteja coerente com o set point
if (!MKS057DService.Referenciando && (Modulo.DirMotor.UltimoComandoEnviado.AddMilliseconds(MKS057DService.TaxaAmostragem) < DateTime.Now) && !Modulo.DirMotor.AtingiuAnguloSP)
if (!MKS057DCanService.Referenciando && (Modulo.DirMotor.UltimoComandoEnviado.AddMilliseconds(MKS057DCanService.TaxaAmostragem) < DateTime.Now) && !Modulo.DirMotor.AtingiuAnguloSP)
{
var Controle = Variaveis.OperacaoEmAndamento.Controle.TiposControle?.FirstOrDefault(x => x.Tipo == T_Code.Dir);
if (Controle != null)
@ -361,8 +364,8 @@ namespace AgroBase.Models.Modules
}
}
MKS057DService.TaxaAmostragem = MKS057DService.Referenciando ? 200 : 500;
tmrRegistradorDIR.SetInterval(MKS057DService.TaxaAmostragem);
MKS057DCanService.TaxaAmostragem = MKS057DCanService.Referenciando ? 200 : 500;
tmrRegistradorDIR.SetInterval(MKS057DCanService.TaxaAmostragem);
}
@ -417,7 +420,7 @@ namespace AgroBase.Models.Modules
public async Task RealizarReferenciamentoDirecional()
{
if (!MKS057DService.Referenciando)
if (!MKS057DCanService.Referenciando)
{
TipoMovimentoDirecional tipoControle = Variaveis.OperacaoEmAndamento.Controle.TipoMovimento;

View File

@ -1272,7 +1272,7 @@ namespace AgroBase.Models
var _Controle = Variaveis.OperacaoEmAndamento.Controle;
bool MovimentoLiberado = Variaveis.OperacaoEmAndamento.StatusAtual == StatusOperacao.EmAndamento && !MKS057DService.Referenciando;
bool MovimentoLiberado = Variaveis.OperacaoEmAndamento.StatusAtual == StatusOperacao.EmAndamento && !MKS057DCanService.Referenciando;
if (MovimentoLiberado || ForcarEnvio)
{

View File

@ -54,7 +54,7 @@ namespace AgroBase.Models
public static List<IDispositivosService> DispositivosConectados { get; set; } = new List<IDispositivosService>();
public static OperacaoModel OperacaoEmAndamento { get; set; } = new OperacaoModel(ModoOperacao.Manual);
public static MqttService MqttService { get; set; } = new MqttService("localhost", 1883);
public static LoRaService ConexaoLoRa = new LoRaService();
public static LoRaService ConexaoLoRa { get; set; } = new LoRaService();
public static string FaixaIPwifi { get; set; } = "192.168.100";
public static string FaixaIPethernet { get; set; } = "192.168.105";
public static string IP_Host { get; set; } = FaixaIPwifi + ".105";

View File

@ -0,0 +1,351 @@
using AgroBase.Models;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using static AgroBase.Models.Enums;
namespace AgroBase.Services
{
public class CanMessage
{
public DateTime Momento { get; set; }
public T_Code Dispositivo { get; set; }
public byte Id { get; set; }
public byte funcCode { get; set; }
public byte[] DataTx { get; set; }
public byte[] DataRx { get; set; }
public bool Enviado { get; set; }
public DateTime EnviadoEm { get; set; }
public bool ComResposta { get; set; }
public bool Respondido { get; set; }
public DateTime RespondidoEm { get; set; }
}
public interface ICanMessageHandler
{
void ProcessarMensagem(CanMessage mensagem);
}
public class CanService : IDisposable
{
private static SerialPort _serialPort;
public static string _portName;
private static int _baudRate;
private static object _lock = new object();
public static bool IsConnected { get; private set; }
private static AsyncTaskTimerModel tmrEnviarCAN;
private static AsyncTaskTimerModel tmrOuvirCAN;
private static StringBuilder SerialCANBuffer = new StringBuilder();
private static readonly ConcurrentDictionary<T_Code, ICanMessageHandler> _roteadores = new ConcurrentDictionary<T_Code, ICanMessageHandler>();
private static byte? _ultimoIdEnviado = null;
private static List<CanMessage> Mensagens = new List<CanMessage>();
public CanService()
{
}
public static void RegistrarHandler(T_Code dispositivo, ICanMessageHandler handler)
{
_roteadores[dispositivo] = handler;
}
public static void AbrirComunicacao(SerialPort porta)
{
try
{
porta.Close();
_portName = porta.PortName;
_baudRate = 115200;
_serialPort = new SerialPort(_portName, _baudRate, Parity.None, 8, StopBits.One);
_serialPort.Open();
EnviarComando("S6\r"); // 500Kbps
Thread.Sleep(100);
EnviarComando("O\r"); // Open CAN
Thread.Sleep(100);
tmrOuvirCAN?.Dispose();
tmrOuvirCAN = new AsyncTaskTimerModel("tmrOuvirCAN", OuvirCAN, 10);
tmrOuvirCAN.Start();
tmrEnviarCAN?.Dispose();
tmrEnviarCAN = new AsyncTaskTimerModel("tmrEnviarCAN", EnviarCAN, 10);
tmrEnviarCAN.Start();
IsConnected = true;
}
catch (Exception ex)
{
Console.WriteLine($"Erro ao abrir comunicacao CAN: {ex.Message}");
tmrOuvirCAN?.Dispose();
IsConnected = false;
}
}
private static async Task OuvirCAN()
{
if (_serialPort.BytesToRead > 0)
{
byte[] tempBuffer = await SerialService.LerDadosDaPortaSerialAsync(_serialPort, _serialPort.BytesToRead);
foreach (byte b in tempBuffer)
{
char c = (char)b;
if (c == '\r')
{
var frame = SerialCANBuffer.ToString();
SerialCANBuffer.Clear();
if (!string.IsNullOrWhiteSpace(frame))
{
ProcessarFrameCAN(frame);
}
}
else
{
SerialCANBuffer.Append(c);
}
}
}
}
private static void ProcessarFrameCAN(string frame)
{
// Ex: t00183301020304
if (!frame.StartsWith("t")) return;
try
{
if (frame.Length < 5) return;
int id = Convert.ToInt32(frame.Substring(1, 3), 16);
int len = int.Parse(frame.Substring(4, 1));
byte[] data = new byte[len];
for (int i = 0; i < len; i++)
{
data[i] = Convert.ToByte(frame.Substring(5 + i * 2, 2), 16);
}
byte funcCode = data[0];
var mensagem = new CanMessage();
lock (Mensagens)
{
mensagem = Mensagens.OrderByDescending(x => x.EnviadoEm).FirstOrDefault(x => x.Id == id && x.funcCode == funcCode && x.Enviado && !x.Respondido);
}
if (mensagem == null)
{
mensagem = new CanMessage { Id = (byte)id, DataRx = data };
}
mensagem.DataRx = data;
mensagem.Respondido = true;
mensagem.RespondidoEm = DateTime.Now;
if (_roteadores.TryGetValue(mensagem.Dispositivo, out var handler))
{
handler.ProcessarMensagem(mensagem);
}
else
{
Console.WriteLine($"[CAN] FuncCode não tratado: 0x{funcCode:X2}");
}
}
catch (Exception ex)
{
Console.WriteLine($"[CAN] Erro ao processar frame: {ex.Message}");
}
}
public static void AdicionarMensagemNaFila(T_Code Dispositivo, byte id, byte funcCode, byte[] payload = null, bool get = true)
{
if (_serialPort?.IsOpen != true) return;
var dados = new List<byte> { funcCode };
if (payload != null)
dados.AddRange(payload);
byte crc = CalcularChecksum(id, dados.ToArray());
dados.Add(crc);
//Console.WriteLine($"[CAN OUT] ID: {id:X2} | Func: {funcCode:X2} | Payload: {BitConverter.ToString(dados.ToArray())}");
var msg = new CanMessage
{
Momento = DateTime.Now,
Dispositivo = Dispositivo,
Id = id,
funcCode = funcCode,
DataTx = dados.ToArray(),
ComResposta = get
};
lock (Mensagens)
{
if (Mensagens.Any(x =>
x.Id == msg.Id && // do mesmo Id
x.funcCode == msg.funcCode && // da mesma funcao
x.DataTx.SequenceEqual(msg.DataTx) && // com os mesmos comandos
(!x.Enviado || (x.ComResposta && !x.Respondido)) // ainda nao enviadas ou que aguarda uma resposta
))
{
return;
}
else
{
Mensagens.Add(msg);
}
}
}
private static CanMessage ObterProximaMensagem()
{
lock (Mensagens)
{
var idsDisponiveis = Mensagens
.Where(x => !x.Enviado)
.Select(x => x.Id)
.Distinct()
.OrderBy(id => id)
.ToList();
if (!idsDisponiveis.Any())
return null;
byte proximoId;
if (!_ultimoIdEnviado.HasValue || !idsDisponiveis.Contains(_ultimoIdEnviado.Value))
{
// Começa pelo menor ID disponível
proximoId = idsDisponiveis.First();
}
else
{
// Busca o próximo ID após o último usado
var index = idsDisponiveis.IndexOf(_ultimoIdEnviado.Value);
if (index + 1 < idsDisponiveis.Count)
proximoId = idsDisponiveis[index + 1];
else
proximoId = idsDisponiveis.First(); // ciclo completo
}
var msg = Mensagens
.Where(x => !x.Enviado && x.Id == proximoId)
.OrderBy(x => x.Momento)
.FirstOrDefault();
return msg;
}
}
private static async Task EnviarCAN()
{
LimparMensagensAntigas();
if (_serialPort?.IsOpen != true) return;
CanMessage msg = ObterProximaMensagem();
if (msg != null)
{
string frame = CriarFrame(msg);
if (_ultimoIdEnviado.HasValue && msg.Id == _ultimoIdEnviado.Value)
{
await Task.Delay(50);
}
lock (_lock)
{
EnviarComando(frame);
msg.Enviado = true;
msg.EnviadoEm = DateTime.Now;
_ultimoIdEnviado = msg.Id;
}
}
}
private static string CriarFrame(CanMessage msg)
{
string frame = $"t{msg.Id:X3}{msg.DataTx.Length}";
foreach (byte b in msg.DataTx)
frame += b.ToString("X2");
frame += "\r";
return frame;
}
private static void EnviarComando(string comando)
{
if (_serialPort?.IsOpen == true)
{
_serialPort.Write(comando);
}
}
private static void LimparMensagensAntigas()
{
lock (Mensagens)
{
var limite = DateTime.Now.AddSeconds(-5);
Mensagens.RemoveAll(x =>
(!x.ComResposta && x.Enviado) || // mensagens enviadas que nao exigem resposta
(x.Respondido && x.RespondidoEm < limite) || // mensagens respondidas a mais de 5 segundos
(x.Enviado && x.EnviadoEm < limite && !x.Respondido) // mensagens enviadas e nao respondidas a mais de 5 segundos
);
}
}
public static void Fechar()
{
tmrOuvirCAN?.Dispose();
tmrEnviarCAN?.Dispose();
lock (Mensagens)
{
Mensagens.Clear();
}
SerialCANBuffer.Clear();
_roteadores.Clear();
_ultimoIdEnviado = null;
if (_serialPort?.IsOpen == true)
{
EnviarComando("C\r");
_serialPort.Close();
}
IsConnected = false;
}
public void Dispose()
{
Fechar();
}
private static byte CalcularChecksum(byte id, byte[] data)
{
int soma = id;
foreach (var b in data)
soma += b;
return (byte)(soma & 0xFF);
}
}
}

View File

@ -0,0 +1,385 @@
using AgroBase.Models;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Threading.Tasks;
using static AgroBase.Models.Enums;
using static AgroBase.Services.MKS057DCanService.MksHandler;
namespace AgroBase.Services
{
public class MKS057DCanService
{
public static List<MKS057DModel> DadosLeitura = new List<MKS057DModel>();
private static int _MStep { get; set; } = 16;
private static T_Code Dispositivo { get; set; } = T_Code.Mks;
private static MksHandler _MksHandler { get; set; } = new MksHandler();
public static bool Iniciado
{
get
{
return CanService.IsConnected && SerialService.DispositivosMapeados.Any(x => x.Dispositivo == T_Code.Dir) && DadosLeitura.Any(x => x.Iniciado);
}
}
public static byte AddrRef = 0x00;
public static bool Referenciando
{
get
{
return AddrRef > 0x00;
}
}
public static DateTime UltimoReferenciamento = DateTime.MinValue;
public static int TaxaAmostragem { get; set; } = 500;
public MKS057DCanService()
{
}
public static async Task<bool> VerificaPortaMKS(SerialPort porta)
{
if (!CanService.IsConnected)
{
CanService.AbrirComunicacao(porta);
CanService.RegistrarHandler(Dispositivo, _MksHandler);
}
if (CanService.IsConnected)
{
List<string> Mod_IDs = new List<string>();
// Verifica e inicializa cada módulo conectado
foreach (var Modulo in Variaveis.OperacaoEmAndamento.DispMvd.Dados.Modulos.Where(x => !x.DirMotor.Inicializado))
{
byte Addr = Modulo.DirMotor.EnderecoByte;
// Envia comando relevante para verificar o dispositivo
RequisitarDado(Addr, MksFuncCode.Versao);
await Task.Delay(1000);
if (DadosLeitura.Any(x => x.Endereco == Addr && x.Iniciado))
{
Mod_IDs.Add(Modulo.Modulo_ID);
}
}
// Define os dispositivos inicializados na lista de dispositivos mapeados
if (Mod_IDs.Any())
{
DefinirDispositivo(Mod_IDs);
}
}
else
{
return false;
}
if (!Iniciado)
{
CanService.Fechar();
}
return Iniciado;
}
private static void DefinirDispositivo(List<string> Mod_IDs)
{
foreach (var Mod_ID in Mod_IDs)
{
var Modulo = Variaveis.OperacaoEmAndamento.DispMvd.Dados.Modulos.FirstOrDefault(x => x.Modulo_ID == Mod_ID);
byte Addr = Modulo.DirMotor.EnderecoByte;
if (!SerialService.DispositivosMapeados.Any(x => x.Dispositivo == T_Code.Dir && x.Mod_ID == Mod_ID))
{
var Leitura = DadosLeitura.FirstOrDefault(x => x.Endereco == Addr);
if (Leitura != null)
{
SerialService.DispositivosMapeados.Add(new DispositivoDetalhesModel()
{
Endereco = CanService._portName,
Dispositivo = T_Code.Dir,
Erro = (Leitura.Mensagem ?? "") != "",
Versao = (Leitura.FV ?? "").ToString(),
Mod_ID = Mod_ID,
});
}
}
}
}
#region UTILS
private static int ConverterAnguloParaValor(double _angulo, ModosControle modo)
{
int val = 0;
if (modo == ModosControle.Pulsos)
{
double pulsos = _MStep * 200.0;
double relacao = (pulsos * VariaveisEquipamento.ReducaoDirecional) / 360.0;
val = Convert.ToInt32(_angulo * relacao);
}
else
{
val = Convert.ToInt32(_angulo * VariaveisEquipamento.ReducaoDirecional);
}
return val;
}
#endregion
#region COMANDOS
private static void EnviarComando(T_Code Dispositivo, byte id, byte funcCode, byte[] payload = null, bool get = true)
{
CanService.AdicionarMensagemNaFila(Dispositivo, id, funcCode, payload, get);
}
public static void SetModoOperacao(byte id, byte modo)
{
EnviarComando(Dispositivo, id, 0x82, new byte[] { modo }, false);
}
public static void RequisitarDado(byte id, MksFuncCode dado)
{
EnviarComando(Dispositivo, id, (byte)dado);
}
public static void SetZero(byte id)
{
EnviarComando(Dispositivo, id, (byte)MksFuncCode.SetZero, null, false);
}
public static void Parar(byte id, ModosControle modo = ModosControle.AnguloAbsoluto)
{
byte funcCode =
modo == ModosControle.Pulsos ? (byte)MksFuncCode.ModoControlePulsos :
modo == ModosControle.AnguloRelativo ? (byte)MksFuncCode.ModoControleAnguloRelativo :
(byte)MksFuncCode.ModoControleAnguloAbsoluto;
EnviarComando(Dispositivo, id, funcCode, new byte[] { 0x00 }, false);
}
public static void Movimento(byte id, double angulo, int velocidade, Sentido sentido = Sentido.Horario, ModosControle modo = ModosControle.AnguloAbsoluto)
{
List<byte> payload = new List<byte>();
ushort vel = (ushort)velocidade;
byte[] VelocidadeBytes = BitConverter.GetBytes(vel);
byte acc = 2;
if (modo == ModosControle.Pulsos)
{
byte _Sentido = sentido == Sentido.Horario ? (byte)0x80 : (byte)0x00;
uint pulsos = (uint)ConverterAnguloParaValor(angulo, modo);
byte[] PulsosBytes = BitConverter.GetBytes(pulsos); // Little Endian padrão [0]=LSB
// Igual no RS485: sentido no bit alto da velocidade alta (VelocidadeBytes[1])
VelocidadeBytes[1] |= _Sentido;
// Ordem dos bytes: [MSB, LSB] da velocidade
payload.Add(VelocidadeBytes[1]);
payload.Add(VelocidadeBytes[0]);
payload.Add(acc);
// Agora: ordem dos pulsos → Big Endian (MSB → LSB), igual ao driver RS485
payload.Add(PulsosBytes[2]);
payload.Add(PulsosBytes[1]);
payload.Add(PulsosBytes[0]);
EnviarComando(Dispositivo, id, (byte)MksFuncCode.ModoControlePulsos, payload.ToArray(), false);
}
else
{
int pos = ConverterAnguloParaValor(angulo, modo);
long AbsAxisText = Convert.ToInt32(pos.ToString(), 10);
byte[] AbsAxis = BitConverter.GetBytes(AbsAxisText * 16384 / 360);
byte[] posInt24 = new byte[] { AbsAxis[2], AbsAxis[1], AbsAxis[0] };
payload.AddRange(new byte[] { VelocidadeBytes[1], VelocidadeBytes[0] }); // 2 bytes
payload.Add(acc); // 1 byte
payload.AddRange(posInt24); // 3 bytes
byte funcCode = modo == ModosControle.AnguloRelativo ? (byte)MksFuncCode.ModoControleAnguloRelativo : (byte)MksFuncCode.ModoControleAnguloAbsoluto;
EnviarComando(Dispositivo, id, funcCode, payload.ToArray(), false);
}
}
public static void AlterarStatusMotor(byte id, bool Habilitado)
{
byte comando = (Habilitado ? (byte)0x01 : (byte)0x00);
EnviarComando(Dispositivo, id, (byte)MksFuncCode.HabilitarMotor, new byte[] { comando }, false);
}
#endregion
public class MksHandler : ICanMessageHandler
{
public enum MksFuncCode : byte
{
EncoderCarregado = 0x30,
EncoderAcumulado = 0x31,
RPM = 0x32,
PulsosRecebidos = 0x33,
IO = 0x34,
Versao = 0x40,
ErroAcumulado = 0x36,
SetZero = 0x92,
HabilitarMotor = 0xF3,
ModoControleAnguloRelativo = 0xF4,
ModoControleAnguloAbsoluto = 0xF5,
ModoControlePulsos = 0xFD
}
private long DecodeInt48(byte[] data, int startIndex)
{
byte[] buffer = new byte[8];
// inverter a ordem dos 6 bytes (big endian → little endian)
for (int i = 0; i < 6; i++)
buffer[i] = data[startIndex + 5 - i]; // inverter os 6 bytes
// Preencher os dois bytes restantes com sinal (baseado no MSB original)
buffer[6] = (buffer[5] & 0x80) != 0 ? (byte)0xFF : (byte)0x00;
buffer[7] = buffer[6]; // mesmo valor para byte 7
return BitConverter.ToInt64(buffer, 0);
}
private static ushort DecodeUInt16BE(byte[] data, int startIndex)
{
return (ushort)((data[startIndex] << 8) | data[startIndex + 1]);
}
private double PulsosRecebidosParaAngulo(int valor)
{
double reducao = VariaveisEquipamento.ReducaoDirecional;
double pulsos = _MStep * 200.0;
double relacao = (pulsos * reducao) / 360.0;
double angulo = valor / relacao;
return angulo;
}
private double PulsosEncoderParaAngulo(int valor)
{
return valor * 360.0 / 16384.0;
}
private MKS057DModel ObterOuCriar(byte id)
{
lock (DadosLeitura)
{
var item = DadosLeitura.FirstOrDefault(x => x.Endereco == id);
if (item == null)
{
item = new MKS057DModel { Endereco = id };
DadosLeitura.Add(item);
}
return item;
}
}
public void ProcessarMensagem(CanMessage mensagem)
{
MksFuncCode func = (MksFuncCode)mensagem.DataRx[0];
byte id = mensagem.Id;
var data = mensagem.DataRx;
var item = ObterOuCriar(id);
switch (func)
{
case MksFuncCode.EncoderCarregado:
if (data != null && data.Length >= 7)
{
int carry = (data[1] << 24) | (data[2] << 16) | (data[3] << 8) | data[4]; // bytes 14 Quantas voltas completas em torno do eixo
ushort value = (ushort)((data[5] << 8) | data[6]); // bytes 56 Quantos pulsos por volta
int pulsos = (int)(carry * 16384.0) + value;
item.NumeroPulsosRelativo = pulsos;
item.AnguloPulsosRelativo = PulsosEncoderParaAngulo(pulsos);
}
break;
case MksFuncCode.EncoderAcumulado:
if (data != null && data.Length >= 7)
{
long pulsos = DecodeInt48(data, 1); // lê [1]..[6]
item.NumeroPulsosAbsoluto = (int)pulsos;
item.AnguloPulsosAbsoluto = PulsosEncoderParaAngulo((int)pulsos);
}
break;
case MksFuncCode.RPM:
if (data != null && data.Length >= 3)
{
item.Velocidade = DecodeUInt16BE(data, 1);
}
break;
case MksFuncCode.PulsosRecebidos:
if (data != null && data.Length >= 6)
{
int pulsos = (data[1] << 24) | (data[2] << 16) | (data[3] << 8) | data[4];
if ((data[1] & 0x80) != 0) // se MSB estiver setado, é número negativo
{
pulsos |= unchecked((int)0xFF000000); // preencher sinal
}
item.NumeroPulsos = pulsos;
item.AnguloPulsos = PulsosRecebidosParaAngulo(pulsos);
}
break;
case MksFuncCode.IO:
if (data != null && data.Length >= 3)
{
byte status = data[1];
item.Entradas = new List<bool>() { false, false };
item.Entradas[0] = (status & 0b00000001) != 0;
item.Entradas[1] = (status & 0b00000010) != 0;
item.Saidas = new List<bool>() { false, false };
item.Saidas[0] = (status & 0b00000100) != 0;
item.Saidas[1] = (status & 0b00001000) != 0;
}
break;
case MksFuncCode.ErroAcumulado:
if (data != null && data.Length >= 3)
{
item.ErroAcumulado = DecodeUInt16BE(data, 1);
}
break;
case MksFuncCode.Versao:
if (data != null && data.Length >= 6)
{
string versao = $"{data[1]}.{data[2]}.{data[3]}.{data[4]}";
item.FV = versao;
}
break;
}
item.UltimoComandoRecebido = DateTime.Now;
}
}
}
}

View File

@ -9,7 +9,7 @@ using static AgroBase.Models.Enums;
namespace AgroBase.Services
{
public class MKS057DService
public class MKS057DRs485Service
{
private static EthernetService _ethernetService;
public static bool Iniciado

View File

@ -252,6 +252,12 @@ namespace AgroBase.Services
continue;
}
}
bool DispMks = await ProcuraDispositivoMKS(_Porta);
if (DispMks)
{
continue;
}
}
catch (Exception ex)
{
@ -706,11 +712,11 @@ namespace AgroBase.Services
ethernetEncontrado = true;
}
bool DispMks = await ProcuraDispositivoMKS();
/*bool DispMks = await ProcuraDispositivoMKS();
if (DispMks)
{
ethernetEncontrado = true;
}
}*/
return ethernetEncontrado;
}
@ -822,12 +828,12 @@ namespace AgroBase.Services
return OIDService.Iniciado;
}
private static async Task<bool> ProcuraDispositivoMKS()
private static async Task<bool> ProcuraDispositivoMKS(SerialPort porta)
{
if (!MKS057DService.Referenciando && (!MKS057DService.Iniciado || MKS057DService.DadosLeitura.Count(x => x.Iniciado) < (Variaveis.OperacaoEmAndamento.DispMvd?.Dados?.Modulos?.Count() ?? 4)))
if (!MKS057DCanService.Referenciando && (!MKS057DCanService.Iniciado || MKS057DCanService.DadosLeitura.Count(x => x.Iniciado) < (Variaveis.OperacaoEmAndamento.DispMvd?.Dados?.Modulos?.Count() ?? 4)))
{
AtualizarConsole("Procurando dispositivos MKS");
bool Encontrado = await MKS057DService.VerificaPortaMKS();
bool Encontrado = await MKS057DCanService.VerificaPortaMKS(porta);
if (Encontrado)
{
AtualizarConsole("Dispositivo MKS encontrado");
@ -835,7 +841,7 @@ namespace AgroBase.Services
}
}
return MKS057DService.Iniciado;
return MKS057DCanService.Iniciado;
}

View File

@ -1 +1 @@
{"tmrRegistrador":{"_uiControl":null,"State":2,"IsRunning":false,"IsStopped":true,"IsCreated":false,"Interval":500,"StackTrace":"AtuadorModel.IniciarRegistrador","Id":"tmrRegistrador_Atu","TimeTick":"00:00:00.0003149"},"Modulo_ID":"Atu","IP":"192.168.100.13","RequisitarDados":true,"Conectado":false,"QuantidadeBicos":4,"DensidadeHerbicida":1.05,"BicosPulverizadores":[{"ID":"B01","Posicao":1,"Componente":422,"AtuacaoNivelAlto":true,"ComandoAtuar":false,"Comandar":true,"Testando":false,"Funcoes":[21],"LeituraStatusBico":false,"MediaNivelFluxo":0.0,"Leitura":null,"Inicializado":false,"Atuacoes":0,"InicioAtuacao":"0001-01-01T00:00:00","TempoAtuado":0.0},{"ID":"B02","Posicao":2,"Componente":422,"AtuacaoNivelAlto":true,"ComandoAtuar":false,"Comandar":true,"Testando":false,"Funcoes":[21],"LeituraStatusBico":false,"MediaNivelFluxo":0.0,"Leitura":null,"Inicializado":false,"Atuacoes":0,"InicioAtuacao":"0001-01-01T00:00:00","TempoAtuado":0.0},{"ID":"B03","Posicao":3,"Componente":422,"AtuacaoNivelAlto":true,"ComandoAtuar":false,"Comandar":true,"Testando":false,"Funcoes":[21],"LeituraStatusBico":false,"MediaNivelFluxo":0.0,"Leitura":null,"Inicializado":false,"Atuacoes":0,"InicioAtuacao":"0001-01-01T00:00:00","TempoAtuado":0.0},{"ID":"B04","Posicao":4,"Componente":422,"AtuacaoNivelAlto":true,"ComandoAtuar":false,"Comandar":true,"Testando":false,"Funcoes":[21],"LeituraStatusBico":false,"MediaNivelFluxo":0.02674584437758935,"Leitura":null,"Inicializado":false,"Atuacoes":0,"InicioAtuacao":"0001-01-01T00:00:00","TempoAtuado":0.0}],"BombasPressurizadoras":[{"ID":"BOMBA","ComandoAtuar":false,"Componente":325,"LeituraEstado":false,"Comandar":true,"Testando":false,"Funcoes":[14,35,36,37,5],"LeituraPotencia":0.0,"LeituraPressaoSP":0.0,"LeituraPressao":0.0,"Leitura":null,"Inicializado":false}],"Sensores":[{"LogGrafico":[],"ID":"FLXLN","Prioridade":23,"Descricao":"Fluxo na linha principal","Componente":198,"Aferir":true,"DelayAmostragem":300,"Leitura":null,"Inicializado":false,"Testando":false,"Funcoes":[25],"Parametros":[],"UnidadeMedida":"mL/s","LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"MASRS","Prioridade":3,"Descricao":"Massa do reservatório de herbicida","Componente":532,"Aferir":true,"DelayAmostragem":1000,"Leitura":null,"Inicializado":false,"Testando":false,"Funcoes":[22,23],"Parametros":[],"UnidadeMedida":"Kg","LimiteMaximo":50.0,"LimiteMinimo":5.0},{"LogGrafico":[],"ID":"PRSLN","Prioridade":3,"Descricao":"Pressão na linha principal","Componente":333,"Aferir":true,"DelayAmostragem":1000,"Leitura":null,"Inicializado":false,"Testando":false,"Funcoes":[24],"Parametros":[["Vmin","000.00"],["Vmax","004.50"],["Pmax","174.04"]],"UnidadeMedida":"psi","LimiteMaximo":120.0,"LimiteMinimo":60.0}],"BombaPressurizadora":{"ID":"BOMBA","ComandoAtuar":false,"Componente":325,"LeituraEstado":false,"Comandar":true,"Testando":false,"Funcoes":[14,35,36,37,5],"LeituraPotencia":0.0,"LeituraPressaoSP":0.0,"LeituraPressao":0.0,"Leitura":null,"Inicializado":false},"ScriptDeteccaoErvas":"weed_detector_oak-1_0.py","DadosLeitura":{"Momento":"0001-01-01T00:00:00","Conectado":false,"Mod_ID":null,"QualidadeWifi":0,"LatenciaLoop":0,"BicosPulverizadores":[],"BombasPressurizadoras":[],"SensoresFluxo":[],"SensoresMassa":[],"SensoresPressao":[]},"_MassaRef":0.8,"_MassaLeituraRef":40876.37,"_MassaLeituraExtra":1895800.0,"MassaReservatorio":0.0,"VolumeReservatorio":0.0,"PercentualReservatorio":0.0,"VolumeVazaoAferido":0.0,"_FluxoMlRef":102.0,"_FluxoPulsoRef":80.0,"VazaoFluxoMLpSInstantanea":0.0,"VazaoFluxoMLpSMedia":0.0,"VolumeVazaoML":0.0,"InicioAtuacao":"0001-01-01T00:00:00","TempoAtuado":0.0,"_PressaoVmin":0.0,"_PressaoVmax":4.5,"_PressaoMax":174.045,"PressaoLinha":0.0,"PressaoLinhaCalc":0.0,"PercentualErvasTerreno":0.0}
{"tmrRegistrador":{"_uiControl":null,"State":2,"IsRunning":false,"IsStopped":true,"IsCreated":false,"Interval":500,"StackTrace":"AtuadorModel.IniciarRegistrador","Id":"tmrRegistrador_Atu","TimeTick":"00:00:00"},"Modulo_ID":"Atu","IP":"192.168.100.13","RequisitarDados":true,"Conectado":false,"QuantidadeBicos":4,"DensidadeHerbicida":1.05,"BicosPulverizadores":[{"ID":"B01","Posicao":1,"Componente":422,"AtuacaoNivelAlto":true,"ComandoAtuar":false,"Comandar":true,"Testando":false,"Funcoes":[21],"LeituraStatusBico":false,"MediaNivelFluxo":0.0,"Leitura":null,"Inicializado":false,"Atuacoes":0,"InicioAtuacao":"0001-01-01T00:00:00","TempoAtuado":0.0},{"ID":"B02","Posicao":2,"Componente":422,"AtuacaoNivelAlto":true,"ComandoAtuar":false,"Comandar":true,"Testando":false,"Funcoes":[21],"LeituraStatusBico":false,"MediaNivelFluxo":0.0,"Leitura":null,"Inicializado":false,"Atuacoes":0,"InicioAtuacao":"0001-01-01T00:00:00","TempoAtuado":0.0},{"ID":"B03","Posicao":3,"Componente":422,"AtuacaoNivelAlto":true,"ComandoAtuar":false,"Comandar":true,"Testando":false,"Funcoes":[21],"LeituraStatusBico":false,"MediaNivelFluxo":0.0,"Leitura":null,"Inicializado":false,"Atuacoes":0,"InicioAtuacao":"0001-01-01T00:00:00","TempoAtuado":0.0},{"ID":"B04","Posicao":4,"Componente":422,"AtuacaoNivelAlto":true,"ComandoAtuar":false,"Comandar":true,"Testando":false,"Funcoes":[21],"LeituraStatusBico":false,"MediaNivelFluxo":0.02674584437758935,"Leitura":null,"Inicializado":false,"Atuacoes":0,"InicioAtuacao":"0001-01-01T00:00:00","TempoAtuado":0.0}],"BombasPressurizadoras":[{"ID":"BOMBA","ComandoAtuar":false,"Componente":325,"LeituraEstado":false,"Comandar":true,"Testando":false,"Funcoes":[14,35,36,37,5],"LeituraPotencia":0.0,"LeituraPressaoSP":0.0,"LeituraPressao":0.0,"Leitura":null,"Inicializado":false}],"Sensores":[{"LogGrafico":[],"ID":"FLXLN","Prioridade":23,"Descricao":"Fluxo na linha principal","Componente":198,"Aferir":true,"DelayAmostragem":300,"Leitura":null,"Inicializado":false,"Testando":false,"Funcoes":[25],"Parametros":[],"UnidadeMedida":"mL/s","LimiteMaximo":0.0,"LimiteMinimo":0.0},{"LogGrafico":[],"ID":"MASRS","Prioridade":3,"Descricao":"Massa do reservatório de herbicida","Componente":532,"Aferir":true,"DelayAmostragem":1000,"Leitura":null,"Inicializado":false,"Testando":false,"Funcoes":[22,23],"Parametros":[],"UnidadeMedida":"Kg","LimiteMaximo":50.0,"LimiteMinimo":5.0},{"LogGrafico":[],"ID":"PRSLN","Prioridade":3,"Descricao":"Pressão na linha principal","Componente":333,"Aferir":true,"DelayAmostragem":1000,"Leitura":null,"Inicializado":false,"Testando":false,"Funcoes":[24],"Parametros":[["Vmin","000.00"],["Vmax","004.50"],["Pmax","174.04"]],"UnidadeMedida":"psi","LimiteMaximo":120.0,"LimiteMinimo":60.0}],"BombaPressurizadora":{"ID":"BOMBA","ComandoAtuar":false,"Componente":325,"LeituraEstado":false,"Comandar":true,"Testando":false,"Funcoes":[14,35,36,37,5],"LeituraPotencia":0.0,"LeituraPressaoSP":0.0,"LeituraPressao":0.0,"Leitura":null,"Inicializado":false},"ScriptDeteccaoErvas":"weed_detector_oak-1_0.py","DadosLeitura":{"Momento":"0001-01-01T00:00:00","Conectado":false,"Mod_ID":null,"QualidadeWifi":0,"LatenciaLoop":0,"BicosPulverizadores":[],"BombasPressurizadoras":[],"SensoresFluxo":[],"SensoresMassa":[],"SensoresPressao":[]},"_MassaRef":0.8,"_MassaLeituraRef":40876.37,"_MassaLeituraExtra":1895800.0,"MassaReservatorio":0.0,"VolumeReservatorio":0.0,"PercentualReservatorio":0.0,"VolumeVazaoAferido":0.0,"_FluxoMlRef":102.0,"_FluxoPulsoRef":80.0,"VazaoFluxoMLpSInstantanea":0.0,"VazaoFluxoMLpSMedia":0.0,"VolumeVazaoML":0.0,"InicioAtuacao":"0001-01-01T00:00:00","TempoAtuado":0.0,"_PressaoVmin":0.0,"_PressaoVmax":4.5,"_PressaoMax":174.045,"PressaoLinha":0.0,"PressaoLinhaCalc":0.0,"PercentualErvasTerreno":0.0}

File diff suppressed because one or more lines are too long

View File

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

View File

@ -1 +1 @@
72612633a638e852d1ad773fe9be7468ab3bb5f45f191001dba7ac9c77d8755b
f39b92273c9c03cda7c582e217d44bdff2f7e8f40e6698f917ed1f00569a75c7

View File

@ -0,0 +1,4 @@
[default]
interface = "slcan"
channel = "COM6" # sua porta COM do conversor
bitrate = 500000

View File

@ -0,0 +1,31 @@
import can
def calcular_checksum(data):
return sum(data) & 0xFF
def main():
bus = can.interface.Bus(interface='slcan', channel='COM6', bitrate=500000)
device_id = 0x01
func_code = 0x30
data = [func_code]
crc = calcular_checksum([device_id] + data)
full_data = data + [crc]
msg = can.Message(arbitration_id=device_id, data=full_data, is_extended_id=False)
try:
bus.send(msg)
print("Comando 0x30 enviado com sucesso!")
except can.CanError as e:
print("Erro ao enviar:", e)
print("Aguardando resposta...")
resposta = bus.recv(timeout=1.0)
if resposta:
print(f"Resposta recebida: ID={hex(resposta.arbitration_id)}, Dados={resposta.data.hex()}")
else:
print("Nenhuma resposta.")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,23 @@
import serial
import time
def testar_serial_can():
try:
ser = serial.Serial('COM6', 115200, timeout=1) # ou tente 9600, 38400, 500000...
print("Conectado na COM6")
# Teste simples: enviar algum dado (exemplo: comando comum de entrada CAN?)
ser.write(b'\x01\x30\x31') # Exemplo CAN ID 01, comando 0x30 (ler posição), CRC 0x31
print("Comando enviado, aguardando resposta...")
time.sleep(0.5)
while ser.in_waiting:
resposta = ser.read(ser.in_waiting)
print("Resposta recebida:", resposta.hex())
ser.close()
except Exception as e:
print("Erro:", e)
testar_serial_can()