ajustes lora e deteccao de obstaculos
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1660,6 +1660,7 @@ namespace AgroBase.Models.Modules
|
|||
Componente = S_Code.sLRA,
|
||||
Funcoes = new List<FuncoesPinout>()
|
||||
{
|
||||
FuncoesPinout.ENA,
|
||||
FuncoesPinout.M0,
|
||||
FuncoesPinout.M1,
|
||||
FuncoesPinout.Aux,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ namespace AgroBase.Services.Operadores
|
|||
if (pronto())
|
||||
{
|
||||
MostrarLog("Processamento iniciado com sucesso");
|
||||
DadosLeitura.Iniciado = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"}}}
|
||||
|
|
@ -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}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
140.0.3485.54
|
||||
140.0.3485.66
|
||||
|
|
@ -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":""}}}
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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":
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"description": "Microsoft CRLSet",
|
||||
"name": "MicrosoftCRLSet",
|
||||
"version": "6498.2024.12.2"
|
||||
"version": "6498.2025.9.4"
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 19 KiB |