Universal robot controller for UGV

Before deep diving into the controller, clone the following GitHub repository to your PC. The code is itself around 350+ lines so some parts are to be discussed:

https://github.com/avirup171/bet_controller_urc

So initially let's design the UI first:

Screenshot of URC

For simplicity two sections of fast and slow controls are included. However it can be merged into one and using a checkbox. We have a connection pane on the right hand top side. The commands are displayed. A default password for 12345 was added which was done to avoid crashes and unauthorized use. However it's a simple controller and can be used with UGVs pretty much efficiently.

If you have a close look over the UI, then you will find a button named Press to activate keyboard control. Once you click on the button, the keyboard control gets activated. Now here you need to assign keyboard pressed and keyboard release event. This can be done by selecting the control and in the properties windows, click on the following icon. This manages all the event handlers for the selected control:

Properties window
When we press the key on a keyboard two events are triggered. The first is when we press the key and the second is when we release the key

Now when you click on it you will get all the possible events associated with it. Scroll down to KeyDown and KeyUp. Double click on both to create the associated event handlers. The control buttons have a different event associated with them. That is we send data when the button is pressed. When the button is released, 5 which is for stop is sent. You can assign the events by the properties window as shown earlier:

<Button x:Name="front_fast" Content="Front" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Margin="204,56,0,0" Height="48" GotMouseCapture="front_fast_GotMouseCapture" LostMouseCapture="front_fast_LostMouseCapture" />

Assign names to all the buttons and create their respective event handlers. We have also created three progress bars. A xaml code for a progress bar is shown as follows:

<ProgressBar x:Name="pb1" HorizontalAlignment="Left" Height="10" Margin="92,273,0,0" VerticalAlignment="Top" Width="300"/>

For the keyboard up and down events, the respective xaml code is:

<Button Content="Press to activate keyboard controls" Name="kbp" HorizontalAlignment="Left" Margin="582,454,0,0" VerticalAlignment="Top" Width="202" Height="52" KeyDown="kbp_KeyDown" KeyUp="Kbp_KeyUp"/>
Two events are created. One for the key pressed and another for key released.

The xaml code for the preceding UI is given as follows:

<Window x:Class="BET_Controller_v2.MainWindow"        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        Title="URC V1.0.0.1" Height="720" Width="1360" Loaded="Window_Loaded">
<Grid>
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap"
Text="Controls invloving high speed" VerticalAlignment="Top"
Height="25" Width="269" Margin="10,0,0,0"/>
<Rectangle Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="13"
Stroke="Black" VerticalAlignment="Top" Width="498"
Margin="10,25,0,0"/>
<Button x:Name="front_fast" Content="Front"
HorizontalAlignment="Left" VerticalAlignment="Top" Width="75"
Margin="204,56,0,0" Height="48"
GotMouseCapture="front_fast_GotMouseCapture"
LostMouseCapture="front_fast_LostMouseCapture" />
<Button x:Name="back_fast" Content="back"
HorizontalAlignment="Left" VerticalAlignment="Top" Width="75"
Margin="204,193,0,0" Height="53"
GotMouseCapture="back_fast_GotMouseCapture"
LostMouseCapture="back_fast_LostMouseCapture"/>
<
Button x:Name="left_fast" Content="left"
HorizontalAlignment="Left" VerticalAlignment="Top" Width="74"
Margin="92,125,0,0" Height="50"
GotMouseCapture="left_fast_GotMouseCapture"
LostMouseCapture="left_fast_LostMouseCapture" />
<Button x:Name="right_fast" Content="right"
HorizontalAlignment="Left" VerticalAlignment="Top" Width="76"
Margin="316,125,0,0" Height="50"
GotMouseCapture="right_fast_GotMouseCapture"
LostMouseCapture="right_fast_LostMouseCapture" />
<Button x:Name="stop_fast" Content="stop"
HorizontalAlignment="Left" VerticalAlignment="Top" Width="75"
Margin="204,125,0,0" Height="50"
RenderTransformOrigin="0.362,0.5" Click="stop_fast_Click" />
<Rectangle Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="13"
Stroke="Black" VerticalAlignment="Top" Width="498"
Margin="10,305,0,0"/>
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap"
Text="Controls invloving low speed" VerticalAlignment="Top"
Height="25" Width="269" Margin="10,323,0,0"/>
<Button x:Name="front_slow" Content="front"
HorizontalAlignment="Left" Margin="204,374,0,0"
VerticalAlignment="Top" Width="75" Height="53"
GotMouseCapture="front_slow_GotMouseCapture"
LostMouseCapture="front_slow_LostMouseCapture"/>
<Button x:Name="back_slow" Content="back"
HorizontalAlignment="Left" Margin="204,526,0,0"
VerticalAlignment="Top" Width="75" Height="53"
LostMouseCapture="back_slow_LostMouseCapture"
GotMouseCapture="back_slow_GotMouseCapture" />
<Button x:Name="right_slow" Content="right"
HorizontalAlignment="Left" Margin="316,454,0,0"
VerticalAlignment="Top" Width="76" Height="53"
LostMouseCapture="right_slow_LostMouseCapture"
GotMouseCapture="right_slow_GotMouseCapture" />
<Button x:Name="left_slow" Content="left"
HorizontalAlignment="Left" Margin="92,454,0,0"
VerticalAlignment="Top" Width="74" Height="53"
GotMouseCapture="left_slow_GotMouseCapture"
LostMouseCapture="left_slow_LostMouseCapture" />
<Button x:Name="stop_slow" Content="stop"
HorizontalAlignment="Left" Margin="204,454,0,0"
VerticalAlignment="Top" Width="75" Height="53"
Click="stop_slow_Click"/>
<Rectangle Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="13"
Stroke="Black" VerticalAlignment="Top" Width="255"
Margin="552,25,0,0"/>
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap"
Text="Special controls" VerticalAlignment="Top" Height="25"
Width="269" Margin="552,0,0,0"/>
<Button x:Name="rr360" Content="360 deg rotation right"
HorizontalAlignment="Left" Margin="607,94,0,0"
VerticalAlignment="Top" Width="138" Height="53"
RenderTransformOrigin="0.498,0.524" Click="rr360_Click"/>
<Button x:Name="lr360" Content="360 deg rotation left"
HorizontalAlignment="Left" Margin="607,193,0,0"
VerticalAlignment="Top" Width="138" Height="53"
RenderTransformOrigin="0.498,0.524" Click="lr360_Click" />
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap"
Text="Command will be displayed below" VerticalAlignment="Top"
Height="25" Width="484" Margin="858,13,0,0"/>
<Rectangle Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="10"
Stroke="Black" VerticalAlignment="Top" Width="484"
Margin="858,43,0,0"/>
<TextBlock x:Name="cmd" HorizontalAlignment="Left"
Margin="858,72,0,0" TextWrapping="Wrap" Text="Commands"
VerticalAlignment="Top" Height="174" Width="484"/>
<TextBox x:Name="cno" HorizontalAlignment="Left" Height="29"
Margin="858,273,0,0" TextWrapping="Wrap" Text="COM13"
VerticalAlignment="Top" Width="85"/>
<Button x:Name="connect" Content="Connect"
HorizontalAlignment="Left" Margin="858,307,0,0"
VerticalAlignment="Top" Width="85" Height="41"
RenderTransformOrigin="0.498,0.524" Click="connect_Click" />
<Button x:Name="disconnect" Content="Disconnect"
HorizontalAlignment="Left" Margin="964,307,0,0"
VerticalAlignment="Top" Width="85" Height="41"
RenderTransformOrigin="0.498,0.524" Click="disconnect_Click" />
<Button x:Name="rst" Content="Reset" HorizontalAlignment="Left"
Margin="607,295,0,0" VerticalAlignment="Top" Width="138"
Height="53" RenderTransformOrigin="0.498,0.524" Click="rst_Click"
/>
<TextBlock HorizontalAlignment="Left" Margin="858,353,0,0" x:Name="s"
TextWrapping="Wrap" Text="Click Connect to connect"
VerticalAlignment="Top" Height="33" Width="191"/>
<ProgressBar x:Name="pbkc" HorizontalAlignment="Left" Height="10"
Margin="549,569,0,0" VerticalAlignment="Top" Width="272"/>
<ProgressBar x:Name="pb2" HorizontalAlignment="Left" Height="10"
Margin="92,631,0,0" VerticalAlignment="Top" Width="300"/>
<ProgressBar x:Name="pb1" HorizontalAlignment="Left" Height="10"
Margin="92,273,0,0" VerticalAlignment="Top" Width="300"/>
<Rectangle Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="12"
Stroke="Black" VerticalAlignment="Top" Width="269"
Margin="552,374,0,0"/>
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap"
Text="Keybooard controls" VerticalAlignment="Top" Height="25"
Width="269" Margin="552,392,0,0"/>
<Button Content="Press to activate keyboard controls" Name="kbp"
HorizontalAlignment="Left" Margin="582,454,0,0"
VerticalAlignment="Top" Width="202" Height="52"
KeyDown="kbp_KeyDown" KeyUp="Kbp_KeyUp"/>
<Rectangle Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="11"
Stroke="Black" VerticalAlignment="Top" Width="484"
Margin="858,391,0,0"/>
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="Enter
the password below to activate all controls. The password was
supplied by the administrator with the bundel."
VerticalAlignment="Top" Height="51" Width="269"
Margin="858,414,0,0"/>
<Button x:Name="activate" Content="Activate"
HorizontalAlignment="Left" Margin="1052,631,0,0"
VerticalAlignment="Top" Width="75" Height="33"
Click="activate_Click" KeyDown="activate_KeyDown"/>
<PasswordBox x:Name="pswrdbox" HorizontalAlignment="Left"
Margin="1025,585,0,0" VerticalAlignment="Top" Height="25" Width="124"
PasswordChar="*" FontSize="24"/>
<Rectangle Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="645"
Stroke="Black" VerticalAlignment="Top" Width="5" Margin="834,8,0,0"
RenderTransformOrigin="0.5,0.5">
</Rectangle><Rectangle Fill="#FFF4F4F5" HorizontalAlignment="Left"
Height="645" Stroke="Black" VerticalAlignment="Top" Width="5"
Margin="539,19,0,0" RenderTransformOrigin="0.5,0.5"/>
</Grid>
</Window>

Now that the UI is ready, let's go to the main C# code. The event handlers are also in place. Initially include the System.IO.Ports namespace and create an object of that class. After that the keyboard pressed event will be handled with our code:

private void kbp_KeyDown(object sender, KeyEventArgs e) 
{
Keyboard.Focus(kbp);
if (e.Key == Key.W)
{
sp.WriteLine("1");
pbkc.IsIndeterminate = true;
cmd.Text = "W: fast forward";
}
else if (e.Key == Key.S)
{
sp.WriteLine("0");
pbkc.IsIndeterminate = true;
cmd.Text = "S: fast back";
}
else if (e.Key == Key.A)
{
sp.WriteLine("4");
pbkc.IsIndeterminate = true;
cmd.Text = "A: fast left";
}
else if (e.Key == Key.D)
{
sp.WriteLine("3");
pbkc.IsIndeterminate = true;
cmd.Text = "D: fast right";
}
else if (e.Key == Key.NumPad8)
{
sp.WriteLine("6");
pbkc.IsIndeterminate = true;
cmd.Text = "9: slow front";
}
else if (e.Key == Key.NumPad2)
{
sp.WriteLine("7");
pbkc.IsIndeterminate = true;
cmd.Text = "2: slow back";
}
else if (e.Key == Key.NumPad6)
{
sp.WriteLine("8");
pbkc.IsIndeterminate = true;
cmd.Text = "6: slow right";
}
else if (e.Key == Key.NumPad4)
{
sp.WriteLine("9");
pbkc.IsIndeterminate = true;
cmd.Text = "D: slow left";
}

}

In the preceding code, we used the following keys:

Serial No

Keyboard keys

Commands executed

1

W

Fast forward

2

A

Fast left turn

3

S

Fast backward

4

D

Fast right turn

5

Numpad 8

Slow forward

6

Numpad 2

Slow Backward

7

Numpad 4

Slow left turn

8

Numpad 6

Slow right turn

Based on the input, we sent that particular character. While for the key up or key released event, we simply send 5 which means stop:

private void Kbp_KeyUp(object sender, KeyEventArgs e) 
{
sp.WriteLine("5");
pbkc.IsIndeterminate = false;
cmd.Text = "STOP";
}

The connect and disconnect events are same as before. Now each button will have two methods. The first one is of GotMouseCapture and the second one is of LostMouseCapture.

Take the example of the front button under fast control:

private void front_fast_GotMouseCapture(object sender, MouseEventArgs e) 
{
sp.WriteLine("1");
cmd.Text = "Fast Forward";
pb1.IsIndeterminate = true;
}

private void front_fast_LostMouseCapture(object sender, MouseEventArgs e)
{
sp.WriteLine("5");
cmd.Text = "STOP";
pb1.IsIndeterminate = false;
}

Similarly apply it for the other controls. Only 360 degree left and right is associated with a button click event. The entire code is pasted as shown below of MainWindow.xaml.cs:

using System; 
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO.Ports;

namespace BET_Controller_v2
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
SerialPort sp = new SerialPort();
public MainWindow()
{
InitializeComponent();
Closing += new System.ComponentModel.CancelEventHandler(MainWindow_Closing);
}

private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
if (MessageBox.Show("Do you really want to exit?", "Exit", MessageBoxButton.YesNo) == MessageBoxResult.No)
{
e.Cancel = true;
}
}
/*
* 1: Fast front
* 0: Fast back
* 3: Fast right
* 4: Fast left
* 5: STOP
* 6: Slow front
* 7: Slow back
* 8: Slow right
* 9: Slow left
* */
//Keyboard Controls
private void kbp_KeyDown(object sender, KeyEventArgs e)
{
Keyboard.Focus(kbp);
if (e.Key == Key.W)
{
sp.WriteLine("1");
pbkc.IsIndeterminate = true;
cmd.Text = "W: fast forward";
}
else if (e.Key == Key.S)
{
sp.WriteLine("0");
pbkc.IsIndeterminate = true;
cmd.Text = "S: fast back";
}
else if (e.Key == Key.A)
{
sp.WriteLine("4");
pbkc.IsIndeterminate = true;
cmd.Text = "A: fast left";
}
else if (e.Key == Key.D)
{
sp.WriteLine("3");
pbkc.IsIndeterminate = true;
cmd.Text = "D: fast right";
}
else if (e.Key == Key.NumPad8)
{
sp.WriteLine("6");
pbkc.IsIndeterminate = true;
cmd.Text = "9: slow front";
}
else if (e.Key == Key.NumPad2)
{
sp.WriteLine("7");
pbkc.IsIndeterminate = true;
cmd.Text = "2: slow back";
}
else if (e.Key == Key.NumPad6)
{
sp.WriteLine("8");
pbkc.IsIndeterminate = true;
cmd.Text = "6: slow right";
}
else if (e.Key == Key.NumPad4)
{
sp.WriteLine("9");
pbkc.IsIndeterminate = true;
cmd.Text = "D: slow left";
}

}
//Key release event handlers
private void Kbp_KeyUp(object sender, KeyEventArgs e)
{
sp.WriteLine("5");
pbkc.IsIndeterminate = false;
cmd.Text = "STOP";
}
//Connect to the hardware
private void connect_Click(object sender, RoutedEventArgs e)
{
try
{
String pno = cno.Text;
sp.PortName = pno;
sp.BaudRate = 9600;
sp.Open();
s.Text = "Connected";
}
catch (Exception)
{

MessageBox.Show("Please check the com port number or the hardware attached to it");
}
}
//Disconnect from the hardware
private void disconnect_Click(object sender, RoutedEventArgs e)
{
try
{
sp.Close();
s.Text = "Disconnected";
}
catch (Exception)
{

MessageBox.Show("Some error occured with the connection");
}
}

private void front_fast_GotMouseCapture(object sender, MouseEventArgs e)
{
sp.WriteLine("1");
cmd.Text = "Fast Forward";
pb1.IsIndeterminate = true;
}

private void front_fast_LostMouseCapture(object sender, MouseEventArgs e)
{
sp.WriteLine("5");
cmd.Text = "STOP";
pb1.IsIndeterminate = false;
}

private void back_fast_GotMouseCapture(object sender, MouseEventArgs e)
{
sp.WriteLine("0");
cmd.Text = "Fast Backward";
pb1.IsIndeterminate = true;
}

private void back_fast_LostMouseCapture(object sender, MouseEventArgs e)
{
sp.WriteLine("5");
cmd.Text = "STOP";
pb1.IsIndeterminate = false;
}

private void left_fast_GotMouseCapture(object sender, MouseEventArgs e)
{
sp.WriteLine("4");
cmd.Text = "Fast left";
pb1.IsIndeterminate = true;
}

private void left_fast_LostMouseCapture(object sender, MouseEventArgs e)
{
sp.WriteLine("5");
cmd.Text = "STOP";
pb1.IsIndeterminate = false;
}

private void activate_Click(object sender, RoutedEventArgs e)
{
// Password and activation section
string s = pswrdbox.Password;
if(s=="12345")
{
MessageBox.Show("Congrats Black e Track Controller V2 is activated");
front_fast.IsEnabled = true;
back_fast.IsEnabled = true;
stop_fast.IsEnabled = true;
left_fast.IsEnabled = true;
right_fast.IsEnabled = true;
front_slow.IsEnabled = true;
back_slow.IsEnabled = true;
right_slow.IsEnabled = true;
left_slow.IsEnabled = true;
stop_slow.IsEnabled = true;
rr360.IsEnabled = true;
lr360.IsEnabled = true;
rst.IsEnabled = true;
kbp.IsEnabled = true;
}
else
{
MessageBox.Show("Sorry you have entered wrong password. Please enter the correct credentials or contact your system administrator.");
}
}

private void right_fast_GotMouseCapture(object sender, MouseEventArgs e)
{
sp.WriteLine("3");
cmd.Text = "Fast Right";
pb1.IsIndeterminate = true;
}

private void right_fast_LostMouseCapture(object sender, MouseEventArgs e)
{
sp.WriteLine("5");
cmd.Text = "STOP";
pb1.IsIndeterminate = false;
}

private void front_slow_GotMouseCapture(object sender, MouseEventArgs e)
{
sp.WriteLine("6");
cmd.Text = "Slow Front";
pb2.IsIndeterminate = true;
}


private void front_slow_LostMouseCapture(object sender, MouseEventArgs e)
{
sp.WriteLine("5");
cmd.Text = "STOP";
pb2.IsIndeterminate = false;
}
private void back_slow_LostMouseCapture(object sender, MouseEventArgs e)
{
sp.WriteLine("5");
cmd.Text = "STOP";
pb2.IsIndeterminate = false;
}


private void back_slow_GotMouseCapture(object sender, MouseEventArgs e)
{
sp.WriteLine("7");
cmd.Text = "Slow Back";
pb2.IsIndeterminate = true;
}
private void left_slow_GotMouseCapture(object sender, MouseEventArgs e)
{
sp.WriteLine("9");
cmd.Text = "Slow Left";
pb2.IsIndeterminate = true;
}

private void left_slow_LostMouseCapture(object sender, MouseEventArgs e)
{
sp.WriteLine("5");
cmd.Text = "STOP";
pb2.IsIndeterminate = false;
}

private void right_slow_LostMouseCapture(object sender, MouseEventArgs e)
{
sp.WriteLine("5");
cmd.Text = "STOP";
pb2.IsIndeterminate = false;
}

private void right_slow_GotMouseCapture(object sender, MouseEventArgs e)
{
sp.WriteLine("8");
cmd.Text = "Slow Right";
pb2.IsIndeterminate = true;
}

private void stop_fast_Click(object sender, RoutedEventArgs e)
{
sp.WriteLine("5");
cmd.Text = "STOP";
}

private void stop_slow_Click(object sender, RoutedEventArgs e)
{
sp.WriteLine("5");
cmd.Text = "STOP";
}

private void rr360_Click(object sender, RoutedEventArgs e)
{
sp.WriteLine("4");
cmd.Text = "360 deg right rotation";
}

private void lr360_Click(object sender, RoutedEventArgs e)
{
sp.WriteLine("3");
cmd.Text = "360 deg left rotation";
}

private void rst_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("The control doesn't exist now");
}

//Window loaded event handler for deactivating all controls by default
private void Window_Loaded(object sender, RoutedEventArgs e)
{
front_fast.IsEnabled = false;
back_fast.IsEnabled = false;
stop_fast.IsEnabled = false;
left_fast.IsEnabled = false;
right_fast.IsEnabled = false;
front_slow.IsEnabled = false;
back_slow.IsEnabled = false;
right_slow.IsEnabled = false;
left_slow.IsEnabled = false;
stop_slow.IsEnabled = false;
rr360.IsEnabled = false;
lr360.IsEnabled = false;
rst.IsEnabled = false;
kbp.IsEnabled = false;
}
private void activate_KeyDown(object sender, KeyEventArgs e)
{
if ((e.Key == Key.B) && Keyboard.IsKeyDown(Key.LeftCtrl) && Keyboard.IsKeyDown(Key.LeftAlt))
{
MessageBox.Show("Password: 12345");
}
}
}
}

In the preceding code, some facts to be noted are as follows:

  • If the password is not entered, all the buttons are disabled
  • The password in 12345
  • All buttons are associated with gotMouseCapture and lostMouseCapture
  • Only 360 degree rotation button follows a click event

Once you are able to successfully develop the project, test it out. Connect the RF USB link to your PC. Install all the required drivers and test it out.The entire process is mentioned as follows:

  • Connect the RF USB link to your PC.
  • Make sure your Intel Edison is powered on and connected to our bot. You can use a USB hub to power the Intel Edison and connect the hub to a power bank.
  • After you click on connect, the WPF application should get connected to your RF device.
  • Test whether your robot is working. Use a FPV 5.8 GHz camera to get a live view from your UGV.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.38.92