implemented IndependentRobotConfigurator to adopt robots via UDP,

updated UI to support IndependentRobotConfigurator commands
main
Jonas Arnold 4 years ago
parent d43c04d3ad
commit ad76d09438
  1. 2
      ADIS_Csharp/RobotClientWpf/MainWindow.xaml
  2. 13
      ADIS_Csharp/RobotClientWpf/MainWindow.xaml.cs
  3. 28
      ADIS_Csharp/RobotClientWpf/Views/ConfigView.xaml
  4. 58
      ADIS_Csharp/RobotClientWpf/Views/ConfigView.xaml.cs
  5. 2
      ADIS_Csharp/RobotClientWpf/Views/MainView.xaml
  6. 14
      ADIS_Csharp/RobotClientWpf/Views/MainView.xaml.cs
  7. 73
      ADIS_Csharp/RobotLib/IndependentRobotConfigurator.cs

@ -7,7 +7,7 @@
xmlns:views="clr-namespace:RobotClientWpf.Views"
xmlns:dj="clr-namespace:DJ;assembly=NLogViewer"
mc:Ignorable="d" FontSize="15"
Title="Challenge UI" Height="700" Width="1200" WindowStartupLocation="CenterScreen" ResizeMode="NoResize" Closing="Window_Closing" Loaded="Window_Loaded">
Title="Challenge UI" Height="700" Width="1200" WindowStartupLocation="CenterScreen" ResizeMode="NoResize" Closing="Window_Closing" Loaded="Window_Loaded" KeyDown="Window_KeyDown">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40"/>

@ -20,7 +20,7 @@ namespace RobotClientWpf
private static readonly string mutexName = "00489402-435c-426e-9d11-9a2b839b39b6"; // random guid
private static readonly NLog.Logger log = NLog.LogManager.GetCurrentClassLogger();
private ChallengeFactory? challenge;
private ChallengeFactory challenge;
private bool manualDisconnect;
public MainWindow()
@ -43,9 +43,9 @@ namespace RobotClientWpf
// start window
InitializeComponent();
this.challenge = new ChallengeFactory();
// inform other views about challenge factory
this.mainView.SetChallengeFactory(this.challenge);
this.configView.SetChallengeFactory(this.challenge);
// inform other views about challenge factory and this view
this.mainView.InitializeChildView(this.challenge, this);
this.configView.InitializeChildView(this.challenge, this);
// subscribe to events
this.challenge.PublisherSubscriber.ConnectionStateChanged += PublisherSubscriber_ConnectionStateChanged;
}
@ -173,5 +173,10 @@ namespace RobotClientWpf
{
this.tbIp.Text = Settings.Default.MqttBrokerIp;
}
private void Window_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
this.mainView.HandleKeyDownEvent(sender, e);
}
}
}

@ -5,12 +5,13 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:RobotClientWpf.Views"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
d:DesignHeight="430" d:DesignWidth="1200" FontSize="15">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="120"/>
<RowDefinition Height="120"/>
<RowDefinition Height="150"/>
<RowDefinition Height="*"/>
@ -50,13 +51,12 @@
<Grid Margin="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
@ -65,9 +65,29 @@
<Label Grid.Row="1" Grid.Column="0" Content="Calibration data:" />
<TextBox Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left" x:Name="tbCalibrationData" IsReadOnly="True" Width="500" Height="30" />
<Button Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" x:Name="btnGetCalibrationData" DockPanel.Dock="Right" Content="Refresh" Margin="10 0" Width="100" Height="30" Click="btnGetCalibrationData_Click"/>
<Button Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2" HorizontalAlignment="Right" x:Name="btnGetCalibrationData" Content="Refresh" Width="100" Height="30" Click="btnGetCalibrationData_Click"/>
</Grid>
</DockPanel>
</GroupBox>
<!-- ROBOT CONFIGURATOR -->
<GroupBox Grid.Row="2" Grid.Column="0" Header="Robot configurator">
<DockPanel Margin="5">
<StackPanel Orientation="Vertical">
<StackPanel DockPanel.Dock="Left" Orientation="Horizontal" VerticalAlignment="Top">
<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"/>
<Button DockPanel.Dock="Left" x:Name="btnClearRobotConfHostname" Content="Clear" Margin="5" Width="50" Height="30" Click="btnClearRobotConfHostname_Click" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<Label DockPanel.Dock="Left" Content="Options:" Margin="5 0" Height="30" Width="100"/>
<Button x:Name="btnSetBrokerIp" Content="Update Broker IP" Margin="5" Width="120" Height="30" HorizontalAlignment="Left" Click="btnSetBrokerIp_Click"/>
<Button x:Name="btnReboot" Content="Reboot ESP32" Margin="5" Width="120" Height="30" HorizontalAlignment="Left" Click="btnReboot_Click" />
<Button x:Name="btnSetModeStationary" Content="Set Mode Stationary" Margin="5" Width="150" Height="30" HorizontalAlignment="Left" Click="btnSetModeStationary_Click" />
<Button x:Name="btnSetModeMobile" Content="Set Mode Mobile" Margin="5" Width="120" Height="30" HorizontalAlignment="Left" Click="btnSetModeMobile_Click" />
</StackPanel>
</StackPanel>
</DockPanel>
</GroupBox>
</Grid>
</UserControl>

@ -1,6 +1,7 @@
using RobotClientWpf.Utilities;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
@ -13,15 +14,18 @@ namespace RobotClientWpf.Views
{
private static readonly NLog.Logger log = NLog.LogManager.GetCurrentClassLogger();
private ChallengeFactory? challenge;
private MainWindow? mainWindow;
public ConfigView()
{
InitializeComponent();
this.EnableRobotConfigurationOptions(false);
}
public void SetChallengeFactory(ChallengeFactory challenge)
public void InitializeChildView(ChallengeFactory challenge, MainWindow parent)
{
this.challenge = challenge;
this.mainWindow = parent;
this.challenge.RobotMobile.LineSensor.NewCalibrationDataArrived += LineSensor_NewCalibrationDataArrived;
}
@ -89,5 +93,57 @@ namespace RobotClientWpf.Views
{
this.challenge?.RobotStationary.SplitFlap.InitializeAllSplitflaps();
}
private void tbRobotConfiguratorHostname_TextChanged(object sender, TextChangedEventArgs e)
{
this.EnableRobotConfigurationOptions(String.IsNullOrEmpty(UIAccessHelpers.GetTextboxText(this.tbRobotConfiguratorHostname)) == false);
}
private void EnableRobotConfigurationOptions(bool enabled)
{
UIAccessHelpers.SetButtonState(btnSetBrokerIp, enabled);
UIAccessHelpers.SetButtonState(btnReboot, enabled);
UIAccessHelpers.SetButtonState(btnSetModeStationary, enabled);
UIAccessHelpers.SetButtonState(btnSetModeMobile, enabled);
}
private void btnClearRobotConfHostname_Click(object sender, RoutedEventArgs e)
{
UIAccessHelpers.SetTextboxText(tbRobotConfiguratorHostname, "");
}
private async void btnSetBrokerIp_Click(object sender, RoutedEventArgs e)
{
if (this.mainWindow == null) return;
UIAccessHelpers.SetButtonState(btnSetBrokerIp, false);
var brokerIp = UIAccessHelpers.GetTextboxText(this.mainWindow.tbIp);
var robotHostname = UIAccessHelpers.GetTextboxText(this.tbRobotConfiguratorHostname);
await Task.Run(() => RobotLib.IndependentRobotConfigurator.Adopt(robotHostname, brokerIp));
UIAccessHelpers.SetButtonState(btnSetBrokerIp, true);
}
private async void btnReboot_Click(object sender, RoutedEventArgs e)
{
UIAccessHelpers.SetButtonState(btnReboot, false);
var robotHostname = UIAccessHelpers.GetTextboxText(this.tbRobotConfiguratorHostname);
await Task.Run(() => RobotLib.IndependentRobotConfigurator.RebootEsp32(robotHostname));
UIAccessHelpers.SetButtonState(btnReboot, true);
}
private async void btnSetModeStationary_Click(object sender, RoutedEventArgs e)
{
UIAccessHelpers.SetButtonState(btnSetModeStationary, false);
var robotHostname = UIAccessHelpers.GetTextboxText(this.tbRobotConfiguratorHostname);
await Task.Run(() => RobotLib.IndependentRobotConfigurator.SetRobotMode(robotHostname, "s"));
UIAccessHelpers.SetButtonState(btnSetModeStationary, true);
}
private async void btnSetModeMobile_Click(object sender, RoutedEventArgs e)
{
UIAccessHelpers.SetButtonState(btnSetModeMobile, false);
var robotHostname = UIAccessHelpers.GetTextboxText(this.tbRobotConfiguratorHostname);
await Task.Run(() => RobotLib.IndependentRobotConfigurator.SetRobotMode(robotHostname, "m"));
UIAccessHelpers.SetButtonState(btnSetModeMobile, true);
}
}
}

@ -5,7 +5,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:RobotClientWpf.Views"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800" KeyDown="UserControl_KeyDown">
d:DesignHeight="430" d:DesignWidth="1200" FontSize="15" KeyDown="UserControl_KeyDown">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>

@ -1,5 +1,4 @@
using RobotClientWpf.Utilities;
using System.DirectoryServices.ActiveDirectory;
using System.Windows.Controls;
using System.Windows.Input;
@ -12,6 +11,7 @@ namespace RobotClientWpf.Views
{
private static readonly NLog.Logger log = NLog.LogManager.GetCurrentClassLogger();
private ChallengeFactory? challenge;
private MainWindow? mainWindow;
private const int AMOUNT_SPEED_ADDED_PER_CLICK = 500;
private const int TURN_ANGLE_PER_CLICK = 30;
@ -20,9 +20,10 @@ namespace RobotClientWpf.Views
InitializeComponent();
}
public void SetChallengeFactory(ChallengeFactory challenge)
public void InitializeChildView(ChallengeFactory challenge, MainWindow parent)
{
this.challenge = challenge;
this.mainWindow = parent;
// subscribe to events
this.challenge.RobotStationary.SplitFlap.SplitFlapDisplayChanged += this.SplitFlap_SplitFlapDisplayChanged;
this.challenge.RobotMobile.Battery.BatteryChanged += Battery_BatteryChanged;
@ -67,7 +68,7 @@ namespace RobotClientWpf.Views
this.challenge?.RobotMobile.Movement.Turn(-TURN_ANGLE_PER_CLICK);
}
private void UserControl_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
public void HandleKeyDownEvent(object sender, KeyEventArgs e)
{
if (e.Key == Key.Up)
{
@ -89,11 +90,16 @@ namespace RobotClientWpf.Views
this.challenge?.RobotMobile.Movement.Turn(TURN_ANGLE_PER_CLICK);
e.Handled = true;
}
else if(e.Key == Key.End)
else if (e.Key == Key.End)
{
this.challenge?.RobotMobile.Movement.Stop();
e.Handled = true;
}
}
private void UserControl_KeyDown(object sender, KeyEventArgs e)
{
this.HandleKeyDownEvent(sender, e);
}
}
}

@ -0,0 +1,73 @@
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace RobotLib
{
public static class IndependentRobotConfigurator
{
private static readonly NLog.Logger log = NLog.LogManager.GetCurrentClassLogger();
private const int udpPortRobot = 1818;
/// <summary>
/// Sends a command via UDP to set the MQTT broker IP on a robot.
/// This serves to adopt a robot (get it to communicate via MQTT).
/// Consider rebooting ESP32 with <see cref="RebootEsp32(string)"/> to apply the newly set IP.
/// </summary>
/// <param name="hostnameRobot">hostname or IP address of the robot</param>
/// <param name="brokerIp">ip address of the MQTT broker</param>
public static void Adopt(string hostnameRobot, string brokerIp)
{
// test if IP valid
if (IPAddress.TryParse(brokerIp, out _))
{
SendMessageUdp(hostnameRobot, udpPortRobot, $"mqtt setIp {brokerIp}");
}
else
{
log.Error($"Invalid broker IP address: {brokerIp}");
}
}
/// <summary>
/// Sends a command via UDP to set the challenge mode of a robot.
/// </summary>
/// <param name="hostnameRobot">hostname or IP address of the robot</param>
/// <param name="brokerIp">ip address of the MQTT broker</param>
public static void SetRobotMode(string hostnameRobot, string mode)
{
// test if mode is valid
if (mode == "stationary" || mode == "s" || mode == "mobile" || mode == "m")
{
SendMessageUdp(hostnameRobot, udpPortRobot, $"challenge setMode {mode}");
}
else
{
log.Error($"Invalid robot mode: {mode}");
}
}
/// <summary>
/// Sends a command via UDP to reboot the ESP32 of a robot.
/// For example when a new mqtt broker IP was set, the robot needs to reboot in order to apply the IP and reconnect to a new broker.
/// </summary>
/// <param name="hostnameRobot">hostname or IP address of the robot</param>
public static void RebootEsp32(string hostnameRobot)
{
SendMessageUdp(hostnameRobot, udpPortRobot, $"challenge reboot");
}
private static void SendMessageUdp(string hostname, int port, string message)
{
var udpClient = new UdpClient();
udpClient.Connect(hostname, port);
byte[] data = Encoding.ASCII.GetBytes(message);
udpClient.Send(data, data.Length);
log.Trace($"Msg sent to {udpClient.Client.RemoteEndPoint}: {message}");
udpClient.Close();
}
}
}
Loading…
Cancel
Save