agrobot_base/AgroBase/OperationControl/Windows/MainWindow.xaml.cs

951 lines
40 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Windows;
using ScottPlot; // Plot
using ScottPlot.Plottables; // ISignal / IScatter
using System.Timers;
using Colors = ScottPlot.Colors; // Timer
using System.Windows.Threading;
using OperationControl.Controls;
using System.Diagnostics;
using OperationControl.Models;
using AgroBase.Models.Components;
using OperationControl.Services;
using System.Windows.Controls;
using System.Runtime.CompilerServices;
using System.Windows.Media;
using DotSpatial.Projections.Transforms;
using System;
using LibVLCSharp.Shared;
using System.Windows.Input;
using System.IO;
using MediaPlayer = LibVLCSharp.Shared.MediaPlayer;
using ComboBox = System.Windows.Controls.ComboBox;
using Application = System.Windows.Application;
using MessageBox = System.Windows.MessageBox;
using Brush = System.Windows.Media.Brush;
using Brushes = System.Windows.Media.Brushes;
using Label = System.Windows.Controls.Label;
namespace OperationControl.Windows
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
// buffers (X = tempo em segundos)
private readonly List<double> xs = new();
private readonly List<double> ysCorr = new(); // Corrente (A)
private readonly List<double> ysVolt = new(); // Tensão (V)
private readonly List<double> ysTemp = new(); // Temperatura (°C)
private readonly List<double> ysRpm = new(); // RPM
private readonly System.Timers.Timer tmr = new(1000) { AutoReset = true }; // 10 Hz
private double t = 0;
private readonly Random rng = new();
DispatcherTimer _clock = new DispatcherTimer();
Random _rand = new Random();
private LibVLC _libVLC;
private MediaPlayer _playerFront;
private MediaPlayer _playerWeed;
private Media _mediaFront;
private Media _mediaWeed;
private Label _labelModuloSelecionado;
public MainWindow()
{
InitializeComponent();
AtualizarListaDispositivos(new List<string>() { VariaveisControleOperacao.SelectedRoverId });
// Título / eixos
Plot.Plot.Title("MOV ET Corrente / Tensão / Temp / RPM (últimos 60s)");
Plot.Plot.Axes.Bottom.Label.Text = "Tempo (s)";
Plot.Plot.Axes.Left.Label.Text = "Unidades (A, V, °C, RPM)";
// inicializa com um ponto para cada série
PushSample(initial: true);
// legenda
Plot.Plot.ShowLegend(Alignment.UpperRight);
// loop
tmr.Elapsed += (_, __) => Dispatcher.Invoke(() => PushSample());
tmr.Start();
DataContext = this;
// atualizar as caixas
//BBoxes3D.SetBboxes(new[]
//{
// new AgroBase.Models.LivoxBboxModel{ cx=1.2, cy=0.5, cz=0.4, d=0.6, w=0.4, h=0.8 },
// new AgroBase.Models.LivoxBboxModel{ cx=3.0, cy=-0.7, cz=0.6, d=0.8, w=0.5, h=1.2 },
//});
// Opções focadas em baixa latência
_libVLC = new LibVLC(
"--network-caching=1000", // ms (ajusta depois)
"--clock-jitter=0",
"--clock-synchro=0"
);
// Player da câmera frontal
_playerFront = new MediaPlayer(_libVLC);
VideoFront.MediaPlayer = _playerFront;
_playerWeed = new MediaPlayer(_libVLC);
VideoWeed.MediaPlayer = _playerWeed;
Loaded += MainWindow_Loaded;
Closed += MainWindow_Closed;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
}
private void MainWindow_Closed(object? sender, EventArgs e)
{
PararStreamCameraFrontal(true);
PararStreamCameraErvas(true);
_libVLC?.Dispose();
}
private void PushSample(bool initial = false)
{
// avança tempo
if (!initial) t += 1; // 10 Hz
xs.Add(t);
// ------- MOCK de dados plausíveis -------
// Corrente (A): 312 A com ruído
double corr = 8 + 2 * Math.Sin(t * 0.7) + (rng.NextDouble() - 0.5);
corr = Math.Clamp(corr, 0, 30);
// Tensão (V): 3642 V, ripple leve e queda lenta
double volt = 40.5 + 0.6 * Math.Sin(t * 0.15) - 0.002 * t;
volt = Math.Clamp(volt, 30, 42);
// Temperatura (°C): sobe devagar
double temp = 38 + 4 * Math.Sin(t * 0.05) + 0.01 * t;
temp = Math.Clamp(temp, 20, 85);
// RPM: 01500 com variação
double rpm = 1100 + 200 * Math.Sin(t * 0.9) + 80 * (rng.NextDouble() - 0.5);
rpm = Math.Clamp(rpm, 0, 2000);
ysCorr.Add(corr);
ysVolt.Add(volt);
ysTemp.Add(temp);
ysRpm.Add(rpm);
// mantém só últimos 60 s
while (xs.Count > 0 && xs[^1] - xs[0] > 60.0)
{
xs.RemoveAt(0);
ysCorr.RemoveAt(0);
ysVolt.RemoveAt(0);
ysTemp.RemoveAt(0);
ysRpm.RemoveAt(0);
}
// redesenha (v5: passe arrays diretamente)
Plot.Plot.Clear();
// Corrente (A)
var scCorr = Plot.Plot.Add.Scatter(xs.ToArray(), ysCorr.ToArray());
scCorr.Label = "Corrente (A)";
scCorr.Color = ScottPlot.Colors.Cyan;
scCorr.LineWidth = 2;
// Tensão (V)
var scVolt = Plot.Plot.Add.Scatter(xs.ToArray(), ysVolt.ToArray());
scVolt.Label = "Tensão (V)";
scVolt.Color = ScottPlot.Colors.Lime;
scVolt.LineWidth = 2;
// Temperatura (°C)
var scTemp = Plot.Plot.Add.Scatter(xs.ToArray(), ysTemp.ToArray());
scTemp.Label = "Temp (°C)";
scTemp.Color = ScottPlot.Colors.Magenta;
scTemp.LineWidth = 2;
// RPM
var scRpm = Plot.Plot.Add.Scatter(xs.ToArray(), ysRpm.ToArray());
scRpm.Label = "RPM";
scRpm.Color = ScottPlot.Colors.Orange;
scRpm.LineWidth = 2;
// janela de 60 s rolando
double xEnd = xs[^1];
double xStart = Math.Max(0, xEnd - 60.0);
Plot.Plot.Axes.SetLimitsX(xStart, xEnd);
Plot.Plot.Axes.AutoScaleY(); // ajusta Y automaticamente para caber tudo
Plot.Refresh();
}
#region DISPOSITIVOS
public void AtualizarListaDispositivos(List<string> dispositivos)
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
cmbDispositivo.Items.Clear();
foreach (var d in dispositivos)
{
cmbDispositivo.Items.Add(d);
if (!MAP.markers.Added(d))
{
if (d == VariaveisControleOperacao.BaseMarkerID)
{
MAP.markers.AddMarker(
d,
true,
lat: Variaveis.GpsService?.UltimaLeitura?.Latitude ?? 0,
lon: Variaveis.GpsService?.UltimaLeitura?.Longitude ?? 0,
heading: Variaveis.GpsService?.UltimaLeitura?.OrientacaoReal ?? 0,
label: "Base"
);
}
else
{
var rover = VariaveisControleOperacao.RoversNaRede.FirstOrDefault(x => x.RoverId == d);
if (rover != null)
{
MAP.markers.AddMarker(
d,
false,
lat: rover.DadosLeitura?.Gps?.Latitude ?? 0,
lon: rover.DadosLeitura?.Gps?.Longitude ?? 0,
heading: rover.DadosLeitura?.Gps?.AnguloCarroDefinido ?? 0
);
}
}
}
}
int idx_selected = dispositivos.IndexOf(VariaveisControleOperacao.SelectedRoverId);
if (idx_selected > -1)
cmbDispositivo.SelectedIndex = idx_selected;
}
catch (Exception exUi)
{
Variaveis.MostrarLog($"Erro ao atualizar UI lista dispositivos: {exUi.Message}");
}
}));
}
private void cmbDispositivo_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
var selecionado = ((ComboBox)sender).SelectedItem;
if (selecionado == null) return;
bool dados_base = selecionado == VariaveisControleOperacao.BaseMarkerID;
if (dados_base && !VariaveisControleOperacao.BaseEmFoco)
{
PararStreamCameraFrontal();
PararStreamCameraErvas();
}
VariaveisControleOperacao.SelectedRoverId = selecionado.ToString();
MAP.markers.SetMarkerFocused(selecionado.ToString(), true);
AtualizarDadosTela_Telemetria(selecionado.ToString());
brdResumo.IsEnabled = !dados_base;
brdDiagnostico.IsEnabled = !dados_base;
brdControle.IsEnabled = !dados_base;
brdAjustesOperacao.IsEnabled = !dados_base;
if (!dados_base)
{
sldGNSS_LeverArm.Value = VariaveisControleOperacao.RoverEmFoco.DadosLeitura?.Gps?.LeverArmLateral ?? 0;
btnParametros_Atualizar_Click(sender, e);
IniciarStreamCameraFrontal();
IniciarStreamCameraErvas();
}
}
public void LimparDadosTela_Telemetria(string rover_id)
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
if (!string.IsNullOrEmpty(rover_id))
{
//MAP.markers.RemoveMarker(rover_id);
//cmbDispositivo.Items.Remove(rover_id);
}
else
{
//cmbDispositivo.SelectedIndex = 0;
}
}
catch (Exception exUi)
{
Variaveis.MostrarLog($"Erro ao atualizar UI telemetria (clear): {exUi.Message}");
}
}));
}
public void AtualizarDadosTela_Telemetria(string rover_id)
{
bool dados_base = rover_id == VariaveisControleOperacao.BaseMarkerID;
var rover = VariaveisControleOperacao.RoversNaRede.FirstOrDefault(x => x.RoverId == rover_id);
var dados_leitura = rover?.DadosLeitura;
if (dados_base)
{
MAP.markers.UpdateMarkerPosition(rover_id, lat: Variaveis.GpsService?.UltimaLeitura?.Latitude, lon: Variaveis.GpsService?.UltimaLeitura?.Longitude, heading: Variaveis.GpsService?.UltimaLeitura?.OrientacaoReal);
}
else if (dados_leitura != null)
{
var simulacao = dados_leitura.Controle?.SimulacaoMPC?.Select(x => new double[] { x.longitude, x.latitude })?.ToList();
MAP.markers.UpdateMarkerPosition(rover_id, lat: dados_leitura?.Gps?.Latitude, lon: dados_leitura?.Gps?.Longitude, heading: dados_leitura?.Gps?.OrientacaoReal, predict: simulacao);
MAP.markers.UpdateMarkerInfo(rover_id, status: dados_leitura.StatusOperacao);
}
if (rover_id != VariaveisControleOperacao.SelectedRoverId) return;
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
if (rover_id == VariaveisControleOperacao.BaseMarkerID)
{
Variaveis.MostrarLog($"Atualizando dados da tela para a base");
AtualizarDadosTela_GNSS(Variaveis.GpsService?.UltimaLeitura ?? new AgroBase.Models.GPSModel(), marker_id: VariaveisControleOperacao.BaseMarkerID);
AtualizarDadosTela_Heading(Variaveis.GpsService?.UltimaLeitura?.AnguloCarroDefinido ?? 0);
}
else
{
if (dados_leitura == null) return;
Variaveis.MostrarLog($"Atualizando dados da tela para o dispositivo {rover_id}");
AtualizarDadosTela_Diagnosticos(rover);
if (dados_leitura.Trajetoria != null)
AtualizarDadosTela_Resumo(dados_leitura);
if (dados_leitura.Gps != null)
AtualizarDadosTela_GNSS(dados_leitura.Gps, marker_id: rover_id);
if (dados_leitura.Controle != null)
AtualizarDadosTela_Controle(dados_leitura.Controle, dados_leitura.Movimentacao.AnguloMedio, dados_leitura.Movimentacao.VelocidadeMedia, dados_leitura.Emergencia, !dados_leitura.OperacaoIniciada, dados_leitura.StatusOperacao == AgroBase.Models.Enums.StatusOperacao.Calibrando);
//if (rover.Value.Controle != null)
// AtualizarDadosTela_ParametrosOperacao(rover.Value.Controle);
if (dados_leitura.Trajetoria != null)
AtualizarDadosTela_Mapa(dados_leitura.Trajetoria);
if (dados_leitura.Gps != null)
AtualizarDadosTela_Heading(dados_leitura.Gps.AnguloCarroDefinido, dados_leitura.Modo == AgroBase.Models.Enums.ModoOperacao.Manual ? double.NaN : dados_leitura.Trajetoria.AnguloCaminho);
if (dados_leitura.IMU != null)
AtualizarDadosTela_IMU(dados_leitura.IMU.InclinacaoLateral, dados_leitura.IMU.InclinacaoFrontal);
if (dados_leitura.LivoxLidar != null)
AtualizarDadostela_LIDAR(dados_leitura.LivoxLidar.bboxes);
}
}
catch (Exception exUi)
{
Variaveis.MostrarLog($"Erro ao atualizar UI telemetria (set): {exUi.Message}");
}
}));
}
#endregion
#region RESUMO OPERACIONAL
public void AtualizarDadosTela_Resumo(AgroBase.Models.OperacaoSensoriamentoLogModel dados)
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
pgbResumo_RuaAtual.Value = dados.Trajetoria.PercentualRuaAtual;
lblResumo_RuaAtual.Content = $"{dados.Trajetoria.CorredorAtual.DistanciaPercorridaCorredor.ToString("0.00")} / {dados.Trajetoria.CorredorAtual.DistanciaTotal.ToString("0.00")}";
pgbResumo_AreaTotal.Value = dados.Trajetoria.PercentualOperacao;
lblResumo_AreaTotal.Content = $"{dados.Trajetoria.DistanciaPercorrida.ToString("0.00")} / {dados.Trajetoria.DistanciaTotal.ToString("0.00")}";
pgbResumo_Bateria.Value = dados.Bateria.PorcentagemBateria;
lblResumo_Bateria.Content = $"{dados.Bateria.TensaoInstantanea.ToString("0.00")} V ({dados.Bateria.TempoEstimadoRestanteMinutos})";
pgbResumo_Herbicida.Value = dados.Atuador.PercentualReservatorio;
lblResumo_Herbicida.Content = $"{dados.Atuador.VolumeReservatorio.ToString("0.00")} L ({0.ToString("0.00")})";
pgbResumo_Infestacao.Value = dados.Atuador.PercentualErvasTerreno;
lblResumo_Infestacao.Content = $"{dados.Atuador.VazaoMedia.ToString("0.00")}";
pgbResumo_Conexao.Value = 0;
lblResumo_Conexao.Content = $"0,0 dBi (0,00 m)";
lblResumo_OperacaoLiberada.Content = $"Operação " + (dados.OperacaoLiberada ? "🔓 Liberada" : "🔒 Bloqueada");
lblResumo_OperacaoModo.Content = $"Modo {dados.Modo}";
lblResumo_OperacaoStatus.Content = $"Status {dados.StatusOperacao}" + (dados.StatusOperacao == AgroBase.Models.Enums.StatusOperacao.Aguardando ? $" ({dados.TempoAguardandoSeg.ToString("0")})" : "");
lblResumo_StatusCarro.Content = $"Carro {dados.Trajetoria.StatusCarro}";
lblResumo_TemperaturaGeral.Content = $"Temperatura {(dados.DadosPerformance.CPU_temp ?? 0).ToString("0.00")} °C";
lblResumo_OperacaoDuracao.Content = $"Duração {dados.TempoDecorrido.ToString("HH:mm:ss")} / {dados.Trajetoria.TempoEstimadoOperacao}";
}
catch (Exception exUi)
{
Variaveis.MostrarLog($"Erro ao atualizar UI Resumo: {exUi.Message}");
}
}));
}
#endregion
#region DIAGNOSTICOS
private void AtualizarDadosTela_Diagnosticos(AgroBase.Models.Operacoes.OperacaoParametrosModel dados)
{
lblDiagnosticos_Impedimento.Content = "Impedimento: " + (string.IsNullOrEmpty(dados.DadosLeitura.ErroOperacaoLiberada) ? "Nenhum" : dados.DadosLeitura.ErroOperacaoLiberada);
// Canvas que está dentro do Border
var canvas = brdDiagnostico.Child as Canvas;
if (canvas == null)
return;
// Percorre apenas labels dentro do Canvas com o prefixo desejado
foreach (var lbl in canvas.Children.OfType<Label>().Where(x => x.Name.StartsWith("lblDiagnosticos_")))
{
(var modulo, var mod_label) = GetModuleData(lbl);
if (modulo == AgroBase.Models.Enums.T_Code.Vzo)
continue;
// Procura a saúde desse módulo
var saude = dados.DadosLeitura.ModulosSaude.FirstOrDefault(x => x.modulo == modulo);
if (saude == null)
continue;
var individual = saude.saude_individual.FirstOrDefault(x => x.label == mod_label);
bool mandatorio = dados.DadosLeitura.ModulosMandatorios.Any(x => x.Dispositivo == modulo && x.Mandatorio);
// Aplica cor de acordo com o status
AplicarStatusModuloNaLabel(lbl, individual?.status ?? saude.status, mandatorio);
}
}
private void AplicarStatusModuloNaLabel(Label lbl, AgroBase.Models.Enums.StatusModulo status, bool mandatorio)
{
// você pode ajustar essas cores depois
Brush back;
Brush fore = Brushes.White;
switch (status)
{
case AgroBase.Models.Enums.StatusModulo.Desconectado:
back = mandatorio ? Brushes.Red : Brushes.Gray;
break;
case AgroBase.Models.Enums.StatusModulo.Conectado:
back = Brushes.SteelBlue;
break;
case AgroBase.Models.Enums.StatusModulo.Falha:
back = Brushes.Red;
break;
case AgroBase.Models.Enums.StatusModulo.Alerta:
back = Brushes.Orange;
break;
case AgroBase.Models.Enums.StatusModulo.Operante:
back = Brushes.Green;
break;
default:
back = Brushes.DarkGray;
break;
}
lbl.Background = back;
lbl.Foreground = fore;
}
private (AgroBase.Models.Enums.T_Code, string) GetModuleData(Label lbl)
{
string lbl_name = lbl.Name.Replace("lblDiagnosticos_", "");
string[] pts = lbl_name.Split('_');
string mod_name = pts[0];
string mod_label = pts.Length > 1 ? pts[1] : "";
if (!Enum.TryParse<AgroBase.Models.Enums.T_Code>(mod_name, ignoreCase: true, out var modulo))
return (AgroBase.Models.Enums.T_Code.Vzo, "");
return (modulo, mod_label);
}
private void DiagnosticoModulo_Click(object sender, MouseButtonEventArgs e)
{
if (sender is not Label lbl)
return;
// desfazer seleção antiga
if (_labelModuloSelecionado != null)
{
_labelModuloSelecionado.BorderBrush = Brushes.Transparent;
_labelModuloSelecionado.BorderThickness = new Thickness(1);
_labelModuloSelecionado.Effect = null;
}
// selecionar a nova
_labelModuloSelecionado = lbl;
_labelModuloSelecionado.BorderBrush = Brushes.Yellow;
_labelModuloSelecionado.BorderThickness = new Thickness(2);
// opcional — glow bonito
_labelModuloSelecionado.Effect = new System.Windows.Media.Effects.DropShadowEffect
{
Color = System.Windows.Media.Colors.Yellow,
BlurRadius = 8,
ShadowDepth = 0,
Opacity = 0.9
};
(var modulo, var mod_label) = GetModuleData(lbl);
if (modulo == AgroBase.Models.Enums.T_Code.Vzo)
return;
// Aqui você chama o método que quiser:
AbrirDetalhesModulo(modulo, mod_label);
}
private void AbrirDetalhesModulo(AgroBase.Models.Enums.T_Code modulo, string label)
{
var rover = VariaveisControleOperacao.RoverEmFoco;
var dispositivo = rover?.DadosLeitura?.DispositivosMapeados?.FirstOrDefault(x => x.Dispositivo == modulo && x.Mod_ID == label);
if (dispositivo == null)
{
MessageBox.Show($"Sem dados para o módulo {modulo} ({label})");
return;
}
lblSaude_Descricao.Content = $"Módulo {dispositivo.Dispositivo} {dispositivo.Mod_ID}";
lblSaude_Versao.Content = $"Versão {dispositivo.Versao ?? "-"}";
lblSaude_Status.Content = $"{dispositivo.Status} (Saúde {dispositivo.Saude}%)";
lblSaude_CAN.Content = $"CAN {dispositivo.VelocidadeBarramento} ms";
lblSaude_Latencia.Content = $"Latência {dispositivo.Latencia} ms";
lblSaude_Impedimento.Content = $"Impedimento: {dispositivo.Erros ?? "Nenhum"}";
}
#endregion
#region POSICAO
public void AtualizarDadosTela_GNSS(AgroBase.Models.GPSModel dados, string? marker_id = null, double progresso = double.NaN)
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
bool dados_base = marker_id == VariaveisControleOperacao.BaseMarkerID;
lblGNSS_Posicao.Foreground = new SolidColorBrush(dados.Inicializado ? System.Windows.Media.Colors.Green : System.Windows.Media.Colors.Red);
lblGNSS_Correcao.Content = $"Correção {dados.QualidadeFix} " +
(dados.QualidadeFix == AgroBase.Models.Enums.TiposCorrecaoGPS.BaseFix ?
(dados.OrientacaoReal.ToString("0.00") + "°") :
((dados.Ntrip_ativado ? "N" : "B") + $" {dados.IdadeCorrecao.ToString("0.0")} s"));
lblGNSS_Satelites.Content = $"Satélites {dados.NumeroSatelites} ({dados.PrecisaoCm.ToString("0.00")} cm)";
lblGNSS_Altitude.Content = $"Altitude {dados.Altitude.ToString("0.00")} m";
if (dados_base)
{
sldGNSS_LeverArm.Visibility = Visibility.Hidden;
if (double.IsNaN(progresso))
{
lblGNSS_Progresso.Visibility = Visibility.Hidden;
}
else
{
lblGNSS_Progresso.Visibility = Visibility.Visible;
lblGNSS_Progresso.Content = $"{progresso.ToString("0.00")}%";
}
bool gnss_fix_preciso = new List<AgroBase.Models.Enums.TiposCorrecaoGPS>() { AgroBase.Models.Enums.TiposCorrecaoGPS.RTKFixo, AgroBase.Models.Enums.TiposCorrecaoGPS.RTKFlutuante }.Contains(Variaveis.GpsService?.UltimaLeitura?.QualidadeFix ?? AgroBase.Models.Enums.TiposCorrecaoGPS.SemCorrecao);
bool gnss_fixado = Variaveis.GpsService?.BaseFix?.CorrecaoAbsoluta ?? false;
bool gnss_fixando = btnGNSS_FixarBase.Content.ToString() == "Parar";
btnGNSS_FixarBase.IsEnabled = (gnss_fix_preciso && !gnss_fixado) || gnss_fixando || gnss_fixado;
btnGNSS_FixarBase.Content = gnss_fixado || !gnss_fixando ? "Fixar" : "Parar";
}
else
{
btnGNSS_FixarBase.IsEnabled = true;
sldGNSS_LeverArm.Visibility = Visibility.Visible;
lblGNSS_Progresso.Visibility = Visibility.Visible;
lblGNSS_Progresso.Content = $"{(sldGNSS_LeverArm.Value * 10.0).ToString("0")} cm";
lblGNSS_Progresso.Foreground = new SolidColorBrush(Math.Round(sldGNSS_LeverArm.Value * 10.0, 0) == Math.Round(dados.LeverArmLateral, 0) ? System.Windows.Media.Colors.Black : System.Windows.Media.Colors.Red);
btnGNSS_FixarBase.Content = "Aplicar";
}
}
catch (Exception exUi)
{
Variaveis.MostrarLog($"Erro ao atualizar UI GNSS: {exUi.Message}");
}
}));
}
private void btnGNSS_FixarBase_Click(object sender, RoutedEventArgs e)
{
if (VariaveisControleOperacao.BaseEmFoco)
{
if (!Variaveis.GpsService.BaseFix.FixLiberado)
{
if (Variaveis.GpsService.BaseFix.CorrecaoAbsoluta)
{
var res = MessageBox.Show("Mudar posição da base?", "Tem certeza que deseja fixar a posição da base novamente?", MessageBoxButton.YesNo, MessageBoxImage.Question);
if (res == MessageBoxResult.Yes)
{
btnGNSS_FixarBase.Content = "Parar";
Variaveis.GpsService.BaseFix.FixLiberado = true;
Task.Run(async () => await Variaveis.GpsService.ConfigurarModulo());
}
}
else
{
btnGNSS_FixarBase.Content = "Parar";
Variaveis.GpsService.BaseFix.FixLiberado = true;
}
}
else
{
btnGNSS_FixarBase.Content = "Fixar";
Variaveis.GpsService.BaseFix.FixLiberado = false;
}
}
else
{
VariaveisControleOperacao.EnviarComandoLeverArm(sldGNSS_LeverArm.Value * 10.0);
}
}
private void sldGNSS_LeverArm_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
lblGNSS_Progresso.Content = $"{(sldGNSS_LeverArm.Value * 10.0).ToString("0")} cm";
}
#endregion
#region CONTROLE
public void AtualizarDadosTela_Controle(AgroBase.Models.OperacaoControleModel controle, double angulo, double velocidade, bool emergencia, bool pausa, bool refing)
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
CTRL.AtualizarDadosControle(
angSp: controle.Angulo,
angCur: angulo,
tipoMov: controle.TipoMovimento,
velPct: controle.PercentualVelocidadeSP,
velSp: controle.PercentualVelocidadeSPKmh,
velKmh: velocidade,
emg: emergencia,
pause: pausa,
refing: refing
);
}
catch (Exception exUi)
{
Variaveis.MostrarLog($"Erro ao atualizar UI Controle: {exUi.Message}");
}
}));
}
#endregion
#region PARAMETROS DA OPERACAO
public void AtualizarDadosTela_ParametrosOperacao(AgroBase.Models.Operacoes.OperacaoParametrosControleModel? controle)
{
if (controle == null) return;
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
txtParametros_VelCErvas.Text = controle.MovVelocidadeCErvasPercent.ToString();
txtParametros_VelSErvas.Text = controle.MovVelocidadeSErvasPercent.ToString();
txtParametros_AngMax.Text = controle.DirAnguloMaximo.ToString();
txtParametros_RoiAtuacao.Text = controle.AtuPercentualInicioPulverizacao.ToString();
txtParametros_AreaAtuacao.Text = controle.AtuAlturaAreaPulverizacao.ToString();
txtParametros_PressaoLiha.Text = controle.AtuPressaoLinha.ToString();
txtParametros_PctErvaOn.Text = controle.AtuPercentualErvasBicoOn.ToString();
txtParametros_PctErvaOff.Text = controle.AtuPercentualErvasBicoOff.ToString();
txtParametros_TempoOn.Text = controle.AtuDuracaoAtuacao.ToString();
chbParametros_Pulverizador.IsChecked = controle.PulverizadorAutomatico;
chbParametros_Frenagem.IsChecked = controle.FrenagemAutomatica;
chbParametros_Sonar.IsChecked = controle.SonarAtivado;
}
catch (Exception exUi)
{
Variaveis.MostrarLog($"Erro ao atualizar UI Parametros da Operacao: {exUi.Message}");
}
}));
}
private void btnParametros_Salvar_Click(object sender, RoutedEventArgs e)
{
var modo = (CTRL.TgManual.IsChecked ?? false) ? AgroBase.Models.Enums.ModoOperacao.Manual : AgroBase.Models.Enums.ModoOperacao.MapaGPS;
VariaveisControleOperacao.EnviarParametrosOperacao(new AgroBase.Models.Operacoes.OperacaoParametrosModel()
{
Modo = modo,
Descricao = "Operacao da base",
QtdCamerasSolo = 1,
QtdBicos = 3,
CapacidadeReservatorio = 45,
Controle = new AgroBase.Models.Operacoes.OperacaoParametrosControleModel()
{
MovimentoAutomatico = modo != AgroBase.Models.Enums.ModoOperacao.Manual,
SonarAtivado = chbParametros_Sonar.IsChecked ?? false,
FrenagemAutomatica = chbParametros_Frenagem.IsChecked ?? false,
MovVelocidadeCErvasPercent = int.Parse(txtParametros_VelCErvas.Text),
MovVelocidadeSErvasPercent = int.Parse(txtParametros_VelSErvas.Text),
DirAnguloMaximo = int.Parse(txtParametros_AngMax.Text),
DirTipoMovimento = AgroBase.Models.Enums.TiposControladorDirecional.MPC,
DirVelocidadeMovimento = 50,
PulverizadorAutomatico = chbParametros_Pulverizador.IsChecked ?? false,
AtuPercentualErvasBicoOn = double.Parse(txtParametros_PctErvaOn.Text),
AtuPercentualErvasBicoOff = double.Parse(txtParametros_PctErvaOff.Text),
AtuDuracaoAtuacao = int.Parse(txtParametros_TempoOn.Text),
AtuAlturaAreaPulverizacao = double.Parse(txtParametros_AreaAtuacao.Text),
AtuPercentualInicioPulverizacao = double.Parse(txtParametros_RoiAtuacao.Text),
AtuPressaoLinha = double.Parse(txtParametros_PressaoLiha.Text),
},
ModulosMandatorios = new List<AgroBase.Models.OperacaoModulosMandatoriosModel>(),
ParametrosMandatorios = new List<AgroBase.Models.OperacaoParametrosMandatoriosModel>(),
RuasPercorrer = MAP.RuasMapaCarregado.Where(x => x.Selected).Select(x => x.Id).ToList(),
Mapa = MAP.CriarDadosMapa()
});
}
private void btnParametros_Atualizar_Click(object sender, RoutedEventArgs e)
{
VariaveisControleOperacao.RequisitarParametrosOperacao();
}
#endregion
#region MAPA
private void MAP_MarkerClicked(object? sender, MapMarkerManager.MarkerClickedEventArgs e)
{
if (string.IsNullOrEmpty(e.MarkerId))
{
Variaveis.MostrarLog($"Sem rover em foco");
LimparDadosTela_Telemetria(e.MarkerId);
}
else
{
Variaveis.MostrarLog($"Rover em foco: {e.MarkerId}");
int idx = cmbDispositivo.Items.IndexOf(e.MarkerId);
cmbDispositivo.SelectedIndex = idx;
}
}
private void MAP_StreetMapClicked(object? sender, MapViewControl.StreetMapClickedEventArgs e)
{
Variaveis.MostrarLog($"Rua clicada: {e.StreetId}. Ruas selecionadas: {string.Join(",", e.SelectedStreetsIds)}");
}
private void AtualizarDadosTela_Mapa(AgroBase.Models.OperacaoSensoriamentoLogTrajetoriaModel Trajetoria)
{
lblMapaInfo_Debug.Content = $"" +
$"Próximo Ponto: {Trajetoria.ProximoPonto.idxPonto} | " +
(Trajetoria.ProximoPonto.Aproximando ? "Aproximando" : "Afastando") + " | " +
$"Distância próximo ponto: {Trajetoria.ProximoPonto.DistanciaAtual.ToString("0.00")} m | " +
$"Distância ponto anterior: {Trajetoria.PontoAtual.DistanciaAtual.ToString("0.00")} m | " +
$"Corredor: " + (Trajetoria.CorredorAtual.Dentro ? "Dentro" : "Fora") + " | " +
$"Margem: " + (Trajetoria.NaMargemDoCorredor ? "Sim" : "Não") + " | " +
$"Disância Esquerda: {(Trajetoria.DistanciaEsquerda * 100.0).ToString("0.00")} cm | " +
$"Distância Direita: {(Trajetoria.DistanciaDireita * 100.0).ToString("0.00")} cm | " +
$"Status: {Trajetoria.StatusCarro}";
double erroLateral = (Trajetoria.DistanciaEsquerda - Trajetoria.DistanciaDireita) / 2.0 * 100.0;
AtualizarDadosTela_IMU(erro_lateral: erroLateral);
}
#endregion
#region HEADING
public void AtualizarDadosTela_Heading(double headingRover, double headingCourse = double.NaN)
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
HDG.Heading = headingRover;
HDG.CourseHeading = headingCourse;
}
catch (Exception exUi)
{
Variaveis.MostrarLog($"Erro ao atualizar UI Heading: {exUi.Message}");
}
}));
}
#endregion
#region IMU
public void AtualizarDadosTela_IMU(double? roll = null, double? pitch = null, double? erro_lateral = null)
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
if (roll != null) IMU.RollDeg = (double)roll;
if (pitch != null) IMU.PitchDeg = (double)pitch;
if (erro_lateral != null) IMU.LateralError = (double)erro_lateral;
}
catch (Exception exUi)
{
Variaveis.MostrarLog($"Erro ao atualizar UI IMU: {exUi.Message}");
}
}));
}
#endregion
#region CAMERA FRONTAL
private void IniciarStreamCameraFrontal()
{
var path = @"streams\camera_frontal.sdp";
if (!File.Exists(path))
{
string stream =
"v=0\r\n" +
"o=- 0 0 IN IP4 0.0.0.0\r\n" +
"s=OAK H264\r\n" +
"c=IN IP4 0.0.0.0\r\n" +
"t=0 0\r\n" +
"m=video 5000 RTP/AVP 96\r\n" +
"a=rtpmap:96 H264/90000\r\n" +
"a=fmtp:96 packetization-mode=1\r\n";
File.WriteAllText(path, stream);
}
_mediaFront?.Dispose(); // limpa antigo, se existir
_mediaFront = new Media(_libVLC, path, FromType.FromPath);
// _mediaFront.AddOption(":network-caching=150"); // se quiser por arquivo
_playerFront.Play(_mediaFront);
VariaveisControleOperacao.EnviarComandoTransmissaoVideo(AgroBase.Models.Enums.T_Code.Snr, true);
}
private void PararStreamCameraFrontal(bool finalizar = false)
{
_playerFront?.Stop();
if (finalizar)
{
_mediaFront?.Dispose();
_mediaFront = null;
_playerFront?.Dispose();
_playerFront = null;
}
VariaveisControleOperacao.EnviarComandoTransmissaoVideo(AgroBase.Models.Enums.T_Code.Snr, false);
}
#endregion
#region CAMERA ERVAS
private void IniciarStreamCameraErvas()
{
var path = @"streams\camera_ervas.sdp";
if (!File.Exists(path))
{
string stream =
"v=0\r\n" +
"o=- 0 0 IN IP4 0.0.0.0\r\n" +
"s=OAK H264\r\n" +
"c=IN IP4 0.0.0.0\r\n" +
"t=0 0\r\n" +
"m=video 5002 RTP/AVP 96\r\n" + // <- porta 5001
"a=rtpmap:96 H264/90000\r\n" +
"a=fmtp:96 packetization-mode=1\r\n";
File.WriteAllText(path, stream);
}
_mediaWeed?.Dispose();
_mediaWeed = new Media(_libVLC, path, FromType.FromPath);
// _mediaWeed.AddOption(":network-caching=150");
_playerWeed.Play(_mediaWeed);
VariaveisControleOperacao.EnviarComandoTransmissaoVideo(AgroBase.Models.Enums.T_Code.Cam, true);
}
private void PararStreamCameraErvas(bool finalizar = false)
{
_playerWeed?.Stop();
if (finalizar)
{
_mediaWeed?.Dispose();
_mediaWeed = null;
_playerWeed?.Dispose();
_playerWeed = null;
}
VariaveisControleOperacao.EnviarComandoTransmissaoVideo(AgroBase.Models.Enums.T_Code.Cam, false);
}
#endregion
#region PULVERIZADOR
private void btnB0_Click(object sender, RoutedEventArgs e)
{
btnB0.Content = (btnB0.Content.ToString() == "Ligar") ? "Desligar" : "Ligar";
}
#endregion
#region LIDAR
public void AtualizarDadostela_LIDAR(List<AgroBase.Models.LivoxBboxModel> bboxes)
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
BBoxes3D.SetBboxes(bboxes);
}
catch (Exception exUi)
{
Variaveis.MostrarLog($"Erro ao atualizar UI Lidar: {exUi.Message}");
}
}));
}
#endregion
}
}