melhoria na saude do atuador, bicos com ou sem movimento
This commit is contained in:
parent
64fce863d5
commit
c9f3bd69d7
|
|
@ -135,7 +135,7 @@ namespace AgroBase.Forms
|
||||||
* Hoje pode ficar comentado se UDP não for usado no rover,
|
* Hoje pode ficar comentado se UDP não for usado no rover,
|
||||||
* mas o método fica aqui no lugar certo do lifecycle.
|
* mas o método fica aqui no lugar certo do lifecycle.
|
||||||
*/
|
*/
|
||||||
Variaveis.IniciarUDP();
|
//Variaveis.IniciarUDP();
|
||||||
|
|
||||||
APIService.IniciarRotinas();
|
APIService.IniciarRotinas();
|
||||||
VersionamentoService.IniciarRotinas();
|
VersionamentoService.IniciarRotinas();
|
||||||
|
|
|
||||||
|
|
@ -764,7 +764,7 @@ namespace AgroBase.Models.Modules
|
||||||
posicao = CanMessagePosicaoDados.Dados1,
|
posicao = CanMessagePosicaoDados.Dados1,
|
||||||
indice = 2,
|
indice = 2,
|
||||||
analise_health = true,
|
analise_health = true,
|
||||||
maximo = 100,
|
maximo = 120,
|
||||||
minimo = 0,
|
minimo = 0,
|
||||||
nominal = 0,
|
nominal = 0,
|
||||||
unidade_medida = "mL/s"
|
unidade_medida = "mL/s"
|
||||||
|
|
@ -1181,6 +1181,7 @@ namespace AgroBase.Models.Modules
|
||||||
Componente = S_Code.sBIC,
|
Componente = S_Code.sBIC,
|
||||||
Posicao = posicao,
|
Posicao = posicao,
|
||||||
Inicializado = false,
|
Inicializado = false,
|
||||||
|
ComMovimento = false,
|
||||||
AnguloNeutro = 90,
|
AnguloNeutro = 90,
|
||||||
AnguloControle = 90,
|
AnguloControle = 90,
|
||||||
AnguloAbertura = 30,
|
AnguloAbertura = 30,
|
||||||
|
|
@ -2074,6 +2075,7 @@ namespace AgroBase.Models.Modules
|
||||||
public int Posicao { get; set; }
|
public int Posicao { get; set; }
|
||||||
public S_Code Componente { get; set; } = S_Code.sBIC;
|
public S_Code Componente { get; set; } = S_Code.sBIC;
|
||||||
public bool AtuacaoNivelAlto { get; set; }
|
public bool AtuacaoNivelAlto { get; set; }
|
||||||
|
public bool ComMovimento { get; set; }
|
||||||
public double AnguloNeutro { get; set; }
|
public double AnguloNeutro { get; set; }
|
||||||
public double AnguloControle { get; set; }
|
public double AnguloControle { get; set; }
|
||||||
public double AnguloAbertura { get; set; }
|
public double AnguloAbertura { get; set; }
|
||||||
|
|
@ -2250,8 +2252,12 @@ namespace AgroBase.Models.Modules
|
||||||
AtuacaoNivelAlto = AtuacaoNivelAlto,
|
AtuacaoNivelAlto = AtuacaoNivelAlto,
|
||||||
Atuacoes = Atuacoes,
|
Atuacoes = Atuacoes,
|
||||||
ComandoAtuar = ComandoAtuar,
|
ComandoAtuar = ComandoAtuar,
|
||||||
|
ComMovimento = ComMovimento,
|
||||||
AnguloAbertura = AnguloAbertura,
|
AnguloAbertura = AnguloAbertura,
|
||||||
AnguloControle = AnguloControle,
|
AnguloControle = AnguloControle,
|
||||||
|
UltimoAnguloDesejado = UltimoAnguloDesejado,
|
||||||
|
UltimoComandoEnviado = UltimoComandoEnviado,
|
||||||
|
UltimoStatusDesejado = UltimoStatusDesejado,
|
||||||
Inicializado = Inicializado,
|
Inicializado = Inicializado,
|
||||||
Mandatorio = Mandatorio,
|
Mandatorio = Mandatorio,
|
||||||
Componente = Componente,
|
Componente = Componente,
|
||||||
|
|
|
||||||
|
|
@ -602,9 +602,9 @@ namespace AgroBase.Models.Modules
|
||||||
posicao = CanMessagePosicaoDados.Dados1,
|
posicao = CanMessagePosicaoDados.Dados1,
|
||||||
indice = 1,
|
indice = 1,
|
||||||
analise_health = true,
|
analise_health = true,
|
||||||
maximo = 2200,
|
maximo = 2500,
|
||||||
minimo = 1000,
|
minimo = 400,
|
||||||
nominal = 1700,
|
nominal = 700,
|
||||||
unidade_medida = "mA"
|
unidade_medida = "mA"
|
||||||
},
|
},
|
||||||
new SensorValoresLeituraModel()
|
new SensorValoresLeituraModel()
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@ using System.Drawing;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices.ComTypes;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
@ -30,15 +29,16 @@ namespace AgroBase.Models
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return tmrLogs.Interval;
|
return _tmrLogsOperacao.Interval;
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
tmrLogs.SetInterval((int)value);
|
_tmrLogsOperacao.SetInterval((int)value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private static AsyncTaskTimerModel tmrLogs;
|
private AsyncTaskTimerModel _tmrLogsOperacao;
|
||||||
private int idxLog = 0;
|
private int idxLog = 0;
|
||||||
|
private readonly SemaphoreSlim _salvarLogsGate = new SemaphoreSlim(1, 1);
|
||||||
public double tmrLeiturasInterval
|
public double tmrLeiturasInterval
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
@ -55,8 +55,13 @@ namespace AgroBase.Models
|
||||||
|
|
||||||
public OperacaoModel()
|
public OperacaoModel()
|
||||||
{
|
{
|
||||||
tmrLogs?.Dispose();
|
Variaveis.MostrarLog("[OperacaoModel.ctor] StackTrace: " + Environment.StackTrace);
|
||||||
tmrLogs = new AsyncTaskTimerModel("tmrLogs", tmrLogs_Tick, 1000);
|
|
||||||
|
Variaveis.MostrarLog(
|
||||||
|
$"[OperacaoModel.ctor] Nova instância. Hash={GetHashCode()}, " +
|
||||||
|
$"OperacaoAtual={Variaveis.OperacaoEmAndamento?.ID}, " +
|
||||||
|
$"HashAtual={Variaveis.OperacaoEmAndamento?.GetHashCode()}"
|
||||||
|
);
|
||||||
|
|
||||||
tmrLeituras?.Dispose();
|
tmrLeituras?.Dispose();
|
||||||
tmrLeituras = new AsyncTaskTimerModel("tmrLeitura", tmrLeituras_Tick, 500);
|
tmrLeituras = new AsyncTaskTimerModel("tmrLeitura", tmrLeituras_Tick, 500);
|
||||||
|
|
@ -200,8 +205,6 @@ namespace AgroBase.Models
|
||||||
|
|
||||||
if (CarregarModulos)
|
if (CarregarModulos)
|
||||||
{
|
{
|
||||||
tmrLogs?.Stop();
|
|
||||||
|
|
||||||
var SenConectado = (DispositivosService<SensoriamentoModel>)Variaveis.DispositivosConectados.FirstOrDefault(x => x.Dispositivo == T_Code.Sen);
|
var SenConectado = (DispositivosService<SensoriamentoModel>)Variaveis.DispositivosConectados.FirstOrDefault(x => x.Dispositivo == T_Code.Sen);
|
||||||
var AtuConectado = (DispositivosService<AtuadorModel>)Variaveis.DispositivosConectados.FirstOrDefault(x => x.Dispositivo == T_Code.Atu);
|
var AtuConectado = (DispositivosService<AtuadorModel>)Variaveis.DispositivosConectados.FirstOrDefault(x => x.Dispositivo == T_Code.Atu);
|
||||||
var MvdConectado = (DispositivosService<MovimentacaoUnificadaModel>)Variaveis.DispositivosConectados.FirstOrDefault(x => x.Dispositivo == T_Code.Mvd);
|
var MvdConectado = (DispositivosService<MovimentacaoUnificadaModel>)Variaveis.DispositivosConectados.FirstOrDefault(x => x.Dispositivo == T_Code.Mvd);
|
||||||
|
|
@ -1059,7 +1062,7 @@ namespace AgroBase.Models
|
||||||
|
|
||||||
op.Sensoriamento.UltimoRegistroLog = agora;
|
op.Sensoriamento.UltimoRegistroLog = agora;
|
||||||
op.idxLog = 0;
|
op.idxLog = 0;
|
||||||
tmrLogs?.Start();
|
op.IniciarTimerLogsOperacao();
|
||||||
|
|
||||||
await op.RealizarCalibragemInicialAsync(true);
|
await op.RealizarCalibragemInicialAsync(true);
|
||||||
|
|
||||||
|
|
@ -1087,9 +1090,9 @@ namespace AgroBase.Models
|
||||||
|
|
||||||
op.Sensoriamento.Operacao.DataFim = DateTime.Now;
|
op.Sensoriamento.Operacao.DataFim = DateTime.Now;
|
||||||
|
|
||||||
tmrLogs?.Stop();
|
op.PararTimerLogsOperacao();
|
||||||
|
|
||||||
op.SalvarLogs(false);
|
op.SalvarLogs(true);
|
||||||
|
|
||||||
op.Sensoriamento.Operacao.Finalizando = false;
|
op.Sensoriamento.Operacao.Finalizando = false;
|
||||||
op.Trajetoria?.AutonomiaCorredor?.Parar();
|
op.Trajetoria?.AutonomiaCorredor?.Parar();
|
||||||
|
|
@ -1194,6 +1197,33 @@ namespace AgroBase.Models
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void IniciarTimerLogsOperacao()
|
||||||
|
{
|
||||||
|
_tmrLogsOperacao?.Stop();
|
||||||
|
_tmrLogsOperacao?.Dispose();
|
||||||
|
|
||||||
|
_tmrLogsOperacao = new AsyncTaskTimerModel($"tmrLogs_{ID}", tmrLogs_Tick, 1000);
|
||||||
|
|
||||||
|
_tmrLogsOperacao.Start();
|
||||||
|
|
||||||
|
Variaveis.MostrarLog($"[OperacaoModel.IniciarTimerLogsOperacao] Timer de logs iniciado. Operacao={ID}, Hash={GetHashCode()}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PararTimerLogsOperacao()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_tmrLogsOperacao?.Stop();
|
||||||
|
|
||||||
|
Variaveis.MostrarLog($"[OperacaoModel.PararTimerLogsOperacao] Timer de logs parado. Operacao={ID}, Hash={GetHashCode()}, idxLog={idxLog}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Variaveis.MostrarLog("[OperacaoModel.PararTimerLogsOperacao] Erro ao parar timer de logs: " + ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static string DeserializarDadosOperacao(string caminho, string arquivo)
|
public static string DeserializarDadosOperacao(string caminho, string arquivo)
|
||||||
{
|
{
|
||||||
string pastaBase = Path.GetDirectoryName(caminho) ?? "";
|
string pastaBase = Path.GetDirectoryName(caminho) ?? "";
|
||||||
|
|
@ -2628,7 +2658,24 @@ namespace AgroBase.Models
|
||||||
{
|
{
|
||||||
var op = this;
|
var op = this;
|
||||||
|
|
||||||
if (op.Sensoriamento.Operacao.OperacaoIniciada)
|
if (!ReferenceEquals(Variaveis.OperacaoEmAndamento, op))
|
||||||
|
{
|
||||||
|
Variaveis.MostrarLog($"[OperacaoModel.tmrLogs_Tick] Timer órfão parado. TimerHash={GetHashCode()}, OperacaoTimer={ID}, OperacaoAtual={Variaveis.OperacaoEmAndamento?.ID}");
|
||||||
|
|
||||||
|
PararTimerLogsOperacao();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op.Sensoriamento?.Operacao?.OperacaoIniciada != true)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!await _salvarLogsGate.WaitAsync(0))
|
||||||
|
{
|
||||||
|
Variaveis.MostrarLog($"[OperacaoModel.tmrLogs_Tick] Tick ignorado porque SalvarLogs ainda está em execução. Operacao={ID}, idxLog={idxLog}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
op.SalvarLogs(false);
|
op.SalvarLogs(false);
|
||||||
|
|
||||||
|
|
@ -2639,9 +2686,13 @@ namespace AgroBase.Models
|
||||||
|
|
||||||
if (op.idxLog % 5 == 0 && !op.Sensoriamento.Operacao.Calibrando)
|
if (op.idxLog % 5 == 0 && !op.Sensoriamento.Operacao.Calibrando)
|
||||||
{
|
{
|
||||||
Task.Run(async () => await op.RealizarCalibragemInicialAsync(false));
|
_ = Task.Run(async () => await op.RealizarCalibragemInicialAsync(false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_salvarLogsGate.Release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SalvarLogs(bool Fim)
|
public void SalvarLogs(bool Fim)
|
||||||
|
|
@ -3594,6 +3645,7 @@ namespace AgroBase.Models
|
||||||
Atuacoes = bico.Atuacoes,
|
Atuacoes = bico.Atuacoes,
|
||||||
TempoAtuado = bico.TempoAtuado,
|
TempoAtuado = bico.TempoAtuado,
|
||||||
AnguloAbertura = bico.AnguloAbertura,
|
AnguloAbertura = bico.AnguloAbertura,
|
||||||
|
ComMovimento = bico.ComMovimento,
|
||||||
AnguloControle = bico.AnguloControle
|
AnguloControle = bico.AnguloControle
|
||||||
}).ToList()
|
}).ToList()
|
||||||
};
|
};
|
||||||
|
|
@ -4649,7 +4701,7 @@ namespace AgroBase.Models
|
||||||
DadosPerformance = dadosPerformance,
|
DadosPerformance = dadosPerformance,
|
||||||
LivoxLidar = dadosLivox,
|
LivoxLidar = dadosLivox,
|
||||||
CoolerControl = dadosCooler,
|
CoolerControl = dadosCooler,
|
||||||
Logs = Logs != null ? Logs.Where(x => x?.Momento >= ultimoRegistroLog).ToList() : new List<OperacaoSensoriamentoLogErrosModel>(),
|
Logs = Logs != null ? Logs.Where(x => x != null && x.Momento > ultimoRegistroLog).ToList() : new List<OperacaoSensoriamentoLogErrosModel>(),
|
||||||
UltimoRegistroLog = ultimoRegistroLog,
|
UltimoRegistroLog = ultimoRegistroLog,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -5108,6 +5160,7 @@ namespace AgroBase.Models
|
||||||
public int Atuacoes { get; set; }
|
public int Atuacoes { get; set; }
|
||||||
public double TempoAtuado { get; set; }
|
public double TempoAtuado { get; set; }
|
||||||
public double AnguloAbertura { get; set; }
|
public double AnguloAbertura { get; set; }
|
||||||
|
public bool ComMovimento { get; set; }
|
||||||
public double AnguloControle { get; set; }
|
public double AnguloControle { get; set; }
|
||||||
|
|
||||||
public AtuadorBicoLogModel Clone()
|
public AtuadorBicoLogModel Clone()
|
||||||
|
|
@ -5124,6 +5177,7 @@ namespace AgroBase.Models
|
||||||
Atuacoes = Atuacoes,
|
Atuacoes = Atuacoes,
|
||||||
TempoAtuado = TempoAtuado,
|
TempoAtuado = TempoAtuado,
|
||||||
AnguloAbertura = AnguloAbertura,
|
AnguloAbertura = AnguloAbertura,
|
||||||
|
ComMovimento = ComMovimento,
|
||||||
AnguloControle = AnguloControle
|
AnguloControle = AnguloControle
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -610,8 +610,7 @@ namespace AgroBase.Services
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var agitador =
|
var agitador = op?.DispAtu?.Dados?.AgitadorDeCalda;
|
||||||
op?.DispAtu?.Dados?.AgitadorDeCalda;
|
|
||||||
|
|
||||||
if (!(agitador?.Inicializado ?? false))
|
if (!(agitador?.Inicializado ?? false))
|
||||||
return;
|
return;
|
||||||
|
|
@ -634,32 +633,20 @@ namespace AgroBase.Services
|
||||||
!operacaoConcluida &&
|
!operacaoConcluida &&
|
||||||
PulverizadorLiberado;
|
PulverizadorLiberado;
|
||||||
|
|
||||||
bool bicosAtuando =
|
bool bicosAtuando = op.DispAtu?.Dados?.BicosPulverizadores?.Any(x => x.Comandar && x.ComandoAtuar) ?? false;
|
||||||
op.DispAtu?.Dados?.BicosPulverizadores?
|
|
||||||
.Any(x =>
|
|
||||||
x.Comandar &&
|
|
||||||
x.ComandoAtuar)
|
|
||||||
?? false;
|
|
||||||
|
|
||||||
double potenciaFinal = 0;
|
double potenciaFinal = 0;
|
||||||
DateTime agora = DateTime.Now;
|
DateTime agora = DateTime.Now;
|
||||||
|
|
||||||
if (
|
if (operacaoAtiva && !_agitadorOperacaoAtivaAnterior)
|
||||||
operacaoAtiva &&
|
|
||||||
!_agitadorOperacaoAtivaAnterior
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
_agitadorBoostAte =
|
_agitadorBoostAte = agora.AddMilliseconds(AtuAgitadorBoostRetomadaMs);
|
||||||
agora.AddMilliseconds(
|
|
||||||
AtuAgitadorBoostRetomadaMs
|
|
||||||
);
|
|
||||||
|
|
||||||
_agitadorUltimaTroca = agora;
|
_agitadorUltimaTroca = agora;
|
||||||
_agitadorIntermitenteLigado = true;
|
_agitadorIntermitenteLigado = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool emBoost =
|
bool emBoost = agora < _agitadorBoostAte;
|
||||||
agora < _agitadorBoostAte;
|
|
||||||
|
|
||||||
switch (modo)
|
switch (modo)
|
||||||
{
|
{
|
||||||
|
|
@ -672,18 +659,15 @@ namespace AgroBase.Services
|
||||||
{
|
{
|
||||||
if (emBoost)
|
if (emBoost)
|
||||||
{
|
{
|
||||||
potenciaFinal =
|
potenciaFinal = AtuAgitadorPotenciaBoost;
|
||||||
AtuAgitadorPotenciaBoost;
|
|
||||||
}
|
}
|
||||||
else if (bicosAtuando)
|
else if (bicosAtuando)
|
||||||
{
|
{
|
||||||
potenciaFinal =
|
potenciaFinal = AtuAgitadorPotenciaContinua;
|
||||||
AtuAgitadorPotenciaContinua;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
potenciaFinal =
|
potenciaFinal = AtuAgitadorPotenciaManutencao;
|
||||||
AtuAgitadorPotenciaManutencao;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -697,44 +681,27 @@ namespace AgroBase.Services
|
||||||
}
|
}
|
||||||
else if (emBoost)
|
else if (emBoost)
|
||||||
{
|
{
|
||||||
potenciaFinal =
|
potenciaFinal = AtuAgitadorPotenciaBoost;
|
||||||
AtuAgitadorPotenciaBoost;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int tempoAtualMs =
|
int tempoAtualMs = _agitadorIntermitenteLigado ? AtuAgitadorTempoLigadoMs : AtuAgitadorTempoDesligadoMs;
|
||||||
_agitadorIntermitenteLigado
|
|
||||||
? AtuAgitadorTempoLigadoMs
|
|
||||||
: AtuAgitadorTempoDesligadoMs;
|
|
||||||
|
|
||||||
if (
|
if ((agora - _agitadorUltimaTroca).TotalMilliseconds >= tempoAtualMs)
|
||||||
(agora - _agitadorUltimaTroca)
|
|
||||||
.TotalMilliseconds >=
|
|
||||||
tempoAtualMs
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
_agitadorIntermitenteLigado =
|
_agitadorIntermitenteLigado = !_agitadorIntermitenteLigado;
|
||||||
!_agitadorIntermitenteLigado;
|
|
||||||
|
|
||||||
_agitadorUltimaTroca = agora;
|
_agitadorUltimaTroca = agora;
|
||||||
}
|
}
|
||||||
|
|
||||||
potenciaFinal =
|
potenciaFinal = _agitadorIntermitenteLigado ? AtuAgitadorPotenciaIntermitente : 0;
|
||||||
_agitadorIntermitenteLigado
|
|
||||||
? AtuAgitadorPotenciaIntermitente
|
|
||||||
: 0;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
potenciaFinal =
|
potenciaFinal = Math.Min(potenciaFinal, PotenciaLimitePorNivel(PercentualAtual));
|
||||||
Math.Min(
|
|
||||||
potenciaFinal,
|
|
||||||
PotenciaLimitePorNivel(PercentualAtual)
|
|
||||||
);
|
|
||||||
|
|
||||||
potenciaFinal =
|
potenciaFinal = Clamp(potenciaFinal, 0, 100);
|
||||||
Clamp(potenciaFinal, 0, 100);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Este método é a fonte de verdade do agitador.
|
* Este método é a fonte de verdade do agitador.
|
||||||
|
|
@ -742,12 +709,9 @@ namespace AgroBase.Services
|
||||||
agitador.PotenciaSP = potenciaFinal;
|
agitador.PotenciaSP = potenciaFinal;
|
||||||
agitador.PressaoSP = -1;
|
agitador.PressaoSP = -1;
|
||||||
|
|
||||||
agitador.ComandoAtuar =
|
agitador.ComandoAtuar = agitador.Comandar && potenciaFinal > 0;
|
||||||
agitador.Comandar &&
|
|
||||||
potenciaFinal > 0;
|
|
||||||
|
|
||||||
_agitadorOperacaoAtivaAnterior =
|
_agitadorOperacaoAtivaAnterior = operacaoAtiva;
|
||||||
operacaoAtiva;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -969,6 +969,7 @@ namespace AgroBase.Services.Operadores
|
||||||
estado_leitura = bico._EstadoLeitura,
|
estado_leitura = bico._EstadoLeitura,
|
||||||
angulo_leitura = bico._AnguloBicoLeitura,
|
angulo_leitura = bico._AnguloBicoLeitura,
|
||||||
|
|
||||||
|
com_movimento = bico.ComMovimento,
|
||||||
angulo_neutro = bico.AnguloNeutro,
|
angulo_neutro = bico.AnguloNeutro,
|
||||||
angulo_controle = bico.AnguloControle,
|
angulo_controle = bico.AnguloControle,
|
||||||
angulo_abertura = bico.AnguloAbertura,
|
angulo_abertura = bico.AnguloAbertura,
|
||||||
|
|
|
||||||
|
|
@ -57,54 +57,121 @@ public sealed class UdpReliableChannel : IDisposable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Start(int localPort)
|
public bool Start(int localPort)
|
||||||
{
|
{
|
||||||
if (_udp != null) return;
|
lock (_sockLock)
|
||||||
|
{
|
||||||
|
if (_udp != null || _running || _stopping)
|
||||||
|
return true;
|
||||||
|
|
||||||
_seqTx = 0; // opcional
|
try
|
||||||
_lastSeqRx = 0; // importante
|
{
|
||||||
_running = true;
|
_seqTx = 0;
|
||||||
|
_lastSeqRx = 0;
|
||||||
|
_running = true;
|
||||||
|
_stopping = false;
|
||||||
|
|
||||||
_udp = new UdpClient(localPort);
|
_udp = new UdpClient(localPort);
|
||||||
_udp.Client.ReceiveBufferSize = 1 << 20;
|
_udp.Client.ReceiveBufferSize = 1 << 20;
|
||||||
_udp.Client.SendBufferSize = 1 << 20;
|
_udp.Client.SendBufferSize = 1 << 20;
|
||||||
|
|
||||||
_rxThread = new Thread(RxLoop) { IsBackground = true, Name = "UdpReliableChannel.Rx" };
|
_rxThread = new Thread(RxLoop)
|
||||||
_rxThread.Start();
|
{
|
||||||
|
IsBackground = true,
|
||||||
|
Name = "UdpReliableChannel.Rx"
|
||||||
|
};
|
||||||
|
|
||||||
if (EnableHeartbeat)
|
_rxThread.Start();
|
||||||
StartHeartbeat();
|
|
||||||
|
if (EnableHeartbeat)
|
||||||
|
StartHeartbeat();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (SocketException ex)
|
||||||
|
{
|
||||||
|
_running = false;
|
||||||
|
_stopping = false;
|
||||||
|
|
||||||
|
try { _udp?.Close(); } catch { }
|
||||||
|
try { _udp?.Dispose(); } catch { }
|
||||||
|
|
||||||
|
_udp = null;
|
||||||
|
_rxThread = null;
|
||||||
|
|
||||||
|
// 10048 = address already in use
|
||||||
|
if (ex.SocketErrorCode == SocketError.AddressAlreadyInUse)
|
||||||
|
{
|
||||||
|
// Não relança. Quem chamou decide tentar depois.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
_running = false;
|
||||||
|
_stopping = false;
|
||||||
|
|
||||||
|
try { _udp?.Close(); } catch { }
|
||||||
|
try { _udp?.Dispose(); } catch { }
|
||||||
|
|
||||||
|
_udp = null;
|
||||||
|
_rxThread = null;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Stop()
|
public void Stop()
|
||||||
{
|
{
|
||||||
|
UdpClient udpParaFechar = null;
|
||||||
|
Thread threadParaAguardar = null;
|
||||||
|
|
||||||
lock (_sockLock)
|
lock (_sockLock)
|
||||||
{
|
{
|
||||||
|
if (_stopping)
|
||||||
|
return;
|
||||||
|
|
||||||
_stopping = true;
|
_stopping = true;
|
||||||
_running = false;
|
_running = false;
|
||||||
|
|
||||||
|
udpParaFechar = _udp;
|
||||||
|
threadParaAguardar = _rxThread;
|
||||||
}
|
}
|
||||||
|
|
||||||
// pare heartbeat antes de matar socket
|
|
||||||
StopHeartbeat();
|
StopHeartbeat();
|
||||||
|
|
||||||
try { _udp?.Close(); } catch { }
|
try { udpParaFechar?.Close(); } catch { }
|
||||||
try { _udp?.Dispose(); } catch { }
|
try { udpParaFechar?.Dispose(); } catch { }
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_rxThread != null && _rxThread.IsAlive)
|
if (
|
||||||
_rxThread.Join(2000); // ou sem timeout se preferir travar até fechar
|
threadParaAguardar != null &&
|
||||||
|
threadParaAguardar.IsAlive &&
|
||||||
|
Thread.CurrentThread.ManagedThreadId != threadParaAguardar.ManagedThreadId
|
||||||
|
)
|
||||||
|
{
|
||||||
|
threadParaAguardar.Join(1000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
|
|
||||||
lock (_sockLock)
|
lock (_sockLock)
|
||||||
{
|
{
|
||||||
_udp = null;
|
if (ReferenceEquals(_udp, udpParaFechar))
|
||||||
_rxThread = null;
|
_udp = null;
|
||||||
|
|
||||||
|
if (ReferenceEquals(_rxThread, threadParaAguardar))
|
||||||
|
_rxThread = null;
|
||||||
|
|
||||||
_lastSeqRx = 0;
|
_lastSeqRx = 0;
|
||||||
|
|
||||||
foreach (var kv in _pendingAck)
|
foreach (var kv in _pendingAck)
|
||||||
kv.Value.TrySetResult(false);
|
kv.Value.TrySetResult(false);
|
||||||
|
|
||||||
_pendingAck.Clear();
|
_pendingAck.Clear();
|
||||||
|
|
||||||
_stopping = false;
|
_stopping = false;
|
||||||
|
|
|
||||||
|
|
@ -554,27 +554,38 @@ class ModuloAtuador(ModuloDiagnosticoBase):
|
||||||
def _avaliar_comando_bico(self, item, ctx, motivos, condicoes):
|
def _avaliar_comando_bico(self, item, ctx, motivos, condicoes):
|
||||||
dados = item["dados"]
|
dados = item["dados"]
|
||||||
label = dados.get("label")
|
label = dados.get("label")
|
||||||
|
|
||||||
comando_presente = (
|
comando_presente = (
|
||||||
"comando_atuar" in dados or
|
"comando_atuar" in dados or
|
||||||
"estado_desejado" in dados or
|
"estado_desejado" in dados or
|
||||||
"status_desejado_fisico" in dados or
|
"status_desejado_fisico" in dados or
|
||||||
"ultimo_status_desejado" in dados
|
"ultimo_status_desejado" in dados
|
||||||
)
|
)
|
||||||
|
|
||||||
comando = self._estado_desejado_ligado(dados)
|
comando = self._estado_desejado_ligado(dados)
|
||||||
estado = self._get(dados, "estado_leitura", self._campo_atual(dados, "EstadoLeitura", 0))
|
estado = self._get(dados, "estado_leitura", self._campo_atual(dados, "EstadoLeitura", 0))
|
||||||
estado_on = self._estado_ligado(estado)
|
estado_on = self._estado_ligado(estado)
|
||||||
|
|
||||||
angulo = self._float(
|
usa_servo = dados.get("com_movimento", False)
|
||||||
self._get(dados, "angulo_leitura", self._campo_atual(dados, "ServoAnguloLeitura", 0)),
|
|
||||||
0,
|
|
||||||
)
|
|
||||||
|
|
||||||
angulo_neutro = self._float(dados.get("angulo_neutro", 90), 90)
|
angulo = None
|
||||||
angulo_controle = self._float(dados.get("angulo_controle", dados.get("angulo_sp", 90)), 90)
|
angulo_desejado = None
|
||||||
angulo_desejado = self._float(
|
angulo_neutro = None
|
||||||
dados.get("angulo_desejado", angulo_controle if comando else angulo_neutro),
|
angulo_controle = None
|
||||||
angulo_controle if comando else angulo_neutro,
|
|
||||||
)
|
if usa_servo:
|
||||||
|
angulo = self._float(
|
||||||
|
self._get(dados, "angulo_leitura", self._campo_atual(dados, "ServoAnguloLeitura", 0)),
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
|
||||||
|
angulo_neutro = self._float(dados.get("angulo_neutro", 90), 90)
|
||||||
|
angulo_controle = self._float(dados.get("angulo_controle", dados.get("angulo_sp", 90)), 90)
|
||||||
|
|
||||||
|
angulo_desejado = self._float(
|
||||||
|
dados.get("angulo_desejado", angulo_controle if comando else angulo_neutro),
|
||||||
|
angulo_controle if comando else angulo_neutro,
|
||||||
|
)
|
||||||
|
|
||||||
ultimo_comando_ms = self._float(dados.get("ultimo_comando_ms", 999999), 999999)
|
ultimo_comando_ms = self._float(dados.get("ultimo_comando_ms", 999999), 999999)
|
||||||
tem_idade_comando = ultimo_comando_ms < 900000
|
tem_idade_comando = ultimo_comando_ms < 900000
|
||||||
|
|
@ -585,13 +596,16 @@ class ModuloAtuador(ModuloDiagnosticoBase):
|
||||||
return 92, {
|
return 92, {
|
||||||
"comando_disponivel": False,
|
"comando_disponivel": False,
|
||||||
"estado_on": estado_on,
|
"estado_on": estado_on,
|
||||||
|
"usa_servo": usa_servo,
|
||||||
"angulo": angulo,
|
"angulo": angulo,
|
||||||
|
"angulo_desejado": angulo_desejado,
|
||||||
}
|
}
|
||||||
|
|
||||||
if tem_idade_comando and ultimo_comando_ms < self.COMANDO_GRACE_MS:
|
if tem_idade_comando and ultimo_comando_ms < self.COMANDO_GRACE_MS:
|
||||||
return 96, {
|
return 96, {
|
||||||
"comando_atuar": comando,
|
"comando_atuar": comando,
|
||||||
"estado_on": estado_on,
|
"estado_on": estado_on,
|
||||||
|
"usa_servo": usa_servo,
|
||||||
"angulo": angulo,
|
"angulo": angulo,
|
||||||
"angulo_desejado": angulo_desejado,
|
"angulo_desejado": angulo_desejado,
|
||||||
"ultimo_comando_ms": ultimo_comando_ms,
|
"ultimo_comando_ms": ultimo_comando_ms,
|
||||||
|
|
@ -634,32 +648,36 @@ class ModuloAtuador(ModuloDiagnosticoBase):
|
||||||
|
|
||||||
score = min(score, 25 if severidade > 90 else 65)
|
score = min(score, 25 if severidade > 90 else 65)
|
||||||
|
|
||||||
erro_ang = abs(angulo - angulo_desejado)
|
if usa_servo and angulo is not None and angulo_desejado is not None:
|
||||||
|
erro_ang = abs(angulo - angulo_desejado)
|
||||||
|
|
||||||
if erro_ang > self.ANGULO_TOL_BICO_GRAUS and (comando or estado_on):
|
if erro_ang > self.ANGULO_TOL_BICO_GRAUS and (comando or estado_on):
|
||||||
motivos.append(f"Ângulo do bico distante do desejado ({angulo:.1f}°/{angulo_desejado:.1f}°)")
|
motivos.append(f"Ângulo do bico distante do desejado ({angulo:.1f}°/{angulo_desejado:.1f}°)")
|
||||||
condicoes.append({
|
condicoes.append({
|
||||||
"label": "Ângulo bico",
|
"label": "Ângulo bico",
|
||||||
"valor": angulo,
|
"valor": angulo,
|
||||||
"severidade": min(75, max(30, int(erro_ang * 3))),
|
"severidade": min(75, max(30, int(erro_ang * 3))),
|
||||||
"classe": "processo",
|
"classe": "processo",
|
||||||
"descricao": f"Ângulo do bico {label} distante do desejado",
|
"descricao": f"Ângulo do bico {label} distante do desejado",
|
||||||
"acoes": [
|
"acoes": [
|
||||||
"Verificar servo/posição mecânica do bico.",
|
"Verificar servo/posição mecânica do bico.",
|
||||||
"Conferir neutro e ângulo de abertura configurados.",
|
"Conferir neutro e ângulo de abertura configurados.",
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
score = min(score, 78)
|
score = min(score, 78)
|
||||||
|
|
||||||
return int(max(0, min(100, round(score)))), {
|
return int(max(0, min(100, round(score)))), {
|
||||||
"comando_disponivel": True,
|
"comando_disponivel": True,
|
||||||
"comando_atuar": comando,
|
"comando_atuar": comando,
|
||||||
"estado_on": estado_on,
|
"estado_on": estado_on,
|
||||||
|
"usa_servo": usa_servo,
|
||||||
"angulo": angulo,
|
"angulo": angulo,
|
||||||
"angulo_desejado": angulo_desejado,
|
"angulo_desejado": angulo_desejado,
|
||||||
|
"angulo_neutro": angulo_neutro,
|
||||||
|
"angulo_controle": angulo_controle,
|
||||||
"ultimo_comando_ms": ultimo_comando_ms,
|
"ultimo_comando_ms": ultimo_comando_ms,
|
||||||
}
|
}
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# Bombas
|
# Bombas
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
|
||||||
|
|
@ -350,23 +350,15 @@ namespace OperationControl.Models
|
||||||
HeartbeatPayload = new byte[] { 0 }
|
HeartbeatPayload = new byte[] { 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
channel.Start(
|
channel.Start(VariaveisPortas.Ethernet_UDP_TX);
|
||||||
VariaveisPortas.Ethernet_UDP_TX
|
|
||||||
);
|
|
||||||
|
|
||||||
UdpChannel = channel;
|
UdpChannel = channel;
|
||||||
|
|
||||||
ControlSenderDir = new ManualControlSender(
|
ControlSenderDir = new ManualControlSender(UdpChannel, (byte)AgroBase.Models.Enums.T_Code.Dir);
|
||||||
UdpChannel,
|
|
||||||
(byte)AgroBase.Models.Enums.T_Code.Dir
|
|
||||||
);
|
|
||||||
|
|
||||||
ControlSenderDir.Start();
|
ControlSenderDir.Start();
|
||||||
|
|
||||||
ControlSenderMov = new ManualControlSender(
|
ControlSenderMov = new ManualControlSender(UdpChannel, (byte)AgroBase.Models.Enums.T_Code.Mov);
|
||||||
UdpChannel,
|
|
||||||
(byte)AgroBase.Models.Enums.T_Code.Mov
|
|
||||||
);
|
|
||||||
|
|
||||||
ControlSenderMov.Start();
|
ControlSenderMov.Start();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue