ajustes lora e deteccao de obstaculos

This commit is contained in:
Diego Freitas 2025-09-16 10:31:32 -03:00
parent 9611f564b5
commit e80d8cabcf
169 changed files with 13497 additions and 1426 deletions

Binary file not shown.

View File

@ -754,9 +754,10 @@ namespace AgroBase
private static bool VerificaComandoValidoSonar(Keys Comando)
{
List<Keys> ComandosImpedidos = new List<Keys>();
var Sonar = Variaveis.OperacaoEmAndamento.Sensoriamento.OperadorVisual;
if (Variaveis.OperacaoEmAndamento.Controle.SonarAtivado && Sonar.Iniciado && Sonar.Status == StatusModulo.Operante && (Sonar.Analises.matriz_confianca?.block?.decision?.parar ?? false))
Sonar?.Resumo?.AtualizarStatusBloqueio(false);
var DeveParar = Sonar?.Resumo?.DeveParar ?? false;
if (DeveParar)
{
ComandosImpedidos.Add(Keys.Up);
/*switch (Sonar.Resumo.DirecaoDesvio)

View File

@ -706,6 +706,7 @@ namespace AgroBase.Models.Modules
{
RequisitarDadosModulo(Variaveis.ID_Num_sTOD, CanMessagePosicaoDados.DadosAll, CanMessagePosicaoDados.DadosAll, true);
}
VerificaControleLeitura();
}
AtualizaComponentesIniciados();
@ -751,6 +752,32 @@ namespace AgroBase.Models.Modules
return (_atuadorOperante, ModsComFalha);
}
private void VerificaControleLeitura()
{
if (true) // !frmDiagnosticos.Diagnosticando
{
foreach (var bico in BicosPulverizadores.Where(x => x.Comandar && x.Inicializado))
{
Estado leituraEstado = (Estado?)(bico.ValoresLeituras.FirstOrDefault(x => x.funcao == FuncoesPinout.EstadoLeitura)?.atual?.valor) ?? Estado.Desligado;
Estado comandoEstado = bico.ComandoAtuar ? Estado.Ligado : Estado.Desligado;
if (leituraEstado != comandoEstado)
{
GeneralJoystick.EnviarComandoAtuador(bico.Componente, bico.ComandoAtuar, bico.ID);
}
}
var bomba = BombasPressurizadoras.FirstOrDefault(x => x.Comandar && x.Inicializado);
if (bomba != null)
{
bool leituraEstado = (bomba.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.Potencia)?.atual?.valor ?? 0) > 0;
if (bomba.ComandoAtuar != leituraEstado)
{
GeneralJoystick.EnviarComandoAtuador(bomba.Componente, bomba.ComandoAtuar, bomba.ID);
}
}
}
}
private void AtualizaComponentesIniciados()
{
DateTime Agora = DateTime.Now;
@ -782,7 +809,7 @@ namespace AgroBase.Models.Modules
var Bomba = BombasPressurizadoras.FirstOrDefault();
if (Bomba.Inicializado)
{
GeneralJoystick.EnviarComandoAtuador(S_Code.sBMB, true, Bomba.ID);
GeneralJoystick.EnviarComandoAtuador(Bomba.Componente, true, Bomba.ID);
bool AtingiuPressao() => PressaoLinha >= Variaveis.OperacaoEmAndamento.Controle.PressaoLinha;
@ -796,11 +823,11 @@ namespace AgroBase.Models.Modules
{
if (Bico.Inicializado)
{
GeneralJoystick.EnviarComandoAtuador(S_Code.sBIC, true, Bico.ID);
GeneralJoystick.EnviarComandoAtuador(Bico.Componente, true, Bico.ID);
await Task.Delay(200);
GeneralJoystick.EnviarComandoAtuador(S_Code.sBIC, false, Bico.ID);
GeneralJoystick.EnviarComandoAtuador(Bico.Componente, false, Bico.ID);
}
}

View File

@ -1660,6 +1660,7 @@ namespace AgroBase.Models.Modules
Componente = S_Code.sLRA,
Funcoes = new List<FuncoesPinout>()
{
FuncoesPinout.ENA,
FuncoesPinout.M0,
FuncoesPinout.M1,
FuncoesPinout.Aux,

View File

@ -137,7 +137,8 @@ namespace AgroBase.Models
int qtdCamerasSolo,
TiposControladorDirecional tipoControleDirecional,
bool movimentoAutomatico,
bool pulverizadorAutomatico)
bool pulverizadorAutomatico,
bool frenagemAutomatica)
{
if (string.IsNullOrEmpty(descricao))
{
@ -171,7 +172,8 @@ namespace AgroBase.Models
SonarAtivado = sonarAtivado,
QtdCamerasSolo = qtdCamerasSolo,
MovimentoAutomatico = movimentoAutomatico,
PulverizadorAutomatico = pulverizadorAutomatico
PulverizadorAutomatico = pulverizadorAutomatico,
FrenagemAtuomatica = frenagemAutomatica
};
Parametros.Mapa.LimparDados(true);
@ -231,6 +233,7 @@ namespace AgroBase.Models
TipoControleDirecional = Parametros.DirTipoMovimento,
PulverizadorAutomatico = Parametros.PulverizadorAutomatico,
MovimentoAutomatico = Parametros.MovimentoAutomatico,
FrenagemAutomatica = Parametros.FrenagemAtuomatica,
TipoMovimento = Variaveis.OperacaoEmAndamento.Controle.TipoMovimento,
heartbeat = 0,
SimulacaoMPC = new List<MPCSimulacaoModel>(),
@ -309,6 +312,7 @@ namespace AgroBase.Models
{
MovimentoAutomatico = false,
PulverizadorAutomatico = false,
FrenagemAutomatica = true,
RPM_Max = 100,
RPM_Min = 15,
Angulo_Max = 25,
@ -386,6 +390,7 @@ namespace AgroBase.Models
{
MovimentoAutomatico = true,
PulverizadorAutomatico = true,
FrenagemAutomatica = true,
RPM_Max = 50,
RPM_Min = 20,
Angulo_Max = 30,
@ -486,6 +491,7 @@ namespace AgroBase.Models
{
MovimentoAutomatico = true,
PulverizadorAutomatico = false,
FrenagemAutomatica = false,
RPM_Max = 100,
RPM_Min = 20,
Angulo_Max = 30,
@ -588,6 +594,7 @@ namespace AgroBase.Models
{
MovimentoAutomatico = true,
PulverizadorAutomatico = false,
FrenagemAutomatica = true,
RPM_Max = 40,
RPM_Min = 20,
Angulo_Max = 30,
@ -948,7 +955,11 @@ namespace AgroBase.Models
{
case T_Code.Mov:
{
if (_Controle.RPM_SP == 0)
if (_Controle.FrenagemAutomatica && _Controle.EmFreio)
{
_Controle.Direcao = Direcao.EmFreio;
}
else if (_Controle.RPM_SP == 0)
{
_Controle.Direcao = Direcao.Parado;
}
@ -976,6 +987,7 @@ namespace AgroBase.Models
_ControleAnterior.PercentualVelocidadeSP = _Controle.PercentualVelocidadeSP;
_ControleAnterior.Direcao = _Controle.Direcao;
_ControleAnterior.EmFreio = _Controle.EmFreio;
RedisService.AtualizarCampos(
CtxKey.DadosControle,
@ -1085,9 +1097,12 @@ namespace AgroBase.Models
if (Variaveis.OperacaoEmAndamento.Modo == ModoOperacao.Manual)
{
var Sonar = Variaveis.OperacaoEmAndamento.Sensoriamento.OperadorVisual;
bool deveParar = (Sonar.Analises.matriz_confianca?.block?.decision?.parar ?? false);
bool emMovimento = Variaveis.OperacaoEmAndamento.Controle.TiposControle.FirstOrDefault(x => x.Tipo == T_Code.Mov)?.UltimaDirecao != Direcao.Parado;
if (Variaveis.OperacaoEmAndamento.Controle.SonarAtivado && Sonar.Iniciado && Sonar.Status == StatusModulo.Operante && deveParar && emMovimento)
Sonar?.Resumo?.AtualizarStatusBloqueio(true);
if (Sonar?.Resumo?.EnviarComandoParada ?? false)
{
GeneralJoystick.EnviaComandoMotor(Keys.Space, T_Code.Mov);
}
else if (Sonar?.Resumo?.EnviarComandoRetomada ?? false)
{
GeneralJoystick.EnviaComandoMotor(Keys.Escape, T_Code.Mov);
}
@ -1528,6 +1543,7 @@ namespace AgroBase.Models
return FuncoesMatematicas.Map(RPM_Max, 0, VariaveisEquipamento.RPM_Max_Roda, 0, 100);
}
}
public bool EmFreio { get; set; } = false;
public Direcao Direcao { get; set; } = Direcao.Parado;
private TipoMovimentoDirecional _tipoMovimento = TipoMovimentoDirecional.Diagnostico;
public TipoMovimentoDirecional TipoMovimento
@ -1601,8 +1617,8 @@ namespace AgroBase.Models
_pulverizadorAutomatico = value;
}
}
//public bool MovimentoAutomatico { get; set; }
public bool MovimentoAutomatico { get; set; }
public bool FrenagemAutomatica { get; set; }
public TiposControladorDirecional TipoControleDirecional { get; set; } = TiposControladorDirecional.PID;
public List<MPCSimulacaoModel> SimulacaoMPC { get; set; } = new List<MPCSimulacaoModel>();
@ -1632,9 +1648,11 @@ namespace AgroBase.Models
SimulacaoMPC = new List<MPCSimulacaoModel>(SimulacaoMPC),
PulverizadorAutomatico = PulverizadorAutomatico,
MovimentoAutomatico = MovimentoAutomatico,
FrenagemAutomatica = FrenagemAutomatica,
heartbeat = heartbeat,
ticks_sem_resposta = ticks_sem_resposta,
Latencia = Latencia,
EmFreio = EmFreio,
};
}
}

View File

@ -24,5 +24,6 @@ namespace AgroBase.Models.Operacoes
public int QtdCamerasSolo { get; set; }
public bool MovimentoAutomatico { get; set; }
public bool PulverizadorAutomatico { get; set; }
public bool FrenagemAtuomatica { get; set; }
}
}

View File

@ -48,6 +48,7 @@ namespace AgroBase.Models.Operadores
public class ManagerWorkerMessageResponseComandoModel
{
public double percentual_velocidade { get; set; }
public bool em_freio { get; set; }
public double angulo { get; set; }
public TipoMovimentoDirecional tipo_movimento { get; set; }
public List<double[]> simulacao { get; set; }

View File

@ -17,6 +17,7 @@ namespace AgroBase.Models.Operadores
public VisualWorkerMessageAnaliseModel Analises { get; set; } = new VisualWorkerMessageAnaliseModel();
public VisualWorkerMessageIMUModel Imu { get; set; } = new VisualWorkerMessageIMUModel();
public StatusModulo Status { get; set; }
public VisualWorkerResumoModel Resumo { get; set; }
public VisualWorkerModel Clone()
{
@ -30,7 +31,8 @@ namespace AgroBase.Models.Operadores
Analises = Analises?.Clone(),
Imu = Imu?.Clone(),
UltimaMensagem = UltimaMensagem,
Status = Status
Status = Status,
Resumo = Resumo?.Clone()
};
}
@ -43,10 +45,65 @@ namespace AgroBase.Models.Operadores
CameraFrames = new Dictionary<CameraFrameType, OAKCameraFrameModel>();
Analises = new VisualWorkerMessageAnaliseModel();
Imu = new VisualWorkerMessageIMUModel();
Resumo = new VisualWorkerResumoModel();
Status = StatusModulo.Desconectado;
}
}
public class VisualWorkerResumoModel
{
public bool ObstaculoDetectado { get; set; } = false;
public bool DeveParar { get; set; } = false;
public bool EnviarComandoParada { get; set; } = false;
public bool EnviarComandoRetomada { get; set; } = false;
private bool _comandoParadaEnviado { get; set; } = false;
public void AtualizarStatusBloqueio(bool consideraEmMovimento)
{
var Sonar = Variaveis.OperacaoEmAndamento.Sensoriamento.OperadorVisual;
ObstaculoDetectado = (Sonar.Analises?.matriz_confianca?.block?.decision?.parar ?? false);
if (!Variaveis.OperacaoEmAndamento.Controle.SonarAtivado)
{
_comandoParadaEnviado = false;
DeveParar = false;
EnviarComandoParada = false;
EnviarComandoRetomada = false;
}
else
{
List<Direcao> _direcoesInterromperMovimento = new List<Direcao> { Direcao.Frente, Direcao.Tras };
Direcao _ultimaDirecaoControle = Variaveis.OperacaoEmAndamento.Controle.TiposControle.FirstOrDefault(x => x.Tipo == T_Code.Mov)?.UltimaDirecao ?? Direcao.Parado;
bool _carroEmMovimento = _direcoesInterromperMovimento.Contains(_ultimaDirecaoControle);
bool emMovimento = consideraEmMovimento ? _carroEmMovimento : true;
DeveParar = Sonar.Status == StatusModulo.Operante && ObstaculoDetectado;
EnviarComandoParada = DeveParar && emMovimento;
if (EnviarComandoParada)
{
_comandoParadaEnviado = true;
}
EnviarComandoRetomada = !ObstaculoDetectado && _comandoParadaEnviado;
if (EnviarComandoRetomada)
{
_comandoParadaEnviado = false;
}
}
}
public VisualWorkerResumoModel Clone()
{
return new VisualWorkerResumoModel()
{
ObstaculoDetectado = ObstaculoDetectado,
DeveParar = DeveParar,
EnviarComandoParada = EnviarComandoParada,
EnviarComandoRetomada = EnviarComandoRetomada,
_comandoParadaEnviado = _comandoParadaEnviado,
};
}
}
public class VisualWorkerDadosModel
{
public bool DesvioNecessario { get; set; }

View File

@ -696,6 +696,7 @@ namespace AgroBase.Models
var dictParams = JObject.Parse(controleStr);
dictParams.TryGetValue("angulo_sp", out var _angulo);
dictParams.TryGetValue("velocidade_sp", out var _velocidade);
dictParams.TryGetValue("em_freio", out var _em_freio);
dictParams.TryGetValue("tipo_movimento_direcional", out var _movimento);
dictParams.TryGetValue("simulacao", out var _simulacao);
dictParams.TryGetValue("heartbeat", out var _heartbeat);
@ -704,6 +705,7 @@ namespace AgroBase.Models
{
angulo = Convert.ToDouble(_angulo),
percentual_velocidade = Convert.ToDouble(_velocidade),
em_freio = Convert.ToBoolean(_em_freio),
tipo_movimento = (TipoMovimentoDirecional)Convert.ToInt32(_movimento),
simulacao = JsonConvert.DeserializeObject<List<double[]>>((_simulacao ?? "").ToString()),
heartbeat = Convert.ToInt32(_heartbeat),
@ -718,13 +720,14 @@ namespace AgroBase.Models
DateTime agora = DateTime.Now;
var _Controle = Variaveis.OperacaoEmAndamento.Controle;
bool comandoMudou = (_Controle.Angulo != novoComando.angulo || _Controle.PercentualVelocidadeSP != novoComando.percentual_velocidade || _Controle.TipoMovimento != novoComando.tipo_movimento);
bool comandoMudou = (_Controle.Angulo != novoComando.angulo || _Controle.PercentualVelocidadeSP != novoComando.percentual_velocidade || _Controle.TipoMovimento != novoComando.tipo_movimento || _Controle.EmFreio != novoComando.em_freio);
bool mangerDestravou = (_Controle.ticks_sem_resposta.AddMilliseconds(min_ticks_sem_resposta) < agora && novoComando.heartbeat != _Controle.heartbeat);
if (novoComando != null && (comandoMudou || mangerDestravou))
{
_Controle.Angulo = novoComando.angulo;
_Controle.TipoMovimento = novoComando.tipo_movimento;
_Controle.PercentualVelocidadeSP = novoComando.percentual_velocidade;
_Controle.EmFreio = novoComando.em_freio;
_Controle.SimulacaoMPC = novoComando.simulacao?.Select(x => new MPCSimulacaoModel() { latitude = x[0], longitude = x[1], orientacao = x[2] }).ToList() ?? new List<MPCSimulacaoModel>();
_Controle.Latencia = novoComando.latencia;
Variaveis.OperacaoEmAndamento.AtualizaInformacoesControleOperacao();

View File

@ -6,7 +6,7 @@ namespace AgroBase.Services
{
public class CanManager
{
public static bool UseCanSerial = false;
public static bool UseCanSerial = true;
private static CanServiceWaveshare CanWaveshare = new CanServiceWaveshare();
private static CanServiceSerial CanSerial = new CanServiceSerial();

View File

@ -8,7 +8,6 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using static AgroBase.Models.Enums;
using static AgroBase.Services.LoRaEspService;
namespace AgroBase.Services
{
@ -102,36 +101,42 @@ namespace AgroBase.Services
_PortaCAN.DiscardInBuffer();
_PortaCAN.DiscardOutBuffer();
UltimoRx = DateTime.Now;
UltimoTx = DateTime.Now;
tmrOuvirCAN?.Dispose();
tmrOuvirCAN = new AsyncTaskTimerModel("tmrOuvirCAN", OuvirCAN, 1);
tmrOuvirCAN.Start();
tmrEnviarCAN?.Dispose();
tmrEnviarCAN = new AsyncTaskTimerModel("tmrEnviarCAN", EnviarCAN, 3);
tmrEnviarCAN.Start();
tmrProcessarCAN?.Dispose();
tmrProcessarCAN = new AsyncTaskTimerModel("tmrProcessarCAN", ProcessarCAN, 5);
tmrProcessarCAN.Start();
IsConnected = true;
}
UltimoRx = DateTime.Now;
UltimoTx = DateTime.Now;
tmrOuvirCAN?.Dispose();
tmrOuvirCAN = new AsyncTaskTimerModel("tmrOuvirCAN", OuvirCAN, 1);
tmrOuvirCAN.Start();
tmrEnviarCAN?.Dispose();
tmrEnviarCAN = new AsyncTaskTimerModel("tmrEnviarCAN", EnviarCAN, 3);
tmrEnviarCAN.Start();
tmrProcessarCAN?.Dispose();
tmrProcessarCAN = new AsyncTaskTimerModel("tmrProcessarCAN", ProcessarCAN, 5);
tmrProcessarCAN.Start();
IsConnected = true;
}
if (_PortaCAN != null && !_PortaCAN.IsOpen)
lock (_lock)
{
_PortaCAN.Open();
if (_PortaCAN != null && !_PortaCAN.IsOpen)
{
_PortaCAN.Open();
}
}
return IsConnected;
}
catch (Exception ex)
{
_PortaCAN = null;
lock (_lock)
{
_PortaCAN = null;
}
return false;
}
}
@ -434,14 +439,17 @@ namespace AgroBase.Services
private bool EnviarComando(string comando)
{
if (_PortaCAN?.IsOpen == true)
lock (_lock)
{
_PortaCAN.Write(comando);
//Console.WriteLine($"[CAN] Frame enviado: {comando}");
UltimoTx = DateTime.Now;
return true;
if (_PortaCAN?.IsOpen == true)
{
_PortaCAN.Write(comando);
//Console.WriteLine($"[CAN] Frame enviado: {comando}");
UltimoTx = DateTime.Now;
return true;
}
return false;
}
return false;
}
private void LimparMensagensAntigas()
@ -473,16 +481,7 @@ namespace AgroBase.Services
UltimoRx = Agora;
UltimoTx = Agora;
MostrarLog("Muito tempo sem receber novos dados, reiniciando conexao CAN...", 0);
try { _PortaCAN?.Close(); } catch { }
try
{
_PortaCAN?.Open();
EnviarComando("C\r"); Thread.Sleep(50);
EnviarComando("Z0\r"); Thread.Sleep(50);
EnviarComando(ComandoBitRate(_bitRate)); Thread.Sleep(50);
EnviarComando("O\r"); Thread.Sleep(50);
}
catch { }
ReabrirPortaSegura();
}
}
@ -556,8 +555,6 @@ namespace AgroBase.Services
}
}
private string ComandoBitRate(int rate)
{
switch (rate)
@ -585,5 +582,37 @@ namespace AgroBase.Services
}
}
private void ReabrirPortaSegura()
{
tmrEnviarCAN?.Stop();
tmrOuvirCAN?.Stop();
tmrProcessarCAN?.Stop();
lock (_LockMensagens)
{
Mensagens.Clear();
}
lock (_lock)
{
try { _PortaCAN?.Close(); } catch { }
try
{
_PortaCAN?.Open();
_PortaCAN.DiscardInBuffer();
_PortaCAN.DiscardOutBuffer();
EnviarComando("C\r"); Thread.Sleep(50);
EnviarComando("Z0\r"); Thread.Sleep(50);
EnviarComando(ComandoBitRate(_bitRate)); Thread.Sleep(50);
EnviarComando("O\r"); Thread.Sleep(50);
}
catch { /* log */ }
}
tmrEnviarCAN?.Start();
tmrOuvirCAN?.Start();
tmrProcessarCAN?.Start();
}
}
}

View File

@ -39,10 +39,7 @@ namespace AgroBase.Services
public List<(int, CanMessagePosicaoDados, byte[])> ProtocoloConfiguracao(PinoutDataModel Pinout, bool conectar)
{
List<byte> config1 = new List<byte>()
{
Variaveis.LoraBaseParametros?.address ?? 0x01
};
List<byte> config1 = new List<byte>();
var _pinout = Pinout.Clone();
_pinout.Pinos = _pinout.Pinos.Where(x => x.ComponenteID == ID).ToList();
if (_pinout.Pinos.Count > 0)
@ -53,6 +50,7 @@ namespace AgroBase.Services
List<byte> config2 = new List<byte>
{
Variaveis.LoraBaseParametros?.address ?? 0x01,
ParametrosSet.address,
ParametrosSet.baudAndAirRate,
ParametrosSet.packetSizeAndPower,

View File

@ -271,7 +271,8 @@ namespace AgroBase.Services.Operadores
RedisService.AtualizarCampos(
CtxKey.DadosControle,
("pulverizador_automatico", Variaveis.OperacaoEmAndamento.Controle.PulverizadorAutomatico),
("movimento_automatico", Variaveis.OperacaoEmAndamento.Controle.MovimentoAutomatico)
("movimento_automatico", Variaveis.OperacaoEmAndamento.Controle.MovimentoAutomatico),
("frenagem_automatica", Variaveis.OperacaoEmAndamento.Controle.FrenagemAutomatica)
);
}

View File

@ -55,6 +55,7 @@ namespace AgroBase.Services.Operadores
{
dictParams.TryGetValue("angulo_sp", out object _angulo);
dictParams.TryGetValue("velocidade_sp", out object _velocidade);
dictParams.TryGetValue("em_freio", out object _em_freio);
dictParams.TryGetValue("tipo_movimento_direcional", out object _movimento);
dictParams.TryGetValue("simulacao", out object _simulacao);
dictParams.TryGetValue("heartbeat", out object _heartbeat);
@ -62,6 +63,7 @@ namespace AgroBase.Services.Operadores
{
angulo = Convert.ToDouble(_angulo),
percentual_velocidade = Convert.ToDouble(_velocidade),
em_freio = Convert.ToBoolean(_em_freio),
tipo_movimento = (Enums.TipoMovimentoDirecional)Convert.ToInt32(_movimento),
simulacao = JsonConvert.DeserializeObject<List<double[]>>((_simulacao ?? "").ToString()),
heartbeat = Convert.ToInt32(_heartbeat)
@ -73,12 +75,13 @@ namespace AgroBase.Services.Operadores
}
var _Controle = Variaveis.OperacaoEmAndamento.Controle;
bool comandoMudou = (_Controle.Angulo != novoComando.angulo || _Controle.PercentualVelocidadeSP != novoComando.percentual_velocidade || _Controle.TipoMovimento != novoComando.tipo_movimento);
bool comandoMudou = (_Controle.Angulo != novoComando.angulo || _Controle.PercentualVelocidadeSP != novoComando.percentual_velocidade || _Controle.TipoMovimento != novoComando.tipo_movimento || _Controle.EmFreio != novoComando.em_freio);
if (novoComando != null && comandoMudou)
{
_Controle.Angulo = novoComando.angulo;
_Controle.TipoMovimento = novoComando.tipo_movimento;
_Controle.PercentualVelocidadeSP = novoComando.percentual_velocidade;
_Controle.EmFreio = novoComando.em_freio;
_Controle.SimulacaoMPC = novoComando.simulacao?.Select(x => new MPCSimulacaoModel() { latitude = x[0], longitude = x[1], orientacao = x[2] }).ToList() ?? new List<MPCSimulacaoModel>();
Variaveis.OperacaoEmAndamento.AtualizaInformacoesControleOperacao();
}

View File

@ -39,6 +39,7 @@ namespace AgroBase.Services.Operadores
if (pronto())
{
MostrarLog("Processamento iniciado com sucesso");
DadosLeitura.Iniciado = true;
return true;
}

View File

@ -1,12 +1,5 @@
{
"epochs": [ {
"calculation_time": "13399827811771001",
"config_version": 0,
"model_version": "0",
"padded_top_topics_start_index": 0,
"taxonomy_version": 0,
"top_topics_and_observing_domains": [ ]
}, {
"calculation_time": "13400595140854297",
"config_version": 0,
"model_version": "0",
@ -27,7 +20,14 @@
"padded_top_topics_start_index": 0,
"taxonomy_version": 0,
"top_topics_and_observing_domains": [ ]
}, {
"calculation_time": "13402425506182172",
"config_version": 0,
"model_version": "0",
"padded_top_topics_start_index": 0,
"taxonomy_version": 0,
"top_topics_and_observing_domains": [ ]
} ],
"hex_encoded_hmac_key": "40F346D3248C3AFDF2BEE1FE496DBD32F7CED6E5AE98B881ABC421AA7E7B5642",
"next_scheduled_calculation_time": "13402424980889277"
"next_scheduled_calculation_time": "13403030306182389"
}

View File

@ -1,3 +1,3 @@
2025/09/09-15:46:04.235 680c Reusing MANIFEST C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Local Storage\leveldb/MANIFEST-000001
2025/09/09-15:46:04.241 680c Recovering log #3
2025/09/09-15:46:04.244 680c Reusing old log C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Local Storage\leveldb/000003.log
2025/09/15-17:35:19.244 585c Reusing MANIFEST C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Local Storage\leveldb/MANIFEST-000001
2025/09/15-17:35:19.253 585c Recovering log #3
2025/09/15-17:35:19.256 585c Reusing old log C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Local Storage\leveldb/000003.log

View File

@ -1,3 +1,3 @@
2025/09/09-15:09:11.525 3c58 Reusing MANIFEST C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Local Storage\leveldb/MANIFEST-000001
2025/09/09-15:09:11.532 3c58 Recovering log #3
2025/09/09-15:09:11.536 3c58 Reusing old log C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Local Storage\leveldb/000003.log
2025/09/15-15:57:42.267 2cc0 Reusing MANIFEST C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Local Storage\leveldb/MANIFEST-000001
2025/09/15-15:57:42.276 2cc0 Recovering log #3
2025/09/15-15:57:42.279 2cc0 Reusing old log C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Local Storage\leveldb/000003.log

View File

@ -1 +1 @@
{"net":{"http_server_properties":{"servers":[{"alternative_service":[{"advertised_alpns":["h3"],"expiration":"13402003564945866","port":443,"protocol_str":"quic"}],"anonymization":["DAAAAAcAAABmaWxlOi8vAA==",false,0],"network_stats":{"srtt":37908},"server":"https://tile.openstreetmap.org","supports_spdy":true}],"supports_quic":{"address":"2804:d78:6a8:5d00:593a:511a:74dd:807b","used_quic":true},"version":5},"network_qualities":{"CAASABiAgICA+P////8B":"4G","CAESABiAgICA+P////8B":"4G","CAISABiAgICA+P////8B":"4G","CAYSABiAgICA+P////8B":"Offline"}}}
{"net":{"http_server_properties":{"servers":[{"alternative_service":[{"advertised_alpns":["h3"],"expiration":"13402522885929406","port":443,"protocol_str":"quic"}],"anonymization":["DAAAAAcAAABmaWxlOi8vAA==",false,0],"network_stats":{"srtt":27069},"server":"https://tile.openstreetmap.org","supports_spdy":true}],"supports_quic":{"address":"2804:d78:67d:1400:60e0:3daf:3723:e31f","used_quic":true},"version":5},"network_qualities":{"CAASABiAgICA+P////8B":"4G","CAESABiAgICA+P////8B":"4G","CAISABiAgICA+P////8B":"4G","CAYSABiAgICA+P////8B":"Offline"}}}

View File

@ -1 +1 @@
{"sts":[{"expiry":1788979564.946284,"host":"bWGAftl61rqoc0YzqPncsLvQQh/iC2Bdp3ejUeGC83w=","mode":"force-https","sts_include_subdomains":true,"sts_observed":1757443564.946287}],"version":2}
{"sts":[{"expiry":1789498662.856284,"host":"bWGAftl61rqoc0YzqPncsLvQQh/iC2Bdp3ejUeGC83w=","mode":"force-https","sts_include_subdomains":true,"sts_observed":1757962662.856286}],"version":2}

File diff suppressed because one or more lines are too long

View File

@ -1,3 +1,3 @@
2025/09/09-15:58:01.007 680c Reusing MANIFEST C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Session Storage/MANIFEST-000001
2025/09/09-15:58:01.008 680c Recovering log #3
2025/09/09-15:58:01.011 680c Reusing old log C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Session Storage/000003.log
2025/09/15-17:36:02.774 585c Reusing MANIFEST C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Session Storage/MANIFEST-000001
2025/09/15-17:36:02.775 585c Recovering log #3
2025/09/15-17:36:02.778 585c Reusing old log C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Session Storage/000003.log

View File

@ -1,3 +1,3 @@
2025/09/09-15:44:08.465 3c58 Reusing MANIFEST C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Session Storage/MANIFEST-000001
2025/09/09-15:44:08.467 3c58 Recovering log #3
2025/09/09-15:44:08.470 3c58 Reusing old log C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Session Storage/000003.log
2025/09/15-16:16:16.964 2cc0 Reusing MANIFEST C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Session Storage/MANIFEST-000001
2025/09/15-16:16:16.966 2cc0 Recovering log #3
2025/09/15-16:16:16.969 2cc0 Reusing old log C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Session Storage/000003.log

View File

@ -1,3 +1,3 @@
2025/09/09-15:46:04.142 58d8 Reusing MANIFEST C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Site Characteristics Database/MANIFEST-000001
2025/09/09-15:46:04.143 58d8 Recovering log #7
2025/09/09-15:46:04.144 58d8 Reusing old log C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Site Characteristics Database/000007.log
2025/09/15-17:35:19.173 1788 Reusing MANIFEST C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Site Characteristics Database/MANIFEST-000001
2025/09/15-17:35:19.176 1788 Recovering log #7
2025/09/15-17:35:19.176 1788 Reusing old log C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Site Characteristics Database/000007.log

View File

@ -1,3 +1,3 @@
2025/09/09-15:09:11.448 1b60 Reusing MANIFEST C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Site Characteristics Database/MANIFEST-000001
2025/09/09-15:09:11.449 1b60 Recovering log #7
2025/09/09-15:09:11.450 1b60 Reusing old log C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Site Characteristics Database/000007.log
2025/09/15-15:57:42.197 4e88 Reusing MANIFEST C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Site Characteristics Database/MANIFEST-000001
2025/09/15-15:57:42.199 4e88 Recovering log #7
2025/09/15-15:57:42.199 4e88 Reusing old log C:\ZendionInc\agrobot_base\AgroBase\AgroBase\bin\x64\Debug\AgroBase.exe.WebView2\EBWebView\Default\Site Characteristics Database/000007.log

View File

@ -1 +1 @@
140.0.3485.54
140.0.3485.66

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
{"hashes":{"00AF3F07B5ABB71F6D30337E1EEF62FA280F06EF19485C0CF6B72171F92CCC0A":{"appid":"kpfehajjjbbcifeehjgfgnabifknmdad","fp":"1.00AF3F07B5ABB71F6D30337E1EEF62FA280F06EF19485C0CF6B72171F92CCC0A"},"452064dcff76e03e0e81b4bb3c48ab1c432e040094f7546c7261a90d4a1c1bbf":{"appid":"fgbafbciocncjfbbonhocjaohoknlaco","fp":""},"4B81B4DF3AD971287E1AE02C449344FCFA5D20431DE17B2BA8854CC9CDCE4089":{"appid":"ahmaebgpfccdhgidjaidaoojjcijckba","fp":"1.4B81B4DF3AD971287E1AE02C449344FCFA5D20431DE17B2BA8854CC9CDCE4089"},"8482d8cbe30fdc7c561f12ce566b64102191a99798dae98132c35714020e1aad":{"appid":"jbfaflocpnkhbgcijpkiafdpbjkedane","fp":""},"89f43cb3df807293de2772d5f01ac2fc1482b38ccc8fdaee859b80642b7a0487":{"appid":"pghocgajpebopihickglahgebcmkcekh","fp":""},"95FD9D48E4FC245A3F3A99A3A16ECD1355050BA3F4AFC555F19A97C7F9B49677":{"appid":"ohckeflnhegojcjlcpbfpciadgikcohk","fp":"1.95FD9D48E4FC245A3F3A99A3A16ECD1355050BA3F4AFC555F19A97C7F9B49677"},"A81D1959892AE4180554347DF1B97834ABBA2E1A5E6B9AEBA000ECEA26EABECC":{"appid":"fppmbhmldokgmleojlplaaodlkibgikh","fp":"1.A81D1959892AE4180554347DF1B97834ABBA2E1A5E6B9AEBA000ECEA26EABECC"},"A99D66CFCE8CA170740CE0403956F4DFAF4683829A89F4B7AD9C95303871E284":{"appid":"eeobbhfgfagbclfofmgbdfoicabjdbkn","fp":"1.A99D66CFCE8CA170740CE0403956F4DFAF4683829A89F4B7AD9C95303871E284"},"b987bdc4f2ad2a409b964921d4a5db1cdbe07f9c98f868293b4cc32acdc42cec":{"appid":"alpjnmnfbgfkmmpcfpejmmoebdndedno","fp":""},"bcb93cba8636743d1fbd32be3bd8ce8ff602323895bf4d136c26b9bc64b0a6a4":{"appid":"ndikpojcjlepofdkaaldkinkjbeeebkl","fp":""},"fa29a6d5775ff340900a65b39b02fc8b4b77d403c048d8debf22f2f5d09c61a0":{"appid":"oankkpibpaokgecfckkdkgaoafllipag","fp":""}}}
{"hashes":{"00AF3F07B5ABB71F6D30337E1EEF62FA280F06EF19485C0CF6B72171F92CCC0A":{"appid":"kpfehajjjbbcifeehjgfgnabifknmdad","fp":"1.00AF3F07B5ABB71F6D30337E1EEF62FA280F06EF19485C0CF6B72171F92CCC0A"},"452064dcff76e03e0e81b4bb3c48ab1c432e040094f7546c7261a90d4a1c1bbf":{"appid":"fgbafbciocncjfbbonhocjaohoknlaco","fp":""},"4B81B4DF3AD971287E1AE02C449344FCFA5D20431DE17B2BA8854CC9CDCE4089":{"appid":"ahmaebgpfccdhgidjaidaoojjcijckba","fp":"1.4B81B4DF3AD971287E1AE02C449344FCFA5D20431DE17B2BA8854CC9CDCE4089"},"89f43cb3df807293de2772d5f01ac2fc1482b38ccc8fdaee859b80642b7a0487":{"appid":"pghocgajpebopihickglahgebcmkcekh","fp":""},"95FD9D48E4FC245A3F3A99A3A16ECD1355050BA3F4AFC555F19A97C7F9B49677":{"appid":"ohckeflnhegojcjlcpbfpciadgikcohk","fp":"1.95FD9D48E4FC245A3F3A99A3A16ECD1355050BA3F4AFC555F19A97C7F9B49677"},"A81D1959892AE4180554347DF1B97834ABBA2E1A5E6B9AEBA000ECEA26EABECC":{"appid":"fppmbhmldokgmleojlplaaodlkibgikh","fp":"1.A81D1959892AE4180554347DF1B97834ABBA2E1A5E6B9AEBA000ECEA26EABECC"},"A99D66CFCE8CA170740CE0403956F4DFAF4683829A89F4B7AD9C95303871E284":{"appid":"eeobbhfgfagbclfofmgbdfoicabjdbkn","fp":"1.A99D66CFCE8CA170740CE0403956F4DFAF4683829A89F4B7AD9C95303871E284"},"b987bdc4f2ad2a409b964921d4a5db1cdbe07f9c98f868293b4cc32acdc42cec":{"appid":"alpjnmnfbgfkmmpcfpejmmoebdndedno","fp":""},"bcb93cba8636743d1fbd32be3bd8ce8ff602323895bf4d136c26b9bc64b0a6a4":{"appid":"ndikpojcjlepofdkaaldkinkjbeeebkl","fp":""},"fa29a6d5775ff340900a65b39b02fc8b4b77d403c048d8debf22f2f5d09c61a0":{"appid":"oankkpibpaokgecfckkdkgaoafllipag","fp":""},"ff87fddb54d7bdc8ab8c2697bc92337c914803fb22cd32e445389e8042159ce9":{"appid":"jbfaflocpnkhbgcijpkiafdpbjkedane","fp":""}}}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -17,7 +17,7 @@
<meta name="viewport" content="width=device-width,
initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<style>
#map_0d47d5844cb03a1b59409c5f2e45d89e {
#map_413b17cf3f148cf9e5299ab727cb1cef {
position: relative;
width: 100.0%;
height: 100.0%;
@ -54,14 +54,14 @@
<body>
<div class="folium-map" id="map_0d47d5844cb03a1b59409c5f2e45d89e" ></div>
<div class="folium-map" id="map_413b17cf3f148cf9e5299ab727cb1cef" ></div>
</body>
<script>
var map_0d47d5844cb03a1b59409c5f2e45d89e = L.map(
"map_0d47d5844cb03a1b59409c5f2e45d89e",
var map_413b17cf3f148cf9e5299ab727cb1cef = L.map(
"map_413b17cf3f148cf9e5299ab727cb1cef",
{
center: [0.0, 0.0],
crs: L.CRS.EPSG3857,
@ -77,26 +77,6 @@
var tile_layer_833f84bdc2b417e2650cc33bb5c7c348 = L.tileLayer(
"https://tile.openstreetmap.org/{z}/{x}/{y}.png",
{
"minZoom": 0,
"maxZoom": 19,
"maxNativeZoom": 19,
"noWrap": false,
"attribution": "\u0026copy; \u003ca href=\"https://www.openstreetmap.org/copyright\"\u003eOpenStreetMap\u003c/a\u003e contributors",
"subdomains": "abc",
"detectRetina": false,
"tms": false,
"opacity": 1,
}
);
tile_layer_833f84bdc2b417e2650cc33bb5c7c348.addTo(map_0d47d5844cb03a1b59409c5f2e45d89e);
</script>
<script>
@ -116,7 +96,7 @@
}
trajeto_json_add({"features": []});
trajeto_json.addTo(map_0d47d5844cb03a1b59409c5f2e45d89e);
trajeto_json.addTo(map_413b17cf3f148cf9e5299ab727cb1cef);
function adicionarGeometria(novaGeometria) {
trajeto_json.addData(novaGeometria);
@ -179,9 +159,9 @@
var marcadorEquipamento = L.marker([0, 0], {
icon: customIcon
}).addTo(map_0d47d5844cb03a1b59409c5f2e45d89e);
}).addTo(map_413b17cf3f148cf9e5299ab727cb1cef);
var marcadorBase = L.marker([0, 0], {}).addTo(map_0d47d5844cb03a1b59409c5f2e45d89e);
var marcadorBase = L.marker([0, 0], {}).addTo(map_413b17cf3f148cf9e5299ab727cb1cef);
var icon = L.AwesomeMarkers.icon(
{"extraClasses": "fa-rotate-0", "icon": "info-sign", "iconColor": "white", "markerColor": "red", "prefix": "glyphicon"}
);
@ -246,7 +226,7 @@
}
if (foco) {
map_0d47d5844cb03a1b59409c5f2e45d89e.setView(novaPosicao, map_0d47d5844cb03a1b59409c5f2e45d89e.getZoom());
map_413b17cf3f148cf9e5299ab727cb1cef.setView(novaPosicao, map_413b17cf3f148cf9e5299ab727cb1cef.getZoom());
}
}
@ -268,7 +248,7 @@
marcadorDinamico.setRotationAngle(angulo);
adicionarCoordenada("Tj", [novaLongitude, novaLatitude]);
map_0d47d5844cb03a1b59409c5f2e45d89e.setView(novaPosicao, map_0d47d5844cb03a1b59409c5f2e45d89e.getZoom());*/
map_413b17cf3f148cf9e5299ab727cb1cef.setView(novaPosicao, map_413b17cf3f148cf9e5299ab727cb1cef.getZoom());*/
});
function calcularOrientacao(P1latitude, P1longitude, P2latitude, P2longitude) {

File diff suppressed because one or more lines are too long

View File

@ -29,7 +29,7 @@ def definir_comando(pid: PIDAdaptativo, envio_necessario: bool):
if not _snapshot_vw:
visual_worker_atualizado = False
else:
visual_worker_atualizado = (time.time() - _snapshot_vw.get("ts", 0.0) <= 0.15)
visual_worker_atualizado = (time.perf_counter() - _snapshot_vw.get("ts", 0.0) <= 1.0)
if visual_worker_atualizado:
custo, conf, anom, nav = unpack_snapshot(_snapshot_vw)
dists = _snapshot_vw.get("row_dist_m", None)
@ -169,7 +169,7 @@ def definir_comando(pid: PIDAdaptativo, envio_necessario: bool):
except Exception as e:
mostrar_log(f"❌ Erro ao definir comando direcional: {e}")
def _comando_direcional_parado(definido: bool):
def _comando_direcional_parado(definido: bool, frear: bool = False):
try:
angulo, tipo = comando_parado()
_cmd = {
@ -180,7 +180,8 @@ def _comando_direcional_parado(definido: bool):
"latencia": 0.0,
"angulo": angulo,
"tipo": tipo.value,
"simulacao": []
"simulacao": [],
"frear": frear
}
return _cmd
except Exception as e:
@ -229,7 +230,7 @@ def _regras_taticas(contexto):
if decision.get("parar", False):
mostrar_log(f"🟥 Parada necessaria por {reason}.")
return _comando_direcional_parado(True)
return _comando_direcional_parado(True, frear=True)
# motivo narrow: não para, mas dá dica lateral
if isinstance(block, dict) and reason == "narrow":

View File

@ -1,9 +1,10 @@
from shared.enums import ModoOperacao, StatusOperacao, StatusCarroMapa
import time
from shared.enums import ModoOperacao, StatusModulo, StatusOperacao, StatusCarroMapa, T_Code
from shared.contexto_global_redis import ContextoGlobalRedis, CtxKey
from manager_worker.config import mostrar_log
from manager_worker.filtros import FiltroVelocidade
def definir_comando(parada_necessaria: bool, erro: bool, filtro_vel: FiltroVelocidade):
def definir_comando(parada_necessaria: bool, frear: bool, erro: bool, filtro_vel: FiltroVelocidade):
try:
_operacao = ContextoGlobalRedis.get_operacao()
status_operacao = StatusOperacao(_operacao.get("status", StatusOperacao.NaoIniciado.value))
@ -11,15 +12,28 @@ def definir_comando(parada_necessaria: bool, erro: bool, filtro_vel: FiltroVeloc
if erro:
mostrar_log("🟥 Movimento parado: erro ao definir comando direcional.")
return 0.0
return _montar_comando_retorno(0.0, False)
if parada_necessaria:
mostrar_log("🟥 Movimento parado: direcional sem possibilidade de desvio.")
return 0.0
frenagem_automatica = ContextoGlobalRedis.get_controle().get("frenagem_automatica", False)
deve_frear = frenagem_automatica and frear
return _montar_comando_retorno(0.0, deve_frear)
if (status_operacao != StatusOperacao.EmAndamento) or finalizando:
mostrar_log(f"🟥 Movimento parado: operação não está em andamento ou finalizando: {status_operacao.name}")
return 0.0
return _montar_comando_retorno(0.0, False)
_dados_ww = ContextoGlobalRedis.get(CtxKey.DadosWeedWorker, {}).get("analise", {})
_snr = ContextoGlobalRedis.get_modulo(T_Code.Snr)
sonar_ativado = _operacao.get("Snr", {}).get("sonar_ativado", False)
visual_worker_operante = (_snr.get("saude", {}).get("status", StatusModulo.DESCONECTADO.value)) == StatusModulo.OPERANTE.value
analise_deteccao_atualizada = (time.perf_counter() - _dados_vw.get("matriz_confianca", {}).get("ts", 10.0) <= 1.0)
obstaculo_detectado = _dados_vw.get("matriz_confianca", {}).get("block", {}).get("decision", {}).get("parar", False) if analise_deteccao_atualizada else False
if (sonar_ativado and visual_worker_operante and obstaculo_detectado):
mostrar_log(f"🟥 Movimento parado: obstaculo proximo detectado no sonar")
return _montar_comando_retorno(0.0, True)
op_modo = ModoOperacao(_operacao.get("modo", ModoOperacao.NaoDefinido.value))
_contexto = ContextoGlobalRedis.get_contexto()
@ -27,7 +41,7 @@ def definir_comando(parada_necessaria: bool, erro: bool, filtro_vel: FiltroVeloc
pulverizador_automatico = _controle.get("pulverizador_automatico", False)
#ervas_no_radar = _contexto.get("Gerais", {}).get("ervas_no_radar", False)
#percentual_ervas_no_radar = (_contexto.get("Gerais", {}).get("percentual_ervas_no_radar", 0)) * 100.0
_dados_ww = ContextoGlobalRedis.get(CtxKey.DadosWeedWorker, {}).get("analise", {})
ervas_no_radar = _dados_ww.get("ervas_no_radar", False)
percentual_ervas_no_radar = _dados_ww.get("estatisticas", {}).get("ema_global", 0.0)
@ -41,6 +55,7 @@ def definir_comando(parada_necessaria: bool, erro: bool, filtro_vel: FiltroVeloc
status_carro = StatusCarroMapa.Parado
erro = 0
manobrando = False
reduzir_para_pulverizar = False
if op_modo == ModoOperacao.MapaGPS:
_trajetoria = _contexto.get("Trajetoria", {})
@ -64,7 +79,8 @@ def definir_comando(parada_necessaria: bool, erro: bool, filtro_vel: FiltroVeloc
elif status_carro in [StatusCarroMapa.EntrandoRua, StatusCarroMapa.SaindoRua, StatusCarroMapa.Manobrando]:
velocidade_sp = min(vel_min, vel_com_ervas)
elif status_carro == StatusCarroMapa.CaminhandoRua:
if pulverizador_automatico and ervas_no_radar and percentual_ervas_no_radar > ervas_min_percenet:
reduzir_para_pulverizar = pulverizador_automatico and ervas_no_radar and percentual_ervas_no_radar > ervas_min_percenet
if reduzir_para_pulverizar:
velocidade_sp = vel_com_ervas
else:
velocidade_sp = calcular_velocidade_relativa(vel_com_ervas, vel_sem_ervas, ang_max, erro)
@ -72,14 +88,14 @@ def definir_comando(parada_necessaria: bool, erro: bool, filtro_vel: FiltroVeloc
# Aplica limites
velocidade_sp = max(vel_com_ervas, min(vel_sem_ervas, velocidade_sp))
if velocidade_sp < 1.0:
if velocidade_sp < 1.0 or reduzir_para_pulverizar:
filtro_vel.reset(velocidade_sp)
else:
velocidade_sp = filtro_vel.filtrar(velocidade_sp)
#mostrar_log(f"🚗 Velocidade definida: {velocidade_sp:.1f}%")
return velocidade_sp
return _montar_comando_retorno(velocidade_sp, False)
except Exception as e:
mostrar_log(f"Erro ao definir o comando de movimentacao: {e}")
@ -90,3 +106,9 @@ def calcular_velocidade_relativa(vel_min, vel_max, ang_max, erro_orientacao):
faixa = vel_max - vel_min
velocidade = vel_max - (faixa * penalidade)
return round(velocidade, 2)
def _montar_comando_retorno(velocidade_sp: float, frear: bool):
return {
"velocidade": velocidade_sp,
"frear": frear
}

View File

@ -21,19 +21,20 @@ class ProcessadorEmAndamento(ProcessadorBase):
saida_min=-ang_max,
saida_max=ang_max
)
self.ultimo_comando_enviado = time.time()
self.ultimo_comando_enviado = time.perf_counter()
def processar(self):
try:
agora = time.time()
agora = time.perf_counter()
envio_necessario = (agora - self.ultimo_comando_enviado) > 0.3
comando_dir = definir_comando_dir(self.pid_dir, envio_necessario)
if comando_dir.get("enviar_comando", False):
self.ultimo_comando_enviado = agora
velocidade_sp = definir_comando_mov(comando_dir.get("parada_necessaria", False), comando_dir.get("erro", False), self.filtro_mov)
comando_mov = definir_comando_mov(comando_dir.get("parada_necessaria", False), comando_dir.get("frear", False), comando_dir.get("erro", False), self.filtro_mov)
return comando_controle(
percentual_velocidade=velocidade_sp,
percentual_velocidade=comando_mov.get("velocidade"),
frear=comando_mov.get("frear", False),
angulo=comando_dir.get("angulo"),
tipo_movimento=comando_dir.get("tipo"),
simulacao=comando_dir.get("simulacao"),

View File

@ -3,7 +3,7 @@ from shared.enums import ModoOperacao, StatusOperacao
from manager_worker.config import mostrar_log
from shared.contexto_global_redis import ContextoGlobalRedis, CtxKey
def comando_controle(percentual_velocidade: float, angulo: float, tipo_movimento: int, simulacao = [], erro: bool = False, latencia: float = 0.0):
def comando_controle(percentual_velocidade: float, frear: bool, angulo: float, tipo_movimento: int, simulacao = [], erro: bool = False, latencia: float = 0.0):
hb_atual = ContextoGlobalRedis.get_controle().get("heartbeat", 0)
if erro == False:
try:
@ -17,12 +17,14 @@ def comando_controle(percentual_velocidade: float, angulo: float, tipo_movimento
angulo_sp=angulo,
tipo_movimento_direcional=tipo_movimento,
velocidade_sp=percentual_velocidade,
em_freio=frear,
simulacao=simulacao,
heartbeat=hb_atual,
latencia=latencia
)
return {
"velocidade_sp": percentual_velocidade,
"em_freio": frear,
"angulo_sp": angulo,
"tipo_movimento_direcional": tipo_movimento,
"simulacao": simulacao,

View File

@ -126,10 +126,10 @@ def carregar_labelmap_completo(caminho):
id_para_nome[idx] = nome_classe
idx += 1
print(f"Mapa: {cor_para_id}")
print(f"Colormap RGB: {cores_rgb}")
print(f"Classes: {id_para_nome}")
print(f"Ignore RGB: {ignore_rgb}")
#print(f"Mapa: {cor_para_id}")
#print(f"Colormap RGB: {cores_rgb}")
#print(f"Classes: {id_para_nome}")
#print(f"Ignore RGB: {ignore_rgb}")
return cor_para_id, cores_rgb, id_para_nome, ignore_rgb

View File

@ -875,218 +875,222 @@ class CameraManager:
# --- NOVOS (debug/uso opcional) ---
det_cov_max, det_conf_max, det_score
"""
if class_ids is None:
class_ids = {'rua': 0, 'cana': 1, 'obs': 2}
try:
if class_ids is None:
class_ids = {'rua': 0, 'cana': 1, 'obs': 2}
# ---------- defaults detecção ----------
_det = {
# peso da penalização no custo
"w4": 0.25, # quão forte a detecção pesa no custo (0..1)
# limiar pra "bloquear" navegação só por detecção
"thr_det_block": 0.35, # se det_score >= isso, célula deixa de ser navegável
# mínimo de interseção da bbox com a célula pra considerar (fração da célula)
"min_cell_coverage": 0.10,
# confiança mínima da bbox pra considerar
"min_det_conf": 0.35,
# pesos por classe (se não souber o id, usa 1.0)
"class_weights": {}, # ex: {'person':1.0,'car':0.9,'dog':0.6}
# classes que vetam (tratadas como peso 1.0 e sem atenuação)
"veto_labels": set(["person"]),
# como combinar múltiplas bboxes na célula: "max" ou "sum_clamped"
"combine": "max",
# derrubar um pouco a conf_cell quando há detecção
"conf_drop_alpha": 0.15, # 0 = não derruba; 0.15 = derruba 15% * det_score
}
if det_params:
_det.update(det_params)
# ---------- defaults detecção ----------
_det = {
# peso da penalização no custo
"w4": 0.25, # quão forte a detecção pesa no custo (0..1)
# limiar pra "bloquear" navegação só por detecção
"thr_det_block": 0.35, # se det_score >= isso, célula deixa de ser navegável
# mínimo de interseção da bbox com a célula pra considerar (fração da célula)
"min_cell_coverage": 0.10,
# confiança mínima da bbox pra considerar
"min_det_conf": 0.35,
# pesos por classe (se não souber o id, usa 1.0)
"class_weights": {}, # ex: {'person':1.0,'car':0.9,'dog':0.6}
# classes que vetam (tratadas como peso 1.0 e sem atenuação)
"veto_labels": set(["person"]),
# como combinar múltiplas bboxes na célula: "max" ou "sum_clamped"
"combine": "max",
# derrubar um pouco a conf_cell quando há detecção
"conf_drop_alpha": 0.15, # 0 = não derruba; 0.15 = derruba 15% * det_score
}
if det_params:
_det.update(det_params)
grid_w, grid_h = grid_shape
H0, W0 = depth_mm.shape
grid_w, grid_h = grid_shape
H0, W0 = depth_mm.shape
# --- 1) Resize depth para 512x288 ---
d_small = cv2.resize(depth_mm, (512, 288), interpolation=cv2.INTER_NEAREST).astype(np.float32)
d_small[(d_small < valid_mm[0]) | (d_small > valid_mm[1])] = np.nan
# --- 1) Resize depth para 512x288 ---
d_small = cv2.resize(depth_mm, (512, 288), interpolation=cv2.INTER_NEAREST).astype(np.float32)
d_small[(d_small < valid_mm[0]) | (d_small > valid_mm[1])] = np.nan
# --- 2) Bordas da grid ---
x_edges = np.linspace(0, 512, grid_w + 1, dtype=int)
y_edges = np.linspace(0, 288, grid_h + 1, dtype=int)
# --- 2) Bordas da grid ---
x_edges = np.linspace(0, 512, grid_w + 1, dtype=int)
y_edges = np.linspace(0, 288, grid_h + 1, dtype=int)
# --- 3) Saídas ---
pct_rua = np.zeros((grid_h, grid_w), np.float32)
pct_cana = np.zeros((grid_h, grid_w), np.float32)
pct_obs = np.zeros((grid_h, grid_w), np.float32)
z_med = np.full((grid_h, grid_w), np.nan, np.float32)
depth_valid_frac = np.zeros((grid_h, grid_w), np.float32)
# --- 3) Saídas ---
pct_rua = np.zeros((grid_h, grid_w), np.float32)
pct_cana = np.zeros((grid_h, grid_w), np.float32)
pct_obs = np.zeros((grid_h, grid_w), np.float32)
z_med = np.full((grid_h, grid_w), np.nan, np.float32)
depth_valid_frac = np.zeros((grid_h, grid_w), np.float32)
# --- 3b) mapas da detecção (debug/uso) ---
det_cov_max = np.zeros((grid_h, grid_w), np.float32) # cobertura máxima (0..1)
det_conf_max = np.zeros((grid_h, grid_w), np.float32) # conf máx (0..1)
det_score = np.zeros((grid_h, grid_w), np.float32) # score combinado (0..1)
det_top_label_id = -np.ones((grid_h, grid_w), np.int32) # -1 = nenhuma
det_top_conf = np.zeros((grid_h, grid_w), np.float32) # conf da dominante
# --- 3b) mapas da detecção (debug/uso) ---
det_cov_max = np.zeros((grid_h, grid_w), np.float32) # cobertura máxima (0..1)
det_conf_max = np.zeros((grid_h, grid_w), np.float32) # conf máx (0..1)
det_score = np.zeros((grid_h, grid_w), np.float32) # score combinado (0..1)
det_top_label_id = -np.ones((grid_h, grid_w), np.int32) # -1 = nenhuma
det_top_conf = np.zeros((grid_h, grid_w), np.float32) # conf da dominante
# --- 4) grid_ref 2D ---
if grid_ref.ndim == 1:
if grid_ref.shape[0] != grid_h:
raise ValueError(f"grid_ref 1D deve ter len={grid_h}, veio {grid_ref.shape}")
Z_ref = np.repeat(grid_ref[:, None], grid_w, axis=1)
else:
Z_ref = grid_ref
if Z_ref.shape != (grid_h, grid_w):
raise ValueError(f"grid_ref 2D deve ser {(grid_h, grid_w)}, veio {Z_ref.shape}")
# --- 4) grid_ref 2D ---
if grid_ref.ndim == 1:
if grid_ref.shape[0] != grid_h:
raise ValueError(f"grid_ref 1D deve ter len={grid_h}, veio {grid_ref.shape}")
Z_ref = np.repeat(grid_ref[:, None], grid_w, axis=1)
else:
Z_ref = grid_ref
if Z_ref.shape != (grid_h, grid_w):
raise ValueError(f"grid_ref 2D deve ser {(grid_h, grid_w)}, veio {Z_ref.shape}")
# pré-slices por linha
for j in range(grid_h):
y0, y1 = y_edges[j], y_edges[j+1]
seg_row = seg_ids_512x288[y0:y1, :]
depth_row = d_small[y0:y1, :]
row_h = max(1, y1 - y0)
for i in range(grid_w):
x0, x1 = x_edges[i], x_edges[i+1]
col_w = max(1, x1 - x0)
# pré-slices por linha
for j in range(grid_h):
y0, y1 = y_edges[j], y_edges[j+1]
seg_row = seg_ids_512x288[y0:y1, :]
depth_row = d_small[y0:y1, :]
row_h = max(1, y1 - y0)
for i in range(grid_w):
x0, x1 = x_edges[i], x_edges[i+1]
col_w = max(1, x1 - x0)
seg_block = seg_row[:, x0:x1]
depth_block = depth_row[:, x0:x1]
seg_block = seg_row[:, x0:x1]
depth_block = depth_row[:, x0:x1]
n = seg_block.size
if n == 0:
continue
n = seg_block.size
if n == 0:
continue
# % por classe
n_rua = np.count_nonzero(seg_block == ClassesSegmentacao.RUA.value)
n_cana = np.count_nonzero(seg_block == ClassesSegmentacao.CANA.value)
n_obs = np.count_nonzero(seg_block == ClassesSegmentacao.OBSTACULO.value)
pct_rua[j, i] = n_rua / n
pct_cana[j, i] = n_cana / n
pct_obs[j, i] = n_obs / n
# % por classe
n_rua = np.count_nonzero(seg_block == ClassesSegmentacao.RUA.value)
n_cana = np.count_nonzero(seg_block == ClassesSegmentacao.CANA.value)
n_obs = np.count_nonzero(seg_block == ClassesSegmentacao.OBSTACULO.value)
pct_rua[j, i] = n_rua / n
pct_cana[j, i] = n_cana / n
pct_obs[j, i] = n_obs / n
# depth
vals = depth_block[~np.isnan(depth_block)]
valid = vals.size
depth_valid_frac[j, i] = valid / n
if valid >= max(int(min_valid_frac * n), 1):
z_med[j, i] = np.nanmedian(vals) / 1000.0
# depth
vals = depth_block[~np.isnan(depth_block)]
valid = vals.size
depth_valid_frac[j, i] = valid / n
if valid >= max(int(min_valid_frac * n), 1):
z_med[j, i] = np.nanmedian(vals) / 1000.0
# --- 6) Confiança ---
t0, t1 = conf_params
conf_seg = np.maximum.reduce([pct_rua, pct_cana, pct_obs])
conf_dep = np.clip((depth_valid_frac - t0) / (t1 - t0), 0.0, 1.0)
conf_cell = 0.6 * conf_seg + 0.4 * conf_dep
# --- 6) Confiança ---
t0, t1 = conf_params
conf_seg = np.maximum.reduce([pct_rua, pct_cana, pct_obs])
conf_dep = np.clip((depth_valid_frac - t0) / (t1 - t0), 0.0, 1.0)
conf_cell = 0.6 * conf_seg + 0.4 * conf_dep
# --- 6b) Rasterizar detecções (opcional) ---
if deteccoes:
# percorre bboxes e projeta para grid
for det in deteccoes:
conf = float(det.get("conf", 0.0))
if conf < _det["min_det_conf"]:
continue
# --- 6b) Rasterizar detecções (opcional) ---
if deteccoes:
# percorre bboxes e projeta para grid
for det in deteccoes:
conf = float(det.get("conf", 0.0))
if conf < _det["min_det_conf"]:
continue
label = str(det.get("label", ""))
w_class = _det["class_weights"].get(label, 1.0)
veto = (label in _det["veto_labels"])
label = str(det.get("label", ""))
w_class = _det["class_weights"].get(label, 1.0)
veto = (label in _det["veto_labels"])
# caixa em px (melhor usar bbox_px se já veio arredondado no teu pipeline)
if "bbox_px" in det and det["bbox_px"]:
x0p, y0p, x1p, y1p = det["bbox_px"]
else:
x0n, y0n, x1n, y1n = det["bbox_norm"]
x0p = int(np.clip(x0n * 512, 0, 511)); x1p = int(np.clip(x1n * 512, 0, 512))
y0p = int(np.clip(y0n * 288, 0, 287)); y1p = int(np.clip(y1n * 288, 0, 288))
if x1p <= x0p or y1p <= y0p:
continue
# caixa em px (melhor usar bbox_px se já veio arredondado no teu pipeline)
if "bbox_px" in det and det["bbox_px"]:
x0p, y0p, x1p, y1p = det["bbox_px"]
else:
x0n, y0n, x1n, y1n = det["bbox_norm"]
x0p = int(np.clip(x0n * 512, 0, 511)); x1p = int(np.clip(x1n * 512, 0, 512))
y0p = int(np.clip(y0n * 288, 0, 287)); y1p = int(np.clip(y1n * 288, 0, 288))
if x1p <= x0p or y1p <= y0p:
continue
bbox_area = float((x1p - x0p) * (y1p - y0p))
if bbox_area <= 1.0:
continue
bbox_area = float((x1p - x0p) * (y1p - y0p))
if bbox_area <= 1.0:
continue
# descobre células que sobrepõem a bbox
# índices i (colunas) e j (linhas) candidatas
i0 = max(0, np.searchsorted(x_edges, x0p, side="right") - 1)
i1 = min(grid_w-1, np.searchsorted(x_edges, x1p, side="left"))
j0 = max(0, np.searchsorted(y_edges, y0p, side="right") - 1)
j1 = min(grid_h-1, np.searchsorted(y_edges, y1p, side="left"))
# descobre células que sobrepõem a bbox
# índices i (colunas) e j (linhas) candidatas
i0 = max(0, np.searchsorted(x_edges, x0p, side="right") - 1)
i1 = min(grid_w-1, np.searchsorted(x_edges, x1p, side="left"))
j0 = max(0, np.searchsorted(y_edges, y0p, side="right") - 1)
j1 = min(grid_h-1, np.searchsorted(y_edges, y1p, side="left"))
for j in range(j0, j1+1):
y0, y1 = y_edges[j], y_edges[j+1]
for i in range(i0, i1+1):
x0, x1 = x_edges[i], x_edges[i+1]
# interseção
ix0 = max(x0, x0p); ix1 = min(x1, x1p)
iy0 = max(y0, y0p); iy1 = min(y1, y1p)
if ix1 <= ix0 or iy1 <= iy0:
continue
inter = float((ix1 - ix0) * (iy1 - iy0))
for j in range(j0, j1+1):
y0, y1 = y_edges[j], y_edges[j+1]
for i in range(i0, i1+1):
x0, x1 = x_edges[i], x_edges[i+1]
# interseção
ix0 = max(x0, x0p); ix1 = min(x1, x1p)
iy0 = max(y0, y0p); iy1 = min(y1, y1p)
if ix1 <= ix0 or iy1 <= iy0:
continue
inter = float((ix1 - ix0) * (iy1 - iy0))
# cobertura em relação à célula (mais conservador que em relação à bbox)
cell_area = float((x1 - x0) * (y1 - y0))
if cell_area <= 0:
continue
cov = inter / cell_area
# cobertura em relação à célula (mais conservador que em relação à bbox)
cell_area = float((x1 - x0) * (y1 - y0))
if cell_area <= 0:
continue
cov = inter / cell_area
if cov < _det["min_cell_coverage"]:
continue
if cov < _det["min_cell_coverage"]:
continue
# score local da detecção nesta célula
# se for classe vetada, zera atenuações
base = conf if not veto else 1.0
s = base * cov * w_class
det_cov_max[j, i] = max(det_cov_max[j, i], cov)
det_conf_max[j, i] = max(det_conf_max[j, i], conf)
# score local da detecção nesta célula
# se for classe vetada, zera atenuações
base = conf if not veto else 1.0
s = base * cov * w_class
det_cov_max[j, i] = max(det_cov_max[j, i], cov)
det_conf_max[j, i] = max(det_conf_max[j, i], conf)
if _det["combine"] == "sum_clamped":
det_score[j, i] = np.clip(det_score[j, i] + s, 0.0, 1.0)
else: # "max"
det_score[j, i] = max(det_score[j, i], s)
if _det["combine"] == "sum_clamped":
det_score[j, i] = np.clip(det_score[j, i] + s, 0.0, 1.0)
else: # "max"
det_score[j, i] = max(det_score[j, i], s)
# critério: escolhe como dominante a de MAIOR (conf * cov)
keyval = conf * cov
if keyval > det_top_conf[j, i]:
det_top_conf[j, i] = keyval
det_top_label_id[j, i] = int(det.get("label_id", -1))
# critério: escolhe como dominante a de MAIOR (conf * cov)
keyval = conf * cov
if keyval > det_top_conf[j, i]:
det_top_conf[j, i] = keyval
det_top_label_id[j, i] = int(det.get("label_id", -1))
# opcional: derruba um pouco a confiança onde há detecção
if _det["conf_drop_alpha"] > 0.0:
conf_cell = np.clip(conf_cell * (1.0 - _det["conf_drop_alpha"] * det_score), 0.0, 1.0)
# opcional: derruba um pouco a confiança onde há detecção
if _det["conf_drop_alpha"] > 0.0:
conf_cell = np.clip(conf_cell * (1.0 - _det["conf_drop_alpha"] * det_score), 0.0, 1.0)
# --- 7) Anomalia (igual à tua) ---
delta = Z_ref - z_med
delta = np.where(np.isnan(z_med), 0.0, np.maximum(delta, 0.0))
anom_raw = np.clip(delta / anom_satur_m, 0.0, 1.0)
anom = anom_raw * (delta > anom_tau_min).astype(np.float32) * conf_dep
# --- 7) Anomalia (igual à tua) ---
delta = Z_ref - z_med
delta = np.where(np.isnan(z_med), 0.0, np.maximum(delta, 0.0))
anom_raw = np.clip(delta / anom_satur_m, 0.0, 1.0)
anom = anom_raw * (delta > anom_tau_min).astype(np.float32) * conf_dep
# --- 8) Custo e navegabilidade ---
nao_rua = 1.0 - pct_rua
w1, w2, w3 = w
custo = w1 * nao_rua + w2 * anom + w3 * (1.0 - conf_cell)
# --- 8) Custo e navegabilidade ---
nao_rua = 1.0 - pct_rua
w1, w2, w3 = w
custo = w1 * nao_rua + w2 * anom + w3 * (1.0 - conf_cell)
# penalização por detecção (se houver)
if deteccoes:
custo = np.clip(custo + _det["w4"] * det_score, 0.0, 1.0)
# penalização por detecção (se houver)
if deteccoes:
custo = np.clip(custo + _det["w4"] * det_score, 0.0, 1.0)
# regra de navegabilidade com detecção (bloqueia se score alto)
if deteccoes:
navegavel = (pct_rua >= 0.55) & (anom < 0.4) & (conf_cell >= 0.5) & (det_score < _det["thr_det_block"])
else:
navegavel = (pct_rua >= 0.55) & (anom < 0.4) & (conf_cell >= 0.5)
# regra de navegabilidade com detecção (bloqueia se score alto)
if deteccoes:
navegavel = (pct_rua >= 0.55) & (anom < 0.4) & (conf_cell >= 0.5) & (det_score < _det["thr_det_block"])
else:
navegavel = (pct_rua >= 0.55) & (anom < 0.4) & (conf_cell >= 0.5)
return {
"pct_rua": pct_rua,
"pct_cana": pct_cana,
"pct_obs": pct_obs,
"z_med": z_med,
"z_ref": Z_ref,
"depth_valid_frac": depth_valid_frac,
"conf": np.clip(custo*0 + conf_cell, 0.0, 1.0), # garante 0..1
"anom": np.clip(anom, 0.0, 1.0),
"custo": np.clip(custo, 0.0, 1.0),
"navegavel": navegavel.astype(np.uint8),
# ---- extras p/ debug/telemetria ----
"det_cov_max": det_cov_max,
"det_conf_max": det_conf_max,
"det_score": det_score,
"det_top_label_id": det_top_label_id,
"det_top_conf": det_top_conf,
}
return {
"pct_rua": pct_rua,
"pct_cana": pct_cana,
"pct_obs": pct_obs,
"z_med": z_med,
"z_ref": Z_ref,
"depth_valid_frac": depth_valid_frac,
"conf": np.clip(custo*0 + conf_cell, 0.0, 1.0), # garante 0..1
"anom": np.clip(anom, 0.0, 1.0),
"custo": np.clip(custo, 0.0, 1.0),
"navegavel": navegavel.astype(np.uint8),
# ---- extras p/ debug/telemetria ----
"det_cov_max": det_cov_max,
"det_conf_max": det_conf_max,
"det_score": det_score,
"det_top_label_id": det_top_label_id,
"det_top_conf": det_top_conf,
}
except Exception as e:
self.mostrar_log(f"Erro ao construir grid de confianca: {e}")
return None
def _put_text_centered(self, img, text, cx, cy, font_scale=0.4, thickness=1, color=(255,255,255), outline=True):
font = cv2.FONT_HERSHEY_SIMPLEX
@ -1400,193 +1404,197 @@ class CameraManager:
a_max_freio=0.8, # << NOVO (m/s²)
margem_parada=0.25, # << NOVO (m)
):
# --- unpack do snapshot ---
custo_f, conf_f, anom_f, nav_f = unpack_snapshot(snapshot)
row_dist_m = np.asarray(snapshot.get("row_dist_m"), dtype=np.float32)
row_scale_x_m = np.asarray(snapshot.get("row_scale_x_m"), dtype=np.float32)
fuse = snapshot.get("fuse", {})
central_cols = fuse.get("central_cols", None)
if central_cols is None:
# fallback: terço central
H, W = custo_f.shape
central_cols = (W//3, 2*W//3)
else:
central_cols = (int(central_cols[0]), int(central_cols[1]))
# prioriza near_is_bottom do snap, se vier
if "near_is_bottom" in fuse:
near_is_bottom = bool(fuse["near_is_bottom"])
rgb_frame = cv2.resize(rgb_frame, (1280, 720))
Hf, Wf = rgb_frame.shape[:2]
H, W = custo_f.shape
# --- métricas: usa do snap se existir; senão calcula ---
metrics = snapshot.get("block")
blocked = bool(metrics.get("blocked", False))
reason = metrics.get("reason", "none") or "none"
reason_detail = metrics.get("reason_detail", "none") or "none"
d_obs_min = metrics.get("d_obs_true_min_m", None)
j_block = metrics.get("j_block", None)
cov_cent = metrics.get("coverage", {}).get("central_max", 0.0)
cov_glob = metrics.get("coverage", {}).get("global", 0.0)
decision = metrics.get("decision", {})
sb = metrics.get("side_bias", {}) or {}
side_val = float(sb.get("value", 0.0))
left_frac = float(sb.get("left_frac", 0.0))
right_frac= float(sb.get("right_frac", 0.0))
# --- overlays ---
mask_rgb, mask_anom, mask_cost, mask_conf = self._colorize_masks(
anom_f, custo_f, conf_f,
thr_anom_block=thr_anom_block,
thr_cost_block=thr_cost_block,
thr_conf_low=thr_conf_low
)
mask_rgb_resized = cv2.resize(mask_rgb, (Wf, Hf), interpolation=cv2.INTER_NEAREST)
vis = rgb_frame.copy()
vis = cv2.addWeighted(vis, 1.0, mask_rgb_resized, alpha, 0)
# --- desenha linha/retângulo na j_block ---
if j_block is not None and 0 <= j_block < H:
y = int((j_block + 0.5) * Hf / H)
color_line = (0, 0, 255) if blocked else (0, 255, 255)
cv2.line(vis, (0, y), (Wf, y), color_line, 2)
c0, c1 = central_cols
c0 = max(0, min(W-1, int(c0)))
c1 = max(0, min(W, int(c1)))
if c1 <= c0:
c0, c1 = W//3, 2*W//3
width_need_m = robot_width_m + margin_m
sx = row_scale_x_m[j_block] if row_scale_x_m.size == H else (width_need_m / max(1, (c1 - c0)))
if not np.isfinite(sx) or sx <= 1e-6:
ncols = (c1 - c0)
try:
# --- unpack do snapshot ---
custo_f, conf_f, anom_f, nav_f = unpack_snapshot(snapshot)
row_dist_m = np.asarray(snapshot.get("row_dist_m"), dtype=np.float32)
row_scale_x_m = np.asarray(snapshot.get("row_scale_x_m"), dtype=np.float32)
fuse = snapshot.get("fuse", {})
central_cols = fuse.get("central_cols", None)
if central_cols is None:
# fallback: terço central
H, W = custo_f.shape
central_cols = (W//3, 2*W//3)
else:
ncols = int(np.ceil(width_need_m / sx))
ncols = max(1, min(W, ncols))
central_cols = (int(central_cols[0]), int(central_cols[1]))
mid = (c0 + c1) // 2
half = ncols // 2
a = max(0, mid - half)
b = min(W, a + ncols)
a = max(0, b - ncols)
# prioriza near_is_bottom do snap, se vier
if "near_is_bottom" in fuse:
near_is_bottom = bool(fuse["near_is_bottom"])
x1 = int(a * Wf / W)
x2 = int(b * Wf / W)
cv2.rectangle(vis, (x1, max(0, y-12)), (x2, min(Hf-1, y+12)), (0, 255, 0), 2)
rgb_frame = cv2.resize(rgb_frame, (1280, 720))
txt = f"{reason.upper()} | d={d_obs_min:.2f} m" if d_obs_min is not None else f"{reason.upper()} | d="
cv2.putText(vis, txt, (10, max(20, y-10)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, color_line, 2, cv2.LINE_AA)
Hf, Wf = rgb_frame.shape[:2]
H, W = custo_f.shape
# --- HUDs (legíveis) ---
x0, y0 = 10, 30
bar_w, bar_h = 200, 12
line_gap = 8
font = cv2.FONT_HERSHEY_SIMPLEX
font_scale = 0.60
thick = 2
# --- métricas: usa do snap se existir; senão calcula ---
metrics = snapshot.get("block")
def put_text_outlined(img, text, org, font, font_scale, color_fg, thickness):
# contorno preto
cv2.putText(img, text, org, font, font_scale, (0,0,0), thickness+2, cv2.LINE_AA)
# texto
cv2.putText(img, text, org, font, font_scale, color_fg, thickness, cv2.LINE_AA)
blocked = bool(metrics.get("blocked", False))
reason = metrics.get("reason", "none") or "none"
reason_detail = metrics.get("reason_detail", "none") or "none"
d_obs_min = metrics.get("d_obs_true_min_m", None)
j_block = metrics.get("j_block", None)
cov_cent = metrics.get("coverage", {}).get("central_max", 0.0)
cov_glob = metrics.get("coverage", {}).get("global", 0.0)
decision = metrics.get("decision", {})
sb = metrics.get("side_bias", {}) or {}
side_val = float(sb.get("value", 0.0))
left_frac = float(sb.get("left_frac", 0.0))
right_frac= float(sb.get("right_frac", 0.0))
def draw_bar(img, label, frac, top_left, color_fill=(0,255,255)):
x, y = top_left
# label acima da barra
put_text_outlined(img, label, (x, y-2), font, font_scale, (255,255,255), thick)
# moldura
cv2.rectangle(img, (x, y+4), (x + bar_w, y + 4 + bar_h), (220,220,220), 1)
# preenchimento
fw = int(bar_w * float(np.clip(frac, 0, 1)))
if fw > 0:
cv2.rectangle(img, (x, y+4), (x + fw, y + 4 + bar_h), color_fill, -1)
# --- overlays ---
mask_rgb, mask_anom, mask_cost, mask_conf = self._colorize_masks(
anom_f, custo_f, conf_f,
thr_anom_block=thr_anom_block,
thr_cost_block=thr_cost_block,
thr_conf_low=thr_conf_low
)
mask_rgb_resized = cv2.resize(mask_rgb, (Wf, Hf), interpolation=cv2.INTER_NEAREST)
# mede a altura ocupada pelo bloco para pintar um painel ao fundo
panel_h = (
# 2 barras (cada uma tem label+barra) + gaps
(bar_h + 4) * 2 + (line_gap + 14) * 2
)
panel_w = max(260, bar_w + 70)
vis = rgb_frame.copy()
vis = cv2.addWeighted(vis, 1.0, mask_rgb_resized, alpha, 0)
# painel semi-transparente
overlay = vis.copy()
cv2.rectangle(overlay, (x0-6, y0-6), (x0-6 + panel_w, y0-6 + panel_h), (0,0,0), -1)
cv2.addWeighted(overlay, 0.35, vis, 0.65, 0, vis)
# --- desenha linha/retângulo na j_block ---
if j_block is not None and 0 <= j_block < H:
y = int((j_block + 0.5) * Hf / H)
color_line = (0, 0, 255) if blocked else (0, 255, 255)
cv2.line(vis, (0, y), (Wf, y), color_line, 2)
# barras Global / Central
draw_bar(vis, f"Global {cov_glob:.2f}", cov_glob, (x0, y0))
y0 += bar_h + line_gap + 14
draw_bar(vis, f"Central {cov_cent:.2f}", cov_cent, (x0, y0))
y0 += bar_h + line_gap + 14
c0, c1 = central_cols
c0 = max(0, min(W-1, int(c0)))
c1 = max(0, min(W, int(c1)))
if c1 <= c0:
c0, c1 = W//3, 2*W//3
# SideBias
put_text_outlined(vis, f"SideBias {side_val:+.2f}", (x0, y0),
font, font_scale, (255,255,255), thick)
cx = x0 + bar_w//2
y_bar = y0 + 14
# linha base -1..+1
cv2.line(vis, (x0, y_bar), (x0+bar_w, y_bar), (220,220,220), 1)
# marca central
cv2.line(vis, (cx, y_bar-4), (cx, y_bar+4), (255,255,255), 1)
# cursor do bias
bx = int(cx + (bar_w//2) * float(np.clip(side_val, -1, 1)))
cv2.circle(vis, (bx, y_bar), 5, (0,255,0), -1)
width_need_m = robot_width_m + margin_m
sx = row_scale_x_m[j_block] if row_scale_x_m.size == H else (width_need_m / max(1, (c1 - c0)))
if not np.isfinite(sx) or sx <= 1e-6:
ncols = (c1 - c0)
else:
ncols = int(np.ceil(width_need_m / sx))
ncols = max(1, min(W, ncols))
# L / R
put_text_outlined(vis, f"L:{left_frac:.2f} R:{right_frac:.2f}", (x0, y_bar + 20),
font, font_scale, (255,255,255), thick)
mid = (c0 + c1) // 2
half = ncols // 2
a = max(0, mid - half)
b = min(W, a + ncols)
a = max(0, b - ncols)
# --- DECISION HUD: PARAR / LIVRE ---
# empurra um pouco pra baixo do L/R
y0_dec = y_bar + 50
x1 = int(a * Wf / W)
x2 = int(b * Wf / W)
cv2.rectangle(vis, (x1, max(0, y-12)), (x2, min(Hf-1, y+12)), (0, 255, 0), 2)
parada_necessaria = decision.get("parar", False)
dec_txt = "PARAR" if parada_necessaria else "LIVRE"
dec_col = (0, 0, 255) if parada_necessaria else (0, 200, 0)
dec_info = (f"v={velocidade_media:.3f} m/s d_obs={('-' if d_obs_min is None else f'{d_obs_min:.2f} m')} "
f"d_necess={decision.get('dist_necessaria', 0.0):.2f} m")
txt = f"{reason.upper()} | d={d_obs_min:.2f} m" if d_obs_min is not None else f"{reason.upper()} | d=-"
cv2.putText(vis, txt, (10, max(20, y-10)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, color_line, 2, cv2.LINE_AA)
# painel por trás para legibilidade
panel_w2 = max(280, bar_w + 100)
overlay2 = vis.copy()
cv2.rectangle(overlay2, (x0-6, y0_dec-24), (x0-6 + panel_w2, y0_dec+26), (0,0,0), -1)
cv2.addWeighted(overlay2, 0.35, vis, 0.65, 0, vis)
# --- HUDs (legíveis) ---
x0, y0 = 10, 30
bar_w, bar_h = 200, 12
line_gap = 8
font = cv2.FONT_HERSHEY_SIMPLEX
font_scale = 0.60
thick = 2
# linha 1: PARAR / LIVRE (grande)
put_text_outlined(vis, f"{dec_txt}", (x0, y0_dec-4), font, 0.80, dec_col, thick)
def put_text_outlined(img, text, org, font, font_scale, color_fg, thickness):
# contorno preto
cv2.putText(img, text, org, font, font_scale, (0,0,0), thickness+2, cv2.LINE_AA)
# texto
cv2.putText(img, text, org, font, font_scale, color_fg, thickness, cv2.LINE_AA)
# linha 2: detalhes (menor)
put_text_outlined(vis, dec_info, (x0, y0_dec+18), font, 0.58, (255,255,255), thick)
def draw_bar(img, label, frac, top_left, color_fill=(0,255,255)):
x, y = top_left
# label acima da barra
put_text_outlined(img, label, (x, y-2), font, font_scale, (255,255,255), thick)
# moldura
cv2.rectangle(img, (x, y+4), (x + bar_w, y + 4 + bar_h), (220,220,220), 1)
# preenchimento
fw = int(bar_w * float(np.clip(frac, 0, 1)))
if fw > 0:
cv2.rectangle(img, (x, y+4), (x + fw, y + 4 + bar_h), color_fill, -1)
# linha 3: detalhes (menor)
put_text_outlined(vis, reason_detail, (x0, y0_dec+50), font, 0.58, (255,255,255), thick)
# mede a altura ocupada pelo bloco para pintar um painel ao fundo
panel_h = (
# 2 barras (cada uma tem label+barra) + gaps
(bar_h + 4) * 2 + (line_gap + 14) * 2
)
panel_w = max(260, bar_w + 70)
# painel semi-transparente
overlay = vis.copy()
cv2.rectangle(overlay, (x0-6, y0-6), (x0-6 + panel_w, y0-6 + panel_h), (0,0,0), -1)
cv2.addWeighted(overlay, 0.35, vis, 0.65, 0, vis)
# barras Global / Central
draw_bar(vis, f"Global {cov_glob:.2f}", cov_glob, (x0, y0))
y0 += bar_h + line_gap + 14
draw_bar(vis, f"Central {cov_cent:.2f}", cov_cent, (x0, y0))
y0 += bar_h + line_gap + 14
# SideBias
put_text_outlined(vis, f"SideBias {side_val:+.2f}", (x0, y0),
font, font_scale, (255,255,255), thick)
cx = x0 + bar_w//2
y_bar = y0 + 14
# linha base -1..+1
cv2.line(vis, (x0, y_bar), (x0+bar_w, y_bar), (220,220,220), 1)
# marca central
cv2.line(vis, (cx, y_bar-4), (cx, y_bar+4), (255,255,255), 1)
# cursor do bias
bx = int(cx + (bar_w//2) * float(np.clip(side_val, -1, 1)))
cv2.circle(vis, (bx, y_bar), 5, (0,255,0), -1)
# L / R
put_text_outlined(vis, f"L:{left_frac:.2f} R:{right_frac:.2f}", (x0, y_bar + 20),
font, font_scale, (255,255,255), thick)
# --- DECISION HUD: PARAR / LIVRE ---
# empurra um pouco pra baixo do L/R
y0_dec = y_bar + 50
parada_necessaria = decision.get("parar", False)
dec_txt = "PARAR" if parada_necessaria else "LIVRE"
dec_col = (0, 0, 255) if parada_necessaria else (0, 200, 0)
dec_info = (f"v={velocidade_media:.3f} m/s d_obs={('-' if d_obs_min is None else f'{d_obs_min:.2f} m')} "
f"d_necess={decision.get('dist_necessaria', 0.0):.2f} m")
# painel por trás para legibilidade
panel_w2 = max(280, bar_w + 100)
overlay2 = vis.copy()
cv2.rectangle(overlay2, (x0-6, y0_dec-24), (x0-6 + panel_w2, y0_dec+26), (0,0,0), -1)
cv2.addWeighted(overlay2, 0.35, vis, 0.65, 0, vis)
# linha 1: PARAR / LIVRE (grande)
put_text_outlined(vis, f"{dec_txt}", (x0, y0_dec-4), font, 0.80, dec_col, thick)
# linha 2: detalhes (menor)
put_text_outlined(vis, dec_info, (x0, y0_dec+18), font, 0.58, (255,255,255), thick)
# linha 3: detalhes (menor)
put_text_outlined(vis, reason_detail, (x0, y0_dec+50), font, 0.58, (255,255,255), thick)
legend = [
("Anom >= thr", (255, 0, 255)),
("Custo >= thr", (0,165,255)),
("Conf < thr", (255, 0, 0)),
]
lx, ly = 10, Hf - 10 - 18*len(legend)
for i, (txt, col) in enumerate(legend):
y = ly + i*18
cv2.rectangle(vis, (lx, y-12), (lx+18, y+2), col, -1)
cv2.putText(vis, txt, (lx+24, y), cv2.FONT_HERSHEY_SIMPLEX, 0.48, (255,255,255), 1, cv2.LINE_AA)
legend = [
("Anom >= thr", (255, 0, 255)),
("Custo >= thr", (0,165,255)),
("Conf < thr", (255, 0, 0)),
]
lx, ly = 10, Hf - 10 - 18*len(legend)
for i, (txt, col) in enumerate(legend):
y = ly + i*18
cv2.rectangle(vis, (lx, y-12), (lx+18, y+2), col, -1)
cv2.putText(vis, txt, (lx+24, y), cv2.FONT_HERSHEY_SIMPLEX, 0.48, (255,255,255), 1, cv2.LINE_AA)
status_txt = f"BLOCKED: {blocked} ({reason})"
status_col = (0,0,255) if blocked else (0,255,0)
cv2.putText(vis, status_txt, (Wf - 40 - 8*len(status_txt), 24), cv2.FONT_HERSHEY_SIMPLEX, 0.6, status_col, 2, cv2.LINE_AA)
status_txt = f"BLOCKED: {blocked} ({reason})"
status_col = (0,0,255) if blocked else (0,255,0)
cv2.putText(vis, status_txt, (Wf - 40 - 8*len(status_txt), 24), cv2.FONT_HERSHEY_SIMPLEX, 0.6, status_col, 2, cv2.LINE_AA)
cv2.imshow(win_name, vis)
cv2.waitKey(1)
return vis, metrics
cv2.imshow(win_name, vis)
cv2.waitKey(1)
return vis, metrics
except Exception as e:
self.mostrar_log(f"Erro ao criar debug blockage imshow: {e}")
return None, None
def _overlay_deteccoes(
@ -1610,99 +1618,102 @@ class CameraManager:
}
Retorna: (frame_com_overlay, fps_state, keep_loop_bool)
"""
img = cv2.resize(rgb_frame.copy(), (1280, 720))
H, W = img.shape[:2]
try:
img = cv2.resize(rgb_frame.copy(), (1280, 720))
H, W = img.shape[:2]
# paleta simples por classe
palette = [
(255, 56, 56), (255, 157, 151), (72, 249, 10), (0, 255, 0), (0, 0, 255),
(255, 0, 255), (0, 255, 255), (255, 191, 0), (52, 148, 230), (147, 112, 219)
]
# paleta simples por classe
palette = [
(255, 56, 56), (255, 157, 151), (72, 249, 10), (0, 255, 0), (0, 0, 255),
(255, 0, 255), (0, 255, 255), (255, 191, 0), (52, 148, 230), (147, 112, 219)
]
def _map_bbox_norm_to_full(bn):
# bn é [x0n,y0n,x1n,y1n] relativo ao input da ROI (0..1)
x0n, y0n, x1n, y1n = bn
def _map_bbox_norm_to_full(bn):
# bn é [x0n,y0n,x1n,y1n] relativo ao input da ROI (0..1)
x0n, y0n, x1n, y1n = bn
if roi_frac is not None:
rx1, ry1, rx2, ry2 = roi_frac
sx, sy = (rx2 - rx1), (ry2 - ry1)
x0 = int(round((rx1 + x0n * sx) * W))
y0 = int(round((ry1 + y0n * sy) * H))
x1 = int(round((rx1 + x1n * sx) * W))
y1 = int(round((ry1 + y1n * sy) * H))
else:
x0 = int(round(x0n * W))
y0 = int(round(y0n * H))
x1 = int(round(x1n * W))
y1 = int(round(y1n * H))
# clamp
x0 = max(0, min(W - 1, x0)); x1 = max(0, min(W - 1, x1))
y0 = max(0, min(H - 1, y0)); y1 = max(0, min(H - 1, y1))
return x0, y0, x1, y1
def _put_label(img, text, x, y, bg):
(tw, th), _ = cv2.getTextSize(text, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1)
cv2.rectangle(img, (x, max(0, y - th - 6)), (x + tw + 6, y), bg, -1)
cv2.putText(img, text, (x + 3, y - 4), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1, cv2.LINE_AA)
# desenhar ROI (opcional, ajuda debug)
if roi_frac is not None:
rx1, ry1, rx2, ry2 = roi_frac
sx, sy = (rx2 - rx1), (ry2 - ry1)
x0 = int(round((rx1 + x0n * sx) * W))
y0 = int(round((ry1 + y0n * sy) * H))
x1 = int(round((rx1 + x1n * sx) * W))
y1 = int(round((ry1 + y1n * sy) * H))
else:
x0 = int(round(x0n * W))
y0 = int(round(y0n * H))
x1 = int(round(x1n * W))
y1 = int(round(y1n * H))
# clamp
x0 = max(0, min(W - 1, x0)); x1 = max(0, min(W - 1, x1))
y0 = max(0, min(H - 1, y0)); y1 = max(0, min(H - 1, y1))
return x0, y0, x1, y1
x0r, y0r = int(rx1 * W), int(ry1 * H)
x1r, y1r = int(rx2 * W), int(ry2 * H)
cv2.rectangle(img, (x0r, y0r), (x1r, y1r), (60, 60, 60), 1)
def _put_label(img, text, x, y, bg):
(tw, th), _ = cv2.getTextSize(text, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1)
cv2.rectangle(img, (x, max(0, y - th - 6)), (x + tw + 6, y), bg, -1)
cv2.putText(img, text, (x + 3, y - 4), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1, cv2.LINE_AA)
# desenhar ROI (opcional, ajuda debug)
if roi_frac is not None:
rx1, ry1, rx2, ry2 = roi_frac
x0r, y0r = int(rx1 * W), int(ry1 * H)
x1r, y1r = int(rx2 * W), int(ry2 * H)
cv2.rectangle(img, (x0r, y0r), (x1r, y1r), (60, 60, 60), 1)
# desenhar detecções
for d in dets:
if d.get("conf", 0.0) < conf_thr:
continue
# bbox em px do frame
if "bbox_full" in d and d["bbox_full"]:
x0, y0, x1, y1 = d["bbox_full"]
# clamp se necessário
x0 = max(0, min(W - 1, int(x0))); x1 = max(0, min(W - 1, int(x1)))
y0 = max(0, min(H - 1, int(y0))); y1 = max(0, min(H - 1, int(y1)))
else:
bn = d.get("bbox_norm", None)
if not bn:
# desenhar detecções
for d in dets:
if d.get("conf", 0.0) < conf_thr:
continue
x0, y0, x1, y1 = _map_bbox_norm_to_full(bn)
if x1 <= x0 or y1 <= y0:
continue
# bbox em px do frame
if "bbox_full" in d and d["bbox_full"]:
x0, y0, x1, y1 = d["bbox_full"]
# clamp se necessário
x0 = max(0, min(W - 1, int(x0))); x1 = max(0, min(W - 1, int(x1)))
y0 = max(0, min(H - 1, int(y0))); y1 = max(0, min(H - 1, int(y1)))
else:
bn = d.get("bbox_norm", None)
if not bn:
continue
x0, y0, x1, y1 = _map_bbox_norm_to_full(bn)
lid = int(d.get("label_id", -1))
color = palette[lid % len(palette)] if lid >= 0 else (0, 255, 0)
if x1 <= x0 or y1 <= y0:
continue
cv2.rectangle(img, (x0, y0), (x1, y1), color, 2)
lid = int(d.get("label_id", -1))
color = palette[lid % len(palette)] if lid >= 0 else (0, 255, 0)
name = d.get("label", None)
txt = f"{name or f'id:{lid}'} {d.get('conf', 0.0):.2f}"
_put_label(img, txt, x0, y0, color)
cv2.rectangle(img, (x0, y0), (x1, y1), color, 2)
# FPS (EMA)
now = time.monotonic()
if fps_state is None:
fps_state = {}
t_prev = fps_state.get("t_prev")
fps_ema = fps_state.get("fps_ema")
if t_prev is not None:
dt = now - t_prev
if dt > 0:
fps_inst = 1.0 / dt
alpha = 0.90
fps_ema = fps_inst if fps_ema is None else (alpha * fps_ema + (1 - alpha) * fps_inst)
fps_state["t_prev"] = now
fps_state["fps_ema"] = fps_ema
name = d.get("label", None)
txt = f"{name or f'id:{lid}'} {d.get('conf', 0.0):.2f}"
_put_label(img, txt, x0, y0, color)
if fps_ema:
cv2.putText(img, f"FPS: {fps_ema:.1f}", (10, 22), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (50, 220, 50), 2, cv2.LINE_AA)
# FPS (EMA)
now = time.monotonic()
if fps_state is None:
fps_state = {}
t_prev = fps_state.get("t_prev")
fps_ema = fps_state.get("fps_ema")
if t_prev is not None:
dt = now - t_prev
if dt > 0:
fps_inst = 1.0 / dt
alpha = 0.90
fps_ema = fps_inst if fps_ema is None else (alpha * fps_ema + (1 - alpha) * fps_inst)
fps_state["t_prev"] = now
fps_state["fps_ema"] = fps_ema
keep = True
if show:
cv2.imshow(janela, img)
k = cv2.waitKey(1) & 0xFF
keep = (k != 27) # ESC para sair
if fps_ema:
cv2.putText(img, f"FPS: {fps_ema:.1f}", (10, 22), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (50, 220, 50), 2, cv2.LINE_AA)
return img, fps_state, keep
keep = True
if show:
cv2.imshow(janela, img)
k = cv2.waitKey(1) & 0xFF
keep = (k != 27) # ESC para sair
return img, fps_state, keep
except Exception as e:
self.mostrar_log(f"Erro ao gerar overlay de deteccoes")

View File

@ -62,6 +62,7 @@
this.cmbConfiguracaoUltrassom = new System.Windows.Forms.ComboBox();
this.btnConfigurar = new System.Windows.Forms.Button();
this.gpbLocomocao = new System.Windows.Forms.GroupBox();
this.chbMovimentacaoAutomatica = new System.Windows.Forms.CheckBox();
this.nudVelMin = new System.Windows.Forms.NumericUpDown();
this.nudVelMax = new System.Windows.Forms.NumericUpDown();
this.lblKmh2 = new System.Windows.Forms.Label();
@ -71,6 +72,7 @@
this.lblVelocidadeComErvas = new System.Windows.Forms.Label();
this.lblVelocidadeSemErvas = new System.Windows.Forms.Label();
this.gpbAtuador = new System.Windows.Forms.GroupBox();
this.chbPulverizadorAutomatico = new System.Windows.Forms.CheckBox();
this.txtQtdCameras = new System.Windows.Forms.TextBox();
this.lblQuantidadeCamerasSolo = new System.Windows.Forms.Label();
this.lblMs = new System.Windows.Forms.Label();
@ -121,8 +123,7 @@
this.chbMapa = new System.Windows.Forms.CheckBox();
this.rtbCam = new System.Windows.Forms.RichTextBox();
this.chbCameraSolo = new System.Windows.Forms.CheckBox();
this.chbPulverizadorAutomatico = new System.Windows.Forms.CheckBox();
this.chbMovimentacaoAutomatica = new System.Windows.Forms.CheckBox();
this.chbFrenagemAutomatica = new System.Windows.Forms.CheckBox();
this.gpbModulos.SuspendLayout();
this.pnlModulos.SuspendLayout();
this.tabControl1.SuspendLayout();
@ -492,6 +493,7 @@
this.chbSonarAtivado.TabIndex = 13;
this.chbSonarAtivado.Text = "Utilizar dados visuais do Sonar";
this.chbSonarAtivado.UseVisualStyleBackColor = true;
this.chbSonarAtivado.CheckedChanged += new System.EventHandler(this.chbSonarAtivado_CheckedChanged);
//
// rtbDescricao
//
@ -535,6 +537,7 @@
//
// gpbLocomocao
//
this.gpbLocomocao.Controls.Add(this.chbFrenagemAutomatica);
this.gpbLocomocao.Controls.Add(this.chbMovimentacaoAutomatica);
this.gpbLocomocao.Controls.Add(this.nudVelMin);
this.gpbLocomocao.Controls.Add(this.nudVelMax);
@ -551,6 +554,16 @@
this.gpbLocomocao.TabStop = false;
this.gpbLocomocao.Text = "Locomoção";
//
// chbMovimentacaoAutomatica
//
this.chbMovimentacaoAutomatica.AutoSize = true;
this.chbMovimentacaoAutomatica.Location = new System.Drawing.Point(9, 85);
this.chbMovimentacaoAutomatica.Name = "chbMovimentacaoAutomatica";
this.chbMovimentacaoAutomatica.Size = new System.Drawing.Size(191, 17);
this.chbMovimentacaoAutomatica.TabIndex = 8;
this.chbMovimentacaoAutomatica.Text = "Controle de Movimento Automático";
this.chbMovimentacaoAutomatica.UseVisualStyleBackColor = true;
//
// nudVelMin
//
this.nudVelMin.Location = new System.Drawing.Point(358, 55);
@ -650,6 +663,16 @@
this.gpbAtuador.TabStop = false;
this.gpbAtuador.Text = "Atuador";
//
// chbPulverizadorAutomatico
//
this.chbPulverizadorAutomatico.AutoSize = true;
this.chbPulverizadorAutomatico.Location = new System.Drawing.Point(9, 192);
this.chbPulverizadorAutomatico.Name = "chbPulverizadorAutomatico";
this.chbPulverizadorAutomatico.Size = new System.Drawing.Size(209, 17);
this.chbPulverizadorAutomatico.TabIndex = 15;
this.chbPulverizadorAutomatico.Text = "Pulverizador Com Ativação Automática";
this.chbPulverizadorAutomatico.UseVisualStyleBackColor = true;
//
// txtQtdCameras
//
this.txtQtdCameras.Location = new System.Drawing.Point(358, 163);
@ -1183,25 +1206,15 @@
this.chbCameraSolo.UseVisualStyleBackColor = false;
this.chbCameraSolo.CheckedChanged += new System.EventHandler(this.chbParametro_CheckedChanged);
//
// chbPulverizadorAutomatico
// chbFrenagemAutomatica
//
this.chbPulverizadorAutomatico.AutoSize = true;
this.chbPulverizadorAutomatico.Location = new System.Drawing.Point(9, 192);
this.chbPulverizadorAutomatico.Name = "chbPulverizadorAutomatico";
this.chbPulverizadorAutomatico.Size = new System.Drawing.Size(209, 17);
this.chbPulverizadorAutomatico.TabIndex = 15;
this.chbPulverizadorAutomatico.Text = "Pulverizador Com Ativação Automática";
this.chbPulverizadorAutomatico.UseVisualStyleBackColor = true;
//
// chbMovimentacaoAutomatica
//
this.chbMovimentacaoAutomatica.AutoSize = true;
this.chbMovimentacaoAutomatica.Location = new System.Drawing.Point(9, 85);
this.chbMovimentacaoAutomatica.Name = "chbMovimentacaoAutomatica";
this.chbMovimentacaoAutomatica.Size = new System.Drawing.Size(191, 17);
this.chbMovimentacaoAutomatica.TabIndex = 8;
this.chbMovimentacaoAutomatica.Text = "Controle de Movimento Automático";
this.chbMovimentacaoAutomatica.UseVisualStyleBackColor = true;
this.chbFrenagemAutomatica.AutoSize = true;
this.chbFrenagemAutomatica.Location = new System.Drawing.Point(235, 85);
this.chbFrenagemAutomatica.Name = "chbFrenagemAutomatica";
this.chbFrenagemAutomatica.Size = new System.Drawing.Size(281, 17);
this.chbFrenagemAutomatica.TabIndex = 9;
this.chbFrenagemAutomatica.Text = "Frenagem automática ao detectar obstáculos no radar";
this.chbFrenagemAutomatica.UseVisualStyleBackColor = true;
//
// frmAjustesOperacao
//
@ -1346,5 +1359,6 @@
private System.Windows.Forms.CheckBox chbLoRa_M;
private System.Windows.Forms.CheckBox chbMovimentacaoAutomatica;
private System.Windows.Forms.CheckBox chbPulverizadorAutomatico;
private System.Windows.Forms.CheckBox chbFrenagemAutomatica;
}
}

View File

@ -17,6 +17,7 @@ namespace AgroMonitor.Forms
string path = Variaveis.CaminhoSistema + Variaveis.CaminhoOperacoes + "\\" + MapasVariaveisModel.NomeArquivoMapaInterativoSaida;
UltrasonicA05Configuracoes ConfigUltrassom = UltrasonicA05Helper.CarregarConfiguracaoPadrao(ConfiguracaoSensorUltrassonico.NaoUtilizado);
bool carregarOpPadrao = true;
bool carregandoOperacao = false;
MapaDinamicoModel MapaDinamico;
public frmAjustesOperacao()
@ -55,6 +56,8 @@ namespace AgroMonitor.Forms
private void AtualizarDadosOperacao()
{
carregandoOperacao = true;
if (carregarOpPadrao)
{
OperacaoModel.CarregarParametrosOperacaoPadrao((ModoOperacao)cmbModosOperacao.SelectedIndex);
@ -68,7 +71,12 @@ namespace AgroMonitor.Forms
T_Code Dispositivo = (T_Code)Enum.Parse(typeof(T_Code), disp);
var P = Variaveis.OperacaoEmAndamento.ModulosMandatorios.FirstOrDefault(x => x.Dispositivo == Dispositivo);
chb.Checked = P?.Utilizar ?? false;
FuncoesGlobais.FindControlRecursive<CheckBox>(pnlModulos, chb.Name + "_M").Checked = P?.Mandatorio ?? false;
var chbMandatorio = FuncoesGlobais.FindControlRecursive<CheckBox>(pnlModulos, chb.Name + "_M");
if (chb.Checked)
{
chbMandatorio.Enabled = chb.Checked;
chbMandatorio.Checked = P?.Mandatorio ?? false;
}
}
foreach (var chb in pnlParametrosMandatorios.Controls.OfType<CheckBox>().Where(x => !x.Name.Contains("_M")))
@ -77,7 +85,12 @@ namespace AgroMonitor.Forms
ParametrosOperacao Parametro = (ParametrosOperacao)Enum.Parse(typeof(ParametrosOperacao), parametro);
var P = Variaveis.OperacaoEmAndamento.ParametrosMandatorios.FirstOrDefault(x => x.Parametro == Parametro);
chb.Checked = P?.Utilizar ?? false;
FuncoesGlobais.FindControlRecursive<CheckBox>(pnlParametrosMandatorios, chb.Name + "_M").Checked = P?.Mandatorio ?? false;
var chbMandatorio = FuncoesGlobais.FindControlRecursive<CheckBox>(pnlParametrosMandatorios, chb.Name + "_M");
if (chb.Checked)
{
chbMandatorio.Enabled = chb.Checked;
chbMandatorio.Checked = P?.Mandatorio ?? false;
}
}
var _Controle = Variaveis.OperacaoEmAndamento.Controle;
@ -106,6 +119,9 @@ namespace AgroMonitor.Forms
cmbConfiguracaoUltrassom.SelectedIndex = (int)ConfigUltrassom.Configuracao;
}
chbSonarAtivado.Checked = _Controle.SonarAtivado;
chbFrenagemAutomatica.Checked = _Controle.FrenagemAutomatica;
carregandoOperacao = false;
}
private void btnProximo_Click(object sender, EventArgs e)
@ -199,7 +215,8 @@ namespace AgroMonitor.Forms
qtdCameras,
(TiposControladorDirecional)cmbTipoMovimentoDirecional.SelectedIndex,
chbMovimentacaoAutomatica.Checked,
chbPulverizadorAutomatico.Checked
chbPulverizadorAutomatico.Checked,
chbFrenagemAutomatica.Checked
);
if (!sucesso)
{
@ -236,6 +253,7 @@ namespace AgroMonitor.Forms
chbMovimentacaoAutomatica.Checked = Variaveis.OperacaoEmAndamento.Controle.MovimentoAutomatico;
chbPulverizadorAutomatico.Checked = Variaveis.OperacaoEmAndamento.Controle.PulverizadorAutomatico;
chbFrenagemAutomatica.Checked = Variaveis.OperacaoEmAndamento.Controle.FrenagemAutomatica;
MessageBox.Show("Operação carregada com sucesso!", "Sucesso", MessageBoxButtons.OK, MessageBoxIcon.Information);
@ -258,6 +276,8 @@ namespace AgroMonitor.Forms
private void chbModulo_CheckedChanged(object sender, EventArgs e)
{
if (carregandoOperacao) return;
CheckBox chb = (CheckBox)sender;
string ModID = chb.Name.Replace("chb", "");
T_Code Dispositivo = (T_Code)Enum.Parse(typeof(T_Code), ModID);
@ -288,6 +308,8 @@ namespace AgroMonitor.Forms
private void chbModuloMandatorio_CheckedChanged(object sender, EventArgs e)
{
if (carregandoOperacao) return;
CheckBox chb = (CheckBox)sender;
string ModID = chb.Name.Replace("chb", "").Replace("_M", "");
T_Code Dispositivo = (T_Code)Enum.Parse(typeof(T_Code), ModID);
@ -313,6 +335,8 @@ namespace AgroMonitor.Forms
private void chbParametro_CheckedChanged(object sender, EventArgs e)
{
if (carregandoOperacao) return;
CheckBox chb = (CheckBox)sender;
string parametro = chb.Name.Replace("chb", "");
ParametrosOperacao Parametro = (ParametrosOperacao)Enum.Parse(typeof(ParametrosOperacao), parametro);
@ -346,6 +370,8 @@ namespace AgroMonitor.Forms
private void chbParametroMandatorio_CheckedChanged(object sender, EventArgs e)
{
if (carregandoOperacao) return;
CheckBox chb = (CheckBox)sender;
string parametro = chb.Name.Replace("chb", "").Replace("_M", "");
ParametrosOperacao Parametro = (ParametrosOperacao)Enum.Parse(typeof(ParametrosOperacao), parametro);
@ -405,6 +431,13 @@ namespace AgroMonitor.Forms
pnlZoomMapa.Visible = chbMapaDinamico.Checked;
}
private void chbSonarAtivado_CheckedChanged(object sender, EventArgs e)
{
chbFrenagemAutomatica.Enabled = chbSonarAtivado.Checked;
if (!chbFrenagemAutomatica.Enabled)
{
chbFrenagemAutomatica.Checked = false;
}
}
}
}

View File

@ -1,21 +1,4 @@
0:02:15 Microsoft.Shutdown.TabStripModel.RunUnloadListenerBeforeClosing_false
0:02:15 Microsoft.Shutdown.TabStripModel.InternalCloseTabsImpl_ClosedAll
0:02:15 Microsoft.Shutdown.TabStripModel.SendDetachWebContentsNotifications
0:02:15 Microsoft.UnloadController.ClearUnloadState
0:02:15 Browser1 Close Tab1 at 0
0:02:15 Tab1 WebContentsDestroyed
0:02:15 Microsoft.UnloadController.TabStripEmpty
0:02:15 Microsoft.UnloadController.IsUnclosableApp_IsNotWebApp
0:02:15 Microsoft.UnloadController.HasCompletedUnloadProcessing_True
0:02:15 Microsoft.Shutdown.OnWindowClosing
0:02:15 Microsoft.UnloadController.IsUnclosableApp_IsNotWebApp
0:02:15 Microsoft.UnloadController.HasCompletedUnloadProcessing_True
0:02:15 Microsoft.Shutdown.OnWindowClosingPostClearBrowsingData_NoBrowsingDataCleared
0:02:15 Widget Closed: BrowserFrame
0:02:15 Microsoft.UnloadController.HasCompletedUnloadProcessing_True
0:02:15 Microsoft.Shutdown.OnWindowClosing
0:02:15 Microsoft.Shutdown.OnWindowClosing_DeleteScheduled
0:02:15 Microsoft.Last_Browser_Removed
0:09:19 Microsoft.Shutdown.TabStripModel.SendDetachWebContentsNotifications
0:00:00 Startup
0:00:00 Microsoft.DeleteProfileHelper.CleanUpEphemeralProfiles
0:00:00 Microsoft.DeleteProfileHelper.CleanUpDeletedProfiles
@ -23,62 +6,40 @@
0:00:00 Microsoft.BrowserList.AddBrowser
0:00:00 Browser1 Insert active Tab1 at 0
0:00:00 Tab1 StartNav1 #auto_toplevel
0:00:00 Tab1 StartNav2 #typed
0:00:00 Tab1 FinishNav1
0:00:00 Tab1 PageLoad
0:00:00 Tab1 FinishNav2
0:00:00 Tab1 PageLoad
0:00:25 Memory Pressure: Critical
0:01:35 Microsoft.NewBrowser_Popup
0:01:35 Microsoft.BrowserList.AddBrowser
0:01:35 Browser2 Insert active Tab2 at 0
0:01:35 Tab2 StartNav3 #auto_toplevel
0:01:35 Tab2 StartNav4 #typed
0:01:36 Tab2 FinishNav3
0:01:36 Tab2 PageLoad
0:01:36 Tab2 FinishNav4
0:01:36 Tab2 PageLoad
0:01:57 Memory Pressure: Critical
0:03:34 Microsoft.NewBrowser_Popup
0:03:34 Microsoft.BrowserList.AddBrowser
0:03:34 Browser3 Insert active Tab3 at 0
0:03:34 Tab3 StartNav5 #auto_toplevel
0:03:34 Tab3 StartNav6 #typed
0:03:34 Tab3 FinishNav5
0:03:34 Tab3 PageLoad
0:03:34 Tab3 FinishNav6
0:03:35 Tab3 PageLoad
0:04:19 Memory Pressure: Critical
0:05:10 Microsoft.NewBrowser_Popup
0:05:10 Microsoft.BrowserList.AddBrowser
0:05:10 Browser4 Insert active Tab4 at 0
0:05:10 Tab4 StartNav7 #auto_toplevel
0:05:10 Tab4 StartNav8 #typed
0:05:10 Tab4 FinishNav7
0:05:10 Tab4 PageLoad
0:05:10 Tab4 FinishNav8
0:05:10 Tab4 PageLoad
0:05:47 Memory Pressure: Critical
0:00:00 Startup
0:00:00 Microsoft.DeleteProfileHelper.CleanUpEphemeralProfiles
0:00:00 Microsoft.DeleteProfileHelper.CleanUpDeletedProfiles
0:00:00 Microsoft.NewBrowser_Popup
0:00:00 Microsoft.BrowserList.AddBrowser
0:00:00 Browser1 Insert active Tab1 at 0
0:00:00 Tab1 StartNav1 #auto_toplevel
0:00:00 Tab1 StartNav2 #typed
0:00:00 Tab1 FinishNav1
0:00:00 Tab1 PageLoad
0:00:00 Tab1 FinishNav2
0:00:00 Tab1 PageLoad
0:00:25 Memory Pressure: Critical
0:02:59 Microsoft.NewBrowser_Popup
0:02:59 Microsoft.BrowserList.AddBrowser
0:02:59 Browser2 Insert active Tab2 at 0
0:02:59 Tab2 StartNav3 #auto_toplevel
0:02:59 Tab2 StartNav4 #typed
0:02:59 Tab2 FinishNav3
0:02:59 Tab2 PageLoad
0:02:59 Tab2 FinishNav4
0:02:59 Tab2 PageLoad
0:05:10 Memory Pressure: Critical
0:00:01 Memory Pressure: Critical
0:00:11 Tab1 StartNav2 #typed
0:00:11 Tab1 FinishNav2
0:00:12 Tab1 PageLoad
0:00:35 Microsoft.NewBrowser_Popup
0:00:35 Microsoft.BrowserList.AddBrowser
0:00:35 Browser2 Insert active Tab2 at 0
0:00:35 Tab2 StartNav3 #auto_toplevel
0:00:35 Tab2 StartNav4 #typed
0:00:35 Tab2 FinishNav3
0:00:35 Tab2 PageLoad
0:00:35 Tab2 FinishNav4
0:00:35 Tab2 PageLoad
0:00:41 Memory Pressure: Critical
0:01:48 Microsoft.NewBrowser_Popup
0:01:48 Microsoft.BrowserList.AddBrowser
0:01:48 Browser3 Insert active Tab3 at 0
0:01:48 Tab3 StartNav5 #auto_toplevel
0:01:48 Tab3 FinishNav5
0:01:48 Tab3 PageLoad
0:01:50 Tab3 StartNav6 #typed
0:01:50 Tab3 FinishNav6
0:01:50 Tab3 PageLoad
0:02:04 Memory Pressure: Critical
0:02:56 Microsoft.NewBrowser_Popup
0:02:56 Microsoft.BrowserList.AddBrowser
0:02:56 Browser4 Insert active Tab4 at 0
0:02:56 Tab4 StartNav7 #auto_toplevel
0:02:56 Tab4 StartNav8 #typed
0:02:56 Tab4 FinishNav7
0:02:56 Tab4 PageLoad
0:02:56 Tab4 FinishNav8
0:02:56 Tab4 PageLoad
0:05:15 Memory Pressure: Critical
0:05:16 Microsoft.UnloadController.IsUnclosableApp_IsNotWebApp

View File

@ -1,13 +1,13 @@
{
"epochs": [ {
"calculation_time": "13399989621907661",
"calculation_time": "13400859163413956",
"config_version": 0,
"model_version": "0",
"padded_top_topics_start_index": 0,
"taxonomy_version": 0,
"top_topics_and_observing_domains": [ ]
}, {
"calculation_time": "13400859163413956",
"calculation_time": "13402493510652849",
"config_version": 0,
"model_version": "0",
"padded_top_topics_start_index": 0,
@ -15,5 +15,5 @@
"top_topics_and_observing_domains": [ ]
} ],
"hex_encoded_hmac_key": "171DAE543B88106F5155169E0A8C7502CB2A0757E4948C32E2A04D196E23BE70",
"next_scheduled_calculation_time": "13401463963414108"
"next_scheduled_calculation_time": "13403098310652891"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Some files were not shown because too many files have changed in this diff Show More