added status of mobile robot in UI

implemented battery state for both robots in RobotLib
main
Jonas Arnold 4 years ago
parent 82c449ba29
commit 630f504785
  1. 16
      ADIS_Csharp/RobotClientWpf/Utilities/UIAccessHelpers.cs
  2. 2
      ADIS_Csharp/RobotClientWpf/Views/ConfigView.xaml
  3. 8
      ADIS_Csharp/RobotClientWpf/Views/ConfigView.xaml.cs
  4. 19
      ADIS_Csharp/RobotClientWpf/Views/MainView.xaml
  5. 17
      ADIS_Csharp/RobotClientWpf/Views/MainView.xaml.cs
  6. 40
      ADIS_Csharp/RobotLib/Battery/DevBattery.cs
  7. 2
      ADIS_Csharp/RobotLib/Communication/MqttPublisherSubscriber.cs
  8. 20
      ADIS_Csharp/RobotLib/Robot.cs

@ -3,6 +3,7 @@ using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Controls.Primitives; using System.Windows.Controls.Primitives;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Shapes;
namespace RobotClientWpf.Utilities namespace RobotClientWpf.Utilities
{ {
@ -99,5 +100,20 @@ namespace RobotClientWpf.Utilities
textBlock.Foreground = foregroundColor; textBlock.Foreground = foregroundColor;
} }
} }
public static void SetShapeVisibility(Shape shape, bool visible)
{
if (!Application.Current.Dispatcher.CheckAccess())
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
SetShapeVisibility(shape, visible);
}));
}
else
{
shape.Opacity = visible?100:0;
}
}
} }
} }

@ -76,7 +76,7 @@
<StackPanel Orientation="Vertical"> <StackPanel Orientation="Vertical">
<StackPanel DockPanel.Dock="Left" Orientation="Horizontal" VerticalAlignment="Top"> <StackPanel DockPanel.Dock="Left" Orientation="Horizontal" VerticalAlignment="Top">
<Label DockPanel.Dock="Left" Content="Hostname:" Margin="5 0" Height="30" Width="100"/> <Label DockPanel.Dock="Left" Content="Hostname:" Margin="5 0" Height="30" Width="100"/>
<TextBox DockPanel.Dock="Left" x:Name="tbRobotConfiguratorHostname" Width="200" Height="30" Margin="5" TextChanged="tbRobotConfiguratorHostname_TextChanged"/> <TextBox DockPanel.Dock="Left" x:Name="tbRobotConfiguratorHostname" Width="300" Height="30" Margin="5" Text="ADISRobotExx.simple.eee.intern" TextChanged="tbRobotConfiguratorHostname_TextChanged"/>
<Button DockPanel.Dock="Left" x:Name="btnClearRobotConfHostname" Content="Clear" Margin="5" Width="50" Height="30" Click="btnClearRobotConfHostname_Click" /> <Button DockPanel.Dock="Left" x:Name="btnClearRobotConfHostname" Content="Clear" Margin="5" Width="50" Height="30" Click="btnClearRobotConfHostname_Click" />
</StackPanel> </StackPanel>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">

@ -101,10 +101,10 @@ namespace RobotClientWpf.Views
private void EnableRobotConfigurationOptions(bool enabled) private void EnableRobotConfigurationOptions(bool enabled)
{ {
UIAccessHelpers.SetButtonState(btnSetBrokerIp, enabled); if (btnSetBrokerIp != null) UIAccessHelpers.SetButtonState(btnSetBrokerIp, enabled);
UIAccessHelpers.SetButtonState(btnReboot, enabled); if (btnReboot != null) UIAccessHelpers.SetButtonState(btnReboot, enabled);
UIAccessHelpers.SetButtonState(btnSetModeStationary, enabled); if (btnSetModeStationary != null) UIAccessHelpers.SetButtonState(btnSetModeStationary, enabled);
UIAccessHelpers.SetButtonState(btnSetModeMobile, enabled); if (btnSetModeMobile != null) UIAccessHelpers.SetButtonState(btnSetModeMobile, enabled);
} }
private void btnClearRobotConfHostname_Click(object sender, RoutedEventArgs e) private void btnClearRobotConfHostname_Click(object sender, RoutedEventArgs e)

@ -9,7 +9,7 @@
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
<ColumnDefinition Width="200"/> <ColumnDefinition Width="400"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="200"/> <RowDefinition Height="200"/>
@ -21,10 +21,19 @@
<GroupBox Header="Splitflap Display" Margin="10" HorizontalAlignment="Right" Width="180"> <GroupBox Header="Splitflap Display" Margin="10" HorizontalAlignment="Right" Width="180">
<TextBox x:Name="tbSplitflapText" Height="70" Width="150" FontSize="30" IsReadOnly="True" TextWrapping="NoWrap" HorizontalAlignment="Left"/> <TextBox x:Name="tbSplitflapText" Height="70" Width="150" FontSize="30" IsReadOnly="True" TextWrapping="NoWrap" HorizontalAlignment="Left"/>
</GroupBox> </GroupBox>
<GroupBox Header="Robot battery" Margin="10" HorizontalAlignment="Right" Width="180"> <GroupBox Header="Robot" Margin="10" HorizontalAlignment="Right" Width="350">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Vertical">
<TextBox x:Name="tbRoboVoltage" Height="25" Width="100" FontSize="15" IsReadOnly="True" TextWrapping="NoWrap" HorizontalAlignment="Left">NaN</TextBox> <StackPanel Orientation="Horizontal">
<Label Content="V" Margin="10 0"/> <Label Content="Battery" Margin="10 0"/>
<TextBox x:Name="tbRoboVoltage" Height="25" Width="100" FontSize="15" IsReadOnly="True" TextWrapping="NoWrap" HorizontalAlignment="Left">NaN</TextBox>
<Label Content="V" Margin="10 0"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Label Content="State" Margin="10 0"/>
<Ellipse Fill="Red" x:Name="ellipseRed" Width="20" Height="20" Margin="15 0" Opacity="0"/>
<Ellipse Fill="Green" x:Name="ellipseGreen" Width="20" Height="20" Margin="0 0" Opacity="0"/>
</StackPanel>
</StackPanel> </StackPanel>
</GroupBox> </GroupBox>
</StackPanel> </StackPanel>

@ -12,7 +12,7 @@ namespace RobotClientWpf.Views
private static readonly NLog.Logger log = NLog.LogManager.GetCurrentClassLogger(); private static readonly NLog.Logger log = NLog.LogManager.GetCurrentClassLogger();
private ChallengeFactory? challenge; private ChallengeFactory? challenge;
private MainWindow? mainWindow; private MainWindow? mainWindow;
private const int AMOUNT_SPEED_ADDED_PER_CLICK = 500; private const int AMOUNT_SPEED_ADDED_PER_CLICK = 200;
private const int TURN_ANGLE_PER_CLICK = 30; private const int TURN_ANGLE_PER_CLICK = 30;
public MainView() public MainView()
@ -27,6 +27,21 @@ namespace RobotClientWpf.Views
// subscribe to events // subscribe to events
this.challenge.RobotStationary.SplitFlap.SplitFlapDisplayChanged += this.SplitFlap_SplitFlapDisplayChanged; this.challenge.RobotStationary.SplitFlap.SplitFlapDisplayChanged += this.SplitFlap_SplitFlapDisplayChanged;
this.challenge.RobotMobile.Battery.BatteryChanged += Battery_BatteryChanged; this.challenge.RobotMobile.Battery.BatteryChanged += Battery_BatteryChanged;
this.challenge.RobotMobile.Battery.SecondsSinceLastResponseUpdate += Battery_SecondsSinceLastResponseUpdate;
}
private void Battery_SecondsSinceLastResponseUpdate(object? sender, int e)
{
if(e > 15)
{
UIAccessHelpers.SetShapeVisibility(ellipseRed, true);
UIAccessHelpers.SetShapeVisibility(ellipseGreen, false);
}
else
{
UIAccessHelpers.SetShapeVisibility(ellipseRed, false);
UIAccessHelpers.SetShapeVisibility(ellipseGreen, true);
}
} }
private void Battery_BatteryChanged(object? sender, RobotLib.Battery.BatteryEventArgs e) private void Battery_BatteryChanged(object? sender, RobotLib.Battery.BatteryEventArgs e)

@ -1,6 +1,7 @@
using RobotLib.Communication; using RobotLib.Communication;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Text.Json; using System.Text.Json;
namespace RobotLib.Battery namespace RobotLib.Battery
@ -8,11 +9,15 @@ namespace RobotLib.Battery
public class DevBattery : DevBase public class DevBattery : DevBase
{ {
private float voltage; private float voltage;
private int secondsSinceLastResponse = 0;
private Stopwatch stopwatchLastResponse = new();
private const string TOPIC_ROBO_REQ_BATTERY = "/mobile/cmd/battery/get_volt"; private const string TOPIC_ROBO_REQ_BATTERY = "/both/cmd/battery/get_volt";
private const string TOPIC_ROBO_RESP_BATTERY = "/mobile/state/battery/voltage"; private const string TOPIC_ROBO_RESP_BATTERY = "/mobile/state/battery/voltage";
private const string TOPIC_STAT_RESP_BATTERY = "/stationary/state/battery/voltage";
public event EventHandler<BatteryEventArgs> BatteryChanged; public event EventHandler<BatteryEventArgs> BatteryChanged;
public event EventHandler<int> SecondsSinceLastResponseUpdate;
public float Voltage public float Voltage
{ {
@ -29,17 +34,46 @@ namespace RobotLib.Battery
} }
} }
public DevBattery(IPublisherSubscriber com) : base(com, new List<string>() { TOPIC_ROBO_RESP_BATTERY }) { } public int SecondsSinceLastResponse
{
get { return secondsSinceLastResponse; }
private set
{
secondsSinceLastResponse = value;
SecondsSinceLastResponseUpdate?.Invoke(this, secondsSinceLastResponse);
}
}
public DevBattery(IPublisherSubscriber com, RobotMode mode) : base(com, GenerateListOfRelevantTopics(mode)) { }
private static List<string> GenerateListOfRelevantTopics(RobotMode mode)
{
if (mode == RobotMode.Stationary)
{
return new List<string>() { TOPIC_STAT_RESP_BATTERY };
}
else
{
return new List<string>() { TOPIC_ROBO_RESP_BATTERY };
}
}
public void RequestBatteryVoltage() public void RequestBatteryVoltage()
{ {
base.SendMessage(TOPIC_ROBO_REQ_BATTERY, true.ToString()); base.SendMessage(TOPIC_ROBO_REQ_BATTERY, true.ToString());
if (this.stopwatchLastResponse.IsRunning)
{
SecondsSinceLastResponse = this.stopwatchLastResponse.Elapsed.Seconds;
}
} }
protected override void ParseMessage(string fromTopic, string message) protected override void ParseMessage(string fromTopic, string message)
{ {
if (fromTopic == TOPIC_ROBO_RESP_BATTERY) if (fromTopic == TOPIC_ROBO_RESP_BATTERY || fromTopic == TOPIC_STAT_RESP_BATTERY)
{ {
this.stopwatchLastResponse.Stop();
this.stopwatchLastResponse.Start();
SecondsSinceLastResponse = 0;
var parsedString = GetValueFromMesage<string>("voltage", message); var parsedString = GetValueFromMesage<string>("voltage", message);
if (parsedString == null) parsedString = "?"; if (parsedString == null) parsedString = "?";

@ -136,7 +136,7 @@ namespace RobotLib.Communication
lock (clientLock) lock (clientLock)
{ {
IsConnected = false; IsConnected = false;
log.Info($"Connection was closed."); log.Warn($"Connection was closed.");
} }
} }

@ -9,38 +9,40 @@ namespace RobotLib
{ {
public class Robot public class Robot
{ {
public Robot(IPublisherSubscriber com, RobotMode type) public Robot(IPublisherSubscriber com, RobotMode mode)
{ {
Com = com; Com = com;
Type = type; Mode = mode;
if(type == RobotMode.Undefined) if(mode == RobotMode.Undefined)
{ {
throw new System.ArgumentException("Undefined robot mode, must define mode!"); throw new System.ArgumentException("Undefined robot mode, must define mode!");
} }
if(type == RobotMode.Mobile) // battery is applicable for both modes
Battery = new DevBattery(Com, mode);
if(mode == RobotMode.Mobile)
{ {
//Buzzer = new DevBuzzer(Com); //Buzzer = new DevBuzzer(Com);
Battery = new DevBattery(Com);
LineSensor = new DevLineSensor(com); LineSensor = new DevLineSensor(com);
Movement = new DevMovement(com); Movement = new DevMovement(com);
Status = new DevStatus(com); Status = new DevStatus(com);
} }
else if(type == RobotMode.Stationary) else if(mode == RobotMode.Stationary)
{ {
SplitFlap = new DevSplitFlap(com); SplitFlap = new DevSplitFlap(com);
} }
Timer timer = new Timer Timer timer = new Timer
{ {
Interval = 10000 Interval = 15000
}; };
timer.Enabled= true; timer.Enabled= true;
timer.Elapsed += Timer_Elapsed; timer.Elapsed += Timer_Elapsed;
} }
public IPublisherSubscriber Com { get; } public IPublisherSubscriber Com { get; }
public RobotMode Type { get; } public RobotMode Mode { get; }
//public DevBuzzer Buzzer { get; } //public DevBuzzer Buzzer { get; }
public DevBattery Battery { get; } public DevBattery Battery { get; }
@ -64,7 +66,7 @@ namespace RobotLib
{ {
if (Com.IsConnected) if (Com.IsConnected)
{ {
Battery?.RequestBatteryVoltage(); //Battery?.RequestBatteryVoltage();
} }
} }
} }

Loading…
Cancel
Save