Ajustes no MPC e finalizacao de abertura da curva

This commit is contained in:
Diego Freitas 2026-02-27 17:00:45 -03:00
parent f4e1a2fe2e
commit 4425e03168
16 changed files with 161 additions and 1984 deletions

View File

@ -132,10 +132,15 @@ namespace AgroBase.Forms
if (_Trajetoria == null)
{
Variaveis.OperacaoEmAndamento.Mapa.AtualizarRuasSelecionadas();
AtualizandoTela = false;
return;
}
if (_Sensoriamento.Trajetoria == null) return;
if (_Sensoriamento.Trajetoria == null)
{
AtualizandoTela = false;
return;
}
lblStatus.Text = $"Carro: {_Sensoriamento.Trajetoria.StatusCarro} ({_Sensoriamento.OperadorVisual.Analises.segmentacao.status_corredor})";
lblDirecao.Text = $"Direção: {_Sensoriamento.Trajetoria.DirecaoCaminho}";

View File

@ -156,7 +156,7 @@ namespace AgroBase.Models
//public List<OperacaoModulosMandatoriosModel> ModulosMandatorios { get; set; } = new List<OperacaoModulosMandatoriosModel>();
//public List<OperacaoParametrosMandatoriosModel> ParametrosMandatorios { get; set; } = new List<OperacaoParametrosMandatoriosModel>();
public int TempoIniciarOperacao { get; set; } = 30;
public int TempoIniciarOperacao { get; set; } = 10;
public string ID { get; set; }
public double tmrLogsInterval
{
@ -1517,7 +1517,7 @@ namespace AgroBase.Models
Variaveis.OperacaoEmAndamento.DefinirComponentesEmUso();
}
HealthWorkerService.AtualizarDadosOperacao();
HealthWorkerService.AtualizarDadosOperacao(true);
break;
case BotoesJoystick.L1: // Inicia o modo simulador
if (!Variaveis.OperacaoEmAndamento.Iniciado)
@ -1896,8 +1896,9 @@ namespace AgroBase.Models
}
string nome = Variaveis.OperacaoEmAndamento.idxLog.ToString();
Camera.SaveFrames(new List<TipoFrameCamera>() { TipoFrameCamera.Rgb, TipoFrameCamera.Segmentacao }, nome, Caminho); // TipoFrameCamera.Raw4
var frames_salvar = new List<TipoFrameCamera>() { TipoFrameCamera.Rgb, TipoFrameCamera.Segmentacao };
if (Variaveis.OperacaoEmAndamento.Parametros.Controle.RegistrarDadosPosProcessamento) frames_salvar.Add(TipoFrameCamera.Raw4);
Camera.SaveFrames(frames_salvar, nome, Caminho);
var cameras_conectadas = JsonConvert.DeserializeObject<Dictionary<string, object>>(RedisService.Get(CtxKey.DadosCameras));
bool conectada = cameras_conectadas.ContainsKey(Camera?.Id ?? "");
@ -1920,8 +1921,9 @@ namespace AgroBase.Models
}
string nome = Variaveis.OperacaoEmAndamento.idxLog.ToString();
Camera.SaveFrames(new List<TipoFrameCamera>() { TipoFrameCamera.Rgb, TipoFrameCamera.Segmentacao }, nome, Caminho); // CameraFrameType.Heatmap, CameraFrameType.RadarTopDown
var frames_salvar = new List<TipoFrameCamera>() { TipoFrameCamera.Rgb, TipoFrameCamera.Segmentacao };
if (Variaveis.OperacaoEmAndamento.Parametros.Controle.RegistrarDadosPosProcessamento) frames_salvar.Add(TipoFrameCamera.Heatmap);
Camera.SaveFrames(frames_salvar, nome, Caminho);
var cameras_conectadas = JsonConvert.DeserializeObject<Dictionary<string, object>>(RedisService.Get(CtxKey.DadosCameras));
bool conectada = cameras_conectadas.ContainsKey(Camera?.Id ?? "");

View File

@ -39,6 +39,8 @@ namespace AgroBase.Models.Operacoes
public bool ImuParadaPorInclinacao { get; set; }
public bool FrenagemAutomaticaAoParar { get; set; }
public bool RegistrarDadosPosProcessamento { get; set; } = false;
public int MovVelocidadeSErvasPercent { get; set; }
public int MovRpmMax
{
@ -64,6 +66,10 @@ namespace AgroBase.Models.Operacoes
public double AtuAlturaAreaPulverizacao { get; set; }
public double AtuPercentualErvasBicoOn { get; set; }
public double AtuPercentualErvasBicoOff { get; set; }
public bool MpcMatrizCusto { get; set; } = true;
public double MpcHorizonteMin { get; set; } = 1.0;
public double MpcHorizonteMax { get; set; } = 2.0;
}
public class OperacaoParametrosDadosModel

View File

@ -21,6 +21,7 @@ namespace AgroBase.Models
#region PARAMETROS
public double AnguloAberturaCurva { get; set; } = 45; // Angulo usado para deslocar o ponto de curva
public double DistanciaProjecaoRua { get; set; } = 1.5; // Distancia para projetar o primeiro ponto para fora do corredor
public static double DistanciaEntrePontos { get; set; } = 0.8; // Distancia entre os pontos dentro do corredor
public static double DistanciaEntrePontosCurva { get; set; } = 0.25; // Distancia entre os pontos durante a curva entre corredores
@ -430,11 +431,12 @@ namespace AgroBase.Models
{
if ((RetornandoBase && CorredorAtual.Dentro) || (!RetornandoBase && Variaveis.OperacaoEmAndamento.StatusAtual == StatusOperacao.EmAndamento))
{
PontoAtual.AtualizarPropriedades();
if (!CorredorAtual.Dentro && ProximoPonto.DistanciaAtual > DistanciaManobraEntreRuas)
{
StatusAtual = StatusCarroMapa.Direcionando;
}
else if (!CorredorAtual.Dentro && (PontoAtual.PontoBorda || PontoAtual.PontoLigacao || ProximoPonto.Tipo == TipoPontoRua.LigacaoEntrada || PontoAtual.Tipo == TipoPontoRua.CruvaEntreCorredores))
else if (!CorredorAtual.Dentro && (PontoAtual.PontoBorda || PontoAtual.PontoLigacao || PontoAtual.Tipo == TipoPontoRua.CruvaEntreCorredores || PontoAtual.Tipo == TipoPontoRua.Desvio || ProximoPonto.Tipo == TipoPontoRua.LigacaoEntrada))
{
StatusAtual = StatusCarroMapa.Manobrando;
}
@ -772,8 +774,9 @@ namespace AgroBase.Models
private void VerificaFimCorredorSegmentacao()
{
if (CorredorAtual == null) return;
if (CorredorAtual.DadosVisuais.JaAntecipado) return;
bool modoSimulador = true && Variaveis.OperacaoEmAndamento.Simulando;
bool modoSimulador = false && Variaveis.OperacaoEmAndamento.Simulando;
// Limiar de "margem" para considerar proximidade do fim
double limiarDistanciaMargem = DistanciaErroMapaPlantacao > -1 ? DistanciaErroMapaPlantacao : 5.0;
@ -880,11 +883,11 @@ namespace AgroBase.Models
bool podeUsarSegmentacao = modoSimulador || (dadoFresco && dv.CorredorConfirmado);
bool fimAntecipado = podeUsarSegmentacao && pertoDoFim && foraDoCorredorAgora && foraContinuoSuficiente;
CorredorAtual.DadosVisuais.JaAntecipado = podeUsarSegmentacao && pertoDoFim && foraDoCorredorAgora && foraContinuoSuficiente;
Console.WriteLine($"podeUsarSegmentacao: {podeUsarSegmentacao}, pertoDoFim: {pertoDoFim}, foraDoCorredorAgora: {foraDoCorredorAgora}, foraContinuoSuficiente: {foraContinuoSuficiente}");
if (fimAntecipado)
if (CorredorAtual.DadosVisuais.JaAntecipado)
{
List<PontoTrajetoriaModel> pontosRemover = CorredorAtual.Pontos.Where(x => !x.Visitado).ToList();
pontosRemover.ForEach(x => x.Visitado = true);
@ -897,9 +900,9 @@ namespace AgroBase.Models
_TrajetoriaFixa.Remove(ponto);
}
var pls = CorredorAtual.Pontos[CorredorAtual.Pontos.Count - 1];
if (CorredorAtual.Pontos.Count >= 2)
{
var pls = CorredorAtual.Pontos[CorredorAtual.Pontos.Count - 1];
var pbs = CorredorAtual.Pontos[CorredorAtual.Pontos.Count - 2];
pls.AlterarTipo(TipoPontoRua.LigacaoSaida);
pbs.AlterarTipo(TipoPontoRua.BordaSaida);
@ -907,17 +910,29 @@ namespace AgroBase.Models
_TrajetoriaFixa.FirstOrDefault(x => ReferenceEquals(x, pbs))?.AlterarTipo(pbs.Tipo);
}
double anguloControle = CorredorAtual.idxRuaDireita > CorredorAtual.idxRuaEsquerda ? -Variaveis.OperacaoEmAndamento.Parametros.Controle.DirAnguloMaximo : Variaveis.OperacaoEmAndamento.Parametros.Controle.DirAnguloMaximo;
double anguloDesvio = PontoAtual.Orientacao + anguloControle;
var pontoDesvio = GPSUtils.GerarPontoDeslocado(PontoAtual.Posicao, anguloDesvio, 1.5);
IncluirDesvioNaTrajetoria(new List<GPSModel>() { pontoDesvio }, PontoAtual.idxPonto);
// Garante que os primeiros pontos do corredor atual estão como visitados
// acha o ponto mais próximo do corredor seguinte
var pc = _Corredores[CorredorAtual.Idx + 1];
// acha o ponto mais próximo
(GPSModel pp, double distanciaAtual) = GPSUtils.CalcularPontoMaisProximoTrajetoria(Variaveis.OperacaoEmAndamento.Sensoriamento.Gps, pc.Pontos.Select(x => x.Posicao).ToList());
var _pp = pc.Pontos.FirstOrDefault(x => Math.Abs(x.Posicao.Latitude - pp.Latitude) < 1e-8 && Math.Abs(x.Posicao.Longitude - pp.Longitude) < 1e-8);
double anguloControle = CorredorAtual.idxRuaDireita > CorredorAtual.idxRuaEsquerda ? -AnguloAberturaCurva : AnguloAberturaCurva;
double anguloDesvio = PontoAtual.Orientacao + anguloControle;
double fd = FuncoesMatematicas.Map(Variaveis.OperacaoEmAndamento.Sensoriamento.Controle.PercentualVelocidadeSP, 10, 100, 0.7, 2.5);
var pontoDesvio = GPSUtils.GerarPontoDeslocado(pls.Posicao, anguloDesvio, DistanciaProjecaoRua * fd);
double _FatorLarguraCorredor = CorredorAtual.Largura / LarguraCorredorPadrao;
var proximoPontoProximoCorredor = pc.Pontos[_pp.idxPontoCorredor].Posicao;
List<GPSModel> CurvaConexao = CriarCurvaEntrePontos(pontoDesvio, proximoPontoProximoCorredor, DistanciaProjecaoRua * 1.5, pls.Orientacao, 6, false);
CurvaConexao.Insert(0, pontoDesvio);
IncluirDesvioNaTrajetoria(CurvaConexao, pls.idxPonto, pls.LarguraCorredor * 0.8);
// Garante que os primeiros pontos do corredor atual estão como visitados
if (_pp != null)
{
int idxProx = _pp.idxPontoCorredor;
@ -946,8 +961,8 @@ namespace AgroBase.Models
ReindexarTrajetoriaFixa();
RedisService.AtualizarCampos(CtxKey.DadosOperacao, ("configurado", false));
Variaveis.OperacaoEmAndamento.Sensoriamento.AtualizarDados();
HealthWorkerService.AtualizarDadosOperacao(true);
}
}
}
@ -1350,7 +1365,7 @@ namespace AgroBase.Models
int idxEsq = 0;
int idxDir = 0;
double anguloAcrescentar = direcaoAtual == DirecaoCarroRua.Ida ? 45 : -45;
double anguloAcrescentar = direcaoAtual == DirecaoCarroRua.Ida ? AnguloAberturaCurva : -AnguloAberturaCurva;
for (int idx = 0; idx < Corredores.Count(); idx++)
{
@ -1416,13 +1431,10 @@ namespace AgroBase.Models
if (distanciaMinima && false)
{
int pontosAdicionr = Convert.ToInt32(CorredoresLarguras[idx] / (DistanciaEntrePontosCurva * _FatorLarguraCorredor));
var _penultimoPonto = _trajetoriaFixa[_trajetoriaFixa.Count() - 2].Posicao;
double anguloProjecao = GPSUtils.CalcularOrientacao(Corredores[idx - 1].First(), Corredores[idx - 1].Last());
GPSModel _ultimoPonto = GPSUtils.ProjetarPontoDeslocado(Corredores[idx - 1].Last(), DistanciaProjecaoRua, anguloProjecao);
GPSModel P0 = CalcularPontoControle(_penultimoPonto, _ultimoPonto, PrimeiroPonto, DistanciaProjecaoRua * 2.0);
List<GPSModel> CurvaConexao = GerarCurvaConexao(ultimoPontoTrajetoria.Posicao, PrimeiroPonto, P0, pontosAdicionr);
List<GPSModel> CurvaConexao = CriarCurvaEntrePontos(ultimoPontoTrajetoria.Posicao, PrimeiroPonto, DistanciaProjecaoRua * 2.0, anguloProjecao, pontosAdicionr, false);
for (int i = 0; i < CurvaConexao.Count; i++)
{
@ -1556,6 +1568,15 @@ namespace AgroBase.Models
RedisService.AtualizarCampos(CtxKey.DadosOperacao, ("configurado", false));
}
private List<GPSModel> CriarCurvaEntrePontos(GPSModel _p1, GPSModel _p2, double distanciaCurva, double anguloCurva, int qtdPontos, bool manterPontos)
{
GPSModel P0 = CalcularPontoControle(anguloCurva, _p1, _p2, distanciaCurva);
List<GPSModel> curva = GerarCurvaConexao(_p1, _p2, P0, qtdPontos);
if (manterPontos) curva.Insert(0, _p1);
else curva.RemoveAt(curva.Count - 1);
return curva;
}
private (int, int) AtualizaIndiceRuaLateralCorredor(int i, int idxDir, int incDir, int incEsq)
{
bool par = (i % 2 == 0);
@ -1575,9 +1596,8 @@ namespace AgroBase.Models
return (incDir, incEsq);
}
public static GPSModel CalcularPontoControle(GPSModel penultimoPontoRuaAtual, GPSModel ultimoPontoRuaAtual, GPSModel primeiroPontoProximaRua, double distancia)
public static GPSModel CalcularPontoControle(double anguloCurva, GPSModel ultimoPontoRuaAtual, GPSModel primeiroPontoProximaRua, double distancia)
{
double anguloCurva = GPSUtils.CalcularOrientacao(penultimoPontoRuaAtual, ultimoPontoRuaAtual);
double angulo = GPSUtils.CalcularOrientacao(ultimoPontoRuaAtual, primeiroPontoProximaRua);
// Calcular a diferença de ângulo corretamente no espaço de 360 graus
@ -2306,7 +2326,7 @@ namespace AgroBase.Models
private void IncluirDesvioNaTrajetoria(List<GPSModel> pontos, int idxPontoApartir)
private void IncluirDesvioNaTrajetoria(List<GPSModel> pontos, int idxPontoApartir, double larguraCorredor)
{
if (pontos == null || pontos.Count == 0)
return;
@ -2331,7 +2351,7 @@ namespace AgroBase.Models
idxCorredor = pa.idxCorredor,
Posicao = pontoGps,
Direcao = pa.Direcao,
LarguraCorredor = pa.LarguraCorredor,
LarguraCorredor = larguraCorredor,
Orientacao = GPSUtils.CalcularOrientacao(pontoGps, pa.Posicao),
Visitado = false
};
@ -2472,6 +2492,7 @@ namespace AgroBase.Models
public class DadosVisuaisCorredor
{
public bool JaAntecipado { get; set; } = false;
// Quanto já andou DENTRO do corredor (EntrandoRua, CaminhandoRua, SaindoRua)
public double TempoDentroRuaTotal { get; set; } = 0;
public double DistanciaDentroRuaTotal { get; set; } = 0;
@ -2539,6 +2560,8 @@ namespace AgroBase.Models
public void AlterarTipo(Enums.TipoPontoRua novo)
{
Tipo = novo;
PontoBorda = Tipo == Enums.TipoPontoRua.BordaEntrada || Tipo == Enums.TipoPontoRua.BordaSaida;
PontoLigacao = Tipo == Enums.TipoPontoRua.LigacaoEntrada || Tipo == Enums.TipoPontoRua.LigacaoSaida;
}
public void AtualizarPropriedades()

View File

@ -195,10 +195,13 @@ namespace AgroBase.Services.Operadores
);
}
public static void AtualizarDadosOperacao()
public static void AtualizarDadosOperacao(bool forcar = false)
{
if (AtualizandoRedis)
if (AtualizandoRedis && !forcar)
return;
while (AtualizandoRedis && forcar) {}
AtualizandoRedis = true;
AtualizarDadosEquipamento();
@ -221,6 +224,7 @@ namespace AgroBase.Services.Operadores
("modulos_mandatorios", _Parametros.ModulosMandatorios.Where(x => x.Mandatorio && x.Utilizar).Select(x => (int)x.Dispositivo).ToArray()),
("modulos_opcionais", _Parametros.ModulosMandatorios.Where(x => !x.Mandatorio && x.Utilizar).Select(x => (int)x.Dispositivo).ToArray()),
("parametros_mandatorios", _Parametros.ParametrosMandatorios.Where(x => x.Mandatorio && x.Utilizar).Select(x => (int)x.Parametro).ToArray()),
("ponto_mapa_ref", Variaveis.OperacaoEmAndamento.Trajetoria?._TrajetoriaFixa?.Select(p => new double[] { p.Posicao.Latitude, p.Posicao.Longitude }).FirstOrDefault()),
("Mov", new
{
percent_vel_max = pControle.MovVelocidadeSErvasPercent,
@ -243,15 +247,14 @@ namespace AgroBase.Services.Operadores
distanciaMargem = p.LarguraCorredor * 0.8
})
.ToList(),
horizonte = 2.0,
horizonte_min = 1.2,
horizonte_max = 2.8,
horizonte_parado = 1.2,
horizonte_min = pControle.MpcHorizonteMin,
horizonte_max = pControle.MpcHorizonteMax,
angulo_max_graus = pControle.DirAnguloMaximo,
velocidade_min = FuncoesMatematicas.CalculaVelocidadeMsPercentual(pControle.MovVelocidadeCErvasPercent),
velocidade_max = FuncoesMatematicas.CalculaVelocidadeMsPercentual(pControle.MovVelocidadeSErvasPercent),
velocidade_min = Math.Round(FuncoesMatematicas.CalculaVelocidadeMsPercentual(pControle.MovVelocidadeCErvasPercent), 4),
velocidade_max = Math.Round(FuncoesMatematicas.CalculaVelocidadeMsPercentual(pControle.MovVelocidadeSErvasPercent), 4),
tempo_entre_comandos = (Variaveis.OperacaoEmAndamento.Controle.TiposControle.FirstOrDefault(x => x.Tipo == Enums.T_Code.Dir)?.DelayEnvioComando ?? 500) / 1000.0,
passos_atraso = 1
passos_atraso = 1,
usa_matriz_custo = pControle.MpcMatrizCusto
}
}
),
@ -285,6 +288,8 @@ namespace AgroBase.Services.Operadores
RedisService.Publish(CmdKey.HealthWorkerRx, JsonConvert.SerializeObject(comando));
}
//Console.WriteLine("Dados de operacao atualizados com sucesso!");
AtualizandoRedis = false;
}
@ -298,7 +303,9 @@ namespace AgroBase.Services.Operadores
("direcional_automatico", pControle.DirecionalAutomatico),
("frenagem_automatica", pControle.FrenagemAutomaticaAoParar),
("oak_parada_por_bloqueio", pControle.OakParadaPorObstaculo),
("imu_parada_por_inclinacao", pControle.ImuParadaPorInclinacao)
("imu_parada_por_inclinacao", pControle.ImuParadaPorInclinacao),
("registrar_dados_pos_processamento", pControle.RegistrarDadosPosProcessamento)
);
}

View File

@ -132,7 +132,7 @@ namespace AgroBase.Services.Operadores
TempoDesconectado = 0;
if (!Variaveis.OperacaoEmAndamento.OperacaoConfigurada)
{
HealthWorkerService.AtualizarDadosOperacao();
HealthWorkerService.AtualizarDadosOperacao(true);
}
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -83,7 +83,10 @@ def main():
acao = HealthWorkerCommandType(dados.get("cmd", 0))
if acao == HealthWorkerCommandType.AtualizarPontosMapa:
ContextoGlobalRedis._atualizar_pontos_mapa()
try:
ContextoGlobalRedis._atualizar_pontos_mapa()
except Exception as e:
mostrar_log(f"Erro ao atualizar pontos do mapa: {e}")
mostrar_log("Dados de mapa da Operacao atualizados com sucesso!")
def inicializar():

View File

@ -10,7 +10,6 @@ def main():
from manager_worker.gerenciador import ManagerWorker
from manager_worker.config import mostrar_log
from shared.enums import ManagerWorkerCommandType
from manager_worker.modulos.mpc import inicializar as iniciar_mpc
from shared.contexto_global_redis import ContextoGlobalRedis, CmdKey, CtxKey
from shared.mensagem_worker import WorkerFilaMensagens
@ -58,12 +57,19 @@ def main():
acao = ManagerWorkerCommandType(dados.get("cmd", 0))
if acao == ManagerWorkerCommandType.IniciarMPC:
parametros = dados.get("params", {}).get("parametros")
mapa = dados.get("params", {}).get("mapa")
iniciar_operacao = dados.get("params", {}).get("iniciar_operacao", False)
if parametros is not None:
p_ref = ContextoGlobalRedis.get_operacao().get("ponto_mapa_ref", [])
iniciar_mpc(parametros, mapa, p_ref, iniciar_operacao)
try:
_p = dados.get("params")
if _p is not None:
parametros = _p.get("parametros")
mapa = _p.get("mapa")
iniciar_operacao = _p.get("iniciar_operacao", False)
p_ref = _p.get("p_ref", [])
from manager_worker.modulos.mpc import inicializar as iniciar_mpc
iniciar_mpc(parametros, mapa, p_ref, iniciar_operacao)
else:
ContextoGlobalRedis()._atualizar_mpc(do_manager=True, iniciar_operacao=False)
except Exception as e:
mostrar_log(f"Erro ao Iniciar MPC: {e}")
elif acao == ManagerWorkerCommandType.AtualizarDadosControle:
#mostrar_log("Adicionado na fila")
fila.adicionar(acao)

View File

@ -19,6 +19,7 @@ def definir_comando(pid: PIDAdaptativo, envio_necessario: bool):
_snr = ContextoGlobalRedis.get_modulo(T_Code.Snr)
visual_worker_ativado = _controle.get("sonar_ativado", False)
usa_matriz_custo = _controle.get("usa_matriz_custo", False)
visual_worker_operante = (_snr.get("saude", {}).get("status", StatusModulo.DESCONECTADO.value)) == StatusModulo.OPERANTE.value
_dados_vw = ContextoGlobalRedis.get(CtxKey.DadosVisualWorker, {})
_snapshot_vw = _dados_vw.get("matriz_confianca")
@ -56,10 +57,6 @@ def definir_comando(pid: PIDAdaptativo, envio_necessario: bool):
Vmin = 0.1 # if _trajetoria.get("status", StatusCarroMapa.Parado.value) == StatusCarroMapa.CaminhandoRua.value else 0.8
contexto = {
"Operacao": {
"Status": _operacao.get("status"),
"Finalizando": _operacao.get("finalizando")
},
"GPS": {
"Latitude": _gps.get("lat", 0),
"Longitude": _gps.get("lon", 0),
@ -88,6 +85,7 @@ def definir_comando(pid: PIDAdaptativo, envio_necessario: bool):
"Operante": visual_worker_operante,
"Atualizado": visual_worker_atualizado,
"MatrizCusto": {
"EmUso": usa_matriz_custo,
"Valida": visual_worker_ativado and visual_worker_operante and visual_worker_atualizado,
"Custo": custo,
"Navegavel": nav,
@ -95,21 +93,10 @@ def definir_comando(pid: PIDAdaptativo, envio_necessario: bool):
"EscalasX": escalas,
"Block": block
},
"Camera": {
"FovH": ContextoGlobalRedis.get(CtxKey.DadosVisualWorker, {}).get("parametros", {}).get("fov_h", 0.7),
"DistanciaMax": _operacao.get("Snr", {}).get("distancia_maxima", 5000) / 1000.0,
"DistanciaMin": _operacao.get("Snr", {}).get("distancia_minima", 500) / 1000.0,
}
},
"RegrasAtivas": {
"matriz_custo": False,
"deteccao_obstaculos": False,
},
"Equipamento": {
"largura": _equipamento.get("largura", 0.85),
"entre_eixos": _equipamento.get("distancia_entre_eixos", 0.92),
"angulo_roll_max": _equipamento.get("angulo_roll_max", 15.0),
"angulo_pitch_max": _equipamento.get("angulo_pitch_max", 30.0),
"entre_eixos": _equipamento.get("distancia_entre_eixos", 0.92)
}
}

View File

@ -37,13 +37,11 @@ class ControladorMPC:
self.dt = 0
#print(parametros_mpc)
self.angulo_max_graus = parametros_mpc.get("angulo_max_graus", 30.0)
self.velocidade_min = parametros_mpc.get("velocidade_min", 0.4)
self.velocidade_max = parametros_mpc.get("velocidade_max", 1.9)
self.horizonte = parametros_mpc.get("horizonte", 2.5)
self.horizonte_min = parametros_mpc.get("horizonte_min", 0.6)
self.horizonte_max = parametros_mpc.get("horizonte_max", 2.8)
self.horizonte_parado = parametros_mpc.get("horizonte_parado", 0.5)
self.angulo_max_graus = parametros_mpc.get("angulo_max_graus")
self.velocidade_min = parametros_mpc.get("velocidade_min")
self.velocidade_max = parametros_mpc.get("velocidade_max")
self.horizonte_min = parametros_mpc.get("horizonte_min")
self.horizonte_max = parametros_mpc.get("horizonte_max")
self._beam_traj_min = parametros_mpc.get("beam_traj_min", 3) # nº mínimo de trajetórias completas que queremos
self._beam_topN_max = parametros_mpc.get("beam_topN_max", 5) # limite superior de candidatos ativos
self._beam_topN_min = parametros_mpc.get("beam_topN_min", 2) # limite inferior
@ -357,64 +355,6 @@ class ControladorMPC:
# UTILS
def _corrigir_pontos_visitados_new(self, x, y, pontos_visitados: np.ndarray, idx_atual: int = -1, limite_max_avanco: float = 5.0, limite_max_pontos: int = 10, velocidade: float = -1, dt: float = -1, look_ahead: bool = True):
try:
p_xy, p_mg, p_s = self._p_xy, self._p_margem, self._p_s
N = p_xy.shape[0]
if N == 0:
return -1
# --- (1) Igual ao antigo: marcar EXCLUSIVO quando idx_atual vier do C# ---
if idx_atual > -1:
pontos_visitados[:idx_atual+1] = True # <<< EXCLUSIVO (antes era :idx_atual+1)
return idx_atual
if pontos_visitados.all():
return N - 1
start_idx = int(np.argmax(~pontos_visitados))
# janela por metros + clamp por nº de pontos (compatível com o antigo)
s_start = p_s[start_idx]
s_lim = s_start + float(limite_max_avanco)
end_idx = int(np.searchsorted(p_s, s_lim, side="right") - 1)
if end_idx < start_idx:
end_idx = start_idx
end_idx = min(end_idx, start_idx + int(limite_max_pontos))
sl = slice(start_idx, end_idx + 1)
dx = x - p_xy[sl, 0]
dy = y - p_xy[sl, 1]
dist2 = dx*dx + dy*dy
margem2 = p_mg[sl] * p_mg[sl]
# --- (2) Opcional para fidelidade ao antigo: usar '<' em vez de '<=' ---
hits = dist2 < margem2 # era <=
if np.any(hits):
off = int(np.argmax(hits))
idx = start_idx + off
pontos_visitados[:idx] = True
if velocidade > -1 and look_ahead:
s_hit = self._p_s[idx]
s_goal = s_hit + self.d_look_ahead_m(velocidade, dt)
idx_alvo = int(np.searchsorted(self._p_s, s_goal, side="left"))
idx_alvo = min(idx_alvo, len(self._p_s)-1)
return idx_alvo
return idx
# --- (3) Fallback robusto para “próximo não visitado” ---
nv = np.flatnonzero(~pontos_visitados)
return int(nv[0]) if nv.size else (N - 1)
except Exception as e:
mostrar_log(f"Erro ao corrigir pontos visitados: {e}")
try:
nv = np.flatnonzero(~pontos_visitados)
return int(nv[0]) if nv.size else (N - 1)
except Exception:
return -1
def _proximo_nao_visitado(self, visitados):
try:
for i, v in enumerate(visitados):
@ -590,64 +530,6 @@ class ControladorMPC:
# theta = (theta + np.pi) % (2*np.pi) - np.pi
return x, y, theta, visitados
def d_look_ahead_m(self, velocidade, dt: float = None):
"""
Retorna look-ahead em METROS.
- velocidade: pode vir em m/s ou normalizada (0-1). Detecto automaticamente.
- dt: passo real do MPC (s) para suavização adaptativa (opcional).
"""
# --- 1) Normalização de velocidade ---------------------------------------
# tente usar self.vel_max_m_s se já existir; senão, usa 6.8 km/h (~1.889 m/s)
vel_max_ms = getattr(self, "vel_max_m_s", 6.8/3.6)
v = float(velocidade)
#if v <= 1.05: # heurística: trata <=1.0 como v_norm
# v = max(0.0, min(1.0, v)) * vel_max_ms
#else:
# v = max(0.0, v) # já está em m/s
v = max(0.0, v) # já está em m/s
# --- 2) Base polinomial (suave e previsível) ------------------------------
# L_base = L0 + a*v + b*v^2 (clamp em [Lmin, Lmax])
Lmin, Lmax = self.horizonte_min, self.horizonte_max # bom para teu range (1.36.8 km/h)
L0, a, b = self.horizonte_parado, 0.70, 0.20
L = L0 + a*v + b*(v*v)
if L < Lmin: L = Lmin
if L > Lmax: L = Lmax
# --- 3) Redução por curvatura e erro de orientação ------------------------
# Se você já calcula curvatura/erro, exponha em self; senão, assumo 0.
kappa = abs(getattr(self, "curvatura_atual", 0.0)) # 1/m
err_yaw = abs(getattr(self, "erro_angular_atual", 0.0)) # rad
# Fatores <=1.0: reduzem o L em curva forte e/ou erro de yaw grande.
# Ajuste c_k, c_e conforme seu corredor (mais alto = reduz mais).
c_k, c_e = 3.0, 1.2
f_k = 1.0 / (1.0 + c_k * kappa)
f_e = 1.0 / (1.0 + c_e * err_yaw)
L *= min(f_k, f_e)
# --- 4) Compensação de latência de controle/planta ------------------------
# Se você tem latência medida, exponha em self.tau_ctrl (s). Senão: ~0.15 s.
tau = float(getattr(self, "tau_ctrl", 0.15))
L += v * tau # “empurra” o alvo à frente para cobrir atraso
# Clamp final para garantir limites mesmo após fatores
if L < Lmin: L = Lmin
if L > Lmax: L = Lmax
# --- 5) Suavização temporal (anti-chatter) --------------------------------
# EMA com constante de tempo ~0.4 s (ajuste T_ema). Usa dt se informado.
T_ema = 0.40
if dt is None:
dt = float(getattr(self, "dt", 0.15)) # teu MPC já guarda dt
alpha = max(0.0, min(1.0, 1.0 - pow(2.718281828, -dt / T_ema)))
L_suave = getattr(self, "_L_ema", L)
L_suave = (1.0 - alpha) * L_suave + alpha * L
self._L_ema = L_suave
return L_suave
def _wrap_pi(self, a):
try:
@ -792,6 +674,7 @@ class ControladorMPC:
self.tempo_execucao_local = contexto.get("Carro", {}).get("TempoEntreComandos", 0.5)
self.passos_horizonte_local = max(1, math.floor(1 / self.tempo_execucao_local))
self.passos_horizonte_local = 1
# -------------------- Correção por latência (vida real) --------------------
# Mantém correção com 'self.dt' e 'velocidade' REAIS
@ -819,8 +702,8 @@ class ControladorMPC:
idx_alvo_correcao = self._corrigir_pontos_visitados(x, y, self.visitados_execucao, idx_proximo_ponto_real)
# -------------------- Planejamento: horizonte ESPACIAL fixo --------------------
S_ALVO = float(getattr(self, "horizonte", 2.5))
V_FLOOR = float(getattr(self, "_vmin_planejamento", 0.40))
S_ALVO = self.horizonte_max
V_FLOOR = float(getattr(self, "_vmin_planejamento", 0.30))
DT_MIN = float(getattr(self, "_dt_pred_min", 0.05))
DT_MAX = float(getattr(self, "_dt_pred_max", 0.25))
K_ALVO = int(getattr(self, "_k_alvo", 16))
@ -864,6 +747,8 @@ class ControladorMPC:
self.qtd_comandos_sucessivos = K
#print(f"S_ALVO: {S_ALVO}, v_sim: {v_sim}, passos_local: {self.passos_horizonte_local}, K: {K}, dt_pred: {dt_pred}")
# -------------------- Seleção do comando --------------------
angulo_anterior = np.radians(comando_anterior.get("angulo", 0.0))
tipo_anterior = TipoMovimentoDirecional(comando_anterior.get("tipo", TipoMovimentoDirecional.RodasDianteiras.value))
@ -1079,7 +964,7 @@ class ControladorMPC:
# -------------------- Debug opcional da matriz de custo --------------------
self._tick_id = getattr(self, "_tick_id", 0) + 1
if (getattr(self, "debug_cost_vis", False) and contexto.get("RegrasAtivas", {}).get("matriz_custo", False) and (self._tick_id % 10 == 0)):
if (getattr(self, "debug_cost_vis", False) and contexto.get("VisualWorker", {}).get("MatrizCusto", {}).get("EmUso", False) and (self._tick_id % 10 == 0)):
dados_matriz_custo = contexto.get("VisualWorker", {}).get("MatrizCusto", {})
deadline_dbg = time.perf_counter() + 0.03
tipos_dbg, angs_dbg, _ = self._gerar_angulos_candidatos_receding(
@ -1184,9 +1069,9 @@ class ControladorMPC:
# 3) Flags de matriz
dados_matriz_custo = contexto.get("VisualWorker", {}).get("MatrizCusto", {})
regra_matriz_custo = bool(dados_matriz_custo.get("EmUso", False))
matriz_custo_valida = bool(dados_matriz_custo.get("Valida", False))
regra_matriz_custo = bool(contexto.get("RegrasAtivas", {}).get("matriz_custo", False))
filtrar_matriz = matriz_custo_valida and regra_matriz_custo
filtrar_matriz = regra_matriz_custo and matriz_custo_valida
# 4) Geração bruta (graus)
angulos_raw = self._gerar_candidatos_brutos(angulo_ideal_deg, filtrar_matriz)

View File

@ -132,7 +132,7 @@ class ContextoGlobalRedis:
dados = json.loads(mensagem["data"])
funcao_callback(dados)
except Exception as e:
mostrar_log(f"Erro ao processar comando recebido: {e}")
mostrar_log(f"Erro ao processar comando recebido: {mensagem['data']} | {e}")
# Roda o ouvinte em uma thread separada (não bloqueia)
threading.Thread(target=_ouvinte, daemon=True).start()
@ -553,24 +553,23 @@ class ContextoGlobalRedis:
if (dados_dir.get("tipo_controle", TiposControladorDirecional.Manual.value) == TiposControladorDirecional.MPC.value):
dados_mpc = dados_dir.get("mpc", {})
mapa = cls.get_operacao().get("pontos_mapa", [])
p_ref = cls.get_operacao().get("ponto_mapa_ref", [])
if do_manager:
p_ref = cls.get_operacao().get("ponto_mapa_ref", [])
from manager_worker.modulos.mpc import inicializar as iniciar_mpc
iniciar_mpc(dados_mpc, mapa, p_ref, iniciar_operacao)
else:
cls.publicar_comando(CmdKey.ManagerWorkerRx, { "cmd": ManagerWorkerCommandType.IniciarMPC.value, "params": { "parametros": dados_mpc, "mapa": mapa, "iniciar_operacao": iniciar_operacao } })
cls.publicar_comando(CmdKey.ManagerWorkerRx, { "cmd": ManagerWorkerCommandType.IniciarMPC.value, "params": { "parametros": dados_mpc, "mapa": mapa, "p_ref": p_ref, "iniciar_operacao": iniciar_operacao } })
@classmethod
def _atualizar_pontos_mapa(cls):
pontos_info = []
p_ref = (0, 0)
_operacao = cls.get_operacao()
dados_dir = _operacao.get("Dir", {})
if (dados_dir.get("tipo_controle", TiposControladorDirecional.Manual.value) == TiposControladorDirecional.MPC.value):
dados_mpc = dados_dir.get("mpc", {})
pontos = dados_mpc.get("pontos", [])
if pontos is not None and len(pontos) > 0:
p_ref = pontos[0]["lat"], pontos[0]["lon"]
p_ref = cls.get_operacao().get("ponto_mapa_ref")
from shared.gps_handler import GPSHandler
handler = GPSHandler(p_ref[0], p_ref[1])
for p in pontos:
@ -584,7 +583,6 @@ class ContextoGlobalRedis:
cls.atualizar_ctx_dict(
CtxKey.DadosOperacao,
pontos_mapa=pontos_info,
ponto_mapa_ref=p_ref
)
if len(pontos_info) > 0:

View File

@ -846,7 +846,7 @@ namespace OperationControl.Controls
{
foreach (var rua in RuasMapaCarregado)
{
var dado = Mapa.features.FirstOrDefault(x => x.properties.Id == rua.Id);
var dado = Mapa?.features?.FirstOrDefault(x => x.properties.Id == rua.Id);
if (dado == null) continue;
rua.Selected = RuasSelecionadas.Contains(dado.properties.Id);
}

View File

@ -0,0 +1,37 @@
import matplotlib.pyplot as plt
# Substitua pelas suas coordenadas (lat, lon)
coords = [
[-22.172709676583331,-47.395223974666663],
[-22.172716850972222,-47.395224935138884],
[-22.172725134386194,-47.39523641178512],
[-22.172728586980455,-47.395222881810845],[-22.172727347766877,-47.395217842486744],[-22.172724131546165,-47.395213953604689],[-22.172718938318319,-47.395211215164665],[-22.172711768083332,-47.395209627166665]
#[-22.172711768083332,-47.395209627166665]
]
# Separar latitude e longitude
lats = [c[0] for c in coords]
lons = [c[1] for c in coords]
plt.figure(figsize=(8, 6))
# Linha conectando os pontos
plt.plot(lons, lats, linestyle='-', marker='o')
# Primeiro ponto (verde)
plt.scatter(lons[0], lats[0], color='green', s=100, label='Primeiro')
# Último ponto (vermelho)
plt.scatter(lons[-1], lats[-1], color='red', s=100, label='Último')
# Numerar os pontos
for i, (lat, lon) in enumerate(coords):
plt.text(lon, lat, f' {i}', fontsize=10)
plt.xlabel("Longitude")
plt.ylabel("Latitude")
plt.title("Plot de Coordenadas")
plt.legend()
plt.grid(True)
plt.show()