ajustes na firmware do atuador para estático e ajustes no sistema para ficar compatível

This commit is contained in:
Diego Freitas 2026-03-20 22:48:37 -03:00
parent f77d5daf3e
commit 987899f68a
19 changed files with 1571 additions and 389 deletions

View File

@ -109,16 +109,14 @@ namespace AgroBase.Forms
this.Text = "Pinout - Atuador";
var Bomba = Variaveis.OperacaoEmAndamento.DispAtu.Dados.BombasPressurizadoras.FirstOrDefault();
Funcoes = AtuadorModel.Funcoes.ToList();
Pinout = AtuadorModel.Pinout;
Dispositivos = new List<DispositivoDataModel>();
Dispositivos.Add(new DispositivoDataModel()
Dispositivos.AddRange(Disp.Dados.BombasPressurizadoras.Select(x => new DispositivoDataModel()
{
ID = Bomba.ID,
Funcoes = Bomba.Funcoes
});
ID = x.ID,
Funcoes = x.Funcoes
}).ToList());
Dispositivos.AddRange(Disp.Dados.BicosPulverizadores.Select(x => new DispositivoDataModel()
{
ID = x.ID,
@ -129,11 +127,6 @@ namespace AgroBase.Forms
ID = x.ID,
Funcoes = x.Funcoes
}).ToList());
Dispositivos.AddRange(Disp.Dados.Servos.Select(x => new DispositivoDataModel()
{
ID = x.ID,
Funcoes = x.Funcoes
}));
break;
}
case T_Code.Mvd:

View File

@ -899,14 +899,6 @@ namespace AgroBase
(id_num, posicao, data) = Bico.ProtocoloComando();
}
break;
case S_Code.sSRV:
var Servo = DispAtu?.Dados?.Servos?.FirstOrDefault(x => x.ID == ID && x.Inicializado);
if (Servo != null)
{
if (Valor != null) Servo._AnguloControle = (int)Valor;
(id_num, posicao, data) = Servo.ProtocoloComando();
}
break;
}
DispAtu.AdicionarMensagemFila(id_num, posicao, posicao, data, false);

View File

@ -59,7 +59,6 @@ namespace AgroBase.Models.Modules
public List<AtuadorBicoModel> BicosPulverizadores { get; set; }
public List<AtuadorBombaModel> BombasPressurizadoras { get; set; }
public List<SensorModel> Sensores { get; set; }
public List<SensorServoModel> Servos { get; set; }
public string ScriptDeteccaoErvas { get; set; } = PythonService.ScriptWeedDetector;
public AsyncTaskTimerModel tmrRegistrador;
@ -259,172 +258,19 @@ namespace AgroBase.Models.Modules
_EnderecoCAN_Tx = 0x12,
_EnderecoCAN_Rx = 0x12,
_TaxaAmostragem = 1000,
RequisitarDados = true,
// 71 ~ 77
BicosPulverizadores = new List<AtuadorBicoModel>(),
// 51 ~ 51
BombasPressurizadoras = new List<AtuadorBombaModel>()
{
new AtuadorBombaModel()
{
ID = "BOMBA",
ID_Num = 51,
Sensor_ID_Num = 63,
ComandoAtuar = false,
Componente = S_Code.sBMB,
Comandar = true,
Mandatorio = true,
Funcoes = new List<FuncoesPinout>()
{
FuncoesPinout.ENA,
FuncoesPinout.CS,
FuncoesPinout.INA,
FuncoesPinout.INB,
FuncoesPinout.PWM,
},
ValoresLeituras = new List<SensorValoresLeituraModel>()
{
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.Iniciado,
posicao = CanMessagePosicaoDados.Status,
indice = 0,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.EstadoLeitura,
posicao = CanMessagePosicaoDados.Dados1,
indice = 0,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.Potencia,
posicao = CanMessagePosicaoDados.Dados1,
indice = 1,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.PressaoSP,
posicao = CanMessagePosicaoDados.Dados1,
indice = 2,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.Pressao,
posicao = CanMessagePosicaoDados.Dados1,
indice = 3,
}
}
}
},
// 61 ~ 66
RequisitarDados = true,
// 11 ~ 50
Sensores = new List<SensorModel>()
{
new SensorModel()
{
ID = "FLXLN",
ID_Num = 61,
Descricao = "Fluxo na linha principal",
Componente = S_Code.sFLX,
Aferir = true,
Mandatorio = true,
Funcoes = new List<FuncoesPinout>()
{
FuncoesPinout.Fluxo,
},
Parametros = new List<SensorParametroModel>(),
ValoresLeituras = new List<SensorValoresLeituraModel>()
{
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.Iniciado,
posicao = CanMessagePosicaoDados.Status,
indice = 0,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.QtdPulsos,
posicao = CanMessagePosicaoDados.Dados1,
indice = 0,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.Periodo,
posicao = CanMessagePosicaoDados.Dados1,
indice = 1,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.Fluxo,
posicao = CanMessagePosicaoDados.Dados1,
indice = 2,
analise_health = true,
maximo = 20,
minimo = 0,
nominal = 0,
unidade_medida = "mL/s"
}
}
},
new SensorModel()
{
ID = "MASRS",
ID_Num = 62,
Descricao = "Massa do reservatório de herbicida",
Componente = S_Code.sMAS,
Aferir = true,
Mandatorio = true,
Funcoes = new List<FuncoesPinout>()
{
FuncoesPinout.DT,
FuncoesPinout.SCK,
},
Parametros = new List<SensorParametroModel>()
{
new SensorParametroModel()
{
Descricao = "Offset",
Enviar = true,
Escalar = true,
QtdBytes = 2,
Valor = "0.0"
}
},
ValoresLeituras = new List<SensorValoresLeituraModel>()
{
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.Iniciado,
posicao = CanMessagePosicaoDados.Status,
indice = 0,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.LeituraBruta,
posicao = CanMessagePosicaoDados.Dados1,
indice = 0,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.Massa,
posicao = CanMessagePosicaoDados.Dados1,
indice = 1,
analise_health = true,
maximo = 35,
minimo = 0,
nominal = 30,
unidade_medida = "Kg"
}
}
},
// pressao 11 ~ 20
new SensorModel()
{
ID = "PRSLN",
ID_Num = 63,
ID_Num = 11,
Descricao = "Pressão na linha principal",
Componente = S_Code.sPRS,
Aferir = true,
Mandatorio = true,
Mandatorio = true,
Funcoes = new List<FuncoesPinout>()
{
FuncoesPinout.Pressao,
@ -433,10 +279,10 @@ namespace AgroBase.Models.Modules
{
new SensorParametroModel()
{
Descricao = "Vmin",
Valor = "0",
QtdBytes = 1,
Escalar = false,
Descricao = "Vmin",
Valor = "0",
QtdBytes = 1,
Escalar = false,
Enviar = false
},
new SensorParametroModel()
@ -483,11 +329,111 @@ namespace AgroBase.Models.Modules
}
}
},
// fluxo 21 ~ 30
new SensorModel()
{
ID = "FLXLN",
ID_Num = 21,
Descricao = "Fluxo na linha principal",
Componente = S_Code.sFLX,
Aferir = true,
Mandatorio = true,
Funcoes = new List<FuncoesPinout>()
{
FuncoesPinout.Fluxo,
},
Parametros = new List<SensorParametroModel>(),
ValoresLeituras = new List<SensorValoresLeituraModel>()
{
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.Iniciado,
posicao = CanMessagePosicaoDados.Status,
indice = 0,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.QtdPulsos,
posicao = CanMessagePosicaoDados.Dados1,
indice = 0,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.Periodo,
posicao = CanMessagePosicaoDados.Dados1,
indice = 1,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.Fluxo,
posicao = CanMessagePosicaoDados.Dados1,
indice = 2,
analise_health = true,
maximo = 20,
minimo = 0,
nominal = 0,
unidade_medida = "mL/s"
}
}
},
// massa 31 ~ 40
new SensorModel()
{
ID = "MASRS",
ID_Num = 31,
Descricao = "Massa do reservatório de herbicida",
Componente = S_Code.sMAS,
Aferir = true,
Mandatorio = true,
Funcoes = new List<FuncoesPinout>()
{
FuncoesPinout.DT,
FuncoesPinout.SCK,
},
Parametros = new List<SensorParametroModel>()
{
new SensorParametroModel()
{
Descricao = "Offset",
Enviar = true,
Escalar = true,
QtdBytes = 2,
Valor = "0.0"
}
},
ValoresLeituras = new List<SensorValoresLeituraModel>()
{
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.Iniciado,
posicao = CanMessagePosicaoDados.Status,
indice = 0,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.LeituraBruta,
posicao = CanMessagePosicaoDados.Dados1,
indice = 0,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.Massa,
posicao = CanMessagePosicaoDados.Dados1,
indice = 1,
analise_health = true,
maximo = 35,
minimo = 0,
nominal = 30,
unidade_medida = "Kg"
}
}
},
// magnetico 41 ~ 50
new SensorModel()
{
ID = "MAGESQ",
Descricao = "Angulo Barra Esquerda",
ID_Num = 64,
ID_Num = 41,
Componente = S_Code.sMAG,
Aferir = true,
Mandatorio = true,
@ -542,7 +488,7 @@ namespace AgroBase.Models.Modules
{
ID = "MAGDIR",
Descricao = "Angulo Barra Direita",
ID_Num = 65,
ID_Num = 42,
Componente = S_Code.sMAG,
Aferir = true,
Mandatorio = true,
@ -597,7 +543,7 @@ namespace AgroBase.Models.Modules
{
ID = "MAGALT",
Descricao = "Angulo Barra Altura",
ID_Num = 66,
ID_Num = 43,
Componente = S_Code.sMAG,
Aferir = true,
Mandatorio = true,
@ -649,23 +595,26 @@ namespace AgroBase.Models.Modules
}
},
},
// 91 ~ 97
Servos = new List<SensorServoModel>()
// 51 ~ 51
BombasPressurizadoras = new List<AtuadorBombaModel>()
{
/*new SensorServoModel()
new AtuadorBombaModel()
{
ID = "SRVB1",
ID_Num = 91,
Descricao = "Articulaccao Bico 01",
Componente = S_Code.sSRV,
Controlar = true,
Mandatorio = false,
ID = "BMBLN",
ID_Num = 51,
Sensor_ID_Num = 11,
ComandoAtuar = false,
Componente = S_Code.sBMB,
Comandar = true,
Mandatorio = true,
Funcoes = new List<FuncoesPinout>()
{
FuncoesPinout.Servo,
FuncoesPinout.ENA,
FuncoesPinout.CS,
FuncoesPinout.INA,
FuncoesPinout.INB,
FuncoesPinout.PWM,
},
_AnguloControle = 90,
Incremental = true,
ValoresLeituras = new List<SensorValoresLeituraModel>()
{
new SensorValoresLeituraModel()
@ -676,27 +625,47 @@ namespace AgroBase.Models.Modules
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.ServoAnguloLeitura,
funcao = FuncoesPinout.EstadoLeitura,
posicao = CanMessagePosicaoDados.Dados1,
indice = 0,
analise_health = true
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.Potencia,
posicao = CanMessagePosicaoDados.Dados1,
indice = 1,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.PressaoSP,
posicao = CanMessagePosicaoDados.Dados1,
indice = 2,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.Pressao,
posicao = CanMessagePosicaoDados.Dados1,
indice = 3,
}
}
},
new SensorServoModel()
new AtuadorBombaModel()
{
ID = "SRVB2",
ID_Num = 92,
Descricao = "Articulaccao Bico 02",
Componente = S_Code.sSRV,
Controlar = true,
Mandatorio = false,
ID = "BMBAGT",
ID_Num = 52,
Sensor_ID_Num = -1,
ComandoAtuar = false,
Componente = S_Code.sBMB,
Comandar = true,
Mandatorio = true,
Funcoes = new List<FuncoesPinout>()
{
FuncoesPinout.Servo,
FuncoesPinout.ENA,
FuncoesPinout.CS,
FuncoesPinout.INA,
FuncoesPinout.INB,
FuncoesPinout.PWM,
},
_AnguloControle = 90,
Incremental = true,
ValoresLeituras = new List<SensorValoresLeituraModel>()
{
new SensorValoresLeituraModel()
@ -707,45 +676,33 @@ namespace AgroBase.Models.Modules
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.ServoAnguloLeitura,
funcao = FuncoesPinout.EstadoLeitura,
posicao = CanMessagePosicaoDados.Dados1,
indice = 0,
analise_health = true
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.Potencia,
posicao = CanMessagePosicaoDados.Dados1,
indice = 1,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.PressaoSP,
posicao = CanMessagePosicaoDados.Dados1,
indice = 2,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.Pressao,
posicao = CanMessagePosicaoDados.Dados1,
indice = 3,
}
}
},
new SensorServoModel()
{
ID = "SRVB3",
ID_Num = 93,
Descricao = "Articulaccao Bico 03",
Componente = S_Code.sSRV,
Controlar = true,
Mandatorio = false,
Funcoes = new List<FuncoesPinout>()
{
FuncoesPinout.Servo,
},
_AnguloControle = 90,
Incremental = true,
ValoresLeituras = new List<SensorValoresLeituraModel>()
{
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.Iniciado,
posicao = CanMessagePosicaoDados.Status,
indice = 0,
},
new SensorValoresLeituraModel()
{
funcao = FuncoesPinout.ServoAnguloLeitura,
posicao = CanMessagePosicaoDados.Dados1,
indice = 0,
analise_health = true
},
}
},*/
},
// 61 ~ 67
BicosPulverizadores = new List<AtuadorBicoModel>(),
};
for (int i = 0; i < Variaveis.OperacaoEmAndamento.Parametros.QtdBicos; i++)
{
@ -753,8 +710,7 @@ namespace AgroBase.Models.Modules
Atuador.BicosPulverizadores.Add(new AtuadorBicoModel()
{
ID = "B" + posicao.ToString("00"),
ID_Num = 70 + posicao,
Servo_ID_Num = Atuador.Servos.FirstOrDefault(x => (x.ID_Num - 20) == 70 + posicao)?.ID_Num ?? -1,
ID_Num = 60 + posicao,
Componente = S_Code.sBIC,
Posicao = posicao,
Inicializado = false,
@ -767,6 +723,7 @@ namespace AgroBase.Models.Modules
Funcoes = new List<FuncoesPinout>()
{
FuncoesPinout.Solenoide,
FuncoesPinout.Servo,
},
VazaoMediaMLs = 0,
ValoresLeituras = new List<SensorValoresLeituraModel>()
@ -820,6 +777,7 @@ namespace AgroBase.Models.Modules
Dados.BicosPulverizadores.ForEach(x =>
{
x.ComandoAtuar = false;
x.AnguloControle = 0;
x.VazaoInstantaneaMLs = 0;
x.VolumeVazadoML = 0;
x.VazaoMediaMLs = 0;
@ -925,10 +883,6 @@ namespace AgroBase.Models.Modules
var sensoresConfig = SensoresConfig(Conectar, configurarTodos);
config.AddRange(sensoresConfig);
// Adicionar configurações dos Servos
var servosConfig = ServosConfig(Conectar, configurarTodos);
config.AddRange(servosConfig);
// Adicionar configurações dos Bicos
var bicosConfig = BicosConfig(Conectar, configurarTodos);
config.AddRange(bicosConfig);
@ -1017,26 +971,6 @@ namespace AgroBase.Models.Modules
return config;
}
private List<(int, CanMessagePosicaoDados, byte[])> ServosConfig(bool Conectar, bool ConfigurarTodos)
{
var config = new List<(int, CanMessagePosicaoDados, byte[])>();
foreach (var servo in Servos.Where(x => (x.Controlar && (ConfigurarTodos ? true : x.Inicializado != Conectar)) || (!x.Controlar && x.Inicializado)))
{
if (!servo.Controlar && servo.Inicializado)
{
Conectar = false;
}
(CanMessagePosicaoDados posicao, var payload) = servo.ProtocoloConfiguracao(Pinout, Conectar);
if (payload != null)
{
config.Add((servo.ID_Num, posicao, payload));
}
}
return config;
}
public void IniciarRegistrador()
{
@ -1127,14 +1061,6 @@ namespace AgroBase.Models.Modules
}
}
}
foreach (var servo in Servos.Where(x => x.Controlar && x.Inicializado))
{
if (servo._AnguloControle != servo._AnguloLeiutra)
{
GeneralJoystick.EnviarComandoAtuador(servo.Componente, servo.ID, Valor: servo._AnguloControle);
}
}
}
private void AtualizaComponentesIniciados()
@ -1157,10 +1083,6 @@ namespace AgroBase.Models.Modules
{
sensor.Inicializado = false;
}
foreach (var servo in Servos.Where(x => x.Inicializado && x.UltimaLeitura.AddMilliseconds(TempoLimiteConexao) < Agora))
{
servo.Inicializado = false;
}
}
@ -1317,7 +1239,6 @@ namespace AgroBase.Models.Modules
public int Posicao { get; set; }
public S_Code Componente { get; set; } = S_Code.sBIC;
public bool AtuacaoNivelAlto { get; set; }
public int Servo_ID_Num { get; set; }
public double AnguloControle { get; set; }
public double AnguloAbertura { get; set; }
public bool ComandoAtuar { get; set; }
@ -1357,7 +1278,7 @@ namespace AgroBase.Models.Modules
(byte)Componente,
(byte)(conectar ? 1 : 0),
(byte)(AtuacaoNivelAlto ? 1 : 0),
(byte)Servo_ID_Num,
0x00, //(byte)Servo_ID_Num,
(byte)(pino?.Barramento ?? TiposBarramentos.CONTROLADOR),
(byte)(pino?.Pino ?? PinoutUtils.PINO_INVALIDO)
};
@ -1400,7 +1321,6 @@ namespace AgroBase.Models.Modules
Funcoes = Funcoes,
ID = ID,
ID_Num = ID_Num,
Servo_ID_Num = Servo_ID_Num,
VolumeVazadoML = VolumeVazadoML,
TrechosAtuado = TrechosAtuado,
VazaoInstantaneaMLs = VazaoInstantaneaMLs,
@ -1721,9 +1641,8 @@ namespace AgroBase.Models.Modules
var sensor = Disp.Sensores.FirstOrDefault(x => x.ID_Num == ID_Num);
var bico = Disp.BicosPulverizadores.FirstOrDefault(x => x.ID_Num == ID_Num);
var bomba = Disp.BombasPressurizadoras.FirstOrDefault(x => x.ID_Num == ID_Num);
var servo = Disp.Servos.FirstOrDefault(x => x.ID_Num == ID_Num);
return sensor?.Componente ?? bico?.Componente ?? bomba?.Componente ?? servo?.Componente ?? S_Code.sVZO;
return sensor?.Componente ?? bico?.Componente ?? bomba?.Componente ?? S_Code.sVZO;
}
private void AtualizarDados(int CompID_Num, CanMessagePosicaoDados Posicao, S_Code componente, List<dynamic> Parametros)
@ -1733,14 +1652,12 @@ namespace AgroBase.Models.Modules
var sensor = Dados.Sensores.FirstOrDefault(x => x.ID_Num == CompID_Num);
var bomba = Dados.BombasPressurizadoras.FirstOrDefault(x => x.ID_Num == CompID_Num);
var bico = Dados.BicosPulverizadores.FirstOrDefault(x => x.ID_Num == CompID_Num);
var servo = Dados.Servos.FirstOrDefault(x => x.ID_Num == CompID_Num);
List<SensorValoresLeituraModel> valoresLeituras = new List<SensorValoresLeituraModel>();
if (sensor != null) valoresLeituras = sensor.ValoresLeituras;
else if (bomba != null) valoresLeituras = bomba.ValoresLeituras;
else if (bico != null) valoresLeituras = bico.ValoresLeituras;
else if (servo != null) valoresLeituras = servo.ValoresLeituras;
for (int i = 0; i < valoresLeituras.Where(x => x.posicao == Posicao).Count(); i++)
{
@ -1768,8 +1685,6 @@ namespace AgroBase.Models.Modules
bomba.Inicializado = v;
if (bico != null)
bico.Inicializado = v;
if (servo != null)
servo.Inicializado = v;
}
}
}
@ -1952,25 +1867,6 @@ namespace AgroBase.Models.Modules
}
break;
}
case S_Code.sSRV:
{
switch (posicao)
{
case CanMessagePosicaoDados.Status:
{
bool Iniciado = data[2] == 1;
AtualizarDados(ID_Num, posicao, componente, new List<dynamic>() { Iniciado });
break;
}
case CanMessagePosicaoDados.Dados1:
{
int angulo = data[2];
AtualizarDados(ID_Num, posicao, componente, new List<dynamic>() { angulo });
break;
}
}
break;
}
}

View File

@ -883,7 +883,6 @@ namespace AgroBase.Models
da.Sensores?.ForEach(s => d.Add(s.ID, (s.Mandatorio, s.Aferir)));
da.BombasPressurizadoras?.ForEach(b => d.Add(b.ID, (b.Mandatorio, b.Comandar)));
da.BicosPulverizadores?.ForEach(b => d.Add(b.ID, (b.Mandatorio, b.Comandar)));
da.Servos?.ForEach(s => d.Add(s.ID, (s.Mandatorio, s.Controlar)));
}
break;
case T_Code.Sen:
@ -1638,7 +1637,6 @@ namespace AgroBase.Models
if (d_atu.BicosPulverizadores.Any(x => x.ID == id)) return S_Code.sBIC;
if (d_atu.BombasPressurizadoras.Any(x => x.ID == id)) return S_Code.sBMB;
if (d_atu.Sensores.Any(x => x.ID == id)) return d_atu.Sensores.First(x => x.ID == id).Componente;
if (d_atu.Servos.Any(x => x.ID == id)) return S_Code.sSRV;
return S_Code.sVZO;
}
@ -2444,7 +2442,6 @@ namespace AgroBase.Models
LeituraPotenciaBomba = FuncoesMatematicas.Clamp(_DispAtu.Dados.BombasPressurizadoras.FirstOrDefault()._Potencia, 0, 100),
VolumeVazaoMl = _DispAtu.Dados.VolumeVazadoML,
Iniciados = _DispAtu.Dados.Sensores.Select(s => new { s.ID, s.Inicializado }).Union(_DispAtu.Dados.BicosPulverizadores.Select(b => new { b.ID, b.Inicializado })).Union(_DispAtu.Dados.BombasPressurizadoras.Select(b => new { b.ID, b.Inicializado })).ToDictionary(x => x.ID, x => x.Inicializado),
Servos = _DispAtu.Dados.Servos?.ToDictionary(x => x.ID, y => (y._AnguloControle, y._AnguloLeiutra, y.Incremental)),
AnguloBarraEsquerda = _DispAtu.Dados.AnguloBarraEsquerda,
AnguloBarraDireita = _DispAtu.Dados.AnguloBarraDireita,
AnguloBarraAltura = _DispAtu.Dados.AnguloBarraAltura,
@ -2759,7 +2756,6 @@ namespace AgroBase.Models
public double TempoEstimadoRestanteMinutos { get; set; }
public double DistanciaEstimadaRestanteMetros { get; set; }
public Dictionary<string, bool> Iniciados { get; set; }
public Dictionary<string, (int, int, bool)> Servos { get; set; }
public List<AtuBicoSensoriamentoLogModel> Bicos { get; set; }
public DateTime UltimoComandoRespondido { get; set; }
@ -2791,7 +2787,6 @@ namespace AgroBase.Models
AnguloBarraDireita = AnguloBarraDireita,
AnguloBarraAltura = AnguloBarraAltura,
Iniciados = new Dictionary<string, bool>(Iniciados ?? new Dictionary<string, bool>()),
Servos = new Dictionary<string, (int, int, bool)>(Servos ?? new Dictionary<string, (int, int, bool)>()),
UltimoComandoRespondido = UltimoComandoRespondido,
LPorMetro = LPorMetro,
LPorMinuto = LPorMinuto,

View File

@ -602,7 +602,6 @@ namespace AgroBase.Models.Operacoes
{
ID = x.ID,
ID_Num = x.ID_Num,
Servo_ID_Num = x.Servo_ID_Num,
Inicializado = x.Inicializado,
Posicao = x.Posicao,
AnguloAbertura = x.AnguloAbertura,
@ -630,16 +629,6 @@ namespace AgroBase.Models.Operacoes
TempoAtuado = dAtu?.TempoAtuado ?? 0,
UltimoComandoRespondido = x.UltimaLeitura,
}).ToList(),
Servos = dAtu?.Servos?.Select(x => new OperacaoParametrosDadosServoModel()
{
ID = x.ID,
ID_Num = x.ID_Num,
Inicializado = x.Inicializado,
Incremental = x.Incremental,
ComandoAngulo = x._AnguloControle,
LeituraAngulo = x._AnguloLeiutra,
UltimoComandoRespondido = x.UltimaLeitura,
}).ToList(),
Sensores = dAtu?.Sensores?.Select(x => new OperacaoParametrosDadosSensorModel()
{
Componente = x.Componente,
@ -953,7 +942,6 @@ namespace AgroBase.Models.Operacoes
public List<OperacaoParametrosDadosBicoModel> Bicos { get; set; }
public List<OperacaoParametrosDadosBombaModel> Bombas { get; set; }
public List<OperacaoParametrosDadosServoModel> Servos{ get; set; }
public List<OperacaoParametrosDadosSensorModel> Sensores { get; set; }
public DateTime UltimoComandoRespondido { get; set; }
@ -977,7 +965,6 @@ namespace AgroBase.Models.Operacoes
{
public string ID { get; set; }
public int ID_Num { get; set; }
public int Servo_ID_Num { get; set; }
public bool Inicializado { get; set; }
public int Posicao { get; set; }
public bool ComandoEstado { get; set; }

View File

@ -195,12 +195,6 @@ namespace AgroBase.Comum
clbDispositivos.Items.Add(Sensor.ID.ToString());
clbDispositivos.SetItemChecked(clbDispositivos.Items.Count - 1, Sensor.Aferir);
}
var Servos = atuModel.Servos;
foreach (var Servo in Servos)
{
clbDispositivos.Items.Add(Servo.ID);
clbDispositivos.SetItemChecked(clbDispositivos.Items.Count - 1, Servo.Controlar);
}
}
else if (Dados is MovimentacaoUnificadaModel mvdModel && Dispositivo == T_Code.Mvd)
{
@ -360,10 +354,6 @@ namespace AgroBase.Comum
{
atuModel.BombasPressurizadoras.FirstOrDefault(x => x.ID == Item.ToString()).Comandar = true;
}
else if (atuModel.Servos.Any(x => x.ID == Item.ToString()))
{
atuModel.Servos.First(x => x.ID == Item.ToString()).Controlar = true;
}
}
}
break;

View File

@ -732,47 +732,6 @@ namespace AgroBase.Services.Operadores
atuBombasAtualizados.Add(("bombas.ativos", atuBombasAtivos));
RedisService.AtualizarCampos(RedisService.ModKey(Enums.T_Code.Atu), atuBombasAtualizados.ToArray());
var atuServosAtualizados = new List<(string caminho, object valor)>();
var atuServosAtivos = new List<string>();
foreach (var servo in DadosAtu.Servos)
{
int tipo = (int)servo.Componente;
int id = servo.ID_Num;
string basePath = $"servos.{tipo}.{id}";
var saude = RedisService.GetField<object>(RedisService.ModKey(Enums.T_Code.Atu), $"{basePath}.saude");
var dados = servo.ValoresLeituras
.Where(y => y.analise_health)
.Select(y => new
{
label = y.funcao.ToString(),
atual = y.atual.valor,
freq = y.atual.frequencia
})
.ToList();
var servoObj = new
{
conectado = servo.Inicializado,
id,
label = servo.ID,
tipo,
controlar = servo.Controlar,
mandatorio = servo.Mandatorio,
angulo_sp = servo._AnguloControle,
dados,
timestamp = agora,
saude = saude ?? new { }
};
atuServosAtivos.Add($"{tipo}.{id}");
atuServosAtualizados.Add(($"{basePath}", servoObj));
}
atuServosAtualizados.Add(("servos.ativos", atuServosAtivos));
RedisService.AtualizarCampos(RedisService.ModKey(Enums.T_Code.Atu), atuServosAtualizados.ToArray());
var DadosLra = Variaveis.LoraService;
RedisService.AtualizarCampos(RedisService.ModKey(Enums.T_Code.Lra),
("timestamp", agora),

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 +0,0 @@
{"ExpansorGPIO":false,"EnderecoGPIO":"","ExpansorADS":false,"EnderecoADS":"","Pinos":[{"Controlador":0,"Barramento":0,"Pino":99,"Descricao":"1","Funcao":0,"Habilitado":false,"ComponenteID":""},{"Controlador":0,"Barramento":0,"Pino":98,"Descricao":"2","Funcao":0,"Habilitado":false,"ComponenteID":""},{"Controlador":0,"Barramento":0,"Pino":97,"Descricao":"3","Funcao":0,"Habilitado":false,"ComponenteID":""},{"Controlador":0,"Barramento":0,"Pino":4,"Descricao":"4","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Controlador":0,"Barramento":0,"Pino":5,"Descricao":"5","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Controlador":0,"Barramento":0,"Pino":6,"Descricao":"6","Funcao":24,"Habilitado":true,"ComponenteID":"PRSLN"},{"Controlador":0,"Barramento":0,"Pino":7,"Descricao":"7","Funcao":25,"Habilitado":true,"ComponenteID":"FLXLN"},{"Controlador":0,"Barramento":0,"Pino":15,"Descricao":"8","Funcao":22,"Habilitado":true,"ComponenteID":"MASRS"},{"Controlador":0,"Barramento":0,"Pino":16,"Descricao":"9","Funcao":23,"Habilitado":true,"ComponenteID":"MASRS"},{"Controlador":0,"Barramento":0,"Pino":17,"Descricao":"10","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Controlador":0,"Barramento":0,"Pino":18,"Descricao":"11","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Controlador":0,"Barramento":0,"Pino":8,"Descricao":"12","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Controlador":0,"Barramento":0,"Pino":3,"Descricao":"13","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Controlador":0,"Barramento":0,"Pino":46,"Descricao":"14","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Controlador":0,"Barramento":0,"Pino":9,"Descricao":"15","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Controlador":0,"Barramento":0,"Pino":10,"Descricao":"16","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Controlador":0,"Barramento":0,"Pino":11,"Descricao":"17","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Controlador":0,"Barramento":0,"Pino":12,"Descricao":"18","Funcao":45,"Habilitado":true,"ComponenteID":"SRVB3"},{"Controlador":0,"Barramento":0,"Pino":13,"Descricao":"19","Funcao":45,"Habilitado":true,"ComponenteID":"SRVB2"},{"Controlador":0,"Barramento":0,"Pino":14,"Descricao":"20","Funcao":45,"Habilitado":true,"ComponenteID":"SRVB1"},{"Controlador":0,"Barramento":0,"Pino":96,"Descricao":"21","Funcao":0,"Habilitado":false,"ComponenteID":""},{"Controlador":0,"Barramento":0,"Pino":95,"Descricao":"22","Funcao":0,"Habilitado":false,"ComponenteID":""},{"Controlador":0,"Barramento":0,"Pino":94,"Descricao":"23","Funcao":0,"Habilitado":false,"ComponenteID":""},{"Controlador":0,"Barramento":0,"Pino":93,"Descricao":"24","Funcao":0,"Habilitado":false,"ComponenteID":""},{"Controlador":0,"Barramento":0,"Pino":19,"Descricao":"25","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Controlador":0,"Barramento":0,"Pino":20,"Descricao":"26","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Controlador":0,"Barramento":0,"Pino":21,"Descricao":"27","Funcao":21,"Habilitado":true,"ComponenteID":"B01"},{"Controlador":0,"Barramento":0,"Pino":47,"Descricao":"28","Funcao":21,"Habilitado":true,"ComponenteID":"B02"},{"Controlador":0,"Barramento":0,"Pino":48,"Descricao":"29","Funcao":21,"Habilitado":true,"ComponenteID":"B03"},{"Controlador":0,"Barramento":0,"Pino":45,"Descricao":"30","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Controlador":0,"Barramento":0,"Pino":0,"Descricao":"31","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Controlador":0,"Barramento":0,"Pino":35,"Descricao":"32","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Controlador":0,"Barramento":0,"Pino":36,"Descricao":"33","Funcao":37,"Habilitado":true,"ComponenteID":"BOMBA"},{"Controlador":0,"Barramento":0,"Pino":37,"Descricao":"34","Funcao":36,"Habilitado":true,"ComponenteID":"BOMBA"},{"Controlador":0,"Barramento":0,"Pino":38,"Descricao":"35","Funcao":35,"Habilitado":true,"ComponenteID":"BOMBA"},{"Controlador":0,"Barramento":0,"Pino":39,"Descricao":"36","Funcao":5,"Habilitado":true,"ComponenteID":"BOMBA"},{"Controlador":0,"Barramento":0,"Pino":40,"Descricao":"37","Funcao":14,"Habilitado":true,"ComponenteID":"BOMBA"},{"Controlador":0,"Barramento":0,"Pino":41,"Descricao":"38","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Controlador":0,"Barramento":0,"Pino":42,"Descricao":"39","Funcao":0,"Habilitado":true,"ComponenteID":""},{"Controlador":0,"Barramento":0,"Pino":2,"Descricao":"40","Funcao":34,"Habilitado":true,"ComponenteID":"Atu"},{"Controlador":0,"Barramento":0,"Pino":1,"Descricao":"41","Funcao":33,"Habilitado":true,"ComponenteID":"Atu"},{"Controlador":0,"Barramento":0,"Pino":44,"Descricao":"42","Funcao":0,"Habilitado":false,"ComponenteID":""},{"Controlador":0,"Barramento":0,"Pino":43,"Descricao":"43","Funcao":0,"Habilitado":false,"ComponenteID":""},{"Controlador":0,"Barramento":0,"Pino":92,"Descricao":"44","Funcao":0,"Habilitado":false,"ComponenteID":""}]}

File diff suppressed because one or more lines are too long

View File

@ -67,9 +67,9 @@
"Arquivo": "parametersAtu",
"Diretorio": "Parametros/",
"Extensao": ".par",
"Versao": "1_1",
"Versao": "2_0",
"TipoArquivo": 2,
"ArquivoDownload": "parameters/parametersAtu-1_1.par",
"ArquivoDownload": "parameters/parametersAtu-2_0.par",
},
{
"id": 9,
@ -85,27 +85,27 @@
"Arquivo": "parametersSen",
"Diretorio": "Parametros/",
"Extensao": ".par",
"Versao": "1_3",
"Versao": "2_0",
"TipoArquivo": 4,
"ArquivoDownload": "parameters/parametersSen-1_3.par"
"ArquivoDownload": "parameters/parametersSen-2_0.par"
},
{
"id": 11,
"Arquivo": "pinoutAtu",
"Diretorio": "Parametros/",
"Extensao": ".pin",
"Versao": "1_0",
"Versao": "2_0",
"TipoArquivo": 6,
"ArquivoDownload": "parameters/pinoutAtu-1_0.pin"
"ArquivoDownload": "parameters/pinoutAtu-2_0.pin"
},
{
"id": 12,
"Arquivo": "pinoutSen",
"Diretorio": "Parametros/",
"Extensao": ".pin",
"Versao": "1_2",
"Versao": "2_0",
"TipoArquivo": 7,
"ArquivoDownload": "parameters/pinoutSen-1_2.pin"
"ArquivoDownload": "parameters/pinoutSen-2_0.pin"
},
{
"id": 13,

View File

@ -0,0 +1,8 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
"version": "0.2.0",
"configurations": [
]
}

View File

@ -0,0 +1,366 @@
// Dispositivo: Atuador
// Versão Firmware: 13
// Ultima atualização: 20/03/2026
// Atualização: Firmware mock
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SerialService.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\CanService.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\EepromService.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\I2CService.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\Utils.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\Pinout.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\BicoPulverizadorModel_v2.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\BombaPressurizadoraModel_v2.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorPressaoModel_v2.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorFluxoModel_v2.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorMassaModel_v2.h"
#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorMagneticoModel_v2.h"
// Configurações do CAN
uint8_t CanID = 0x12;
CanService canService = CanService(CanID);
#define D_Code Atu
int VERSION = 13;
const String Mod_ID = "Atu";
#define _pinoLED RGB_BUILTIN
bool Conectado = false;
bool Conectar = false;
int _TaxaAmostragem = 1000;
volatile bool RequisitarDados = false;
int latenciaLoop = 0;
int qtdEnviosStatus = 0;
int maxEnviosStatus = 5;
#pragma region PRESSAO
SensorPressao_v2 sPRS_Linha("PRSLN", 11, 21, TiposBarramentos::CONTROLADOR);
SensorPressao_v2* ObterPressaoPorId(uint8_t idNum) {
switch (idNum) {
case 11: return &sPRS_Linha;
default: return nullptr;
}
}
#pragma endregion
#pragma region FLUXO
SensorFluxo_v2 sFLX_Linha("FLXLN", 21, 47, TiposBarramentos::CONTROLADOR);
SensorFluxo_v2* ObterFluxoPorId(uint8_t idNum) {
switch (idNum) {
case 21: return &sFLX_Linha;
default: return nullptr;
}
}
#pragma endregion
#pragma region MASSA
SensorMassa_v2 sMAS_Reservatorio("MASRS", 31, 48, 45, TiposBarramentos::CONTROLADOR);
SensorMassa_v2* ObterMassaPorId(uint8_t idNum) {
switch (idNum) {
case 31: return &sMAS_Reservatorio;
default: return nullptr;
}
}
#pragma endregion
#pragma region MAGNETICO
SensorMagnetico_v2 sMAG_Esquerdo("MAGDIR", 41, 0x36, 1);
SensorMagnetico_v2 sMAG_Direito("MAGESQ", 42, 0x36, 2);
SensorMagnetico_v2 sMAG_Altura("MAGALT", 43, 0x36, 3);
SensorMagnetico_v2* ObterSensorMagneticoPorId(uint8_t idNum) {
switch (idNum) {
case 41: return &sMAG_Esquerdo;
case 42: return &sMAG_Direito;
case 43: return &sMAG_Altura;
default: return nullptr;
}
}
#pragma endregion
#pragma region BICOS
BicoPulverizador_v2 sBIC_01("B01", 71, 14, true, TiposBarramentos::CONTROLADOR);
BicoPulverizador_v2 sBIC_02("B02", 72, 13, true, TiposBarramentos::CONTROLADOR);
BicoPulverizador_v2 sBIC_03("B03", 73, 12, true, TiposBarramentos::CONTROLADOR);
BicoPulverizador_v2 sBIC_04("B04", 74, 11, true, TiposBarramentos::CONTROLADOR);
BicoPulverizador_v2 sBIC_05("B05", 75, 10, true, TiposBarramentos::CONTROLADOR);
BicoPulverizador_v2 sBIC_06("B06", 76, 9, true, TiposBarramentos::CONTROLADOR);
BicoPulverizador_v2 sBIC_07("B07", 77, 46, true, TiposBarramentos::CONTROLADOR);
BicoPulverizador_v2* ObterBicoPorId(uint8_t idNum) {
switch (idNum) {
case 71: return &sBIC_01;
case 72: return &sBIC_02;
case 73: return &sBIC_03;
case 74: return &sBIC_04;
case 75: return &sBIC_05;
case 76: return &sBIC_06;
case 77: return &sBIC_07;
default: return nullptr;
}
}
#pragma endregion
#pragma region BOMBAS
BombaPressurizadora_v2 sBMB_Linha("BMBLN", 51, 40, 38, 37, 36, 39, TiposBarramentos::CONTROLADOR, 0, &sPRS_Linha);
BombaPressurizadora_v2 sBMB_Agitador("BMBAGT", 52, 6, 7, 15, 16, 17, TiposBarramentos::CONTROLADOR, 1);
BombaPressurizadora_v2* ObterBombaPorId(uint8_t idNum) {
switch (idNum) {
case 51: return &sBMB_Linha;
case 52: return &sBMB_Agitador;
default: return nullptr;
}
}
#pragma endregion
void MostrarLog(String mensagem) {
bool _debugMode = false;
if (_debugMode) {
PrintTela(String("[ATU] ") + mensagem);
}
}
void inicializarDependenciasI2C() {
I2CService::IniciarI2C();
I2CService::IniciarMUX();
}
void setup() {
delay(5000);
inicializarDependenciasI2C();
sPRS_Linha.Inicializar();
sFLX_Linha.Inicializar();
sMAS_Reservatorio.Inicializar();
sMAG_Esquerdo.Inicializar();
sMAG_Direito.Inicializar();
sMAG_Altura.Inicializar();
sBIC_01.Inicializar();
sBIC_02.Inicializar();
sBIC_03.Inicializar();
sBIC_04.Inicializar();
sBIC_05.Inicializar();
sBIC_06.Inicializar();
sBIC_07.Inicializar();
sBMB_Linha.Inicializar();
sBMB_Agitador.Inicializar();
// Registrar callback para processar mensagens CAN recebidas
canService.setReceiveCallback([](int packetSize, int senderId, CanMessagePosicaoDados posicao, byte* data, int dataLength) {
std::vector<uint8_t> fullData;
fullData.push_back(static_cast<uint8_t>(posicao)); // Primeiro byte é sempre a posicao
for (int i = 0; i < dataLength; i++) {
fullData.push_back(data[i]);
}
ProcessarFrameCAN(posicao, fullData);
});
canService.begin();
}
void loop() {
if (!RequisitarDados) {
enviarLogsPeriodicamente();
}
sFLX_Linha.Loop();
sBMB_Linha.Loop();
sBMB_Agitador.Loop();
delay(1);
}
// Função para enviar logs do sensor periodicamente
unsigned long ultimoEnvioLogs = 0;
const unsigned long intervaloEnvioLogs = 1000; // 1 segundo
void enviarLogsPeriodicamente() {
unsigned long tempoAtual = millis();
// Verifica se o intervalo de 5 segundos já passou
if (tempoAtual - ultimoEnvioLogs >= intervaloEnvioLogs) {
ultimoEnvioLogs = tempoAtual; // Atualiza o tempo do último envio
enviarDadosSensores(canService.ID_Num_sTOD, CanMessagePosicaoDados::DadosAll);
}
}
void enviarDadosSensores(uint8_t id_num, CanMessagePosicaoDados posicao) {
if (Conectado || posicao == CanMessagePosicaoDados::Status) {
unsigned long startLoop = millis();
bool enviarStatus = qtdEnviosStatus >= maxEnviosStatus && posicao != CanMessagePosicaoDados::Status;
bool todosDados = posicao == CanMessagePosicaoDados::DadosAll;
bool todosIDs = id_num == canService.ID_Num_sTOD;
if (id_num == canService.ID_Num_sMOD) {
EnviarDadosCAN(canService.MontarFrameReqStatusMod(D_Code, Conectado, VERSION));
return;
}
MostrarLog("Atualizando dados dos sensores...");
if (todosIDs && enviarStatus) {
EnviarDadosCAN(canService.MontarFrameReqStatusMod(D_Code, Conectado, VERSION));
}
ComponenteCAN::ProcessarComponenteCAN(sPRS_Linha, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
ComponenteCAN::ProcessarComponenteCAN(sFLX_Linha, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
ComponenteCAN::ProcessarComponenteCAN(sMAS_Reservatorio, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
ComponenteCAN::ProcessarComponenteCAN(sMAG_Esquerdo, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
ComponenteCAN::ProcessarComponenteCAN(sMAG_Direito, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
ComponenteCAN::ProcessarComponenteCAN(sMAG_Altura, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
ComponenteCAN::ProcessarComponenteCAN(sBIC_01, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
ComponenteCAN::ProcessarComponenteCAN(sBIC_02, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
ComponenteCAN::ProcessarComponenteCAN(sBIC_03, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
ComponenteCAN::ProcessarComponenteCAN(sBIC_04, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
ComponenteCAN::ProcessarComponenteCAN(sBIC_05, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
ComponenteCAN::ProcessarComponenteCAN(sBIC_06, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
ComponenteCAN::ProcessarComponenteCAN(sBIC_07, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
ComponenteCAN::ProcessarComponenteCAN(sBMB_Linha, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
ComponenteCAN::ProcessarComponenteCAN(sBMB_Agitador, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN);
if (enviarStatus) {
qtdEnviosStatus = 0;
}
else {
qtdEnviosStatus++;
}
latenciaLoop = millis() - startLoop;
if (posicao == CanMessagePosicaoDados::DadosAll) {
EnviarDadosCAN(canService.MontarFrameReqDadosFim(latenciaLoop));
}
MostrarLog("Ciclo concluido, latencia de loop: " + String(latenciaLoop));
}
}
void EnviarDadosCAN(std::vector<uint8_t> data) {
if (data.size() > 2) {
canService.adicionarMensagemFila(data);
}
}
void ProcessarFrameCAN(CanMessagePosicaoDados posicao, std::vector<uint8_t> data) {
if (data.size() < 1) return;
F_Code funcao = canService.FuncaoPorPosicao(posicao);
switch (funcao) {
case F_Code::ReqTx: ProcessarReq(data); break;
case F_Code::CmdTx: ProcessarCmd(data); break;
case F_Code::CfgTx: ProcessarCfg(data); break;
}
}
void ProcessarReq(std::vector<uint8_t> data) {
if (data.size() < 2) return;
CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0];
uint8_t id = data[1];
enviarDadosSensores(id, posicao);
}
void ProcessarCfg(std::vector<uint8_t> data) {
if (data.size() < 4) return;
std::vector<uint8_t> _chkRx;
CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0];
uint8_t id = data[1];
S_Code componente = DetectarComponente(id);
if (componente == S_Code::sMOD) {
switch (posicao) {
case CanMessagePosicaoDados::Config1: {
if (data.size() < 7) return;
bool conectar = data[2] == 1;
int taxa = data[3] * 10;
bool requisitar = data[4] == 1;
int pinoSDA = data[5];
int pinoSCL = data[6];
_TaxaAmostragem = taxa;
RequisitarDados = requisitar;
if (pinoSDA != PINO_INVALIDO && pinoSCL != PINO_INVALIDO) {
if (I2CService::DefinirPinos(pinoSDA, pinoSCL) || !I2CService::I2CIniciado) {
inicializarDependenciasI2C();
}
}
vTaskDelay(pdMS_TO_TICKS(100));
Conectado = conectar;
_chkRx = canService.MontarFrameReqStatusMod(D_Code, Conectado, VERSION);
MostrarLog("Configuracao do modulo concluida");
break;
}
}
}
EnviarDadosCAN(_chkRx);
}
void ProcessarCmd(std::vector<uint8_t> data) {
if (data.size() < 2) return;
CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0];
uint8_t id = data[1];
S_Code componente = DetectarComponente(id);
switch (componente) {
case sMOD: {
if (data.size() < 3) return;
switch (posicao) {
case CanMessagePosicaoDados::Command1: {
Estado estado = (Estado)data[2];
if (estado == Estado::Reset) {
delay(100);
esp_restart();
}
break;
}
}
break;
}
case sBIC: {
BicoPulverizador_v2* bico = ObterBicoPorId(id);
if (bico == nullptr)
return;
bico->ProcessarComando(data);
break;
}
case sBMB: {
BombaPressurizadora_v2* bomba = ObterBombaPorId(id);
if (bomba == nullptr)
return;
bomba->ProcessarComando(data);
break;
}
default:
break;
}
}
S_Code DetectarComponente(uint8_t idNum) {
if (idNum == canService.ID_Num_sMOD) return S_Code::sMOD;
if (idNum == canService.ID_Num_sTOD) return S_Code::sTOD;
if (idNum == canService.ID_Num_sLRA) return S_Code::sLRA;
if (idNum >= 11 && idNum <= 20) return S_Code::sPRS;
if (idNum >= 21 && idNum <= 30) return S_Code::sFLX;
if (idNum >= 31 && idNum <= 40) return S_Code::sMAS;
if (idNum >= 41 && idNum <= 50) return S_Code::sMAG;
if (idNum >= 51 && idNum <= 60) return S_Code::sBMB;
if (idNum >= 61 && idNum <= 60) return S_Code::sBIC;
return S_Code::sVZO;
}

View File

@ -0,0 +1,228 @@
#include <ESP32Servo.h>
#include "SerialService.h"
#include "Pinout.h"
#include "Utils.h"
#include "IComponenteCAN.h"
#ifndef BicoPulverizadorModel_v2_h
#define BicoPulverizadorModel_v2_h
class BicoPulverizador_v2 : public ComponenteCAN {
public:
BicoPulverizador_v2(
const String& id,
uint8_t idNum,
int pinoSaida,
bool atuacaoNivelAlto,
TiposBarramentos barramentoSaida,
int pinoServo = -1,
int anguloMin = 0,
int anguloMax = 180,
int anguloInicial = 90
)
: _ID(id),
ID_Num(idNum),
_pinoSaida(pinoSaida, barramentoSaida, _OUTPUT),
_pinoServo(pinoServo),
AtuacaoNivelAlto(atuacaoNivelAlto),
_anguloMin(anguloMin),
_anguloMax(anguloMax),
_anguloInicial(anguloInicial) {
}
String _ID;
uint8_t ID_Num = 0;
bool Iniciado = false;
bool ServoHabilitado = false;
bool AtuacaoNivelAlto = true;
Estado _Status = Estado::Desligado;
int _AnguloAtual = 0;
void Inicializar() {
if (Iniciado) {
MostrarLog("Bico ja inicializado");
return;
}
_pinoSaida.Conectar(!AtuacaoNivelAlto);
bool saidaOk = _pinoSaida.Definido();
ServoHabilitado = false;
if (_pinoServo >= 0) {
try {
_servo.attach(_pinoServo);
_servo.write(_anguloInicial);
_AnguloAtual = _anguloInicial;
ServoHabilitado = true;
MostrarLog("Servo iniciado no pino " + String(_pinoServo));
} catch (...) {
ServoHabilitado = false;
_AnguloAtual = 0;
MostrarLog("Falha ao iniciar servo");
}
} else {
_AnguloAtual = 0;
MostrarLog("Bico sem servo");
}
if (saidaOk) {
DesativarSaidaFisica();
_Status = Desligado;
Iniciado = true;
MostrarLog("Bico iniciado com sucesso");
} else {
Iniciado = false;
MostrarLog("Falha ao iniciar bico");
}
}
void Desligar() {
if (!Iniciado) {
MostrarLog("Bico nao esta inicializado");
return;
}
DesativarSaidaFisica();
if (ServoHabilitado) {
_servo.detach();
ServoHabilitado = false;
}
_pinoSaida.Desconectar();
Iniciado = false;
_Status = Desligado;
_AnguloAtual = 0;
MostrarLog("Bico desligado");
}
void AtualizarStatus(Estado novoEstado, int novoAngulo = -1) {
if (!Iniciado) {
MostrarLog("Ignorando comando: bico nao iniciado");
return;
}
bool saidaFisica = (novoEstado == Ligado);
if (!AtuacaoNivelAlto) {
saidaFisica = !saidaFisica;
}
_pinoSaida.set(saidaFisica);
_Status = novoEstado;
if (ServoHabilitado && novoAngulo >= 0) {
novoAngulo = LimitarAngulo(novoAngulo);
_servo.write(novoAngulo);
_AnguloAtual = novoAngulo;
}
MostrarLog("Status atualizado | ligado=" + String((int)_Status) + " ang=" + String(_AnguloAtual));
}
void Ligar(int angulo = -1) {
AtualizarStatus(Ligado, angulo);
}
void DesligarBico(int angulo = -1) {
AtualizarStatus(Desligado, angulo);
}
void AtualizarLeitura() {
if (!Iniciado) return;
bool estadoFisico = _pinoSaida.get();
bool estadoLogico = AtuacaoNivelAlto ? estadoFisico : !estadoFisico;
_Status = estadoLogico ? Ligado : Desligado;
}
void RequisitarDados() {
AtualizarLeitura();
}
bool ProcessarComando(const std::vector<uint8_t>& data) {
if (data.size() < 3) {
MostrarLog("Comando invalido");
return false;
}
CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0];
uint8_t idNum = data[1];
if (idNum != ID_Num) {
return false;
}
switch (posicao) {
case CanMessagePosicaoDados::Command1: {
Estado novoEstado = (Estado)data[2];
int novoAngulo = (data.size() > 3) ? (int)data[3] : -1;
AtualizarStatus(novoEstado, novoAngulo);
return true;
}
default:
return false;
}
}
std::vector<uint8_t> MontarMensagemCAN(CanMessagePosicaoDados posicao) {
std::vector<uint8_t> data;
data.push_back(static_cast<uint8_t>(posicao));
data.push_back(ID_Num);
switch (posicao) {
case CanMessagePosicaoDados::Status: {
data.push_back(Iniciado ? 1 : 0);
data.push_back(ServoHabilitado ? 1 : 0);
break;
}
case CanMessagePosicaoDados::Dados1: {
AtualizarLeitura();
data.push_back(static_cast<uint8_t>(_Status));
data.push_back(static_cast<uint8_t>(ServoHabilitado ? _AnguloAtual : 0));
break;
}
default:
break;
}
return data;
}
private:
bool DebugMode = false;
PinoModel _pinoSaida;
Servo _servo;
int _pinoServo = -1;
int _anguloMin = 0;
int _anguloMax = 180;
int _anguloInicial = 90;
int LimitarAngulo(int valor) {
if (valor < _anguloMin) return _anguloMin;
if (valor > _anguloMax) return _anguloMax;
return valor;
}
void DesativarSaidaFisica() {
bool saidaFisica = AtuacaoNivelAlto ? false : true;
_pinoSaida.set(saidaFisica);
}
void MostrarLog(String mensagem) {
if (DebugMode) {
PrintTela("[BIC " + _ID + "] " + mensagem);
}
}
};
#endif

View File

@ -0,0 +1,291 @@
#include "SerialService.h"
#include "Pinout.h"
#include "Utils.h"
#include "IComponenteCAN.h"
#include "SensorPressaoModel_v2.h"
#ifndef BombaPressurizadoraModel_v2_h
#define BombaPressurizadoraModel_v2_h
class BombaPressurizadora_v2 : public ComponenteCAN {
public:
BombaPressurizadora_v2(
const String& id,
uint8_t idNum,
int pinoEN,
int pinoCS,
int pinoINA,
int pinoINB,
int pinoPWM,
TiposBarramentos barramento = CONTROLADOR,
int canalPwm = 0,
SensorPressao_v2* sensor = nullptr,
int pressaoInicial = 0
)
: _ID(id),
ID_Num(idNum),
_pinoEN(pinoEN, barramento, _OUTPUT),
_pinoCS(pinoCS, barramento, _INPUT),
_pinoINA(pinoINA, barramento, _OUTPUT),
_pinoINB(pinoINB, barramento, _OUTPUT),
_pinoPWM(pinoPWM, barramento, _PWM),
_canal(canalPwm),
sensorPressao(sensor),
_PressaoSP(pressaoInicial) {
}
String _ID;
uint8_t ID_Num = 0;
PinoModel _pinoEN;
PinoModel _pinoCS;
PinoModel _pinoINA;
PinoModel _pinoINB;
PinoModel _pinoPWM;
int _canal = 0;
float _Kp = 3.0;
float _Ki = 2.2;
float _Kd = 0.5;
int histerese = 3;
int ZeroRampa = 0;
int RampaMax = 1023;
bool Iniciado = false;
bool MalhaFechada = false;
bool bombaDesligadaPorPressao = false;
SensorPressao_v2* sensorPressao = nullptr;
Estado EstadoLeitura = Estado::Desligado;
double PotenciaLeitura = 0;
double PercentualPotenciaLeitura = 0;
Estado _EstadoControle = Estado::Desligado;
double _PressaoSP = 0;
void VincularSensorPressao(SensorPressao_v2* sensor) {
sensorPressao = sensor;
MalhaFechada = (sensorPressao != nullptr);
}
void Inicializar() {
if (Iniciado) {
MostrarLog("Bomba ja inicializada");
return;
}
MalhaFechada = (sensorPressao != nullptr);
_pinoEN.Conectar(false);
_pinoCS.Conectar();
_pinoINA.Conectar(false);
_pinoINB.Conectar(true);
_pinoPWM.Conectar(0);
if (_pinoPWM.Definido()) {
ledcSetup(_canal, 1000, 10);
ledcAttachPin(_pinoPWM.num, _canal);
ledcWrite(_canal, 0);
}
Iniciado =
_pinoEN.Definido() &&
_pinoINA.Definido() &&
_pinoINB.Definido() &&
_pinoPWM.Definido();
if (Iniciado) {
_EstadoControle = Estado::Desligado;
PotenciaLeitura = 0;
PercentualPotenciaLeitura = 0;
EstadoLeitura = Estado::Desligado;
bombaDesligadaPorPressao = false;
MostrarLog(String("Bomba iniciada | malha ") + (MalhaFechada ? "fechada" : "aberta"));
} else {
MostrarLog("Falha ao iniciar bomba");
}
}
void Desligar() {
if (!Iniciado) {
MostrarLog("Bomba nao esta inicializada");
return;
}
_EstadoControle = Estado::Desligado;
AplicarSaida(false, 0);
_pinoPWM.Desconectar();
_pinoEN.Desconectar();
_pinoCS.Desconectar();
_pinoINA.Desconectar();
_pinoINB.Desconectar();
PotenciaLeitura = 0;
PercentualPotenciaLeitura = 0;
EstadoLeitura = Estado::Desligado;
bombaDesligadaPorPressao = false;
Iniciado = false;
MostrarLog("Bomba desligada");
}
void AtualizarControle(Estado novoEstado, double pressaoSP = -1) {
if (!Iniciado) {
MostrarLog("Ignorando comando: bomba nao iniciada");
return;
}
_EstadoControle = novoEstado;
if (pressaoSP >= 0) {
_PressaoSP = pressaoSP;
}
if (_EstadoControle == Estado::Desligado) {
bombaDesligadaPorPressao = false;
AplicarSaida(false, 0);
} else {
AplicarSaida(true, PotenciaLeitura);
}
AtualizarLeitura();
}
void Loop() {
if (!Iniciado) return;
double pressaoAtual = 0;
if (MalhaFechada && sensorPressao != nullptr) {
sensorPressao->RequisitarDados();
pressaoAtual = sensorPressao->Pressao;
if (pressaoAtual >= (_PressaoSP + histerese)) {
bombaDesligadaPorPressao = true;
} else if (pressaoAtual <= (_PressaoSP - histerese)) {
bombaDesligadaPorPressao = false;
}
}
if (_EstadoControle == Estado::Desligado) {
PotenciaLeitura = ZeroRampa;
} else {
if (MalhaFechada) {
PotenciaLeitura = bombaDesligadaPorPressao ? ZeroRampa : RampaMax;
} else {
PotenciaLeitura = RampaMax;
}
}
AplicarSaida(_EstadoControle == Estado::Desligado, PotenciaLeitura);
AtualizarLeitura();
}
void RequisitarDados() {
AtualizarLeitura();
}
bool ProcessarComando(const std::vector<uint8_t>& data) {
if (data.size() < 3) {
MostrarLog("Comando invalido");
return false;
}
CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0];
uint8_t idNum = data[1];
if (idNum != ID_Num) {
return false;
}
switch (posicao) {
case CanMessagePosicaoDados::Command1: {
Estado novoEstado = (Estado)data[2];
double pressao = (data.size() > 3) ? (double)data[3] : _PressaoSP;
AtualizarControle(novoEstado, pressao);
return true;
}
default:
return false;
}
}
std::vector<uint8_t> MontarMensagemCAN(CanMessagePosicaoDados posicao) {
std::vector<uint8_t> data;
data.push_back(static_cast<uint8_t>(posicao));
data.push_back(ID_Num);
switch (posicao) {
case CanMessagePosicaoDados::Status: {
data.push_back(Iniciado ? 1 : 0);
data.push_back(MalhaFechada ? 1 : 0);
break;
}
case CanMessagePosicaoDados::Dados1: {
AtualizarLeitura();
data.push_back(static_cast<uint8_t>(EstadoLeitura));
data.push_back(static_cast<uint8_t>((int)PercentualPotenciaLeitura));
data.push_back(static_cast<uint8_t>((int)_PressaoSP));
int pressaoAtual = 0;
if (sensorPressao != nullptr) {
pressaoAtual = (int)sensorPressao->Pressao;
}
data.push_back(static_cast<uint8_t>(pressaoAtual));
break;
}
}
return data;
}
private:
bool DebugMode = false;
void AplicarSaida(bool ligado, int pwm) {
if (!Iniciado && pwm != 0) return;
_pinoEN.set(ligado);
if (ligado) {
_pinoINA.set(false);
_pinoINB.set(true);
} else {
_pinoINA.set(false);
_pinoINB.set(false);
pwm = 0;
}
pwm = LimitarPWM(pwm);
ledcWrite(_canal, pwm);
}
int LimitarPWM(int valor) {
if (valor < ZeroRampa) return ZeroRampa;
if (valor > RampaMax) return RampaMax;
return valor;
}
void AtualizarLeitura() {
if (!Iniciado) return;
EstadoLeitura = _pinoEN.get() ? Ligado : Desligado;
PercentualPotenciaLeitura = (RampaMax > 0)
? (PotenciaLeitura / (double)RampaMax) * 100.0
: 0.0;
}
void MostrarLog(String mensagem) {
if (DebugMode) {
PrintTela("[BMB " + _ID + "] " + mensagem);
}
}
};
#endif

View File

@ -0,0 +1,170 @@
#include "SerialService.h"
#include "Pinout.h"
#include "IComponenteCAN.h"
#ifndef SensorFluxoModel_v2_h
#define SensorFluxoModel_v2_h
class SensorFluxo_v2 : public ComponenteCAN {
public:
SensorFluxo_v2(
const String& id,
uint8_t idNum,
int pino,
TiposBarramentos barramento = CONTROLADOR
)
: _ID(id),
ID_Num(idNum),
_pino(pino, barramento, _INPUT, DIGITAL) {
}
String _ID;
uint8_t ID_Num = 0;
PinoModel _pino;
bool Iniciado = false;
unsigned long tempoAnterior = 0;
unsigned int _Pulsos = 0;
unsigned long _PeriodoTotal = 0;
bool ultimaLeitura = false;
unsigned int _PulsosLeitura = 0;
unsigned long _PeriodoTotalLeitura = 0;
float _Vazao = 0.0f;
void Inicializar() {
if (Iniciado) {
MostrarLog("Sensor ja inicializado");
return;
}
_pino.Conectar();
Iniciado = _pino.Definido();
if (Iniciado) {
ResetarEstado();
MostrarLog("Sensor iniciado");
} else {
MostrarLog("Sensor nao iniciado");
}
}
void Desligar() {
if (!Iniciado) {
MostrarLog("Sensor nao esta inicializado");
return;
}
_pino.Desconectar();
ResetarEstado();
_PulsosLeitura = 0;
_PeriodoTotalLeitura = 0;
_Vazao = 0.0f;
Iniciado = false;
MostrarLog("Sensor desligado");
}
void Loop() {
if (!Iniciado) return;
bool leituraAtual = (_pino.get() == 1);
if (leituraAtual != ultimaLeitura) {
if (leituraAtual && !ultimaLeitura) {
unsigned long tempoAtual = millis();
unsigned long intervalo = tempoAtual - tempoAnterior;
tempoAnterior = tempoAtual;
_Pulsos++;
_PeriodoTotal += intervalo;
}
ultimaLeitura = leituraAtual;
}
}
void RequisitarDados() {
AtualizarLeitura();
}
std::vector<uint8_t> MontarMensagemCAN(CanMessagePosicaoDados posicao) {
std::vector<uint8_t> data;
data.push_back(static_cast<uint8_t>(posicao));
data.push_back(ID_Num);
switch (posicao) {
case CanMessagePosicaoDados::Status: {
data.push_back(Iniciado ? 1 : 0);
break;
}
case CanMessagePosicaoDados::Dados1: {
AtualizarLeitura();
uint16_t vazaoEscalada = (uint16_t)(_Vazao * 100.0f);
data.push_back((uint8_t)_PulsosLeitura);
data.push_back((uint8_t)(_PeriodoTotalLeitura >> 8));
data.push_back((uint8_t)(_PeriodoTotalLeitura & 0xFF));
data.push_back((uint8_t)(vazaoEscalada >> 8));
data.push_back((uint8_t)(vazaoEscalada & 0xFF));
break;
}
default:
break;
}
return data;
}
private:
bool DebugMode = false;
void AtualizarLeitura() {
if (!Iniciado) return;
_PulsosLeitura = _Pulsos;
_PeriodoTotalLeitura = _PeriodoTotal;
_Vazao = CalcularVazao(_Pulsos, _PeriodoTotal);
ReiniciarAmostragem();
}
void ResetarEstado() {
_Pulsos = 0;
_PeriodoTotal = 0;
tempoAnterior = millis();
ultimaLeitura = (_pino.get() == 1);
}
void ReiniciarAmostragem() {
_Pulsos = 0;
_PeriodoTotal = 0;
tempoAnterior = millis();
}
float CalcularVazao(uint16_t pulsos, unsigned long periodoMs) {
if (periodoMs == 0) return 0.0f;
float frequenciaHz = ((float)pulsos) * 1000.0f / (float)periodoMs;
float q_L_min = (frequenciaHz + 3.0f) / 8.1f;
if (q_L_min < 0.0f) q_L_min = 0.0f;
if (q_L_min > 10.0f) q_L_min = 10.0f;
float q_mL_s = q_L_min * (1000.0f / 60.0f);
return q_mL_s;
}
void MostrarLog(String mensagem) {
if (DebugMode) {
PrintTela("[FLX " + _ID + "] " + mensagem);
}
}
};
#endif

View File

@ -0,0 +1,168 @@
#include "SerialService.h"
#include "Pinout.h"
#include "Utils.h"
#include "IComponenteCAN.h"
#include "HX711.h"
#include <SimpleKalmanFilter.h>
#ifndef SensorMassaModel_v2_h
#define SensorMassaModel_v2_h
class SensorMassa_v2 : public ComponenteCAN {
public:
SensorMassa_v2(
const String& id,
uint8_t idNum,
int pinoDT,
int pinoSCK,
TiposBarramentos barramento = CONTROLADOR,
long offsetHx = 1996283,
float escalaHx = 50857.316406,
float offsetMassa = 0.0
)
: _ID(id),
ID_Num(idNum),
_pinoDT(pinoDT, barramento, _INPUT, DIGITAL),
_pinoSCK(pinoSCK, barramento, _OUTPUT),
_Offset(offsetHx),
_Escala(escalaHx),
_OffsetMassa(offsetMassa),
filtro(0.05, 0.05, 0.25) {
}
String _ID;
uint8_t ID_Num = 0;
PinoModel _pinoDT;
PinoModel _pinoSCK;
long _Offset = 1996283;
float _Escala = 50857.316406f;
float _OffsetMassa = 0.0f;
HX711 balanca;
SimpleKalmanFilter filtro;
float Massa = 0.0f;
float leitura = 0.0f;
float leituraCorrigida = 0.0f;
bool Iniciado = false;
void Inicializar() {
if (Iniciado) {
MostrarLog("Sensor ja inicializado");
return;
}
_pinoDT.Conectar();
_pinoSCK.Conectar(false);
if (_pinoDT.Definido() && _pinoSCK.Definido()) {
balanca.begin(_pinoDT.num, _pinoSCK.num);
balanca.set_offset(_Offset);
balanca.set_scale(_Escala);
leitura = 0.0f;
leituraCorrigida = 0.0f;
Massa = 0.0f;
Iniciado = true;
MostrarLog("Sensor iniciado");
} else {
Iniciado = false;
MostrarLog("Sensor nao iniciado");
}
}
void Desligar() {
if (!Iniciado) {
MostrarLog("Sensor nao esta inicializado");
return;
}
_pinoDT.Desconectar();
_pinoSCK.Desconectar();
leitura = 0.0f;
leituraCorrigida = 0.0f;
Massa = 0.0f;
Iniciado = false;
MostrarLog("Sensor desligado");
}
void RequisitarDados() {
AtualizarLeitura();
}
void AtualizarLeitura() {
if (!Iniciado) return;
if (!balanca.is_ready()) {
MostrarLog("HX711 nao pronto");
return;
}
leitura = balanca.get_units(5);
float valor = -leitura;
valor += _OffsetMassa;
leituraCorrigida = valor;
Massa = filtro.updateEstimate(leituraCorrigida);
if (Massa < 0.0f) Massa = 0.0f;
}
std::vector<uint8_t> MontarMensagemCAN(CanMessagePosicaoDados posicao) {
std::vector<uint8_t> data;
data.push_back(static_cast<uint8_t>(posicao));
data.push_back(ID_Num);
switch (posicao) {
case CanMessagePosicaoDados::Status: {
data.push_back(Iniciado ? 1 : 0);
break;
}
case CanMessagePosicaoDados::Dados1: {
AtualizarLeitura();
uint16_t leituraEscalada = EscalarFloat2Bytes(leituraCorrigida);
uint16_t massaEscalada = EscalarFloat2Bytes(Massa);
data.push_back((uint8_t)(leituraEscalada >> 8));
data.push_back((uint8_t)(leituraEscalada & 0xFF));
data.push_back((uint8_t)(massaEscalada >> 8));
data.push_back((uint8_t)(massaEscalada & 0xFF));
break;
}
default:
break;
}
return data;
}
private:
bool DebugMode = false;
uint16_t EscalarFloat2Bytes(float valor) {
if (valor < 0.0f) valor = 0.0f;
float escalado = valor * 100.0f;
if (escalado > 65535.0f) escalado = 65535.0f;
return (uint16_t)(escalado);
}
void MostrarLog(String mensagem) {
if (DebugMode) {
PrintTela("[MAS " + _ID + "] " + mensagem);
}
}
};
#endif

View File

@ -0,0 +1,143 @@
#include "SerialService.h"
#include "Pinout.h"
#include "Utils.h"
#include "IComponenteCAN.h"
#include <SimpleKalmanFilter.h>
#ifndef SensorPressaoModel_v2_h
#define SensorPressaoModel_v2_h
class SensorPressao_v2 : public ComponenteCAN {
public:
SensorPressao_v2(
const String& id,
uint8_t idNum,
int pino,
TiposBarramentos barramento = TiposBarramentos::CONTROLADOR,
double vmin = 0.0,
double vmax = 4.5,
double pmax = 174.045
)
: _ID(id),
ID_Num(idNum),
_pino(pino, barramento, TiposPinos::_INPUT, TiposLeituras::ANALOGICO),
_Vmin(vmin),
_Vmax(vmax),
_Pmax(pmax),
filtro(2, 2, 0.01) {
}
String _ID;
uint8_t ID_Num = 0;
PinoModel _pino;
double _Vmin = 0.0;
double _Vmax = 4.5;
double _Pmax = 174.045;
int leitura = 0;
double Tensao = 0.0;
double Pressao = 0.0;
bool Iniciado = false;
void Inicializar() {
if (Iniciado) {
MostrarLog("Sensor ja inicializado");
return;
}
leitura = 0;
Tensao = 0.0;
Pressao = 0.0;
_pino.Conectar();
Iniciado = _pino.Definido();
if (Iniciado) {
MostrarLog("Sensor iniciado");
} else {
MostrarLog("Sensor nao iniciado");
}
}
void Desligar() {
if (!Iniciado) {
MostrarLog("Sensor nao esta inicializado");
return;
}
_pino.Desconectar();
Iniciado = false;
leitura = 0;
Tensao = 0.0;
Pressao = 0.0;
MostrarLog("Sensor desligado");
}
void RequisitarDados() {
AtualizarLeitura();
}
void AtualizarLeitura() {
if (!Iniciado) return;
leitura = _pino.get();
double leituraFiltrada = filtro.updateEstimate(leitura);
Tensao = fmap(leituraFiltrada, 0.0, 4095.0, 0.0, 3300.0) / 1000.0;
Pressao = fmap(Tensao, _Vmin, _Vmax, 0.0, _Pmax);
if (Pressao < 0) Pressao = 0;
if (Pressao > _Pmax) Pressao = _Pmax;
}
std::vector<uint8_t> MontarMensagemCAN(CanMessagePosicaoDados posicao) {
std::vector<uint8_t> data;
data.push_back(static_cast<uint8_t>(posicao));
data.push_back(ID_Num);
switch (posicao) {
case CanMessagePosicaoDados::Status: {
data.push_back(Iniciado ? 1 : 0);
break;
}
case CanMessagePosicaoDados::Dados1: {
AtualizarLeitura();
uint16_t pressaoEscalada = (uint16_t)(Pressao * 100.0);
uint16_t tensaoEscalada = (uint16_t)(Tensao * 1000.0);
data.push_back((uint8_t)(leitura >> 8));
data.push_back((uint8_t)(leitura & 0xFF));
data.push_back((uint8_t)(pressaoEscalada >> 8));
data.push_back((uint8_t)(pressaoEscalada & 0xFF));
data.push_back((uint8_t)(tensaoEscalada >> 8));
data.push_back((uint8_t)(tensaoEscalada & 0xFF));
break;
}
default:
break;
}
return data;
}
private:
bool DebugMode = false;
SimpleKalmanFilter filtro;
void MostrarLog(String mensagem) {
if (DebugMode) {
PrintTela("[PRS " + _ID + "] " + mensagem);
}
}
};
#endif