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

367 lines
13 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;
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();
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 },
//});
}
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)
{
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,
Variaveis.GpsService?.UltimaLeitura?.Latitude ?? 0,
Variaveis.GpsService?.UltimaLeitura?.Longitude ?? 0,
Variaveis.GpsService?.UltimaLeitura?.OrientacaoReal ?? 0,
MAP.markers.GetColorForMarker(d, isBase: true),
"Base"
);
}
else
{
var rover = VariaveisControleOperacao.RoversNaRede.FirstOrDefault(x => x.Key == d);
if (rover.Value != null)
{
MAP.markers.AddMarker(
d,
rover.Value.Gps?.Latitude ?? 0,
rover.Value.Gps?.Longitude ?? 0,
rover.Value.Gps?.AnguloCarroDefinido ?? 0,
MAP.markers.GetColorForMarker(d, isBase: false),
rover.Key
);
}
}
}
}
int idx_selected = dispositivos.IndexOf(VariaveisControleOperacao.SelectedRoverId);
if (idx_selected > -1)
cmbDispositivo.SelectedIndex = idx_selected;
}
private void cmbDispositivo_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
AtualizarDadosTela_Telemetria(((ComboBox)sender).SelectedValue.ToString());
}
public void LimparDadosTela_Telemetria()
{
VariaveisControleOperacao.SelectedRoverId = "";
}
public void AtualizarDadosTela_Telemetria(string rover_id)
{
if (rover_id != VariaveisControleOperacao.SelectedRoverId) return;
if (rover_id == VariaveisControleOperacao.BaseMarkerID)
{
Variaveis.MostrarLog($"Atualizando dados da tela para a base");
AtualizarDadosTela_GNSS(Variaveis.GpsService?.UltimaLeitura ?? new AgroBase.Models.GPSModel());
AtualizarDadosTela_Heading(Variaveis.GpsService?.UltimaLeitura?.AnguloCarroDefinido ?? 0);
}
else
{
var rover = VariaveisControleOperacao.RoversNaRede.FirstOrDefault(x => x.Key == rover_id);
if (rover.Value == null) return;
Variaveis.MostrarLog($"Atualizando dados da tela para o dispositivo {rover_id}");
AtualizarDadosTela_GNSS(rover.Value.Gps);
AtualizarDadosTela_Heading(rover.Value.Gps.AnguloCarroDefinido, rover.Value.Modo == AgroBase.Models.Enums.ModoOperacao.Manual ? double.NaN : rover.Value.Trajetoria.AnguloCaminho);
AtualizarDadosTela_IMU(rover.Value.IMU.InclinacaoLateral, rover.Value.IMU.InclinacaoFrontal);
AtualizarDadostela_LIDAR(rover.Value.LivoxLidar.bboxes);
}
}
#endregion
#region IMU
public void AtualizarDadosTela_IMU(double roll, double pitch)
{
IMU.RollDeg = roll;
IMU.PitchDeg = pitch;
}
#endregion
#region HEADING
public void AtualizarDadosTela_Heading(double headingRover, double headingCourse = double.NaN)
{
HDG.Heading = headingRover;
HDG.CourseHeading = headingCourse;
}
#endregion
#region MAPA
private void MAP_MarkerClicked(object? sender, MapMarkerManager.MarkerClickedEventArgs e)
{
Variaveis.MostrarLog($"Rover em foco: {e.MarkerId}");
if (string.IsNullOrEmpty(e.MarkerId))
{
LimparDadosTela_Telemetria();
}
else
{
VariaveisControleOperacao.SelectedRoverId = e.MarkerId;
AtualizarDadosTela_Telemetria(e.MarkerId);
}
}
private void MAP_StreetMapClicked(object? sender, MapViewControl.StreetMapClickedEventArgs e)
{
Variaveis.MostrarLog($"Rua clicada: {e.StreetId}. Ruas selecionadas: {string.Join(",", e.SelectedStreetsIds)}");
}
#endregion
#region PULVERIZADOR
private void btnB0_Click(object sender, RoutedEventArgs e)
{
btnB0.Content = (btnB0.Content.ToString() == "Ligar") ? "Desligar" : "Ligar";
}
#endregion
#region POSICAO
public void AtualizarDadosTela_GNSS(AgroBase.Models.GPSModel dados, string marker_id = null, double progresso = double.NaN)
{
lblGNSS_Posicao.Foreground = dados.Inicializado ? new SolidColorBrush(System.Windows.Media.Colors.Green) : new SolidColorBrush(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 (double.IsNaN(progresso))
{
lblGNSS_Progresso.Visibility = Visibility.Hidden;
btnGNSS_FixarBase.Visibility = Visibility.Hidden;
}
else
{
lblGNSS_Progresso.Visibility = Visibility.Visible;
btnGNSS_FixarBase.Visibility = Visibility.Visible;
lblGNSS_Progresso.Content = $"{progresso.ToString("0.00")}%";
if ((Variaveis.GpsService?.BaseFix?.CorrecaoAbsoluta ?? false) && Variaveis.GpsService.BaseFix.FixLiberado && btnGNSS_FixarBase.Content.ToString() == "Parar")
{
Variaveis.GpsService.BaseFix.FixLiberado = false;
btnGNSS_FixarBase.Content = "Fixar";
}
}
if (!string.IsNullOrEmpty(marker_id))
MAP.markers.UpdateMarkerPosition(marker_id, dados.Latitude, dados.Longitude, dados.OrientacaoReal);
}
private void btnGNSS_FixarBase_Click(object sender, RoutedEventArgs e)
{
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;
}
}
#endregion
#region LIDAR
public void AtualizarDadostela_LIDAR(List<AgroBase.Models.LivoxBboxModel> bboxes)
{
BBoxes3D.SetBboxes(bboxes);
}
#endregion
}
}