ajustes no controle direcional pid

This commit is contained in:
Diego Freitas 2025-04-01 15:56:43 -03:00
parent ec7239b9ab
commit bd4b9717cd
31 changed files with 711 additions and 232 deletions

Binary file not shown.

View File

@ -461,6 +461,7 @@
<Compile Include="Models\Modules\SensoriamentoModel.cs" /> <Compile Include="Models\Modules\SensoriamentoModel.cs" />
<Compile Include="Models\MotorComum.cs" /> <Compile Include="Models\MotorComum.cs" />
<Compile Include="Models\MPCController.cs" /> <Compile Include="Models\MPCController.cs" />
<Compile Include="Models\MPCControllerAprimorado.cs" />
<Compile Include="Models\MPCControllerSimple.cs" /> <Compile Include="Models\MPCControllerSimple.cs" />
<Compile Include="Models\OAKCameraModel.cs" /> <Compile Include="Models\OAKCameraModel.cs" />
<Compile Include="Models\OIDModel.cs" /> <Compile Include="Models\OIDModel.cs" />

View File

@ -54,7 +54,7 @@ namespace AgroBase.Forms.IHM
); );
if (res == DialogResult.Yes) if (res == DialogResult.Yes)
{ {
Variaveis.OperacaoEmAndamento.FinalizarOperacao(); await Variaveis.OperacaoEmAndamento.FinalizarOperacao();
if (Variaveis.OperacaoEmAndamento.Modo == Enums.ModoOperacao.Manual) if (Variaveis.OperacaoEmAndamento.Modo == Enums.ModoOperacao.Manual)
{ {
this.Close(); this.Close();

View File

@ -84,12 +84,12 @@ namespace AgroBase.Forms.Operacoes
private void frmOperacaoManual_FormClosing(object sender, FormClosingEventArgs e) private void frmOperacaoManual_FormClosing(object sender, FormClosingEventArgs e)
{ {
tmrLeitura.Dispose(); tmrLeitura.Dispose();
Variaveis.OperacaoEmAndamento.FinalizarOperacao(); Task.Run(async () => await Variaveis.OperacaoEmAndamento.FinalizarOperacao());
Variaveis.OperacaoEmAndamento.DesligarCameras(); Variaveis.OperacaoEmAndamento.DesligarCameras();
KinectService.picRGB = null; KinectService.picRGB = null;
} }
private async void btnIniciarOperacao_Click(object sender, EventArgs e) private void btnIniciarOperacao_Click(object sender, EventArgs e)
{ {
if (btnIniciarOperacao.Text == "Finalizar Operação") if (btnIniciarOperacao.Text == "Finalizar Operação")
{ {
@ -101,7 +101,7 @@ namespace AgroBase.Forms.Operacoes
}); });
// Executa a finalização da operação // Executa a finalização da operação
Variaveis.OperacaoEmAndamento.FinalizarOperacao(); Task.Run(async () => await Variaveis.OperacaoEmAndamento.FinalizarOperacao());
// Atualiza a UI novamente na thread principal // Atualiza a UI novamente na thread principal
btnIniciarOperacao.Invoke((MethodInvoker)delegate btnIniciarOperacao.Invoke((MethodInvoker)delegate
@ -123,7 +123,7 @@ namespace AgroBase.Forms.Operacoes
if (Variaveis.OperacaoEmAndamento.OperacaoLiberada) if (Variaveis.OperacaoEmAndamento.OperacaoLiberada)
{ {
// Inicia a operação de forma assíncrona // Inicia a operação de forma assíncrona
await Variaveis.OperacaoEmAndamento.IniciarOperacao(); Task.Run(async () => await Variaveis.OperacaoEmAndamento.IniciarOperacao());
// Atualiza a UI após o início da operação // Atualiza a UI após o início da operação
btnIniciarOperacao.Invoke((MethodInvoker)delegate btnIniciarOperacao.Invoke((MethodInvoker)delegate

View File

@ -47,7 +47,7 @@ namespace AgroBase.Forms.Operacoes
private void frmOperacaoMapaGPS_FormClosing(object sender, FormClosingEventArgs e) private void frmOperacaoMapaGPS_FormClosing(object sender, FormClosingEventArgs e)
{ {
tmrLeituras.Dispose(); tmrLeituras.Dispose();
Variaveis.OperacaoEmAndamento.FinalizarOperacao(); Task.Run(async () => await Variaveis.OperacaoEmAndamento.FinalizarOperacao());
Variaveis.OperacaoEmAndamento.DesligarCameras(); Variaveis.OperacaoEmAndamento.DesligarCameras();
} }
@ -143,7 +143,7 @@ namespace AgroBase.Forms.Operacoes
if (btnIniciarOperacao.Text == "Finalizar Operação") if (btnIniciarOperacao.Text == "Finalizar Operação")
{ {
Variaveis.OperacaoEmAndamento.FinalizarOperacao(); await Variaveis.OperacaoEmAndamento.FinalizarOperacao();
} }
else else
{ {

View File

@ -1565,7 +1565,7 @@ namespace AgroBase.Forms.Operacoes
private void pnlOrientacaoDif_Paint(object sender, PaintEventArgs e) private void pnlOrientacaoDif_Paint(object sender, PaintEventArgs e)
{ {
var Logs = LogsOperacao.Where(x => x.Momento == MomentoAtual).ToList(); var Logs = LogsOperacao.Where(x => x.Momento == MomentoAtual).ToList();
double Angulo = Logs.Any() ? Logs.Average(x => x.AnguloDif) : 0; double Angulo = Logs.Any() ? Logs.Average(x => x.Trajetoria.ErroOrientacaoAngularProximoPonto) : 0;
FuncoesGlobais.DesenharInclinacao((Panel)sender, e, (float)Angulo, 90); FuncoesGlobais.DesenharInclinacao((Panel)sender, e, (float)Angulo, 90);
} }

View File

@ -266,7 +266,7 @@ namespace AgroBase
{ {
if (Variaveis.OperacaoEmAndamento.Iniciado) if (Variaveis.OperacaoEmAndamento.Iniciado)
{ {
Variaveis.OperacaoEmAndamento.FinalizarOperacao(); Task.Run(async () => await Variaveis.OperacaoEmAndamento.FinalizarOperacao());
btnIniciarOperacao.Text = "Abrir Operação"; btnIniciarOperacao.Text = "Abrir Operação";
cmbModoOperacao.Enabled = true; cmbModoOperacao.Enabled = true;

View File

@ -367,7 +367,7 @@ namespace AgroBase.Forms
try try
{ {
double angulo = Variaveis.OperacaoEmAndamento.SimulacaoAnguloControle; double angulo = Variaveis.OperacaoEmAndamento.SimulacaoAnguloControle;
double dif = Variaveis.OperacaoEmAndamento.OpMapaGPS.Sensoriamento.AnguloDif; double dif = Variaveis.OperacaoEmAndamento.Sensoriamento.Trajetoria.ErroOrientacaoAngularProximoPonto;
FuncoesGlobais.DesenharInclinacao((Panel)sender, e, (float)angulo, 90, (float)dif); FuncoesGlobais.DesenharInclinacao((Panel)sender, e, (float)angulo, 90, (float)dif);
} }
catch { } catch { }

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq;
using static AgroBase.Models.Enums; using static AgroBase.Models.Enums;
namespace AgroBase.Models namespace AgroBase.Models
@ -404,6 +405,45 @@ namespace AgroBase.Models
return decimalDegrees; return decimalDegrees;
} }
public static double MisturarAngulosPorDistancia(double anguloFrente, double anguloMovimento, double distanciaMetros, double distanciaMaxima, double distanciaMinima = 0.05, double pesoMinFrente = 0.2)
{
// Se robô praticamente não se moveu, confia só na orientação
if (distanciaMetros < distanciaMinima)
return anguloFrente;
double fator = Math.Min(distanciaMetros / distanciaMaxima, 1.0);
double pesoFrente = (1.0 - fator) * (1.0 - pesoMinFrente) + pesoMinFrente;
return MisturarAngulos(anguloFrente, anguloMovimento, pesoFrente);
}
public static double MisturarAngulos(double angulo1, double angulo2, double pesoAngulo1 = 0.5)
{
// Converte os ângulos para vetores unitários no plano
double rad1 = angulo1 * Math.PI / 180.0;
double rad2 = angulo2 * Math.PI / 180.0;
double x = Math.Cos(rad1) * pesoAngulo1 + Math.Cos(rad2) * (1.0 - pesoAngulo1);
double y = Math.Sin(rad1) * pesoAngulo1 + Math.Sin(rad2) * (1.0 - pesoAngulo1);
double resultado = Math.Atan2(y, x) * 180.0 / Math.PI;
return GPSUtils.NormalizarAngulo(resultado);
}
public static (GPSModel ponto, int index) PontoMaisProximoTrechoComIndice(GPSModel pontoRef, List<GPSModel> trecho)
{
if (trecho == null || trecho.Count == 0)
return (null, -1);
var resultado = trecho
.Select((p, i) => (ponto: p, index: i, dist: DistanciaEntrePontos(pontoRef, p)))
.OrderBy(x => x.dist)
.First();
return (resultado.ponto, resultado.index);
}
} }

View File

@ -37,5 +37,16 @@
_valorEstimado = novoValorEstimado; _valorEstimado = novoValorEstimado;
_erroEstimado = 1; _erroEstimado = 1;
} }
public KalmanFilter Clone()
{
return new KalmanFilter()
{
_erroEstimado = _erroEstimado,
_erroMedicao = _erroMedicao,
_erroProcesso = _erroProcesso,
_valorEstimado = _valorEstimado
};
}
} }
} }

View File

@ -0,0 +1,174 @@
using AgroBase.Models;
using AgroBase.Services;
using System;
using System.Collections.Generic;
using System.Linq;
public class MPCControllerAprimorado
{
private double distanciaPrevisao = 2.0;
private int horizonte;
private double maxAnguloDirecao;
private double maxAngulo4Rodas;
private double velocidadeMin;
private double velocidadeMax;
private double pesoOrientacao = 2.5;
private double pesoLateral = 1.5;
private double pesoDistancia = 0.8;
private double pesoSuavidade = 0.5;
private double limiteErroOrientacao = 45.0;
private double limiteErroLateral = 2.5; // metros
private DateTime ultimaAtualizacao = DateTime.MinValue;
public MPCControllerAprimorado()
{
this.maxAnguloDirecao = Variaveis.OperacaoEmAndamento?.Controle?.Angulo_Max ?? 30.0;
this.maxAngulo4Rodas = this.maxAnguloDirecao * 0.8;
this.velocidadeMin = Variaveis.OperacaoEmAndamento?.Controle?.PercentualVelocidadeMin ?? 20.0;
this.velocidadeMax = Variaveis.OperacaoEmAndamento?.Controle?.PercentualVelocidadeMax ?? 100.0;
}
public (double anguloControle, Enums.TipoMovimentoDirecional modo) CalcularControle(GPSModel posicalAtual, double velocidadeAtual, List<GPSModel> proximaTrajetoria, Enums.TipoMovimentoDirecional[] modosPermitidos)
{
if (proximaTrajetoria == null || proximaTrajetoria.Count < 2)
return (0, Enums.TipoMovimentoDirecional.RodasDianteiras);
if (proximaTrajetoria.Count > 3)
{
proximaTrajetoria = new List<GPSModel>(proximaTrajetoria.Take(3));
}
if (ultimaAtualizacao == DateTime.MinValue)
{
ultimaAtualizacao = DateTime.Now.AddMilliseconds(-(1.0 / GPSService.TaxaAmostragemHz));
}
double dt = (DateTime.Now - ultimaAtualizacao).TotalSeconds;
double tempoMax = (1.0 / GPSService.TaxaAmostragemHz) * 1.5;
dt = Math.Max(0.5, Math.Min(dt, tempoMax));
double velMs = FuncoesMatematicas.CalculaVelocidadeMsPercentual(velocidadeAtual);
double passoDist = velMs * dt;
horizonte = Math.Min(Convert.ToInt32(distanciaPrevisao / passoDist), proximaTrajetoria.Count);
var candidatos = GerarCandidatos(modosPermitidos);
double melhorCusto = double.MaxValue;
(double angulo, Enums.TipoMovimentoDirecional modo) melhorControle = (0, Enums.TipoMovimentoDirecional.RodasDianteiras);
foreach (var candidato in candidatos)
{
double custo = SimularTrajetoriaComReavaliacao(posicalAtual, proximaTrajetoria, posicalAtual.AnguloCarroDefinido, candidato.angulo, candidato.modo, velMs, dt);
//Console.WriteLine($"Candidato: {candidato.angulo}, Custo: {custo.ToString()}");
if (custo < melhorCusto)
{
melhorCusto = custo;
melhorControle = candidato;
}
}
ultimaAtualizacao = DateTime.Now;
return melhorControle;
}
private List<(double angulo, Enums.TipoMovimentoDirecional modo)> GerarCandidatos(Enums.TipoMovimentoDirecional[] modos)
{
var candidatos = new List<(double, Enums.TipoMovimentoDirecional)>();
foreach (var modo in modos)
{
double maxAng = (modo == Enums.TipoMovimentoDirecional.MovimentoArco || modo == Enums.TipoMovimentoDirecional.MovimentoDiagonal)
? maxAngulo4Rodas : maxAnguloDirecao;
for (double ang = -maxAng; ang <= maxAng; ang += 5.0)
{
candidatos.Add((ang, modo));
}
}
return candidatos;
}
private double SimularTrajetoriaComReavaliacao(GPSModel posicaoInicial, List<GPSModel> trajeto, double anguloInicial, double anguloControleInicial, Enums.TipoMovimentoDirecional modoInicial, double velocidadeMs, double dt)
{
double custoTotal = 0;
GPSModel posAtual = posicaoInicial;
double anguloAtual = anguloInicial;
double anguloControle = anguloControleInicial;
Enums.TipoMovimentoDirecional modo = modoInicial;
posAtual = VariaveisEquipamento.SimularNovaPosicao(modoInicial, anguloControleInicial, velocidadeMs, dt, anguloAtual, posAtual);
anguloAtual = posAtual.OrientacaoReal;
for (int i = 0; i < horizonte; i++)
{
double melhorCustoIteracao = double.MaxValue;
foreach (var candidato in GerarCandidatos(new[] { modo }))
{
var novaPos = VariaveisEquipamento.SimularNovaPosicao(candidato.modo, candidato.angulo, velocidadeMs, dt, anguloAtual, posAtual);
var pontoAlvo = trajeto[Math.Min(i + 1, trajeto.Count - 1)];
double orientacaoAlvo = GPSUtils.CalcularOrientacao(posAtual, pontoAlvo);
double d0 = GPSUtils.DistanciaEntrePontos(posAtual, novaPos);
double a0 = GPSUtils.CalcularOrientacao(posAtual, novaPos);
double d1 = GPSUtils.DistanciaEntrePontos(posAtual, pontoAlvo);
double a1 = GPSUtils.CalcularOrientacao(posAtual, pontoAlvo);
double d2 = GPSUtils.DistanciaEntrePontos(novaPos, pontoAlvo);
double a2 = GPSUtils.CalcularOrientacao(novaPos, pontoAlvo);
double erroDist = d2 - d1;
double erroOri = Math.Abs(GPSUtils.CalcularDiferencaAngulo(novaPos.OrientacaoReal, orientacaoAlvo));
(GPSModel ponto, int idx) = GPSUtils.PontoMaisProximoTrechoComIndice(posAtual, trajeto);
int idxNovoPonto = Variaveis.OperacaoEmAndamento.Trajetoria.PontoAtual.idxPonto + idx;
PontoTrajetoriaModel pontoAtual = Variaveis.OperacaoEmAndamento.Trajetoria._TrajetoriaFixa[idxNovoPonto].Clone();
int idxRuaEsquerda = Variaveis.OperacaoEmAndamento.Trajetoria._Corredores[pontoAtual.idxCorredor].idxRuaEsquerda;
double distEsq = Variaveis.OperacaoEmAndamento.Trajetoria.CalcularDistanciaLateral(true, posAtual, idxRuaEsquerda, pontoAtual.Direcao);
int idxRuaDireita = Variaveis.OperacaoEmAndamento.Trajetoria._Corredores[pontoAtual.idxCorredor].idxRuaDireita;
double distDir = Variaveis.OperacaoEmAndamento.Trajetoria.CalcularDistanciaLateral(false, posAtual, idxRuaDireita, pontoAtual.Direcao);
double erroLat = Math.Abs(distEsq - distDir);
double deltaAngulo = Math.Abs(GPSUtils.CalcularDiferencaAngulo(novaPos.OrientacaoReal, anguloAtual));
//Console.WriteLine($"Angulo Inicial: {anguloControleInicial}, Passo: {i}, Candidato: {candidato.angulo}, Erro lateral: {erroLat}, Erro orientacao: {erroOri}");
if (false && (erroOri > limiteErroOrientacao || erroLat > limiteErroLateral))
{
continue; // Ignora este candidato
}
double custo = (erroOri * pesoOrientacao) + (erroLat * pesoLateral) + (erroDist * pesoDistancia) + (deltaAngulo * pesoSuavidade);
if (custo < melhorCustoIteracao)
{
melhorCustoIteracao = custo;
posAtual = novaPos;
anguloAtual = novaPos.OrientacaoReal;
anguloControle = candidato.angulo;
modo = candidato.modo;
//Console.WriteLine($"Angulo Inicial: {anguloControleInicial}, Passo: {i}, Candidato: {candidato.angulo}, Custo: {custo}, Erro lateral: {erroLat}, Erro orientacao: {erroOri}, Erro distancia: {erroDist}");
}
}
custoTotal += melhorCustoIteracao;
if (melhorCustoIteracao == double.MaxValue)
{
break;
}
}
return custoTotal;
}
}

View File

@ -414,7 +414,7 @@ namespace AgroBase.Models.Modules
RPM_SP = Convert.ToInt32(RPM_SP * FatorCompensacaoCurvas); RPM_SP = Convert.ToInt32(RPM_SP * FatorCompensacaoCurvas);
Variaveis.OperacaoEmAndamento.SimulacaoRpmControle = (RPM_SP / VariaveisEquipamento.RelacaoRPM); Variaveis.OperacaoEmAndamento.SimulacaoRpmControle = Variaveis.OperacaoEmAndamento.DispMvd.Dados.Modulos.Average(x => x.MovMotor.RPM_SP) / VariaveisEquipamento.RelacaoRPM;
switch (DirecaoAtual) switch (DirecaoAtual)
{ {

View File

@ -37,16 +37,13 @@ namespace AgroBase.Models.Operacoes
} }
case TiposControladorDirecional.MPC: case TiposControladorDirecional.MPC:
{ {
var MPC = Controle.ControladorMPC;
var Trajetoria = Variaveis.OperacaoEmAndamento.Trajetoria; var Trajetoria = Variaveis.OperacaoEmAndamento.Trajetoria;
(double steeringAngle, Enums.TipoMovimentoDirecional mode) = MPC.ComputeControl( var MPC_A = new MPCControllerAprimorado();
GPSService.UltimaLeitura.Latitude, GPSService.UltimaLeitura.Longitude, Variaveis.OperacaoEmAndamento.Sensoriamento.Gps.AnguloCarroDefinido, (double angulo, TipoMovimentoDirecional tipoControle) = MPC_A.CalcularControle(GPSService.UltimaLeitura, Controle.PercentualVelocidadeSP, Trajetoria.TrajetoriaDinamica, new TipoMovimentoDirecional[] { TipoMovimentoDirecional.RodasDianteiras });
Trajetoria.ProximoPonto.Posicao.Latitude, Trajetoria.ProximoPonto.Posicao.Longitude, Trajetoria.ProximoPonto.Orientacao,
Controle.PercentualVelocidadeSP, Trajetoria.DistanciaEsquerda, Trajetoria.DistanciaDireita, new List<Obstaculo>());
Controle.Angulo = steeringAngle; Controle.Angulo = angulo;
Controle.TipoMovimento = mode; Controle.TipoMovimento = tipoControle;
break; break;
} }
} }
@ -61,15 +58,17 @@ namespace AgroBase.Models.Operacoes
private void DefinirTipoMovimento() private void DefinirTipoMovimento()
{ {
var Trajetoria = Variaveis.OperacaoEmAndamento.Trajetoria; var Trajetoria = Variaveis.OperacaoEmAndamento.Sensoriamento.Trajetoria;
var Controle = Variaveis.OperacaoEmAndamento.Controle;
bool arcoNecessario = bool arcoNecessario =
Trajetoria.ManobrandoEntreRuas || Trajetoria.ManobrandoEntreRuas ||
Trajetoria.StatusAtual == StatusCarroMapa.SaindoRua || Trajetoria.StatusCarro == StatusCarroMapa.SaindoRua ||
Trajetoria.StatusAtual == StatusCarroMapa.EntrandoRua || Trajetoria.StatusCarro == StatusCarroMapa.EntrandoRua ||
Math.Abs(Variaveis.OperacaoEmAndamento.OpMapaGPS.Sensoriamento.AnguloDif) >= Variaveis.OperacaoEmAndamento.Controle.Angulo_Max; (Trajetoria.CorredorAtual.Dentro && Math.Abs(Trajetoria.ErroOrientacaoAngularCaminho) >= Controle.Angulo_Max) ||
(!Trajetoria.CorredorAtual.Dentro && Math.Abs(Trajetoria.ErroOrientacaoAngularProximoPonto) >= Controle.Angulo_Max);
Variaveis.OperacaoEmAndamento.Controle.TipoMovimento = Controle.TipoMovimento =
arcoNecessario ? TipoMovimentoDirecional.MovimentoArco : arcoNecessario ? TipoMovimentoDirecional.MovimentoArco :
TipoMovimentoDirecional.RodasDianteiras; TipoMovimentoDirecional.RodasDianteiras;
} }
@ -79,35 +78,21 @@ namespace AgroBase.Models.Operacoes
var _Trajetoria = Variaveis.OperacaoEmAndamento.Sensoriamento.Trajetoria; var _Trajetoria = Variaveis.OperacaoEmAndamento.Sensoriamento.Trajetoria;
var _Controle = Variaveis.OperacaoEmAndamento.Controle; var _Controle = Variaveis.OperacaoEmAndamento.Controle;
double erroOrientacao = 0.0; bool consideraAnguloCorredor =
double anguloCamera = Variaveis.OperacaoEmAndamento.Sensoriamento.AnguloRuaCamera; (_Trajetoria.CorredorAtual.Dentro && Math.Abs(_Trajetoria.ErroLateralAngular) < 30.0 && _Trajetoria.PontoAtual.Tipo != TipoPontoRua.BordaSaida) ||
double anguloCarro = Variaveis.OperacaoEmAndamento.Sensoriamento.Gps.AnguloCarroDefinido; _Trajetoria.PontoAtual.Tipo == TipoPontoRua.BordaEntrada ||
double anguloRua = _Trajetoria.ProximoPonto.OrientacaoAtual; _Trajetoria.PontoAtual.Tipo == TipoPontoRua.LigacaoEntrada;
// Calcula a diferença de ângulo entre o carro e a rua double erroCombinado =
double diferencaAngulo = GPSUtils.CalcularDiferencaAngulo(anguloCarro, anguloRua); consideraAnguloCorredor ? _Trajetoria.ErroOrientacaoAngularCombinado :
_Trajetoria.ErroOrientacaoAngularProximoPonto;
erroOrientacao = diferencaAngulo;
Variaveis.OperacaoEmAndamento.OpMapaGPS.Sensoriamento.AnguloDif = erroOrientacao;
// Calcule o erro lateral baseado nas distâncias entre as ruas do mapa atraves do GPS
double erroLateral =
!_Trajetoria.CorredorAtual.Dentro ? 0 :
(_Trajetoria.DistanciaEsquerda - _Trajetoria.DistanciaDireita);
double distanciaProximoPonto = _Trajetoria.ProximoPonto.DistanciaAtual;
double erroUltrassom = UltrasonicA05Helper.CalcularErroUltrassons();
double erroCombinado = CalcularErroCombinado(erroLateral, erroOrientacao, erroUltrassom, distanciaProximoPonto);
AjustarGanhosPID(_Controle.PercentualVelocidadeSP);
var PID = _Controle.PIDdirecional; var PID = _Controle.PIDdirecional;
// Atualiza o PID com o erro combinado
if (_Trajetoria.StatusCarro != StatusCarroMapa.Parado) if (_Trajetoria.StatusCarro != StatusCarroMapa.Parado)
{ {
// Atualiza o PID com o erro combinado
AjustarGanhosPID(_Controle);
PID.LimiteSaida = _Controle.Angulo_Max; PID.LimiteSaida = _Controle.Angulo_Max;
PID.Atualizar(erroCombinado, 0); PID.Atualizar(erroCombinado, 0);
} }
@ -122,79 +107,23 @@ namespace AgroBase.Models.Operacoes
_Controle.Angulo = correcaoAngulo; _Controle.Angulo = correcaoAngulo;
} }
private double CalcularErroCombinado(double erroLateral, double erroOrientacao, double erroUltrassons, double distanciaProximoPonto) private void AjustarGanhosPID(OperacaoControleModel Controle)
{ {
bool carroDentroRua = Variaveis.OperacaoEmAndamento.Sensoriamento.Trajetoria.CorredorAtual.Dentro; var PID = Controle.PIDdirecional;
bool naMargeRua = Variaveis.OperacaoEmAndamento.Sensoriamento.Trajetoria.NaMargemDoCorredor; double velocidadePercnt = (Controle.PercentualVelocidadeMax - Controle.PercentualVelocidadeMin) * Controle.PercentualVelocidadeSP / 100.0;
// Quando o robô está dentro do corredor, queremos priorizar a centralização primeiro double v = FuncoesMatematicas.Clamp(velocidadePercnt / 100.0, 0.0, 1.0);
double pesoLateral;
double pesoOrientacao;
double pesoUltrassons = 0; // Por enquanto, ultrassons desativados
// Converte erro lateral (metros) para graus // 🔹 Kp reduz suavemente com o quadrado da velocidade (menos agressivo em alta)
double erroLateralEmGraus = Math.Atan2(erroLateral, distanciaProximoPonto) * (180.0 / Math.PI); PID.Kp = PID.KpBase * (1.0 - 0.4 * Math.Pow(v, 2));
if (carroDentroRua) // 🔹 Ki cai mais rápido e zera a partir de 60%
{ PID.Ki = v >= 0.6 ? 0.0 : PID.KiBase * (1.0 - Math.Pow(v, 1.5));
// Normaliza os erros para um intervalo entre 0 e 1
double erroOrientacaoNormalizado = Math.Min(Math.Abs(erroOrientacao) / 5.0, 1.0); // Assume 10° como erro máximo
// Usa a mesma regra de peso dinâmica // 🔹 Kd cresce suavemente (forte amortecimento em alta velocidade)
pesoOrientacao = Math.Max(0.3, erroOrientacaoNormalizado); // Quanto maior o erro de orientação, maior seu peso PID.Kd = PID.KdBase * (1.0 + 1.2 * Math.Pow(v, 1.2));
pesoOrientacao = 1.0; Console.WriteLine($"[PID ADAPT] Vel={velocidadePercnt:F1}% | Kp={PID.Kp:F3}, Ki={PID.Ki:F3}, Kd={PID.Kd:F3}");
pesoLateral = 1.0 - pesoOrientacao; // Quanto menor o erro de orientação, maior o peso lateral
}
else
{
// Quando está fora do corredor, prioriza a orientação
pesoLateral = 0;
pesoOrientacao = 1;
}
// Garante que os pesos somem exatamente 1
pesoUltrassons = Math.Max(0, 1 - pesoLateral - pesoOrientacao);
// Calcula o erro combinado ponderado pelos pesos
double erroCombinado =
(erroOrientacao * pesoOrientacao) +
(erroLateralEmGraus * pesoLateral) +
(erroUltrassons * pesoUltrassons);
return erroCombinado;
}
/*private void AjustarGanhosPID(double velocidadePercnt)
{
var PID = Variaveis.OperacaoEmAndamento.Controle.PIDdirecional;
// Fração da velocidade atual em relação à velocidade máxima (0 a 1)
double fatorVelocidade = Math.Min(velocidadePercnt / 100.0, 1.0);
// Ajuste dinâmico dos ganhos PID com curva exponencial para Kp e Kd
PID.Kp = PID.KpBase - (0.5 * Math.Pow(fatorVelocidade, 2)); // Reduz Kp mais agressivamente em altas velocidades
PID.Ki = fatorVelocidade > 0.8 ? 0.0 : PID.KiBase - (0.01 * fatorVelocidade); // Desativa Ki em altas velocidades
PID.Kd = PID.KdBase + (0.05 * Math.Pow(fatorVelocidade, 2)); // Aumenta Kd exponencialmente para amortecer oscilações
}*/
private void AjustarGanhosPID(double velocidadePercnt)
{
var PID = Variaveis.OperacaoEmAndamento.Controle.PIDdirecional;
double fatorVelocidade = Math.Min(velocidadePercnt / 100.0, 1.0);
// 🔹 Redução mais suave de Kp
PID.Kp = PID.KpBase - (0.4 * Math.Pow(fatorVelocidade, 1.5)); // Ajuste menos agressivo
// 🔹 Redução mais controlada do Ki
PID.Ki = fatorVelocidade > 0.7 ? 0.0 : PID.KiBase - (0.005 * fatorVelocidade); // Ki desativa mais cedo
// 🔹 Aumento um pouco mais forte do Kd
PID.Kd = PID.KdBase + (0.07 * Math.Pow(fatorVelocidade, 2)); // Amortecimento mais forte
// 🔹 Log opcional para monitorar ajustes (remover depois de testes)
Console.WriteLine($"PID Ajustado: Kp={PID.Kp:F3}, Ki={PID.Ki:F3}, Kd={PID.Kd:F3}");
} }
@ -214,11 +143,10 @@ namespace AgroBase.Models.Operacoes
if (Variaveis.OperacaoEmAndamento.StatusAtual != StatusOperacao.EmAndamento) if (Variaveis.OperacaoEmAndamento.StatusAtual != StatusOperacao.EmAndamento)
{ {
Controle.PercentualVelocidadeSP = 0; Controle.PercentualVelocidadeSP = 0;
Controle.FiltroVelocidade.Reset(Controle.PercentualVelocidadeSP);
return; return;
} }
Controle.PercentualVelocidadeSP = CalcularVelocidadeRelativa(Controle);
switch (Variaveis.OperacaoEmAndamento.Trajetoria.StatusAtual) switch (Variaveis.OperacaoEmAndamento.Trajetoria.StatusAtual)
{ {
case StatusCarroMapa.Parado: case StatusCarroMapa.Parado:
@ -232,7 +160,11 @@ namespace AgroBase.Models.Operacoes
bool DesvioSonar = (KinectService.Iniciado && Variaveis.OperacaoEmAndamento.Sensoriamento.SonarFrontal_Kinect.DesvioNecessario); bool DesvioSonar = (KinectService.Iniciado && Variaveis.OperacaoEmAndamento.Sensoriamento.SonarFrontal_Kinect.DesvioNecessario);
if (Manobrando || DesvioSonar) if (Manobrando || DesvioSonar)
{ {
Controle.PercentualVelocidadeSP = Math.Min(20.0, Controle.PercentualVelocidadeMin); Controle.PercentualVelocidadeSP = Controle.PercentualVelocidadeMin;
}
else
{
Controle.PercentualVelocidadeSP = CalcularVelocidadeRelativa(Controle);
} }
break; break;
} }
@ -252,6 +184,10 @@ namespace AgroBase.Models.Operacoes
{ {
Controle.PercentualVelocidadeSP = Controle.PercentualVelocidadeMin; Controle.PercentualVelocidadeSP = Controle.PercentualVelocidadeMin;
} }
else
{
Controle.PercentualVelocidadeSP = CalcularVelocidadeRelativa(Controle);
}
break; break;
} }
case StatusCarroMapa.Manobrando: case StatusCarroMapa.Manobrando:
@ -260,42 +196,41 @@ namespace AgroBase.Models.Operacoes
break; break;
} }
} }
Controle.PercentualVelocidadeSP = Math.Max(Controle.PercentualVelocidadeMin, Controle.PercentualVelocidadeSP);
Controle.PercentualVelocidadeSP = Math.Min(Controle.PercentualVelocidadeMax, Controle.PercentualVelocidadeSP);
if (Controle.PercentualVelocidadeSP == Controle.PercentualVelocidadeMin)
{
Controle.FiltroVelocidade.Reset(Controle.PercentualVelocidadeSP);
}
Console.WriteLine($"Velocidade SP: {Controle.PercentualVelocidadeSP}, ms: {FuncoesMatematicas.CalculaVelocidadeMsPercentual(Controle.PercentualVelocidadeSP)}, km/h: {FuncoesMatematicas.ConverteMsParaKmh(FuncoesMatematicas.CalculaVelocidadeMsPercentual(Controle.PercentualVelocidadeSP))}");
//double velocidadeFiltrada = Controle.FiltroVelocidade.Filtrar(Controle.PercentualVelocidadeSP);
//Controle.PercentualVelocidadeSP = Math.Max(Controle.PercentualVelocidadeMin, velocidadeFiltrada);
} }
private double CalcularVelocidadeRelativa(OperacaoControleModel Controle) private double CalcularVelocidadeRelativa(OperacaoControleModel Controle)
{ {
double limiteAnguloMax = Controle.Angulo_Max; // Ângulo máximo permitido (ex.: 30 graus) double erroCombinado = Variaveis.OperacaoEmAndamento.Sensoriamento.Trajetoria.ErroOrientacaoAngularCombinado;
double anguloAtual = Math.Abs(Controle.Angulo); // Ângulo de controle atual em módulo
double percentualReduzido = anguloAtual / limiteAnguloMax; // Percentual do ângulo de controle usado (0 a 1)
// Obtém os ângulos do carro e da rua // Converte erro para uma penalização de velocidade (até 1.5x mais severa em curvas)
double anguloCarro = Variaveis.OperacaoEmAndamento.Sensoriamento.Gps.AnguloCarroDefinido; double severidade = Math.Min(Math.Abs(erroCombinado) / 30.0, 1.0); // Normaliza até 30°
double anguloCorredor = Variaveis.OperacaoEmAndamento.Trajetoria.AnguloMedioCorredor; double penalidade = severidade * 0.85; // até 85% de penalização
// **Erro de orientação agora é a diferença real entre os ângulos** // Calcula velocidade proporcional
double erroOrientacao = Math.Abs(anguloCarro - anguloCorredor); // Diferenca real de ângulos double faixaVel = Controle.PercentualVelocidadeMax - Controle.PercentualVelocidadeMin;
erroOrientacao = Math.Min(erroOrientacao, 30.0); // Limita a 90° para normalização double velocidadeFinal = Controle.PercentualVelocidadeMax - (faixaVel * penalidade);
// **Peso dinâmico baseado no desalinhamento** double velocidadeRelativa = Math.Round(Math.Max(Controle.PercentualVelocidadeMin, velocidadeFinal), 2);
// Se o erro for grande, reduz mais a velocidade. Se for pequeno, mantém velocidade alta
double pesoErro = erroOrientacao / 30.0; // Normaliza erro para 0 (perfeito) a 1 (erro de 90°)
// **Ajusta a influência do ângulo de controle na velocidade** double velocidadeFiltrada = Controle.FiltroVelocidade.Filtrar(velocidadeRelativa);
double pesoAnguloControle = 1 - pesoErro; // Quanto maior o erro, menor a influência do ângulo de controle
// **Redução dinâmica da velocidade baseada no desalinhamento** return velocidadeFiltrada;
double reducaoPorErroOrientacao = pesoErro * 0.8; // Quanto maior o erro, maior a penalização (ajustável)
// **Calcula a velocidade proporcional combinando os dois efeitos com pesos dinâmicos**
double percentualVelocidadeRelativo = Controle.PercentualVelocidadeMin +
(1 - (pesoAnguloControle * percentualReduzido) - reducaoPorErroOrientacao) * (Controle.PercentualVelocidadeMax - Controle.PercentualVelocidadeMin);
// **Garante que a velocidade fique dentro dos limites aceitáveis (0 a 100%)**
percentualVelocidadeRelativo = Math.Round(Math.Max(Controle.PercentualVelocidadeMin, Math.Min(Controle.PercentualVelocidadeMax, percentualVelocidadeRelativo)), 2);
return percentualVelocidadeRelativo;
} }
#endregion #endregion
#region ATUADOR #region ATUADOR
@ -325,7 +260,6 @@ namespace AgroBase.Models.Operacoes
public int ErvasNoRadar { get; set; } = 0; public int ErvasNoRadar { get; set; } = 0;
public double HerbicidaConsumido { get; set; } = 0; public double HerbicidaConsumido { get; set; } = 0;
public double HerbicidaPorErva { get; set; } = 0; public double HerbicidaPorErva { get; set; } = 0;
public double AnguloDif { get; set; } = 0;
public double AnguloRuaCamera { get; set; } = 0; public double AnguloRuaCamera { get; set; } = 0;
public int ErvasIdentificadas public int ErvasIdentificadas
{ {
@ -347,7 +281,6 @@ namespace AgroBase.Models.Operacoes
ErvasNoRadar = 0; ErvasNoRadar = 0;
HerbicidaConsumido = 0; HerbicidaConsumido = 0;
HerbicidaPorErva = 0; HerbicidaPorErva = 0;
AnguloDif = 0;
AtuacoesPorBico = new List<Dictionary<string, int>>(); AtuacoesPorBico = new List<Dictionary<string, int>>();
if (Variaveis.OperacaoEmAndamento.DispAtu != null) if (Variaveis.OperacaoEmAndamento.DispAtu != null)

View File

@ -104,7 +104,7 @@ namespace AgroBase.Models
{ {
if (Variaveis.OperacaoEmAndamento.Iniciado && !Variaveis.OperacaoEmAndamento.Finalizando) if (Variaveis.OperacaoEmAndamento.Iniciado && !Variaveis.OperacaoEmAndamento.Finalizando)
{ {
Variaveis.OperacaoEmAndamento.FinalizarOperacao(); Task.Run(async () => await Variaveis.OperacaoEmAndamento.FinalizarOperacao());
} }
} }
// Se a operação tiver algum item mandatório interrompido // Se a operação tiver algum item mandatório interrompido
@ -386,6 +386,7 @@ namespace AgroBase.Models
Direcao = Direcao.Parado, Direcao = Direcao.Parado,
PercentualVelocidadeSP = 0, PercentualVelocidadeSP = 0,
PIDdirecional = new PIDModel(), PIDdirecional = new PIDModel(),
FiltroVelocidade = new KalmanFilter(),
TiposControle = Variaveis.OperacaoEmAndamento.Controle.TiposControle.ToList(), TiposControle = Variaveis.OperacaoEmAndamento.Controle.TiposControle.ToList(),
SonarAtivado = Parametros.SonarAtivado, SonarAtivado = Parametros.SonarAtivado,
SegmentacaoSemantica = Parametros.Modo == ModoOperacao.MapaGPS, SegmentacaoSemantica = Parametros.Modo == ModoOperacao.MapaGPS,
@ -795,6 +796,7 @@ namespace AgroBase.Models
LimiteSaida = Controle.Angulo_Max, LimiteSaida = Controle.Angulo_Max,
SetPoint = 0 SetPoint = 0
}; };
Controle.FiltroVelocidade = new KalmanFilter(erroMedicao: 2.0, erroProcesso: 0.05);
Controle.ControladorMPC = new MPCController(); Controle.ControladorMPC = new MPCController();
} }
@ -819,12 +821,21 @@ namespace AgroBase.Models
} }
} }
public void FinalizarOperacao() public async Task FinalizarOperacao()
{ {
if (Variaveis.OperacaoEmAndamento.Finalizando)
{
return;
}
Variaveis.OperacaoEmAndamento.Finalizando = true; Variaveis.OperacaoEmAndamento.Finalizando = true;
PararCarroOperacaoInterrompida(true); PararCarroOperacaoInterrompida(true);
Variaveis.OperacaoEmAndamento.Trajetoria.LoopAtualizaDados();
await Task.Delay(2000);
Variaveis.OperacaoEmAndamento.Iniciado = false; Variaveis.OperacaoEmAndamento.Iniciado = false;
Variaveis.OperacaoEmAndamento.DataFim = DateTime.Now; Variaveis.OperacaoEmAndamento.DataFim = DateTime.Now;
@ -917,6 +928,7 @@ namespace AgroBase.Models
LimiteSaida = Controle.Angulo_Max, LimiteSaida = Controle.Angulo_Max,
SetPoint = 0 SetPoint = 0
}; };
Controle.FiltroVelocidade = new KalmanFilter(erroMedicao: 2.0, erroProcesso: 0.05);
Controle.ControladorMPC = new MPCController(); Controle.ControladorMPC = new MPCController();
} }
@ -930,8 +942,10 @@ namespace AgroBase.Models
{ {
Variaveis.OperacaoEmAndamento.StatusAtual = StatusOperacao.Parametrizando; Variaveis.OperacaoEmAndamento.StatusAtual = StatusOperacao.Parametrizando;
Variaveis.OperacaoEmAndamento.Iniciado = false; Variaveis.OperacaoEmAndamento.Iniciado = false;
Variaveis.OperacaoEmAndamento.Simulando = false;
Variaveis.OperacaoEmAndamento.Mapa = new MapasModel(); Variaveis.OperacaoEmAndamento.Mapa = new MapasModel();
Variaveis.OperacaoEmAndamento.Trajetoria = new TrajetoriaMapaOperacaoModel(new List<List<GPSModel>>()); Variaveis.OperacaoEmAndamento.Trajetoria = new TrajetoriaMapaOperacaoModel(new List<List<GPSModel>>());
Variaveis.OperacaoEmAndamento.GPSTrajetoria = new List<GPSModel>();
var Topico = Variaveis.MqttService.Topicos.FirstOrDefault(x => x.Topico == MapasVariaveisModel.TopicoSelecaoRuasMapa); var Topico = Variaveis.MqttService.Topicos.FirstOrDefault(x => x.Topico == MapasVariaveisModel.TopicoSelecaoRuasMapa);
Topico.Mensagens.Add(new MqttService.MqttTopicosMensagensModel() Topico.Mensagens.Add(new MqttService.MqttTopicosMensagensModel()
@ -975,6 +989,7 @@ namespace AgroBase.Models
LimiteSaida = Controle.Angulo_Max, LimiteSaida = Controle.Angulo_Max,
SetPoint = 0 SetPoint = 0
}; };
Controle.FiltroVelocidade = new KalmanFilter(erroMedicao: 2.0, erroProcesso: 0.05);
} }
Controle.Angulo = 0; Controle.Angulo = 0;
@ -2815,6 +2830,7 @@ namespace AgroBase.Models
public TiposControladorDirecional TipoControleDirecional { get; set; } = TiposControladorDirecional.PID; public TiposControladorDirecional TipoControleDirecional { get; set; } = TiposControladorDirecional.PID;
public PIDModel PIDdirecional { get; set; } = new PIDModel(); public PIDModel PIDdirecional { get; set; } = new PIDModel();
public KalmanFilter FiltroVelocidade { get; set; } = new KalmanFilter();
public MPCController ControladorMPC { get; set; } = new MPCController(); public MPCController ControladorMPC { get; set; } = new MPCController();
public OperacaoControleModel Clone() public OperacaoControleModel Clone()
@ -2829,6 +2845,7 @@ namespace AgroBase.Models
PercentualInicioPulverizacao = PercentualInicioPulverizacao, PercentualInicioPulverizacao = PercentualInicioPulverizacao,
PercentualVelocidadeSP = PercentualVelocidadeSP, PercentualVelocidadeSP = PercentualVelocidadeSP,
PIDdirecional = PIDdirecional.Clone(), PIDdirecional = PIDdirecional.Clone(),
FiltroVelocidade = FiltroVelocidade.Clone(),
PressaoLinha = PressaoLinha, PressaoLinha = PressaoLinha,
PulverizadorAutomatico = PulverizadorAutomatico, PulverizadorAutomatico = PulverizadorAutomatico,
RPM_Max = RPM_Max, RPM_Max = RPM_Max,
@ -2918,7 +2935,6 @@ namespace AgroBase.Models
} }
public double AnguloRuaCamera { get; set; } = 0; public double AnguloRuaCamera { get; set; } = 0;
public double AnguloDif { get; set; } = 0;
public OperacaoSensoriamentoLogAtuModel Atuador { get; set; } public OperacaoSensoriamentoLogAtuModel Atuador { get; set; }
public OperacaoSensoriamentoLogMvdModel Movimentacao { get; set; } public OperacaoSensoriamentoLogMvdModel Movimentacao { get; set; }
@ -2998,15 +3014,22 @@ namespace AgroBase.Models
CorredorAtual = _Trajetoria?.CorredorAtual?.Clone(false) ?? new CorredorTrajetoriaModel(), CorredorAtual = _Trajetoria?.CorredorAtual?.Clone(false) ?? new CorredorTrajetoriaModel(),
DirecaoCaminho = _Trajetoria?.DirecaoCaminho ?? DirecaoCarroRua.Parado, DirecaoCaminho = _Trajetoria?.DirecaoCaminho ?? DirecaoCarroRua.Parado,
AnguloCaminho = _Trajetoria?.AnguloCaminho ?? 0, AnguloCaminho = _Trajetoria?.AnguloCaminho ?? 0,
AnguloMedioCorredor = _Trajetoria?.AnguloMedioCorredor ?? 0,
DistanciaTotal = _Trajetoria?.DistanciaTotal ?? 0, DistanciaTotal = _Trajetoria?.DistanciaTotal ?? 0,
DistanciaPercorrida = _Trajetoria?.DistanciaPercorrida ?? 0, DistanciaPercorrida = _Trajetoria?.DistanciaPercorrida ?? 0,
DistanciaRestante = _Trajetoria?.DistanciaRestante ?? 0, DistanciaRestante = _Trajetoria?.DistanciaRestante ?? 0,
NaMargemDoCorredor = _Trajetoria?.NaMargemDoCorredor ?? false, NaMargemDoCorredor = _Trajetoria?.NaMargemDoCorredor ?? false,
ManobrandoEntreRuas = _Trajetoria?.ManobrandoEntreRuas ?? false,
TempoEstimadoRestante = _Trajetoria?.TempoEstimadoRestante ?? "", TempoEstimadoRestante = _Trajetoria?.TempoEstimadoRestante ?? "",
TempoEstimadoOperacao = _Trajetoria?.TempoEstimadoOperacao ?? "", TempoEstimadoOperacao = _Trajetoria?.TempoEstimadoOperacao ?? "",
ProximoPonto = _Trajetoria?.ProximoPonto?.Clone() ?? new PontoTrajetoriaModel(TipoPontoRua.PosicaoRobo), ProximoPonto = _Trajetoria?.ProximoPonto?.Clone() ?? new PontoTrajetoriaModel(TipoPontoRua.PosicaoRobo),
PontoMaisProximo = _Trajetoria?.PontoMaisProximo?.Clone() ?? new PontoTrajetoriaModel(TipoPontoRua.PosicaoRobo), PontoMaisProximo = _Trajetoria?.PontoMaisProximo?.Clone() ?? new PontoTrajetoriaModel(TipoPontoRua.PosicaoRobo),
PontoAtual = _Trajetoria?.PontoAtual?.Clone() ?? new PontoTrajetoriaModel(TipoPontoRua.PosicaoRobo) PontoAtual = _Trajetoria?.PontoAtual?.Clone() ?? new PontoTrajetoriaModel(TipoPontoRua.PosicaoRobo),
ErroLateralAngular = _Trajetoria?.ErroLateralAngular ?? 0,
ErroOrientacaoAngular = _Trajetoria?.ErroOrientacaoAngular ?? 0,
ErroOrientacaoAngularCombinado = _Trajetoria?.ErroOrientacaoAngularCombinado ?? 0,
ErroOrientacaoAngularCaminho = _Trajetoria?.ErroOrientacaoAngularCaminho ?? 0,
ErroOrientacaoAngularProximoPonto = _Trajetoria?.ErroOrientacaoAngularProximoPonto ?? 0
}; };
var dadosGps = GPSService.UltimaLeitura.Clone(); var dadosGps = GPSService.UltimaLeitura.Clone();
@ -3029,7 +3052,6 @@ namespace AgroBase.Models
DataFim = Variaveis.OperacaoEmAndamento.DataFim, DataFim = Variaveis.OperacaoEmAndamento.DataFim,
TempoDecorridoSeg = Variaveis.OperacaoEmAndamento.TempoDecorridoSegs, TempoDecorridoSeg = Variaveis.OperacaoEmAndamento.TempoDecorridoSegs,
AnguloDif = _OpMapaGPS.Sensoriamento.AnguloDif,
AnguloRuaCamera = Variaveis.OperacaoEmAndamento.CameraCaminho?.Angulo ?? 0, AnguloRuaCamera = Variaveis.OperacaoEmAndamento.CameraCaminho?.Angulo ?? 0,
Atuador = dadosAtuador, Atuador = dadosAtuador,
@ -3057,7 +3079,6 @@ namespace AgroBase.Models
DataInicio = DataInicio, DataInicio = DataInicio,
DataFim = DataFim, DataFim = DataFim,
TempoDecorridoSeg = TempoDecorridoSeg, TempoDecorridoSeg = TempoDecorridoSeg,
AnguloDif = AnguloDif,
AnguloRuaCamera = AnguloRuaCamera, AnguloRuaCamera = AnguloRuaCamera,
Atuador = Atuador.Clone(), Atuador = Atuador.Clone(),
Movimentacao = Movimentacao.Clone(), Movimentacao = Movimentacao.Clone(),
@ -3173,6 +3194,7 @@ namespace AgroBase.Models
public StatusCarroMapa StatusCarro { get; set; } public StatusCarroMapa StatusCarro { get; set; }
public double ProgressoTrajeto { get; set; } public double ProgressoTrajeto { get; set; }
public double AnguloCaminho { get; set; } public double AnguloCaminho { get; set; }
public double AnguloMedioCorredor { get; set; }
public DirecaoCarroRua DirecaoCaminho { get; set; } public DirecaoCarroRua DirecaoCaminho { get; set; }
public CorredorTrajetoriaModel CorredorAtual { get; set; } public CorredorTrajetoriaModel CorredorAtual { get; set; }
public double DistanciaEsquerda { get; set; } public double DistanciaEsquerda { get; set; }
@ -3181,18 +3203,26 @@ namespace AgroBase.Models
public double DistanciaPercorrida { get; set; } public double DistanciaPercorrida { get; set; }
public double DistanciaRestante { get; set; } public double DistanciaRestante { get; set; }
public bool NaMargemDoCorredor { get; set; } public bool NaMargemDoCorredor { get; set; }
public bool ManobrandoEntreRuas { get; set; }
public string TempoEstimadoRestante { get; set; } public string TempoEstimadoRestante { get; set; }
public string TempoEstimadoOperacao { get; set; } public string TempoEstimadoOperacao { get; set; }
public PontoTrajetoriaModel ProximoPonto { get; set; } public PontoTrajetoriaModel ProximoPonto { get; set; }
public PontoTrajetoriaModel PontoAtual { get; set; } public PontoTrajetoriaModel PontoAtual { get; set; }
public PontoTrajetoriaModel PontoMaisProximo { get; set; } public PontoTrajetoriaModel PontoMaisProximo { get; set; }
public double ErroOrientacaoAngular { get; set; }
public double ErroOrientacaoAngularCombinado { get; set; }
public double ErroOrientacaoAngularCaminho { get; set; }
public double ErroOrientacaoAngularProximoPonto { get; set; }
public double ErroLateralAngular { get; set; }
public OperacaoSensoriamentoLogTrajetoriaModel Clone() public OperacaoSensoriamentoLogTrajetoriaModel Clone()
{ {
return new OperacaoSensoriamentoLogTrajetoriaModel() return new OperacaoSensoriamentoLogTrajetoriaModel()
{ {
StatusCarro = StatusCarro, StatusCarro = StatusCarro,
AnguloCaminho = AnguloCaminho, AnguloCaminho = AnguloCaminho,
AnguloMedioCorredor = AnguloMedioCorredor,
DirecaoCaminho = DirecaoCaminho, DirecaoCaminho = DirecaoCaminho,
DistanciaDireita = DistanciaDireita, DistanciaDireita = DistanciaDireita,
DistanciaEsquerda = DistanciaEsquerda, DistanciaEsquerda = DistanciaEsquerda,
@ -3202,8 +3232,14 @@ namespace AgroBase.Models
DistanciaPercorrida = DistanciaPercorrida, DistanciaPercorrida = DistanciaPercorrida,
DistanciaRestante = DistanciaRestante, DistanciaRestante = DistanciaRestante,
NaMargemDoCorredor = NaMargemDoCorredor, NaMargemDoCorredor = NaMargemDoCorredor,
ManobrandoEntreRuas = ManobrandoEntreRuas,
TempoEstimadoRestante = TempoEstimadoRestante, TempoEstimadoRestante = TempoEstimadoRestante,
TempoEstimadoOperacao = TempoEstimadoOperacao, TempoEstimadoOperacao = TempoEstimadoOperacao,
ErroLateralAngular = ErroLateralAngular,
ErroOrientacaoAngularCombinado = ErroOrientacaoAngularCombinado,
ErroOrientacaoAngular = ErroOrientacaoAngular,
ErroOrientacaoAngularCaminho = ErroOrientacaoAngularCaminho,
ErroOrientacaoAngularProximoPonto = ErroOrientacaoAngularProximoPonto,
ProximoPonto = ProximoPonto.Clone(), ProximoPonto = ProximoPonto.Clone(),
PontoAtual = PontoAtual.Clone(), PontoAtual = PontoAtual.Clone(),
PontoMaisProximo = PontoMaisProximo.Clone(), PontoMaisProximo = PontoMaisProximo.Clone(),

View File

@ -120,7 +120,7 @@ namespace AgroBase.Models
{ {
Posicao = GPSService.UltimaLeitura, Posicao = GPSService.UltimaLeitura,
LarguraCorredor = 1.0, LarguraCorredor = 1.0,
idxCorredor = CorredorAtual.Idx, idxCorredor = CorredorAtual?.Idx ?? 0,
Visitado = true Visitado = true
} }
}; };
@ -208,8 +208,8 @@ namespace AgroBase.Models
public double AnguloCaminho { get; private set; } public double AnguloCaminho { get; private set; }
private void AtualizarAnguloCaminho() private void AtualizarAnguloCaminho()
{ {
GPSModel pontoComparar = ProximoPonto != null ? ProximoPonto.Posicao : PontoAtual.Posicao; PontoTrajetoriaModel pontoComparar = PontoAtual.Aproximando ? PontoAtual : ProximoPonto != null ? ProximoPonto : PontoAtual;
AnguloCaminho = GPSUtils.CalcularOrientacao(GPSService.UltimaLeitura, pontoComparar); AnguloCaminho = GPSUtils.CalcularOrientacao(GPSService.UltimaLeitura, pontoComparar.Posicao);
} }
[JsonProperty] [JsonProperty]
public double DistanciaEsquerda { get; private set; } public double DistanciaEsquerda { get; private set; }
@ -217,39 +217,66 @@ namespace AgroBase.Models
public double DistanciaDireita { get; private set; } public double DistanciaDireita { get; private set; }
private void AtualizarDistanciasLaterais() private void AtualizarDistanciasLaterais()
{ {
DistanciaEsquerda = CalcularDistanciaLateral(true); DistanciaEsquerda = CalcularDistanciaLateral(true, GPSService.UltimaLeitura, CorredorAtual.idxRuaEsquerda, PontoAtual.Direcao);
DistanciaDireita = CalcularDistanciaLateral(false); DistanciaDireita = CalcularDistanciaLateral(false, GPSService.UltimaLeitura, CorredorAtual.idxRuaDireita, PontoAtual.Direcao);
} }
private double CalcularDistanciaLateral(bool ladoEsquerdo) public double CalcularDistanciaLateral(bool ladoEsquerdo, GPSModel posicaoAtual, int idxRua, DirecaoCarroRua direcaoAtual)
{ {
// Verifica se o corredor atual existe // Verifica se o corredor atual existe
if (!_CorredorAtualDefinido) return 0; if (!_CorredorAtualDefinido) return 0;
var rua = ladoEsquerdo ? new List<GPSModel>(RuasPlantacao[CorredorAtual.idxRuaEsquerda]) : new List<GPSModel>(RuasPlantacao[CorredorAtual.idxRuaDireita]); List<GPSModel> rua = new List<GPSModel>(RuasPlantacao[idxRua]);
double anguloAprojetar = GPSUtils.CalcularOrientacao(rua[rua.Count - 1], rua[0]); double d0 = double.MaxValue;
double anguloBprojetar = GPSUtils.CalcularOrientacao(rua[0], rua[rua.Count - 1]); int idx = -1;
GPSModel pontoA = GPSUtils.GerarPontoDeslocado(rua[0], anguloAprojetar, 10); for (int i = 0; i < rua.Count; i++)
GPSModel pontoB = GPSUtils.GerarPontoDeslocado(rua[rua.Count - 1], anguloBprojetar, 10); {
double dist = GPSUtils.DistanciaEntrePontos(posicaoAtual, rua[i]);
if (dist < d0)
{
d0 = dist;
idx = i;
}
else
{
break;
}
}
rua.Insert(0, pontoA); GPSModel p0 = rua[idx - (idx > 0 ? 1 : 0)];
rua.Add(pontoB); GPSModel p1 = rua[idx + (idx < (rua.Count - 1) ? 1 : 0)];
int idxPa = rua.IndexOf(p0);
int idxPb = rua.IndexOf(p1);
double anguloAprojetar = GPSUtils.CalcularOrientacao(rua[idxPb], rua[idxPa]);
double anguloBprojetar = GPSUtils.CalcularOrientacao(rua[idxPa], rua[idxPb]);
GPSModel pontoA = GPSUtils.GerarPontoDeslocado(rua[idxPa], anguloAprojetar, DistanciaManobraEntreRuas);
GPSModel pontoB = GPSUtils.GerarPontoDeslocado(rua[idxPb], anguloBprojetar, DistanciaManobraEntreRuas);
List<GPSModel> novaRua = new List<GPSModel>();
novaRua.Add(pontoA);
for (int i = idxPa; i <= idxPb; i++)
{
novaRua.Add(rua[i]);
}
novaRua.Add(pontoB);
rua = novaRua;
int qtdPontosRua = Convert.ToInt32(GPSUtils.DistanciaDoTrecho(rua)); int qtdPontosRua = Convert.ToInt32(GPSUtils.DistanciaDoTrecho(rua));
rua = GPSUtils.InterpolarRota(rua, qtdPontosRua); rua = GPSUtils.InterpolarRota(rua, qtdPontosRua);
double d = GPSUtils.DistanciaDoTrecho(rua);
// Calcula a menor distância entre o robô e a rua // Calcula a menor distância entre o robô e a rua
double distancia = GPSUtils.CalcularMenorDistanciaAteTrecho(GPSService.UltimaLeitura, rua); double distancia = GPSUtils.CalcularMenorDistanciaAteTrecho(posicaoAtual, rua);
// Calcula o vetor entre os pontos da rua e o vetor entre o ponto A e o GPS // Calcula o vetor entre os pontos da rua e o vetor entre o ponto A e o GPS
double crossProduct = double crossProduct =
(pontoB.Longitude - pontoA.Longitude) * (GPSService.UltimaLeitura.Latitude - pontoA.Latitude) - (pontoB.Longitude - pontoA.Longitude) * (posicaoAtual.Latitude - pontoA.Latitude) -
(pontoB.Latitude - pontoA.Latitude) * (GPSService.UltimaLeitura.Longitude - pontoA.Longitude); (pontoB.Latitude - pontoA.Latitude) * (posicaoAtual.Longitude - pontoA.Longitude);
// Ajusta a distância com base no sentido de deslocamento do robô // Ajusta a distância com base no sentido de deslocamento do robô
if ((PontoAtual.Direcao == DirecaoCarroRua.Volta && ladoEsquerdo) || (PontoAtual.Direcao == DirecaoCarroRua.Ida && !ladoEsquerdo)) if ((direcaoAtual == DirecaoCarroRua.Volta && ladoEsquerdo) || (direcaoAtual == DirecaoCarroRua.Ida && !ladoEsquerdo))
{ {
distancia *= crossProduct > 0 ? 1 : -1; distancia *= crossProduct > 0 ? 1 : -1;
} }
@ -378,7 +405,7 @@ namespace AgroBase.Models
private void AtualizarStatusAtual() private void AtualizarStatusAtual()
{ {
StatusAtual = StatusCarroMapa.Parado; StatusAtual = StatusCarroMapa.Parado;
if (ProximoPonto != null && CorredorAtual != null) if (ProximoPonto != null && CorredorAtual != null && Variaveis.OperacaoEmAndamento.StatusAtual == StatusOperacao.EmAndamento)
{ {
if (!CorredorAtual.Dentro && ProximoPonto.DistanciaAtual > DistanciaManobraEntreRuas) if (!CorredorAtual.Dentro && ProximoPonto.DistanciaAtual > DistanciaManobraEntreRuas)
{ {
@ -480,6 +507,63 @@ namespace AgroBase.Models
TempoEstimadoRestante = totalRestante.ToString("HH:mm:ss"); TempoEstimadoRestante = totalRestante.ToString("HH:mm:ss");
} }
[JsonProperty]
public double ErroOrientacaoAngular { get; private set; }
[JsonProperty]
public double ErroOrientacaoAngularCombinado { get; private set; }
[JsonProperty]
public double ErroOrientacaoAngularCaminho { get; private set; }
[JsonProperty]
public double ErroOrientacaoAngularProximoPonto { get; private set; }
[JsonProperty]
public double ErroLateralAngular { get; private set; }
private void AtualizarErroCombinado()
{
var _Sensoriamento = Variaveis.OperacaoEmAndamento.Sensoriamento;
double anguloCamera = _Sensoriamento.AnguloRuaCamera;
double anguloCorredor = AnguloMedioCorredor;
double anguloProximoPonto = AnguloCaminho;
double anguloCarro = _Sensoriamento.Gps.AnguloCarroDefinido;
// Erro 1: Direção para onde o robô deve ir (centro do corredor)
double erroIrParaCentro = GPSUtils.CalcularDiferencaAngulo(anguloCarro, anguloProximoPonto);
// Erro 2: Quanto o robô está desalinhado da orientação da rua
double desalinhamentoComRua = GPSUtils.CalcularDiferencaAngulo(anguloCarro, anguloCorredor);
// Erro 3 (secundário): Diferença entre o ângulo do corredor e o ponto (curva futura)
double curvaDaRua = GPSUtils.CalcularDiferencaAngulo(anguloProximoPonto, anguloCorredor);
// Peso do desalinhamento atual (prioriza alinhar o robô ao corredor)
double pesoAlinhamento = Math.Min(Math.Abs(desalinhamentoComRua) / 30.0, 1.0); // Normaliza até 30°
// Peso do centro (prioriza ir pro ponto central do corredor)
double pesoCentro = 1.0 - pesoAlinhamento;
// Peso extra para curvas mais fechadas
double boostCurva = 1.0 + (Math.Abs(curvaDaRua) / 45.0); // aumenta peso em curvas
// Calcule o erro lateral baseado nas distâncias entre as ruas do mapa atraves do GPS
double erroLateral = !(CorredorAtual?.Dentro ?? false) ? 0 : (DistanciaEsquerda - DistanciaDireita);
double distanciaProximoPonto = ProximoPonto.DistanciaAtual;
double erroLateralGraus = Math.Atan2(erroLateral, distanciaProximoPonto) * (180.0 / Math.PI);
// Calcule o erro do ultrassom
double erroUltrassom = UltrasonicA05Helper.CalcularErroUltrassons();
// Combina os erros com pesos dinâmicos
double erroCombinado = (erroIrParaCentro * pesoCentro) + (desalinhamentoComRua * pesoAlinhamento);
ErroOrientacaoAngularProximoPonto = erroIrParaCentro;
ErroOrientacaoAngularCaminho = desalinhamentoComRua;
ErroOrientacaoAngular = curvaDaRua;
ErroOrientacaoAngularCombinado = erroCombinado * boostCurva;
ErroLateralAngular = erroLateralGraus;
}
private void MarcarPontosIntermediariosNaoVisitados() private void MarcarPontosIntermediariosNaoVisitados()
{ {
if (!_TrajetoriaFixaDefinida) return; if (!_TrajetoriaFixaDefinida) return;
@ -532,6 +616,8 @@ namespace AgroBase.Models
AtualizarPercentualTrajetoria(); AtualizarPercentualTrajetoria();
AtualizarTempoEstimado(); AtualizarTempoEstimado();
AtualizarErroCombinado();
AtualizarTrajetoriaDinamica(); AtualizarTrajetoriaDinamica();
} }
@ -787,7 +873,7 @@ namespace AgroBase.Models
PontoTrajetoriaModel PontoRobo = new PontoTrajetoriaModel(TipoPontoRua.PosicaoRobo) PontoTrajetoriaModel PontoRobo = new PontoTrajetoriaModel(TipoPontoRua.PosicaoRobo)
{ {
idxCorredor = 0, idxCorredor = 0,
idxPonto = _trajetoriaFixa.Count(), idxPonto = 0,
idxPontoCorredor = 0, idxPontoCorredor = 0,
Posicao = GPSService.UltimaLeitura, Posicao = GPSService.UltimaLeitura,
Direcao = direcaoAtual, Direcao = direcaoAtual,
@ -809,7 +895,9 @@ namespace AgroBase.Models
if (_trajetoriaFixa.Count() > 1 && idxEsq == 0 && idxDir == 0) if (_trajetoriaFixa.Count() > 1 && idxEsq == 0 && idxDir == 0)
{ {
(List<GPSModel> ruaEsq, List<GPSModel> ruaDir) = DeterminarRuasLaterais(_trajetoriaFixa[1].Posicao, _trajetoriaFixa[2].Posicao, RuasPlantacao[0], RuasPlantacao[1]); var p0 = _trajetoriaFixa.Where(x => x.Tipo == TipoPontoRua.Rua).Skip(2).FirstOrDefault();
var p1 = _trajetoriaFixa.Where(x => x.Tipo == TipoPontoRua.Rua).Skip(3).FirstOrDefault();
(List<GPSModel> ruaEsq, List<GPSModel> ruaDir) = DeterminarRuasLaterais(p0.Posicao, p1.Posicao, RuasPlantacao[0], RuasPlantacao[1]);
idxEsq = RuasPlantacao.IndexOf(ruaEsq); idxEsq = RuasPlantacao.IndexOf(ruaEsq);
idxDir = RuasPlantacao.IndexOf(ruaDir); idxDir = RuasPlantacao.IndexOf(ruaDir);
} }
@ -847,7 +935,7 @@ namespace AgroBase.Models
Direcao = direcaoAtual, Direcao = direcaoAtual,
Orientacao = GPSUtils.CalcularOrientacao(ultimoPontoTrajetoria.Posicao, PrimeiroPonto), Orientacao = GPSUtils.CalcularOrientacao(ultimoPontoTrajetoria.Posicao, PrimeiroPonto),
Visitado = false, Visitado = false,
LarguraCorredor = LarguraCorredorPadrao LarguraCorredor = larguraCorredorMenor
}; };
bool PontoInicialAdicionado = false; bool PontoInicialAdicionado = false;
@ -919,9 +1007,7 @@ namespace AgroBase.Models
Direcao = direcaoAtual, Direcao = direcaoAtual,
Orientacao = GPSUtils.CalcularOrientacao(_trajetoriaFixa.Last().Posicao, pontoAtual), Orientacao = GPSUtils.CalcularOrientacao(_trajetoriaFixa.Last().Posicao, pontoAtual),
Visitado = false, Visitado = false,
LarguraCorredor = LarguraCorredor = bordaEntrada || bordaSaida ? larguraCorredorMenor : CorredoresLarguras[idx]
distanciaCorredor < DistanciaPrimeirosPontosProjecao && !bordaEntrada && !bordaSaida ? larguraCorredorMenor :
CorredoresLarguras[idx]
}; };
_trajetoriaFixa.Add(PontoTrajetoria); _trajetoriaFixa.Add(PontoTrajetoria);
@ -1110,7 +1196,13 @@ namespace AgroBase.Models
private (List<GPSModel> ruaEsquerda, List<GPSModel> ruaDireita) DeterminarRuasLaterais(GPSModel robo, GPSModel proximoPonto, List<GPSModel> rua1, List<GPSModel> rua2) private (List<GPSModel> ruaEsquerda, List<GPSModel> ruaDireita) DeterminarRuasLaterais(GPSModel robo, GPSModel proximoPonto, List<GPSModel> rua1, List<GPSModel> rua2)
{ {
// Determinar qual está à esquerda e qual está à direita // Determinar qual está à esquerda e qual está à direita
bool rua1EstaEsquerda = EstaEsquerda(robo, proximoPonto, Centroide(rua1)); var r1 = new List<GPSModel>(rua1);
if (ExtremoMaisProximoMapa == 1)
{
r1.Reverse();
}
r1 = r1.Take(3).ToList();
bool rua1EstaEsquerda = EstaEsquerda(robo, proximoPonto, Centroide(r1));
return rua1EstaEsquerda ? (rua1, rua2) : (rua2, rua1); return rua1EstaEsquerda ? (rua1, rua2) : (rua2, rua1);
} }
@ -1221,8 +1313,8 @@ namespace AgroBase.Models
public int idxPontoCorredor { get; set; } public int idxPontoCorredor { get; set; }
public GPSModel Posicao { get; set; } public GPSModel Posicao { get; set; }
public double Orientacao { get; set; } public double Orientacao { get; set; }
public Enums.DirecaoCarroRua Direcao { get; set; } public DirecaoCarroRua Direcao { get; set; }
public Enums.TipoPontoRua Tipo { get; } public TipoPontoRua Tipo { get; }
public double LarguraCorredor { get; set; } public double LarguraCorredor { get; set; }
public double DistanciaMargem { get; private set; } public double DistanciaMargem { get; private set; }
public bool Visitado { get; set; } = false; public bool Visitado { get; set; } = false;

View File

@ -719,35 +719,6 @@ namespace AgroBase.Services
WT901CService.DadosLeitura.AtualizarOffset(UltimaLeitura); WT901CService.DadosLeitura.AtualizarOffset(UltimaLeitura);
/*if (witIniciado && gpsIniciado)
{
// Obtém os ângulos de ambos os sensores
double anguloWT901C = WT901CService.DadosLeitura.AnguloCorrigido;
double anguloGPS = UltimaLeitura.OrientacaoReal;
double anguloGPSMovimento = UltimaLeitura.OrientacaoMovimento;
double distAnguloGPS = UltimaLeitura.Distancia;
anguloFinal = CalcularAnguloUnificado(anguloGPS, UltimaLeitura.QualidadeFix, anguloGPSMovimento, distAnguloGPS, anguloWT901C);
}
else if (witIniciado)
{
// Apenas o WT901C está disponível
anguloFinal = WT901CService.DadosLeitura.AnguloCorrigido;
}
else if (gpsIniciado)
{
// Apenas o GPS está disponível
double anguloGPS = UltimaLeitura.OrientacaoReal;
double anguloGPSMovimento = UltimaLeitura.OrientacaoMovimento;
double distAnguloGPS = UltimaLeitura.Distancia;
anguloFinal = CalcularAnguloUnificado(anguloGPS, UltimaLeitura.QualidadeFix, anguloGPSMovimento, distAnguloGPS);
}
else
{
anguloFinal = UltimaLeitura.OrientacaoMovimento;
}*/
if (gpsIniciado) if (gpsIniciado)
{ {
// O GPS está disponível // O GPS está disponível
@ -758,8 +729,9 @@ namespace AgroBase.Services
double distAnguloGPS = UltimaLeitura.Distancia; double distAnguloGPS = UltimaLeitura.Distancia;
//anguloFinal = CalcularAnguloUnificado(anguloGPS, UltimaLeitura.QualidadeFix, anguloGPSMovimento, distAnguloGPS); //anguloFinal = CalcularAnguloUnificado(anguloGPS, UltimaLeitura.QualidadeFix, anguloGPSMovimento, distAnguloGPS);
anguloFinal = GPSUtils.MisturarAngulosPorDistancia(anguloGPS, anguloGPSMovimento, distAnguloGPS, TrajetoriaMapaOperacaoModel.DistanciaMaximaEntreLeituras, 0.03, 0.3);
anguloFinal = anguloGPS; //anguloFinal = anguloGPS;
} }
else if (witIniciado) else if (witIniciado)
{ {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +1,221 @@
{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"Id":"1","Name":"28_03_2025_14_52_47","Length":24.117658942990531,"Dist1":0.0,"Dist2":0.0},"geometry":{"id":null,"type":"LineString","coordinates":[[-47.395224896,-22.172530905666665],[-47.395224814666669,-22.172530881166665],[-47.395224869166668,-22.172530858666665],[-47.395224843666668,-22.1725308255],[-47.395224782833331,-22.1725309215],[-47.395224707166669,-22.1725309895],[-47.395224716333331,-22.172530981666668],[-47.3952246845,-22.1725309905],[-47.395224654333333,-22.172531001833335],[-47.395224638333332,-22.1725310205],[-47.395224615333333,-22.1725310215],[-47.395224601333332,-22.1725310395],[-47.3952245865,-22.172531038333332],[-47.395224556666669,-22.172531053333334],[-47.395224520833331,-22.1725310615],[-47.395224496833336,-22.172531070166666],[-47.395224473833331,-22.172531077166667],[-47.395224445666663,-22.172531089166668],[-47.395224442166665,-22.172531103166666],[-47.395224427,-22.172531076333332],[-47.395224394833335,-22.1725310685],[-47.395224381666665,-22.1725311315],[-47.395224372666668,-22.172531105666668],[-47.395224357333333,-22.172531095],[-47.395224388166667,-22.172531347666666],[-47.395225137333334,-22.172534490666667],[-47.395225645,-22.172538111],[-47.39522384633333,-22.172540902666668],[-47.39522103583333,-22.172543275166667],[-47.395217679,-22.17254414],[-47.395214692833335,-22.172546121833335],[-47.395210529,-22.172546959833333],[-47.395206482333336,-22.172548131666666],[-47.395202635833336,-22.172548931],[-47.395198742666665,-22.1725496485],[-47.39519530816667,-22.172551297],[-47.395193089166668,-22.172553379166665],[-47.3951906165,-22.172556357833333],[-47.39518954,-22.172558924333334],[-47.3951892955,-22.172562425333332],[-47.395189338666668,-22.172565753333334],[-47.3951903165,-22.172569415833333],[-47.395191980333337,-22.172572816333332],[-47.395194284666665,-22.172577084833332],[-47.395197333333336,-22.172582304666665],[-47.3951991365,-22.172587995166666],[-47.395201415833334,-22.172594441666668],[-47.395203092666669,-22.172602672666667],[-47.395204304333333,-22.172610736333333],[-47.395205132,-22.172618987833335],[-47.395205720666667,-22.172626966833334],[-47.395206206833336,-22.172634488333333],[-47.395206750333337,-22.1726419035],[-47.395207180666667,-22.172649125166668],[-47.3952078105,-22.172656991166665],[-47.395208609,-22.1726643035],[-47.395209229,-22.1726726965],[-47.395209939166669,-22.1726804585],[-47.395211465666669,-22.172686973],[-47.395212691,-22.1726939085],[-47.3952135945,-22.172699633833332],[-47.3952137895,-22.1727036245],[-47.395214332833334,-22.1727079415],[-47.395215900666663,-22.172710840833332],[-47.395216996833334,-22.172713710833332],[-47.395218383666666,-22.172715863833332],[-47.39521935016667,-22.172718333833334],[-47.395218823,-22.172720601166667],[-47.395218898333333,-22.172720221166667],[-47.395218846666666,-22.172720248],[-47.3952188105,-22.172720256333335],[-47.39521881266667,-22.172720288333334],[-47.395218752333335,-22.1727202475],[-47.395218729166665,-22.172720266333332],[-47.3952186995,-22.172720271833334],[-47.395218683,-22.172720275166668],[-47.395218645666667,-22.172720276333333],[-47.395218627666665,-22.1727202785],[-47.3952186145,-22.172720284],[-47.395218570333334,-22.1727203085],[-47.395218561833332,-22.172720305666665],[-47.3952185305,-22.172720299],[-47.3952184855,-22.172720302666665],[-47.3952184605,-22.172720312166668],[-47.39521843233333,-22.172720307833334],[-47.395218399833333,-22.1727203335],[-47.395218375333336,-22.172720338333335],[-47.395218384,-22.172720347666665],[-47.395218363333335,-22.172720357666666],[-47.395218321833333,-22.172720362666666],[-47.3952182875,-22.172720388833334],[-47.395218217666667,-22.172720461333334],[-47.395218247333332,-22.1727204295],[-47.395218216166668,-22.172720418833332],[-47.395218204666669,-22.1727204255],[-47.395218174,-22.172720434166667]]}}]} {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"Id": "1",
"Name": "CidadeJardimTerreno2",
"Length": 14.558011415731592,
"Dist1": 14.558011415731592,
"Dist2": 0.0
},
"geometry": {
"id": null,
"type": "LineString",
"coordinates": [
[
-47.395205344,
-22.172559531333334
],
[
-47.395212610166666,
-22.172614638833334
],
[
-47.395219157,
-22.172656417833334
],
[
-47.395223544833335,
-22.1726892105
],
[
-47.39522414098443,
-22.17269369161165
],
[
-47.395225326538004,
-22.172702654611555
]
]
}
},
{
"type": "Feature",
"properties": {
"Id": "2",
"Name": "CidadeJardimTerreno2",
"Length": 14.771318274761821,
"Dist1": 14.558011415731592,
"Dist2": 0.0
},
"geometry": {
"id": null,
"type": "LineString",
"coordinates": [
[
-47.39521090233333,
-22.172708800833334
],
[
-47.395206943666665,
-22.172679811
],
[
-47.395202420666664,
-22.1726491015
],
[
-47.395198865666664,
-22.172615782833333
],
[
-47.395193255833334,
-22.172577132833332
],
[
-47.395192610024395,
-22.17257265769541
],
[
-47.395191325698136,
-22.172563706509337
]
]
}
},
{
"type": "Feature",
"properties": {
"Id": "3",
"Name": "CidadeJardimTerreno2",
"Length": 14.827915524386164,
"Dist1": 14.558011415731592,
"Dist2": 0.0
},
"geometry": {
"id": null,
"type": "LineString",
"coordinates": [
[
-47.3951762925,
-22.172561603
],
[
-47.395180824166665,
-22.172591686166665
],
[
-47.395185745333336,
-22.172623080166666
],
[
-47.395190433,
-22.172656367166667
],
[
-47.395195199,
-22.172693641833334
],
[
-47.39519576904436,
-22.172698125891035
],
[
-47.39519690267159,
-22.172707094716973
]
]
}
},
{
"type": "Feature",
"properties": {
"Id": "4",
"Name": "CidadeJardimTerreno2",
"Length": 14.785159385903514,
"Dist1": 14.558011415731592,
"Dist2": 0.0
},
"geometry": {
"id": null,
"type": "LineString",
"coordinates": [
[
-47.39518293216667,
-22.1727127985
],
[
-47.39517819266667,
-22.172680514833335
],
[
-47.3951732595,
-22.172646752833334
],
[
-47.39516880516667,
-22.1726149155
],
[
-47.39516381233334,
-22.172581167166665
],
[
-47.39516315429932,
-22.172576693573966
],
[
-47.39516184565584,
-22.172567745443878
]
]
}
},
{
"type": "Feature",
"properties": {
"Id": "5",
"Name": "CidadeJardimTerreno2",
"Length": 14.80117692191233,
"Dist1": 14.558011415731592,
"Dist2": 0.0
},
"geometry": {
"id": null,
"type": "LineString",
"coordinates": [
[
-47.395147317833334,
-22.172566031
],
[
-47.395151503166666,
-22.172595452333333
],
[
-47.3951561855,
-22.172628011166665
],
[
-47.39516159866667,
-22.172663757333332
],
[
-47.39516672716667,
-22.172697770833334
],
[
-47.395167397572706,
-22.172702242832194
],
[
-47.39516873082615,
-22.17271118781009
]
]
}
}
]
}

View File

@ -25,7 +25,7 @@
<meta name="viewport" content="width=device-width, <meta name="viewport" content="width=device-width,
initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<style> <style>
#map_273c4f61c3fbbe6e7f2c94d82e1811b9 { #map_68dcaf9dd7545b82e750e9f498ab7095 {
position: relative; position: relative;
width: 100.0%; width: 100.0%;
height: 100.0%; height: 100.0%;
@ -39,16 +39,16 @@
<body> <body>
<div class="folium-map" id="map_273c4f61c3fbbe6e7f2c94d82e1811b9" ></div> <div class="folium-map" id="map_68dcaf9dd7545b82e750e9f498ab7095" ></div>
</body> </body>
<script> <script>
var map_273c4f61c3fbbe6e7f2c94d82e1811b9 = L.map( var map_68dcaf9dd7545b82e750e9f498ab7095 = L.map(
"map_273c4f61c3fbbe6e7f2c94d82e1811b9", "map_68dcaf9dd7545b82e750e9f498ab7095",
{ {
center: [-22.172625713333332, -47.39520747025], center: [-22.172636164916668, -47.395186322185666],
crs: L.CRS.EPSG3857, crs: L.CRS.EPSG3857,
zoom: 12, zoom: 12,
zoomControl: true, zoomControl: true,
@ -60,13 +60,13 @@
var tile_layer_fa80a60fdccb28e7661c07bfa0881ec8 = L.tileLayer( var tile_layer_18ed5e620d2365ae2eea37d711c8da92 = L.tileLayer(
"https://tile.openstreetmap.org/{z}/{x}/{y}.png", "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
{"attribution": "\u0026copy; \u003ca href=\"https://www.openstreetmap.org/copyright\"\u003eOpenStreetMap\u003c/a\u003e contributors", "detectRetina": false, "maxNativeZoom": 19, "maxZoom": 19, "minZoom": 0, "noWrap": false, "opacity": 1, "subdomains": "abc", "tms": false} {"attribution": "\u0026copy; \u003ca href=\"https://www.openstreetmap.org/copyright\"\u003eOpenStreetMap\u003c/a\u003e contributors", "detectRetina": false, "maxNativeZoom": 19, "maxZoom": 19, "minZoom": 0, "noWrap": false, "opacity": 1, "subdomains": "abc", "tms": false}
); );
tile_layer_fa80a60fdccb28e7661c07bfa0881ec8.addTo(map_273c4f61c3fbbe6e7f2c94d82e1811b9); tile_layer_18ed5e620d2365ae2eea37d711c8da92.addTo(map_68dcaf9dd7545b82e750e9f498ab7095);
@ -82,7 +82,7 @@
}*/ }*/
}); });
} }
function geo_json_35710823a9f19abf47e95c1a9abf984f_onEachFeature(feature, layer) { function geo_json_377712b0416695b2616e159ce6022a2d_onEachFeature(feature, layer) {
layer.on({ layer.on({
click: function(e) { click: function(e) {
@ -118,20 +118,20 @@
}*/ }*/
}); });
}; };
var geo_json_35710823a9f19abf47e95c1a9abf984f = L.geoJson(null, { var geo_json_377712b0416695b2616e159ce6022a2d = L.geoJson(null, {
onEachFeature: geo_json_35710823a9f19abf47e95c1a9abf984f_onEachFeature, onEachFeature: geo_json_377712b0416695b2616e159ce6022a2d_onEachFeature,
}); });
function geo_json_35710823a9f19abf47e95c1a9abf984f_add (data) { function geo_json_377712b0416695b2616e159ce6022a2d_add (data) {
geo_json_35710823a9f19abf47e95c1a9abf984f geo_json_377712b0416695b2616e159ce6022a2d
.addData(data); .addData(data);
} }
geo_json_35710823a9f19abf47e95c1a9abf984f_add({"features": [{"geometry": {"coordinates": [[-47.395224896, -22.172530905666665], [-47.39522481466667, -22.172530881166665], [-47.39522486916667, -22.172530858666665], [-47.39522484366667, -22.1725308255], [-47.39522478283333, -22.1725309215], [-47.39522470716667, -22.1725309895], [-47.39522471633333, -22.172530981666668], [-47.3952246845, -22.1725309905], [-47.39522465433333, -22.172531001833335], [-47.39522463833333, -22.1725310205], [-47.39522461533333, -22.1725310215], [-47.39522460133333, -22.1725310395], [-47.3952245865, -22.172531038333332], [-47.39522455666667, -22.172531053333334], [-47.39522452083333, -22.1725310615], [-47.395224496833336, -22.172531070166666], [-47.39522447383333, -22.172531077166667], [-47.39522444566666, -22.172531089166668], [-47.395224442166665, -22.172531103166666], [-47.395224427, -22.172531076333332], [-47.395224394833335, -22.1725310685], [-47.395224381666665, -22.1725311315], [-47.39522437266667, -22.172531105666668], [-47.39522435733333, -22.172531095], [-47.39522438816667, -22.172531347666666], [-47.395225137333334, -22.172534490666667], [-47.395225645, -22.172538111], [-47.39522384633333, -22.172540902666668], [-47.39522103583333, -22.172543275166667], [-47.395217679, -22.17254414], [-47.395214692833335, -22.172546121833335], [-47.395210529, -22.172546959833333], [-47.395206482333336, -22.172548131666666], [-47.395202635833336, -22.172548931], [-47.395198742666665, -22.1725496485], [-47.39519530816667, -22.172551297], [-47.39519308916667, -22.172553379166665], [-47.3951906165, -22.172556357833333], [-47.39518954, -22.172558924333334], [-47.3951892955, -22.172562425333332], [-47.39518933866667, -22.172565753333334], [-47.3951903165, -22.172569415833333], [-47.39519198033334, -22.172572816333332], [-47.395194284666665, -22.172577084833332], [-47.395197333333336, -22.172582304666665], [-47.3951991365, -22.172587995166666], [-47.395201415833334, -22.172594441666668], [-47.39520309266667, -22.172602672666667], [-47.39520430433333, -22.172610736333333], [-47.395205132, -22.172618987833335], [-47.39520572066667, -22.172626966833334], [-47.395206206833336, -22.172634488333333], [-47.39520675033334, -22.1726419035], [-47.39520718066667, -22.172649125166668], [-47.3952078105, -22.172656991166665], [-47.395208609, -22.1726643035], [-47.395209229, -22.1726726965], [-47.39520993916667, -22.1726804585], [-47.39521146566667, -22.172686973], [-47.395212691, -22.1726939085], [-47.3952135945, -22.172699633833332], [-47.3952137895, -22.1727036245], [-47.39521433283333, -22.1727079415], [-47.39521590066666, -22.172710840833332], [-47.395216996833334, -22.17271371083333], [-47.395218383666666, -22.172715863833332], [-47.39521935016667, -22.172718333833334], [-47.395218823, -22.172720601166667], [-47.39521889833333, -22.172720221166667], [-47.395218846666666, -22.172720248], [-47.3952188105, -22.172720256333335], [-47.39521881266667, -22.172720288333334], [-47.395218752333335, -22.1727202475], [-47.395218729166665, -22.172720266333332], [-47.3952186995, -22.172720271833334], [-47.395218683, -22.172720275166668], [-47.39521864566667, -22.172720276333333], [-47.395218627666665, -22.1727202785], [-47.3952186145, -22.172720284], [-47.395218570333334, -22.1727203085], [-47.39521856183333, -22.172720305666665], [-47.3952185305, -22.172720299], [-47.3952184855, -22.172720302666665], [-47.3952184605, -22.172720312166668], [-47.39521843233333, -22.172720307833334], [-47.39521839983333, -22.1727203335], [-47.395218375333336, -22.172720338333335], [-47.395218384, -22.172720347666665], [-47.395218363333335, -22.172720357666666], [-47.39521832183333, -22.172720362666666], [-47.3952182875, -22.172720388833334], [-47.39521821766667, -22.172720461333334], [-47.39521824733333, -22.1727204295], [-47.39521821616667, -22.172720418833332], [-47.39521820466667, -22.1727204255], [-47.395218174, -22.172720434166667]], "id": null, "type": "LineString"}, "id": 0, "properties": {"Dist1": 0.0, "Dist2": 0.0, "Id": "1", "Length": 24.11765894299053, "Name": "28_03_2025_14_52_47"}, "type": "Feature"}], "type": "FeatureCollection"}); geo_json_377712b0416695b2616e159ce6022a2d_add({"features": [{"geometry": {"coordinates": [[-47.395205344, -22.172559531333334], [-47.395212610166666, -22.172614638833334], [-47.395219157, -22.172656417833334], [-47.395223544833335, -22.1726892105], [-47.39522414098443, -22.17269369161165], [-47.395225326538004, -22.172702654611555]], "id": null, "type": "LineString"}, "id": 0, "properties": {"Dist1": 14.558011415731592, "Dist2": 0.0, "Id": "1", "Length": 14.558011415731592, "Name": "CidadeJardimTerreno2"}, "type": "Feature"}, {"geometry": {"coordinates": [[-47.39521090233333, -22.172708800833334], [-47.395206943666665, -22.172679811], [-47.395202420666664, -22.1726491015], [-47.395198865666664, -22.172615782833333], [-47.395193255833334, -22.172577132833332], [-47.395192610024395, -22.17257265769541], [-47.395191325698136, -22.172563706509337]], "id": null, "type": "LineString"}, "id": 1, "properties": {"Dist1": 14.558011415731592, "Dist2": 0.0, "Id": "2", "Length": 14.771318274761821, "Name": "CidadeJardimTerreno2"}, "type": "Feature"}, {"geometry": {"coordinates": [[-47.3951762925, -22.172561603], [-47.395180824166665, -22.172591686166665], [-47.395185745333336, -22.172623080166666], [-47.395190433, -22.172656367166667], [-47.395195199, -22.172693641833334], [-47.39519576904436, -22.172698125891035], [-47.39519690267159, -22.172707094716973]], "id": null, "type": "LineString"}, "id": 2, "properties": {"Dist1": 14.558011415731592, "Dist2": 0.0, "Id": "3", "Length": 14.827915524386164, "Name": "CidadeJardimTerreno2"}, "type": "Feature"}, {"geometry": {"coordinates": [[-47.39518293216667, -22.1727127985], [-47.39517819266667, -22.172680514833335], [-47.3951732595, -22.172646752833334], [-47.39516880516667, -22.1726149155], [-47.39516381233334, -22.172581167166665], [-47.39516315429932, -22.172576693573966], [-47.39516184565584, -22.172567745443878]], "id": null, "type": "LineString"}, "id": 3, "properties": {"Dist1": 14.558011415731592, "Dist2": 0.0, "Id": "4", "Length": 14.785159385903514, "Name": "CidadeJardimTerreno2"}, "type": "Feature"}, {"geometry": {"coordinates": [[-47.395147317833334, -22.172566031], [-47.395151503166666, -22.172595452333333], [-47.3951561855, -22.172628011166665], [-47.39516159866667, -22.172663757333332], [-47.39516672716667, -22.172697770833334], [-47.395167397572706, -22.172702242832194], [-47.39516873082615, -22.17271118781009]], "id": null, "type": "LineString"}, "id": 4, "properties": {"Dist1": 14.558011415731592, "Dist2": 0.0, "Id": "5", "Length": 14.80117692191233, "Name": "CidadeJardimTerreno2"}, "type": "Feature"}], "type": "FeatureCollection"});
geo_json_35710823a9f19abf47e95c1a9abf984f.addTo(map_273c4f61c3fbbe6e7f2c94d82e1811b9); geo_json_377712b0416695b2616e159ce6022a2d.addTo(map_68dcaf9dd7545b82e750e9f498ab7095);
</script> </script>
@ -152,7 +152,7 @@
} }
trajeto_json_add({"features": []}); trajeto_json_add({"features": []});
trajeto_json.addTo(map_273c4f61c3fbbe6e7f2c94d82e1811b9); trajeto_json.addTo(map_68dcaf9dd7545b82e750e9f498ab7095);
function adicionarGeometria(novaGeometria) { function adicionarGeometria(novaGeometria) {
trajeto_json.addData(novaGeometria); trajeto_json.addData(novaGeometria);
@ -210,7 +210,7 @@
} }
trajeto_dinamico_json_add({"features": []}); trajeto_dinamico_json_add({"features": []});
trajeto_dinamico_json.addTo(map_273c4f61c3fbbe6e7f2c94d82e1811b9); trajeto_dinamico_json.addTo(map_68dcaf9dd7545b82e750e9f498ab7095);
function adicionarGeometriaDinamica(novaGeometria) { function adicionarGeometriaDinamica(novaGeometria) {
trajeto_dinamico_json.addData(novaGeometria); trajeto_dinamico_json.addData(novaGeometria);
@ -263,9 +263,9 @@
var marcadorEquipamento = L.marker([0, 0], { var marcadorEquipamento = L.marker([0, 0], {
icon: customIcon icon: customIcon
}).addTo(map_273c4f61c3fbbe6e7f2c94d82e1811b9); }).addTo(map_68dcaf9dd7545b82e750e9f498ab7095);
var marcadorBase = L.marker([0, 0], {}).addTo(map_273c4f61c3fbbe6e7f2c94d82e1811b9); var marcadorBase = L.marker([0, 0], {}).addTo(map_68dcaf9dd7545b82e750e9f498ab7095);
var icon = L.AwesomeMarkers.icon( var icon = L.AwesomeMarkers.icon(
{"extraClasses": "fa-rotate-0", "icon": "info-sign", "iconColor": "white", "markerColor": "red", "prefix": "glyphicon"} {"extraClasses": "fa-rotate-0", "icon": "info-sign", "iconColor": "white", "markerColor": "red", "prefix": "glyphicon"}
); );
@ -347,7 +347,7 @@
} }
if (foco) { if (foco) {
map_273c4f61c3fbbe6e7f2c94d82e1811b9.setView(novaPosicao, map_273c4f61c3fbbe6e7f2c94d82e1811b9.getZoom()); map_68dcaf9dd7545b82e750e9f498ab7095.setView(novaPosicao, map_68dcaf9dd7545b82e750e9f498ab7095.getZoom());
} }
} }
@ -364,7 +364,7 @@
function atualizarSelecaoRuas(selecionadas) { function atualizarSelecaoRuas(selecionadas) {
selecionadas = JSON.parse(selecionadas); selecionadas = JSON.parse(selecionadas);
RuasSelecionadas = Array.isArray(selecionadas) ? [...selecionadas] : []; RuasSelecionadas = Array.isArray(selecionadas) ? [...selecionadas] : [];
geo_json_35710823a9f19abf47e95c1a9abf984f.eachLayer(function (layer) { geo_json_377712b0416695b2616e159ce6022a2d.eachLayer(function (layer) {
if (RuasSelecionadas.includes(parseInt(layer.feature.id))) { if (RuasSelecionadas.includes(parseInt(layer.feature.id))) {
layer.setStyle({ color: 'blue' }); layer.setStyle({ color: 'blue' });
} else { } else {

View File

@ -1 +1 @@
5941701e8325b99f36fff6b9c1588b65d819d36a36bdbfbca35ae4c40535bf7e 1ccd04225d048dc265da75465ce916117f9ec7d8ad86c56b4979cd52d202386b