using AgroBase.Services; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using static AgroBase.Models.Enums; namespace AgroBase.Models.Modules { public class MovimentacaoUnificadaModel : DispositivoBaseModel { public bool Conectado { get { return Modulos.Any(x => x.Conectado); } set { } } public static int _TaxaAmostragem { get; set; } = 1000; public double DistanciaPercorridaOperacao { get; set; } = 0; public int TempoEmAtividade { get; set; } = 0; public double DistanciaPercorridaTotal { get; set; } = 0; public double DistanciaPercorridaParcial { get; set; } = 0; public double DiametroRoda { get; set; } = 0.3556; public double ReducaoMotorBLDC { get; set; } = 5; public double RPM_Max_MotorBLDC { get; set; } = 500; public string IP_Bld { get; set; } = Variaveis.FaixaIPethernet + ".10"; public string IP_Mks { get; set; } = Variaveis.FaixaIPethernet + ".11"; public static int LogsManter { get; set; } = 60; public AsyncTaskTimerModel tmrRegistrador; public AsyncTaskTimerModel tmrRegistradorBLD; public AsyncTaskTimerModel tmrRegistradorMKS; public List Modulos { get; set; } = new List(); public static Direcao UltimaDirecao { get; set; } = Direcao.Parado; public (bool, List) StatusModulosBLD(Direcao Lado) { string Prefixo = Lado == Direcao.Esquerda ? "E" : Lado == Direcao.Direita ? "D" : ""; var Mods = Modulos.Where(Mod => Mod.Modulo_ID.Contains(Prefixo) && Mod.MovMotor.Comandar).ToList(); var ModsComFalha = Mods .Where(Mod => !Mod.MovMotor.BLD_Inicializado || Mod.MovMotor.CodigoAlarme != 0 || Mod.MovMotor.AlarmeSensores ) .ToList(); bool _operante = ModsComFalha.Count() < Mods.Count(); List ModsInoperantes = ModsComFalha.Select(x => x.Modulo_ID).ToList(); return (_operante, ModsInoperantes); } public (bool, List) StatusModulosMKS(TipoMovimentoDirecional TipoMovimento) { var Mods = Modulos.Where(Mod => Mod.DirMotor.Comandar).ToList(); var ModsComFalha = Mods .Where(Mod => !Mod.DirMotor.MKS_Inicializado && ( Mod.DirMotor.ConfigSentidos[TipoMovimento].Esquerda != Sentido.Parado && Mod.DirMotor.ConfigSentidos[TipoMovimento].Direita != Sentido.Parado ) ); bool _operante = !ModsComFalha.Any(); List ModsInoperantes = ModsComFalha.Select(x => x.Modulo_ID).ToList(); return (_operante, ModsInoperantes); } public static MovimentacaoUnificadaModel CarregarParametrosIniciais() { return new MovimentacaoUnificadaModel() { Modulos = new List() { new ModuloMvdModel() { Modulo_ID = "ET", MovMotor = MvdMotorBLDC.CarregarParametrosIniciais("ET", "0x01"), DirMotor = MvdMotorPasso.CarregarParametrosIniciais("ET", "0x01"), }, new ModuloMvdModel() { Modulo_ID = "EF", MovMotor = MvdMotorBLDC.CarregarParametrosIniciais("EF", "0x03"), DirMotor = MvdMotorPasso.CarregarParametrosIniciais("EF", "0x03") }, new ModuloMvdModel() { Modulo_ID = "DT", MovMotor = MvdMotorBLDC.CarregarParametrosIniciais("DT", "0x02"), DirMotor = MvdMotorPasso.CarregarParametrosIniciais("DT", "0x02") }, new ModuloMvdModel() { Modulo_ID = "DF", MovMotor = MvdMotorBLDC.CarregarParametrosIniciais("DF", "0x04"), DirMotor = MvdMotorPasso.CarregarParametrosIniciais("DF", "0x04") }, }, }; } public void LimparDados(T _dados) { var Dados = _dados as MovimentacaoUnificadaModel; Dados.Modulos.ForEach(x => { x.MovMotor.Leitura = null; x.DirMotor.Leitura = null; }); ReiniciarLeituras(Dados); } public void ReiniciarLeituras(MovimentacaoUnificadaModel Dados) { Dados.DistanciaPercorridaParcial = 0; Dados.DistanciaPercorridaTotal = 0; Dados.DistanciaPercorridaOperacao = 0; Dados.TempoEmAtividade = 0; Dados.Modulos.ForEach(x => { x.MovMotor.AlarmeSensores = false; x.MovMotor.ConfigFreio.Leitura = false; x.MovMotor.LogGrafico = new List(); x.MovMotor.Temperatura = 0; x.MovMotor.RPM_SP = 0; x.MovMotor.RPM_SP_Controle = 0; x.MovMotor.Corrente = 0; x.DirMotor.Angulo_SP = 0; x.DirMotor.Sentido_SP = Sentido.Parado; }); } public Dictionary> ProtocoloConfiguracao(bool Conectar) { var Config = Modulos.Where(x => x.MovMotor.Comandar || x.DirMotor.Comandar).ToDictionary(x => x.Modulo_ID, x => x.ProtocoloConfiguracao(Conectar).ToList()); return Config; } public string ProtocoloVerificacao(bool Completo) { return ""; } public void RecebeProtocoloModulo(string Protocolo) { } public void RegistrarLogMov(ModuloMvdModel Modulo) { Modulo.MovMotor.LogGrafico.Add(new MvdMotorMOVSensorimanetoGrafico() { Momento = DateTime.Now, Modulo_ID = Modulo.Modulo_ID, RPM_SP = Modulo.MovMotor.RPM_SP_Leitura, RPM_Motor = Modulo.MovMotor.RPM_Motor, RPM_Roda = Modulo.MovMotor.RPM_Roda, Corrente = Modulo.MovMotor.Corrente, Sentido = Modulo.MovMotor.Sentido, Temperatura = Modulo.MovMotor.Temperatura, TemperaturaDriver = Modulo.MovMotor.TemperaturaDriver, Tensao = Modulo.MovMotor.Tensao, Velocidade = Modulo.MovMotor.VelocidadeInstantanea }); if (Modulo.MovMotor.LogGrafico.Count > 60) { Modulo.MovMotor.LogGrafico.RemoveAt(0); } } public void DefineStatusConexao(string Mod_ID, bool conecatdo) { var Modulo = Modulos.FirstOrDefault(x => x.Modulo_ID == Mod_ID); if (Modulo != null) { //Modulo.Conectado = conecatdo; } } public string GetTaxaAmostragem() { return _TaxaAmostragem.ToString("00000"); } public void SetTaxaAmostragem(int TaxaAmostragem) { _TaxaAmostragem = TaxaAmostragem; } public bool GetStatusConexao() { return Conectado; } public string GetIP() { return IP_Bld; } public void IniciarRegistrador() { if (!(tmrRegistrador?.IsRunning ?? false)) { LimparDados(this); PararRegistrador(); tmrRegistrador = new AsyncTaskTimerModel("tmrRegistrador_" + T_Code.Mvd.ToString(), tmrRegistrador_Tick, _TaxaAmostragem); tmrRegistrador.Start(); tmrRegistradorBLD = new AsyncTaskTimerModel("tmrRegistrador_" + T_Code.Bld.ToString(), tmrRegistradorBLD_Tick, BLD300RService.TaxaAmostragem); tmrRegistradorBLD.Start(); tmrRegistradorMKS = new AsyncTaskTimerModel("tmrRegistrador_" + T_Code.Mks.ToString(), tmrRegistradorMKS_Tick, MKS057DService.TaxaAmostragem); tmrRegistradorMKS.Start(); } } public void PararRegistrador() { tmrRegistrador?.Dispose(); tmrRegistradorBLD?.Dispose(); tmrRegistradorMKS?.Dispose(); } public async Task tmrRegistrador_Tick() { tmrRegistrador.SetInterval(_TaxaAmostragem); if (UltimaDirecao != Direcao.Parado) { TempoEmAtividade++; double VelocidadeMedia = Modulos.Where(x => x.Conectado && x.MovMotor.ComandoLigado).DefaultIfEmpty().Average(x => x?.MovMotor?.VelocidadeInstantanea ?? 0); VelocidadeMedia /= 3.6; // converter de km/h para m/s double tempo = _TaxaAmostragem / 1000; DistanciaPercorridaTotal += tempo * VelocidadeMedia; DistanciaPercorridaParcial += (UltimaDirecao == Direcao.Frente ? tempo : UltimaDirecao == Direcao.Tras ? -tempo : 0) * VelocidadeMedia; DistanciaPercorridaOperacao += tempo * VelocidadeMedia; Variaveis.OperacaoEmAndamento.Sensoriamento.VelocidadeMedia = VelocidadeMedia; } } private async Task tmrRegistradorBLD_Tick() { if (!BLD300RService.Iniciado && SerialService.DispositivosMapeados.Any(x => x.Dispositivo == T_Code.Bld)) { await BLD300RService.InicializarEthernetService(); foreach (var Leitura in BLD300RService.DadosLeitura.Where(x => x.UltimoComandoRecebido.AddSeconds(10) < DateTime.Now)) { BLD300RService.AdicionarComandoNaFila(new BLD300RService.BLDComandoModel() { Endereco = Leitura.Endereco, Parametro = BLD300RService.Parametros.First(x => x.Chave == "Versao"), Get = true, AguardaResposta = true }); } tmrRegistradorBLD.SetInterval(3000); return; } var Controle = Variaveis.OperacaoEmAndamento.Controle.TiposControle.FirstOrDefault(x => x.Tipo == T_Code.Mov); foreach (var Modulo in Modulos.Where(x => x.MovMotor.BLD_Inicializado).OrderBy(x => x.MovMotor.EnderecoByte)) { foreach (var Parametro in BLD300RService.Parametros.Where(x => x.LeituraLoop)) { var Comando = new BLD300RService.BLDComandoModel() { Endereco = Modulo.MovMotor.EnderecoByte, AguardaResposta = true, Parametro = Parametro, Get = true, TimeoutResposta = 500 }; BLD300RService.AdicionarComandoNaFila(Comando); } Modulo.MovMotor.EnviarComandoControle(Controle.UltimaDirecao); Modulo.MovMotor.ConfigFreio.Leitura = Modulo.MovMotor.Leitura?.Freado ?? false; Variaveis.OperacaoEmAndamento.DispMvd.Dados.RegistrarLogMov(Modulo); } tmrRegistradorBLD.SetInterval(BLD300RService.TaxaAmostragem); } private async Task tmrRegistradorMKS_Tick() { if (!MKS057DService.Iniciado && SerialService.DispositivosMapeados.Any(x => x.Dispositivo == T_Code.Mks)) { await MKS057DService.InicializarEthernetService(); foreach (var Leitura in MKS057DService.DadosLeitura.Where(x => x.UltimoComandoRecebido.AddSeconds(10) < DateTime.Now)) { MKS057DService.AdicionarComandoNaFila(MKS057DService.MontarComandoRequisicaoPulsos(Leitura.Endereco)); } tmrRegistradorMKS.SetInterval(3000); return; } var Controle = Variaveis.OperacaoEmAndamento.Controle.TiposControle.FirstOrDefault(x => x.Tipo == T_Code.Dir); foreach (var Modulo in Modulos.Where(x => x.DirMotor.MKS_Inicializado)) { byte modAddr = Modulo.DirMotor.EnderecoByte; if (!MKS057DService.Referenciando || (MKS057DService.Referenciando && MKS057DService.AddrRef == modAddr)) { bool reqParametros = true; // (!MKS057DService.Referenciando && (tmrRegistradorMKS.Ticks % 5 == 0)) || MKS057DService.Referenciando; if (reqParametros) { MKS057DService.AdicionarComandoNaFila(MKS057DService.MontarComandoRequisicaoPulsos(modAddr)); MKS057DService.AdicionarComandoNaFila(MKS057DService.MontarComandoRequisicaoIO(modAddr)); } // 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(2000) < DateTime.Now) && !Modulo.DirMotor.AtingiuAnguloSP) { Modulo.DirMotor.EnviarComandoControle(Controle.UltimaDirecao, !Modulo.DirMotor.Comandar); } } } MKS057DService.TaxaAmostragem = MKS057DService.Referenciando ? 200 : 1000; tmrRegistradorMKS.SetInterval(MKS057DService.TaxaAmostragem); } public async Task ExecutarMovimentoDirecionalCombinado(Direcao DirecaoAtual) { if (DirecaoAtual == Direcao.Parado) { foreach (var Modulo in Modulos) { Modulo.MovMotor.EnviarComandoControle(Direcao.Parado); } await Task.Delay(1000); } switch (Variaveis.OperacaoEmAndamento.Controle.TipoMovimento) { case TipoMovimentoDirecional.RotacionarNoEixo: case TipoMovimentoDirecional.MovimentoLateral: foreach (var Modulo in Modulos.Where(x => x.DirMotor.MKS_Inicializado && !x.DirMotor.PosicaoTipoMovimentoConcluido(DirecaoAtual))) { Modulo.DirMotor.EnviarComandoControle(DirecaoAtual); } DateTime Agora = DateTime.Now; bool Sucesso = Modulos.All(x => x.DirMotor.PosicaoTipoMovimentoConcluido(DirecaoAtual)); while (Agora.AddMilliseconds(5000) > DateTime.Now && !Sucesso) { await Task.Delay(100); Sucesso = Modulos.All(x => x.DirMotor.PosicaoTipoMovimentoConcluido(DirecaoAtual)); } if (Sucesso && DirecaoAtual != Direcao.Parado) { Variaveis.OperacaoEmAndamento.Controle.PercentualVelocidadeSP = 20; foreach (var Modulo in Modulos) { Modulo.MovMotor.EnviarComandoControle( DirecaoAtual == Direcao.Direita ? Direcao.Frente : DirecaoAtual == Direcao.Esquerda ? Direcao.Tras : Direcao.Parado ); } } break; } } public async Task RealizarReferenciamentoDirecional() { if (!MKS057DService.Referenciando) { TipoMovimentoDirecional tipoControle = Variaveis.OperacaoEmAndamento.Controle.TipoMovimento; Variaveis.OperacaoEmAndamento.Controle.TipoMovimento = TipoMovimentoDirecional.Diagnostico; foreach (var Modulo in Modulos.Where(x => x.DirMotor.Comandar && x.DirMotor.MKS_Inicializado && !x.DirMotor.IN1_Atuado)) { await Modulo.DirMotor.ReferenciaMotor(); } Variaveis.OperacaoEmAndamento.Controle.TipoMovimento = tipoControle; } } } public class ModuloMvdModel { public string Modulo_ID { get; set; } public bool Disponivel { get; set; } public bool RequisitarDados { get; set; } = false; public bool Conectado { get { return MovMotor.BLD_Inicializado || DirMotor.MKS_Inicializado; } } public MvdMotorBLDC MovMotor { get; set; } public MvdMotorPasso DirMotor { get; set; } public static PinoutDataModel Pinout { get; set; } public static List Funcoes { get; set; } = new List() { FuncoesPinout.TX, FuncoesPinout.RX, FuncoesPinout.ModbusDI, FuncoesPinout.ModbusRO, FuncoesPinout.ModbusDE_RE }; public List ProtocoloConfiguracao(bool Conectar) { List Config = new List(); var _pinout = new PinoutDataModel() { ExpansorGPIO = Pinout.ExpansorGPIO, EnderecoExpansor = Pinout.EnderecoExpansor, Pinos = Pinout.Pinos.ToList(), }; _pinout.Pinos = _pinout.Pinos.Where(x => x.ComponenteID == T_Code.Mvd.ToString()).ToList(); string ProtocoloMOD = ((int)F_Code.Cfg).ToString() + SerialService.SplitMessage + Modulo_ID + SerialService.SplitParams + (Conectar ? "1" : "0") + SerialService.SplitParams + MovimentacaoUnificadaModel._TaxaAmostragem.ToString() + SerialService.SplitParams + (RequisitarDados ? "1" : "0") + SerialService.SplitParams + PinoutModel.PinoProtocolo(_pinout, Funcoes, SerialService.SplitParams); if (Conectar) { Config.Add(ProtocoloMOD); } if (MovMotor.Comandar) { Config.Add(MovMotor.ProtocoloConfiguracao(Conectar)); } /*if (DirMotor.Comandar) { Config.Add(DirMotor.ProtocoloConfiguracao(Conectar)); }*/ if (!Conectar) { Config.Add(ProtocoloMOD); } Config.Add(ProtocoloVerificacao(false)); return Config; } public string ProtocoloVerificacao(bool Completo) { if (Completo) { string ProtocoloCheck = SerialService.BeginLine + 0 + SerialService.SplitMessage + Modulo_ID + SerialService.SplitMessage + ((int)F_Code.Chk).ToString() + SerialService.SplitMessage + "check" + SerialService.EndLine; return ProtocoloCheck; } else { string ProtocoloCheck = ((int)F_Code.Chk).ToString() + SerialService.SplitMessage + "check"; return ProtocoloCheck; } } public void AtualizarSensoresMotor() { var sensorTmp = Variaveis.OperacaoEmAndamento.DispSen.Dados.DadosLeitura.SensoresTemperatura.FirstOrDefault(x => x.ID.Contains(Modulo_ID)); if (sensorTmp != null) { MovMotor.Temperatura = sensorTmp.Temperatura; AlarmeModel _Alarme = new AlarmeModel() { Tipo = S_Code.sTMP, Valor = sensorTmp.Temperatura, Maximo = sensorTmp.Temperatura > sensorTmp.LimiteMaximo, Minimo = sensorTmp.Temperatura < sensorTmp.LimiteMinimo, ParaMaximo = false, ParaMinimo = false }; VerificarAlarme(_Alarme); } var sensorCor = Variaveis.OperacaoEmAndamento.DispSen.Dados.DadosLeitura.SensoresCorrente.FirstOrDefault(x => x.ID.Contains(Modulo_ID)); if (sensorCor != null) { MovMotor.Corrente = (double)sensorCor.Current; AlarmeModel _Alarme = new AlarmeModel() { Tipo = S_Code.sCOR, Valor = (double)sensorCor.Current, Maximo = (double)sensorCor.Current > sensorCor.LimiteMaximo, Minimo = (double)sensorCor.Current < sensorCor.LimiteMinimo, ParaMaximo = false, ParaMinimo = false }; VerificarAlarme(_Alarme); } } private void VerificarAlarme(AlarmeModel _Alarme) { bool Adicionado = false; var Alm = MovMotor.Alarmes.FirstOrDefault(x => x.Tipo == _Alarme.Tipo); if (Alm == null) { Alm = _Alarme; MovMotor.Alarmes.Add(Alm); Adicionado = true; } bool AlarmeAnterior = (Alm.Maximo && Alm.ParaMaximo) || (Alm.Minimo && Alm.ParaMinimo); bool AlarmeAtual = (_Alarme.Maximo && _Alarme.ParaMaximo) || (_Alarme.Minimo && _Alarme.ParaMinimo); if (MovMotor.BLD_Inicializado && (!AlarmeAnterior || Adicionado) && AlarmeAtual) // Motor iniciado, Não estava em alarme anteriormente ou foi adicionado agora, alarme atual { MovMotor.EnviarComandoControle(Direcao.Parado); } Alm.Valor = _Alarme.Valor; Alm.Maximo = _Alarme.Maximo; Alm.Minimo = _Alarme.Minimo; MovMotor.AlarmeSensores = MovMotor.Alarmes.Any(x => (x.Maximo && x.ParaMaximo) || (x.Minimo && x.ParaMinimo)); } } public class MvdMotorBLDC { public string ID { get; set; } = T_Code.Mov.ToString(); // SETs public string Endereco { get; set; } public byte EnderecoByte { get { return Convert.ToByte(Endereco.Replace("0x", ""), 16); } } public bool LeituraLigado { get { return Leitura?.Ativado ?? false; } } public bool ComandoLigado { get; set; } = false; //public bool Freio { get; set; } = false; public int CodigoAlarme { get { return Leitura?.CodigoAlarme ?? 0; } } public bool AlarmeMotor { get { return CodigoAlarme > 0 && CodigoAlarme < 99; } } public int RPM_SP { get; set; } = 0; public int RPM_SP_Controle { get; set; } = 0; public int RPM_SP_Leitura { get { return RPM_SP / Convert.ToInt32(Variaveis.OperacaoEmAndamento.DispMvd?.Dados?.ReducaoMotorBLDC ?? 1); } } public Sentido Sentido_SP { get; set; } = Sentido.Parado; public int NumeroPolos { get; set; } = 10; public int Rampa { get; set; } = 0; public double OffsetLeitura { get; set; } = 1.0; // GETs public double RPM_Roda { get { return (Leitura?.RPM ?? 0) * OffsetLeitura; } } public Sentido Sentido { get { return Leitura?.Direcao ?? Sentido.Parado; } } public double Temperatura { get; set; } = 0; public double TemperaturaDriver { get { return Math.Round(Leitura?.Temperatura ?? 0, 2); } } public double Tensao { get { return Math.Round(Leitura?.Tensao ?? 0, 2); } } public double Corrente_Max { get { return Math.Round(Leitura?.CorrenteMax ?? 0, 2); } } public double Corrente { get; set; } = 0; public double RPM_Motor { get { //return Convert.ToInt32(RPM_Motor / VariaveisEquipamento.RelacaoRPM); return RPM_Roda * VariaveisEquipamento.RelacaoRPM; //return RPM_Roda * 0.74; } } public double VelocidadeInstantanea { get { return FuncoesMatematicas.CalculaVelocidadeRPM(RPM_Motor); } } public bool Comandar { get; set; } = false; public bool AlarmeSensores { get; set; } = false; public bool BLD_Inicializado { get { return Leitura?.Iniciado ?? false; } } private BLD300RModel _leitura = null; public BLD300RModel Leitura { get { _leitura = BLD300RService.DadosLeitura?.FirstOrDefault(x => x.Endereco == EnderecoByte); return _leitura; } set { _leitura = value; } } public Dictionary ConfigSentidos { get; set; } public List Funcoes { get; set; } public List LogGrafico { get; set; } = new List(); public List Alarmes { get; set; } = new List(); public MvdServoFreioModel ConfigFreio { get; set; } = new MvdServoFreioModel(); public static MvdMotorBLDC CarregarParametrosIniciais(string Mod_ID, string _Endereco) { return new MvdMotorBLDC() { ID = T_Code.Mov.ToString(), Endereco = _Endereco, Funcoes = new List() { FuncoesPinout.TMP, FuncoesPinout.ENA, FuncoesPinout.DIR, FuncoesPinout.PWM, FuncoesPinout.BRK, }, ConfigFreio = new MvdServoFreioModel() { AnguloInicial = 10, Incremental = Mod_ID.Contains("E"), Leitura = false, }, ConfigSentidos = new Dictionary() { { TipoMovimentoDirecional.RodasDianteiras, new ConfiguracaoSentidoMotor() { Direita = Sentido.Parado, Esquerda = Sentido.Parado, Frente = Mod_ID.Contains("E") ? Sentido.Horario : Sentido.Antihorario, Tras = Mod_ID.Contains("E") ? Sentido.Antihorario : Sentido.Horario } }, { TipoMovimentoDirecional.RodasTraseiras, new ConfiguracaoSentidoMotor() { Direita = Sentido.Parado, Esquerda = Sentido.Parado, Frente = Mod_ID.Contains("E") ? Sentido.Horario : Sentido.Antihorario, Tras = Mod_ID.Contains("E") ? Sentido.Antihorario : Sentido.Horario } }, { TipoMovimentoDirecional.MovimentoDiagonal, new ConfiguracaoSentidoMotor() { Direita = Sentido.Parado, Esquerda = Sentido.Parado, Frente = Mod_ID.Contains("E") ? Sentido.Horario : Sentido.Antihorario, Tras = Mod_ID.Contains("E") ? Sentido.Antihorario : Sentido.Horario } }, { TipoMovimentoDirecional.MovimentoArco, new ConfiguracaoSentidoMotor() { Direita = Sentido.Parado, Esquerda = Sentido.Parado, Frente = Mod_ID.Contains("E") ? Sentido.Horario : Sentido.Antihorario, Tras = Mod_ID.Contains("E") ? Sentido.Antihorario : Sentido.Horario } }, { TipoMovimentoDirecional.RotacionarNoEixo, new ConfiguracaoSentidoMotor() { Direita = Sentido.Parado, Esquerda = Sentido.Parado, Frente = Sentido.Horario, Tras = Sentido.Antihorario } }, { TipoMovimentoDirecional.MovimentoLateral, new ConfiguracaoSentidoMotor() { Direita = Sentido.Parado, Esquerda = Sentido.Parado, Frente = Mod_ID.Contains("T") ? Sentido.Horario : Sentido.Antihorario, Tras = Mod_ID.Contains("T") ? Sentido.Antihorario : Sentido.Horario } }, { TipoMovimentoDirecional.Diagnostico, new ConfiguracaoSentidoMotor() { Direita = Sentido.Parado, Esquerda = Sentido.Parado, Frente = Mod_ID.Contains("E") ? Sentido.Horario : Sentido.Antihorario, Tras = Mod_ID.Contains("E") ? Sentido.Antihorario : Sentido.Horario } }, }, }; } public string ProtocoloConfiguracao(bool Conectar) { var _pinout = new PinoutDataModel() { ExpansorGPIO = ModuloMvdModel.Pinout.ExpansorGPIO, EnderecoExpansor = ModuloMvdModel.Pinout.EnderecoExpansor, Pinos = ModuloMvdModel.Pinout.Pinos.ToList(), }; _pinout.Pinos = _pinout.Pinos.Where(x => x.ComponenteID == ID).ToList(); string Protocolo = ((int)F_Code.Cfg).ToString() + SerialService.SplitMessage + ID + SerialService.SplitParams + (Conectar ? "1" : "0") + SerialService.SplitParams + Endereco + SerialService.SplitParams + NumeroPolos + SerialService.SplitParams + Rampa + SerialService.SplitParams + Variaveis.OperacaoEmAndamento.DispMvd.Dados.RPM_Max_MotorBLDC + SerialService.SplitParams + PinoutModel.PinoProtocolo(_pinout, Funcoes, SerialService.SplitParams); return Protocolo; } public void EnviarComandoControle(Direcao DirecaoAtual) { bool Freado = DirecaoAtual == Direcao.EmFreio; (bool AtuarServo, int AnguloFreio) = ConfigFreio.AtualizarDadosFreio(Freado, 0, -1, 5); if (Comandar && BLD_Inicializado) { if (AlarmeSensores || AlarmeMotor) { DirecaoAtual = Direcao.Parado; Freado = false; (AtuarServo, AnguloFreio) = ConfigFreio.AtualizarDadosFreio(Freado, 0, -1, 5); if (AlarmeMotor) { BLD300RService.RegisrarErrosComunicacao(EnderecoByte, $"Módulo com código de alarme {CodigoAlarme}, reiniciando o módulo..."); BLD300RService.AdicionarComandoNaFila(new BLD300RService.BLDComandoModel() { Endereco = EnderecoByte, AguardaResposta = true, TimeoutResposta = 500, Get = false, Parametro = BLD300RService.Parametros.First(x => x.Chave == "AlarmeCode"), Valor = 0 }); } } else { MovimentacaoUnificadaModel.UltimaDirecao = DirecaoAtual; } RPM_SP_Controle = Variaveis.OperacaoEmAndamento.Controle.RPM_Motor; RPM_SP = DirecaoAtual == Direcao.Parado || Freado ? 0 : RPM_SP_Controle; ComandoLigado = RPM_SP > 0; switch (DirecaoAtual) { case Direcao.Frente: Sentido_SP = ConfigSentidos[Variaveis.OperacaoEmAndamento.Controle.TipoMovimento].Frente; break; case Direcao.Tras: Sentido_SP = ConfigSentidos[Variaveis.OperacaoEmAndamento.Controle.TipoMovimento].Tras; break; default: Sentido_SP = Sentido.Parado; break; } byte Addr = EnderecoByte; DateTime Agora = DateTime.Now; if (Sentido_SP != Sentido.Parado && (Leitura == null || Leitura.Direcao != Sentido_SP)) { BLD300RService.AdicionarComandoNaFila(new BLD300RService.BLDComandoModel() { Endereco = Addr, Parametro = BLD300RService.Parametros.First(x => x.Chave == "Direction"), Valor = Sentido_SP == Sentido.Horario ? 1 : 0, Get = false, AguardaResposta = true, TimeoutResposta = 500, }); } if (ComandoLigado && (Leitura == null || Leitura.RPM_SP != RPM_SP_Controle)) { BLD300RService.AdicionarComandoNaFila(new BLD300RService.BLDComandoModel() { Endereco = Addr, Parametro = BLD300RService.Parametros.First(x => x.Chave == "RPM_SP"), Valor = RPM_SP, Get = false, AguardaResposta = true, TimeoutResposta = 500, }); } if (Leitura == null || Leitura.Freado != Freado) { BLD300RService.AdicionarComandoNaFila(new BLD300RService.BLDComandoModel() { Endereco = Addr, Parametro = BLD300RService.Parametros.First(x => x.Chave == "Breaked"), Valor = Freado ? 1 : 0, Get = false, AguardaResposta = true, TimeoutResposta = 500, }); } if (Leitura == null || ComandoLigado != LeituraLigado) { BLD300RService.AdicionarComandoNaFila(new BLD300RService.BLDComandoModel() { Endereco = Addr, Parametro = BLD300RService.Parametros.First(x => x.Chave == "Enabled"), Valor = ComandoLigado ? 1 : 0, Get = false, AguardaResposta = true, TimeoutResposta = 500, }); } } if (AtuarServo) { string Mod_ID = Variaveis.OperacaoEmAndamento.DispMvd.Dados.Modulos.FirstOrDefault(x => x.MovMotor.Endereco == Endereco)?.Modulo_ID ?? ""; var ServoFreio = Variaveis.OperacaoEmAndamento.DispSen.Dados.Servos.FirstOrDefault(x => x.ID.Contains(Mod_ID) && x.Inicializado && x.Controlar); if (ServoFreio != null) { GeneralJoystick.EnviarComandoSensoriamento(S_Code.sFRO, ServoFreio.ID, AnguloFreio); } } } } public class MvdMotorPasso { public string ID { get; set; } = T_Code.Dir.ToString(); // SETs public string Endereco { get; set; } public byte EnderecoByte { get { return Convert.ToByte(Endereco.Replace("0x", ""), 16); } } public Sentido Sentido_SP { get; set; } = Sentido.Parado; public double Angulo_SP { get; set; } = 0; public double Angulo_Offset { get; set; } = 0; public double Velocidade_Max { get; set; } = 600; public int Velocidade { get { return Convert.ToInt32(((Variaveis.OperacaoEmAndamento.Controle?.VelocidadeMP ?? 0) / 100.0) * Velocidade_Max); } } // GETs public Sentido Sentido { get { return Leitura?.Direcao ?? Sentido.Parado; } } public double Angulo { get { return MKS057DService.PulsosParaAngulo(Leitura?.NumeroPulsos ?? 0); } } public double RPM { get { return Leitura?.RPM ?? 0; } } public bool IN1_Atuado { get { return !(Leitura?.Entradas?[0] ?? true); } } public bool IN2_Atuado { get { return !(Leitura?.Entradas?[1] ?? true); } } public bool Comandar { get; set; } = false; public bool MKS_Inicializado { get { return Leitura?.Iniciado ?? false; } } private MKS057DModel _leitura = null; public MKS057DModel Leitura { get { _leitura = MKS057DService.DadosLeitura?.FirstOrDefault(x => x.Endereco == EnderecoByte); return _leitura; } set { _leitura = value; } } public Direcao UltimaDirecao { get; set; } = Direcao.Parado; public DateTime UltimoComandoEnviado { get; set; } = DateTime.MinValue; public bool RetornandoAzero { get { return (UltimaDirecao != Direcao.Esquerda && UltimaDirecao != Direcao.Direita); } } public bool EmMovimento { get { return RPM != 0; } } public bool AtingiuAnguloSP { get { double anguloSp = Comandar ? Angulo_SP : 0; return FuncoesMatematicas.ValorEstaEntre(Angulo, anguloSp, 1); } } public bool PosicaoTipoMovimentoConcluido(Direcao DirecaoAtual) { var TipoMovimento = Variaveis.OperacaoEmAndamento.Controle.TipoMovimento; switch (TipoMovimento) { case TipoMovimentoDirecional.RotacionarNoEixo: case TipoMovimentoDirecional.MovimentoLateral: int agSP = DirecaoAtual != Direcao.Parado ? VariaveisEquipamento.AnguloMovimento[TipoMovimento] : 0; bool anguloCorreto = agSP == Angulo; if (!anguloCorreto && agSP != 0) { if (agSP > 0) { anguloCorreto = Angulo >= agSP; } else { anguloCorreto = Angulo <= agSP; } } return !Comandar || anguloCorreto; default: return !Comandar || Angulo_SP == Angulo; } } public Dictionary ConfigSentidos { get; set; } public List Funcoes { get; set; } public static MvdMotorPasso CarregarParametrosIniciais(string Mod_ID, string _Endereco) { return new MvdMotorPasso() { ID = T_Code.Dir.ToString(), Endereco = _Endereco, Funcoes = new List() { FuncoesPinout.PUL, FuncoesPinout.DIR, FuncoesPinout.ENA, FuncoesPinout.EncoderAbsoluto }, ConfigSentidos = new Dictionary() { { TipoMovimentoDirecional.RodasDianteiras, new ConfiguracaoSentidoMotor() { Direita = Mod_ID.Contains("E") ? Sentido.Horario : Sentido.Antihorario, Esquerda = Mod_ID.Contains("E") ? Sentido.Antihorario : Sentido.Horario, Frente = Sentido.Parado, Tras = Sentido.Parado } }, { TipoMovimentoDirecional.RodasTraseiras, new ConfiguracaoSentidoMotor() { Direita = Mod_ID.Contains("E") ? Sentido.Horario : Sentido.Antihorario, Esquerda = Mod_ID.Contains("E") ? Sentido.Antihorario : Sentido.Horario, Frente = Sentido.Parado, Tras = Sentido.Parado } }, { TipoMovimentoDirecional.MovimentoDiagonal, new ConfiguracaoSentidoMotor() { Direita = Mod_ID == "EF" || Mod_ID == "DT" ? Sentido.Horario : Sentido.Antihorario, Esquerda = Mod_ID == "EF" || Mod_ID == "DT" ? Sentido.Antihorario : Sentido.Horario, Frente = Sentido.Parado, Tras = Sentido.Parado } }, { TipoMovimentoDirecional.MovimentoArco, new ConfiguracaoSentidoMotor() { Direita = Mod_ID.Contains("E") ? Sentido.Horario : Sentido.Antihorario, Esquerda = Mod_ID.Contains("E") ? Sentido.Antihorario : Sentido.Horario, Frente = Sentido.Parado, Tras = Sentido.Parado } }, { TipoMovimentoDirecional.RotacionarNoEixo, new ConfiguracaoSentidoMotor() { Direita = Sentido.Horario, Esquerda = Sentido.Horario, Frente = Sentido.Parado, Tras = Sentido.Parado } }, { TipoMovimentoDirecional.MovimentoLateral, new ConfiguracaoSentidoMotor() { Direita = Mod_ID == "EF" || Mod_ID == "DT" ? Sentido.Horario : Sentido.Antihorario, Esquerda = Mod_ID == "EF" || Mod_ID == "DT" ? Sentido.Antihorario : Sentido.Horario, Frente = Sentido.Parado, Tras = Sentido.Parado } }, { TipoMovimentoDirecional.Diagnostico, new ConfiguracaoSentidoMotor() { Direita = Sentido.Horario, Esquerda = Sentido.Antihorario, Frente = Sentido.Parado, Tras = Sentido.Parado } }, } }; } public void EnviarComandoControle(Direcao Direcao, bool Forcar = false) { if (MKS_Inicializado && (Comandar || Forcar)) { // Se o motor estiver nao utilizado mas nao estiver no angulo zero if (!Comandar) { Angulo_SP = 0; Sentido_SP = Sentido.Parado; } else { int AnguloTipoMovimento = VariaveisEquipamento.AnguloMovimento[Variaveis.OperacaoEmAndamento.Controle.TipoMovimento]; if (UltimaDirecao != Direcao) { Sentido_SP = Direcao == Direcao.Direita ? ConfigSentidos[Variaveis.OperacaoEmAndamento.Controle.TipoMovimento].Direita : Direcao == Direcao.Esquerda ? ConfigSentidos[Variaveis.OperacaoEmAndamento.Controle.TipoMovimento].Esquerda : Sentido_SP == Sentido.Horario ? Sentido.Antihorario : Sentido_SP == Sentido.Antihorario ? Sentido.Horario : Sentido.Parado; UltimaDirecao = Direcao; } else if (AtingiuAnguloSP && RetornandoAzero && Angulo == 0) { Sentido_SP = Sentido.Parado; } Angulo_SP = RetornandoAzero ? 0 : AnguloTipoMovimento != -1 ? AnguloTipoMovimento : Variaveis.OperacaoEmAndamento.Controle.Angulo; int mx = Sentido_SP == Sentido.Antihorario ? -1 : 1; Angulo_SP = Math.Abs(Angulo_SP) * mx; } if (true || !AtingiuAnguloSP) { MKS057DService.AdicionarComandoNaFila(MKS057DService.MontarComandoMovimento(EnderecoByte, Angulo_SP, Velocidade, Sentido_SP)); UltimoComandoEnviado = DateTime.Now; } } } /*public async Task EnviarComandoControleAsync(Direcao Direcao) { if (Comandar && MKS_Inicializado) { int AnguloTipoMovimento = VariaveisEquipamento.AnguloMovimento[Variaveis.OperacaoEmAndamento.Controle.TipoMovimento]; if (UltimaDirecao != Direcao) { Sentido_SP = Direcao == Direcao.Direita ? ConfigSentidos[Variaveis.OperacaoEmAndamento.Controle.TipoMovimento].Direita : Direcao == Direcao.Esquerda ? ConfigSentidos[Variaveis.OperacaoEmAndamento.Controle.TipoMovimento].Esquerda : Sentido_SP == Sentido.Horario ? Sentido.Antihorario : Sentido_SP == Sentido.Antihorario ? Sentido.Horario : Sentido.Parado; UltimaDirecao = Direcao; } else if (AtingiuAnguloSP && RetornandoAzero && Angulo == 0) { Sentido_SP = Sentido.Parado; } Angulo_SP = RetornandoAzero ? 0 : AnguloTipoMovimento != -1 ? AnguloTipoMovimento : Variaveis.OperacaoEmAndamento.Controle.Angulo; int mx = Sentido_SP == Sentido.Antihorario ? -1 : 1; Angulo_SP = Math.Abs(Angulo_SP) * mx; if (!AtingiuAnguloSP || true) { //await MKS057DService.EnviarComandoControle(MKS057DService.MontarComandoMovimento(EnderecoByte, Angulo_SP, Velocidade, Sentido_SP)); MKS057DService.AdicionarComandoNaFila(MKS057DService.MontarComandoMovimento(EnderecoByte, Angulo_SP, Velocidade, Sentido_SP)); UltimoComandoEnviado = DateTime.Now; } } }*/ public async Task ReferenciaMotor() { byte Addr = EnderecoByte; MKS057DService.AddrRef = Addr; MKS057DService.UltimoReferenciamento = DateTime.Now; await Task.Delay(2000); await MKS057DService.EnviarComandoControle(MKS057DService.MontarComandoSetZero(Addr)); await Task.Delay(500); bool Sucesso = false; bool EstadoInicial = IN1_Atuado; bool EstadoAnterior = EstadoInicial; double _anguloAnterior = Angulo; double _velocidadeAnterior = 0; int _angulo = 45; int _offset = 0; Sentido _sentido = Sentido.Horario; int tentativas = 0; double _anguloEntrada = 9999; double _anguloSaida = 9999; const int MaxTentativas = 10; DateTime TimeoutGeral = DateTime.Now.AddMinutes(2); // Timeout geral para o processo. double anguloMaxVisitado = 0; double anguloMinVisitado = 0; if (!Sucesso) { while (!Sucesso && tentativas < MaxTentativas && DateTime.Now < TimeoutGeral && MKS057DService.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)); DateTime Inicio = DateTime.Now; bool inverterGiro = false; while (!Sucesso && !inverterGiro && Inicio.AddSeconds(120) > DateTime.Now && MKS057DService.Referenciando) { bool _ref = IN1_Atuado; //Sucesso = (EstadoInicial && !_ref) || (!EstadoInicial && _ref); // Comecou com o sensor ja atuado if (EstadoInicial) { // Quando houver alteracao na leitura do sensor if (_ref != EstadoAnterior) { // Se estava atuado e agora nao esta mais, e ainda nao definiu o angulo de entrada if (!_ref && _anguloEntrada == 9999) { _anguloEntrada = Angulo; inverterGiro = true; } // Se estava atuado e agora nao esta mais, e ja definiu o angulo de entrada, e ainda nao definiu o angulo de saida else if (!_ref && _anguloEntrada != 9999 && _anguloSaida == 9999) { _anguloSaida = Angulo; } } } // Comecou com o sensor nao atuado else { // Quando houver alteracao na leitura do sensor if (_ref != EstadoAnterior) { // Se nao estava atuado e agora esta, e ainda nao definiu o angulo de entrada if (_ref && _anguloEntrada == 9999) { _anguloEntrada = Angulo; } // Se estava atuado e agora nao esta mais, e ja definiu o angulo de entrada, e ainda nao definiu o angulo de saida else if (!_ref && _anguloEntrada != 9999 && _anguloSaida == 9999) { _anguloSaida = Angulo; inverterGiro = true; } } } // Realiza a verificacao de necessidade de reverter a rotacao do motor apenas se ainda nao encontrou o angulo de entrada do sensor if (_anguloEntrada == 9999) { inverterGiro = (_angulo > 0 && Angulo >= (_angulo - 0.5)) || (_angulo < 0 && Angulo <= (_angulo + 0.5)); } Sucesso = _anguloEntrada != 9999 && _anguloSaida != 9999; EstadoAnterior = _ref; Console.WriteLine($"Ref {Addr}: Angulo SP = {_angulo}, Velocidade: {VelocidadeGiro}, Angulo Atual = {Angulo}, Sentido SP = {_sentido.ToString()}, Passou = {inverterGiro}, Sucesso = {Sucesso}, Entrada: {_ref}"); if (Sucesso) { await MKS057DService.EnviarComandoControle(MKS057DService.MontarComandoParada(Addr)); await Task.Delay(1500); int _centro = Convert.ToInt32((_anguloEntrada + _anguloSaida) / 2.0); await MKS057DService.EnviarComandoControle(MKS057DService.MontarComandoMovimento(Addr, _centro, 36, Sentido.Horario)); await Task.Delay(2500); await MKS057DService.EnviarComandoControle(MKS057DService.MontarComandoSetZero(Addr)); await Task.Delay(1000); break; } await Task.Delay(200); // Verificações rápidas. VelocidadeGiro = DefineVelocidadeReferenciamento(EstadoInicial, anguloMaxVisitado, anguloMinVisitado); if ( (_anguloAnterior == Angulo && RPM == 0) || // Verifica se o angulo nao foi alterado desde a ultima leitura, e o motor nao esta em movimento (_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)); } _anguloAnterior = Angulo; _velocidadeAnterior = VelocidadeGiro; if (Angulo > anguloMaxVisitado) { anguloMaxVisitado = Angulo; } else if (Angulo < anguloMinVisitado) { anguloMinVisitado = Angulo; } } if (!Sucesso && inverterGiro) { await MKS057DService.EnviarComandoControle(MKS057DService.MontarComandoParada(Addr)); await Task.Delay(500); _sentido = _sentido == Sentido.Horario ? Sentido.Antihorario : Sentido.Horario; _offset = Math.Min(100, _offset + 25); // Limita o offset máximo para evitar valores extremos. int mx = _sentido == Sentido.Antihorario ? -1 : 1; _angulo = (Math.Abs(_angulo) + _offset) * mx; tentativas++; } } } if (!Sucesso) { await MKS057DService.EnviarComandoControle(MKS057DService.MontarComandoParada(Addr)); } MKS057DService.AddrRef = 0x00; MKS057DService.UltimoReferenciamento = DateTime.Now; } private int DefineVelocidadeReferenciamento(bool EstadoInicial, double anguloMaxVisitado, double anguloMinVisitado) { int VelocidadeGiro = EstadoInicial || IN1_Atuado ? 10 : // Se o sensor estiver atuado ou o fluxo tiver iniciado com ele ja atuado, entao deve se mover lentamente para melhor precisao dos angulos de entrada e saida Angulo > (anguloMaxVisitado + 5) || Angulo < (anguloMinVisitado - 5) ? 18 : // Se o angulo atual ainda nao foi visitado, deve se mover em velocidade media 20; // Se o angulo ja foi visitado, deve se mover em uma velocidade maior return VelocidadeGiro; } } public class MvdMotorMOVSensorimanetoGrafico { public DateTime Momento { get; set; } public string Modulo_ID { get; set; } public int RPM_SP { get; set; } public double RPM_Motor { get; set; } public double RPM_Roda { get; set; } public double Temperatura { get; set; } public double TemperaturaDriver { get; set; } public Sentido Sentido { get; set; } public double Velocidade { get; set; } public double Tensao { get; set; } public double Corrente { get; set; } } public class MvdServoFreioModel { public bool Incremental { get; set; } public int AnguloInicial { get; set; } private int AnguloControle { get; set; } = -1; private int AnguloControleMin { get { if (Incremental) { return AnguloMin; } else { return AnguloMax; } } } private int AnguloControleMax { get; set; } = 20; public bool Leitura { get; set; } private bool _controle { get; set; } public bool Controle { get { return _controle; } } private int RPM_SP { get; set; } private int MargemRPM { get; set; } = 2; // Margem de tolerância no RPM private int AnguloMin { get; set; } = 0; // Ângulo mínimo permitido pelo servo private int AnguloMax { get; set; } = 180; // Ângulo máximo permitido pelo servo private int FatorEscala { get; set; } = 10; // Fator de ajuste do controle proporcional public (bool, int) AtualizarDadosFreio(bool status, int rpm_sp = 0, int anguloInicial = -1, int anguloSP = -1) { bool mudou = _controle != status; _controle = status; RPM_SP = rpm_sp; if (!_controle) { AnguloControle = AnguloControleMin; // Solta o freio se não estiver no modo de controle return (mudou, AnguloControle); } if (anguloInicial == -1) { anguloInicial = AnguloInicial; } if (AnguloControle == -1) { AnguloControle = AnguloControleMin; } if (AnguloControle == AnguloControleMin) { AnguloControle = anguloInicial; } int ajuste = anguloSP; if (anguloSP == -1) { double Rpm_Atual = FuncoesMatematicas.CalculaRPMVelocidade(Variaveis.OperacaoEmAndamento.Sensoriamento.VelocidadeMedia); // Garante que os valores de RPM sejam válidos Rpm_Atual = Math.Max(Rpm_Atual, 0); RPM_SP = Math.Max(RPM_SP, 0); // Verifica se o RPM atual está dentro da margem de tolerância if (Math.Abs(Rpm_Atual - RPM_SP) <= MargemRPM) { return (false, AnguloControle); // Se dentro da margem, não ajusta o ângulo } // Calcula o erro e ajusta proporcionalmente int erroRPM = RPM_SP - (int)Rpm_Atual; ajuste = erroRPM / FatorEscala; // Se incremental, aplica um ajuste limitado if (Incremental) { ajuste = Math.Abs(ajuste); // Garante que o ajuste seja positivo } else { ajuste = -Math.Abs(ajuste); // Garante que o ajuste seja negativo } } // Atualiza o ângulo de controle, garantindo que fique dentro dos limites int limiteMax = AnguloInicial + (Incremental ? AnguloControleMax : -AnguloControleMax); if (Incremental) { AnguloControle = (int)FuncoesMatematicas.Clamp(AnguloControle + ajuste, AnguloMin, limiteMax); } else { AnguloControle = (int)FuncoesMatematicas.Clamp(AnguloControle - ajuste, limiteMax, AnguloMax); } return (true, AnguloControle); } } }