remote vehicle networking: the case of vex...
TRANSCRIPT
1 | P a g e
Remote Vehicle Networking: The Case
of VEX ClawBot Testing and Implementation
Matt Grojean and Nathan Hart
April 24th, 2014
CEN 4935 Software Project in Computer Networks
Instructor: Dr. Janusz Zalewski
Computer Science & Software Engineering Programs
Florida Gulf Coast University
Ft. Myers, FL 33965
2 | P a g e
1. Introduction
This remote networking project is inspired by the ability to remotely access and
manipulate a robot from anywhere in the world. Today users can access anything with the click
of a mouse and given the accelerated rate of software development, implementing a remote
development tool is a vastly beneficial addition to today’s software development lifecycle.
The software and robotic system referenced in this document is that of the same system
seen in the Software Design Document of the project Remote Vehicle Networking. “As software
is developed for VEX via a remote location, one can upload the new designs to VEX and carry
out the instructions.”[2] On that notion, the full operation of the Remote Vehicle network
designed for this VEX robot is explained and tested for accuracy in this document.
From the objectives covered in section two of the accompanied SRS document[1], the
items tested include the remote accessibility of the robot, receiving commands from the web-
panel, live stream of the behavior of ClawBot, and the ability for remote uploading user
generated code. The overall section architecture is presented in Figure 1.
Figure 1. System Architecture
3 | P a g e
2. Implementation
To begin building the core functionality of the network to be used for communicating
commands to ClawBot, the connection from the PC to the VEX Cortex must be understood.
Beginning with the programming A-to-A USB cable supplied with the VEX competition kit, the
VEX serial drivers are installed and configured. Having this implemented as the first step
provides and insight into the commands and protocols needed to communicate with the VEX
Cortex. Prior to this, it was quite unknown how the ClawBot was to communicate with the
server. These drivers create a direct COM port connection from the computer to the VEX Cortex
which allows both access to the re-writable memory and to the source of main input which
monitors for incoming commands to the VEX code running on the Cortex. To get a command to
the VEX Cortex, the send code used takes in a string with the command requested and sends it
via the write()function of the serial port class from the PC's web-server code. A sample of the
command function is shown below in figure 2.1.
using (SerialPort sp = new SerialPort(Session["vexPort"].ToString(), 115200, Parity.None))
{ sp.Open(); sp.Write(command); sp.Close(); }
Figure 2.1. Sample write command and Serial Port object initialization.
The implementation of the ClawBot Manager occurs in several different pieces. The
aspect first implemented is sending commands to the ClawBot. This was done using C# code
executed on a button click. The web page can currently support commands for the ClawBot to
move forward, reverse, left, right, raise and lower its arm, open and close the claw. When a user
clicks the forward directional button the C# code is executed which opens a COM port and
writes a specific command to the port using the string command (Figure 2.2).
4 | P a g e
Once sending commands from the website was accomplished via the USB cable directly
attached to the VEX Cortex, the next step is making the system wireless. During this build, only
two options were considered for creating the necessary wireless connection needed to support the
communication and at the range desired. That protocol is 802.11g. Initially the prototype design
was to incorporate a serial to Wi-Fi adapter which sent commands directly into the UART ports
fitted on the VEX cortex. Lacking sufficient documentation on this protocol pushed the design to
focus on the use of VEX based connections. Given the system works directly via the supplied
programming cable, consideration for the VEX programming kit add-on for the remote controller
grew to the most acceptable design. The major benefit to using this programming kit is the
gaining of the connected state desired with the concrete protocol for sending commands to the
Cortex.
Figure 2.2. Flow-chart for manual controls via ClawBot Manager
The add-on kit which connects the controller to the server simulates the hard-wired COM port
initially used for designing the commands to be sent. This was a major step and convenience
which allowed the focus to be shifted to the operation and streamlined behavior of the overall
5 | P a g e
design. Having the communication channel now open from the server to the VEX Cortex,
website design now becomes the next objective to complete.
The second portion of the Web site to be implemented is to allow a user to upload their
code to the ClawBot (Figure 2.3). A discovered limitation with this option is if a user is to upload
code which does not support the directional commands sent from the website then the ClawBot
can no longer be controlled remotely unless he/she has the original code. To avoid this issue a
Restore Default button was incorporated alongside the button to upload user code. This allows
for another user to restore the default behavior back to the ClawBot when necessary.
Figure 2.3. Flow-chart of upload code command.
The final portion of the web site is the functions to allow uploading code to the ClawBot.
To ensure the ClawBot isn’t going to receive “bad” code, the ClawBot Manager first verifies the
user uploaded an actual binary file with a “.bin” extension. The website then saves this binary
file on the server and executes a batch script to send the code to the ClawBot. The code to enter
the ClawBot into programming mode and send the program to the Cortex is borrowed from an
open source project called Purdue Robotics Operating System (PROS)[3].
6 | P a g e
There are a number of VEX proprietary commands which ClawBot uses to enter
programming mode and receive commands and code. The documentation which may have aided
in the development of a more catered solution was not able to be located which is why the
PROS-developed upload code is necessary. The PROS upload code is written in Java and needed
a few minor changes to fit the projects needs and compile into an executable .jar. This .jar
is then executed from the batch scripts. There are two batch scripts created, one passes the JAR
file containing the user’s binary file and the other passes the default binary file housed on the
server for the Restore Default feature.
To understand a bit more of how the batch scripts are implemented with the Java code see
figure 2.4 below. The ExecuteBatFile()method is used to call the two bat files needed for
uploading different programs via the local PC. The method begins by reading the file name to be
executed. A new process is started in the window environment and passed the parameters of the
program needed, the directory, and the script name by the line processInfo = new
ProcessStartInfo("cmd.exe", "/c " + batName; The remaining lines of code are
needed to define the behavior of error reporting and how to display the command window if at
all. Finishing the operation of the code is a while loop reading the outputs of the .bat file. This
avoids losing the errors in method-to-method communication. The final if-else check parses the
output stream and looks for keywords of “EXCEPTION” and “ERROR” and instructs the
method to report to the website an error occurred.
7 | P a g e
private void ExecuteBatFile(string batName) { // upload to vex //execute bat file which will upload the prog to the vex.. //thanks to PUrdue OS for the uploading java code which made this possible... ProcessStartInfo processInfo; Process process; processInfo = new ProcessStartInfo("cmd.exe", "/c " + batName); processInfo.CreateNoWindow = true; processInfo.UseShellExecute = false; // *** Redirect the output *** processInfo.RedirectStandardError = true; processInfo.RedirectStandardOutput = true; process = Process.Start(processInfo); //while (!process.StandardOutput.EndOfStream) //{ // lblInfo.Text = lblInfo.Text + process.StandardOutput.ReadLine() + System.Environment.NewLine; //} process.WaitForExit(); // *** Read the streams *** string output = process.StandardOutput.ReadToEnd().ToUpper(); string error = process.StandardError.ReadToEnd(); //exitCode = process.ExitCode; if (!string.IsNullOrEmpty(error) || output.Contains("EXCEPTION") || output.Contains("ERROR")) { lblInfo.ForeColor = System.Drawing.Color.Red; lblInfo.Text = "Problem uploading code!"; } else { lblInfo.ForeColor = System.Drawing.Color.DarkOrange; lblInfo.Text = "Successfully uploaded!"; } process.Close(); }
Figure 2.4 Java code snippet to execute upload batch scripts.
8 | P a g e
3. Testing
3.1 Test Plan
The following test cases are catered to the feature requirements found in the SRS
document[1].
Test #1 - Req 3.1.1 - The VEX shall be controllable by live manual commands.
Purpose: This test case is to verify the ClawBot Manager is able to send commands to
ClawBot successfully.
Description: From the ClawBot manager, after verifying the live stream is available.
Click the left and then the right navigational keys. The robot is expected to rotate left 45
degrees then rotate the same distance to the right. The ClawBot is expected be in the
position in which the test was started.
Figure 3.1.1. Confirmation of design for Req 3.1.1.
Test #2 - Req 3.1.2 - The ClawBot manager’s hosting server will be available via a static IP.
Purpose: This test case simply confirms the configuration of the website on the ROCK
server and that it is accessible.
Description: As per the design of the website, navigating to vex.cs.fgcu.edu is
expected to resolve to the ClawBot Manager.
9 | P a g e
Test #3 - Req 3.1.3 - The web panel will be secured via restricted user logins and support only
one user at a time.
Purpose: This test case will confirm the accessibility for the website is restricted to those
with privileged access.
Description: To confirm the accepted security of the web-panel, enter the accepted
credentials of username: fgcu and password: vex. The web-panel will grant access as
expected. To also confirm the denial of invalid credentials, enter anything other than
username: fgcu and password: vex to ensure a denial of access to the ClawBot manager.
Figure 3.1.3. Confirmation of design for Req 3.1.3.
Test #4 - Req 3.1.4 - The web panel will have access to the local file system of the user PC
making the connection to the server.
Purpose: This provides the ability to select a local file for upload to VEX and confirms
files can be selected from the local disk and published to the website.
Description: Clicking Choose File will prompt the user to navigate to the needed
directory and select the file for uploading[2] Once the file is selected, clicking Open will
then check the selected file to ensure it is a binary file. A status message will be reflected
according to the file. Upon successful verification, click Upload to send the code to the
ClawBot. Once uploaded the program will begin running as the uploaded code.
10 | P a g e
Following the same instructions selecting a non-binary file, the ClawBot Manager
displays a message reporting the file found is not a binary file. Uploading is not allowed.
Figure 3.1.4. Confirmation of design for Req 3.1.4.
Test #5 - Req 3.1.5 - A live stream of VEX’s view will be seen through the mounted IP camera
and embedded into the web panel.
Purpose: This confirms the ability to view the robot’s behavior on the screen with the mounted
camera with a maximum 750ms delay.
Description: Following successful login to the web‐panel, one is met with the live stream of the
robot view on the left side of the screen.
3.2 Test Report
Test #1 The initial test failed. A modification to the motor duration to a shorter constant
resolved the over-turning observed. The test now passed.
Test #2 This test easily passes as it either works or does not. Initially the site is accessible
via 69.88.163.32 and clicking the VEX link. Following this report, VEX.FGCU.EDU is the
preferred method to resolve the location of the website.
Test #3 This test passes.
11 | P a g e
Test #4 This test passes.
Test #5 Initially, the test failed. The stream was resolving to the wrong IP address. Once
the site is loaded it was trying to resolve the IP address of the local network and not the network
of which the server is on. Changing this to the same IP as the server and proper port number, test
passed.
12 | P a g e
4. Conclusion
Remote networking of this VEX robot was a full success. Full functionality of the web-
panel and desired convenience and accessibility expected is delivered in a neat package for
privileged users. A great deal of serial to IP communication was learned from the issue of
achieving our desired network connectivity of the VEX ClawBot to the server. Once overcoming
the hurdles of VEXnet and the key system, the project was overall most enjoyable of those in the
senior year.
Given the amount of work that was required to implement the core objectives within this
project, adding new features is certainly possible in the future. The next additions should include
the transmission from newly attached sensors. More importantly to track precise location, the
servos should be exchanged with those that can monitor their positions. This info being reported
to not only the VEX Cortex but also the website will make for much more precise development.
A final but more minor addition would be that of a high-definition, wide-angle webcam.
This would allow a much better view of the robot and its surroundings than from the current
camera.
13 | P a g e
5. References
1. Grojean, M., and Hart, N. Automated Robotic Retrieval System – Software
Requirement Specification. Florida Gulf Coast University, 2014
2. Grojean, Matthew, and Nathan Hart. VEX Robotics - Software Design Description.
Florida Gulf Coast University, 2014
3. S. Carlson, Perdue Robotics Operating System, Perdue University - Lafayette, IN
<http://purdueros.sourceforge.net/doc/>
14 | P a g e
6. Appendix
i. ClawBot Manager Source Code
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.IO; using System.IO.Ports; using System.Threading; using System.Diagnostics; namespace ClawBotManager { public partial class Default1 : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { string[] ports = SerialPort.GetPortNames(); if (ports.Length == 0) { lblConnectionErr.Visible = true; setControls(false); } else { lblConnectionErr.Visible = false; setControls(true); Session["vexPort"] = ports[0]; } } } protected void goForward(object sender, EventArgs e) { writeCommand("w"); } protected void goReverse(object sender, EventArgs e) { writeCommand("s"); }
15 | P a g e
protected void goLeft(object sender, EventArgs e) { writeCommand("a"); } protected void goRight(object sender, EventArgs e) { writeCommand("d"); } protected void armUp(object sender, EventArgs e) { writeCommand("u"); } protected void armDown(object sender, EventArgs e) { writeCommand("l"); } protected void clawOpen(object sender, EventArgs e) { writeCommand("o"); } protected void clawClose(object sender, EventArgs e) { writeCommand("t"); } private void writeCommand(string command) { try { using (SerialPort sp = new SerialPort(Session["vexPort"].ToString(), 115200, Parity.None)) { sp.Open(); sp.Write(command); sp.Close(); lblOutOfRange.Visible = false; } } catch (Exception) { lblOutOfRange.Visible = true; } } protected void RestoreDefault(object sender, EventArgs e) { lblInfo.Text = "";
16 | P a g e
string defaultBat = "\"" + @"C:\Users\Nathan\Documents\Visual Studio 2013\Projects\ClawBotManager\ClawBotManager\vexFiles\defaultUpload.bat" + "\""; ExecuteBatFile(defaultBat); } protected void UploadFile(object sender, EventArgs e) { if (fileuploader.HasFile) { // Call a helper method routine to save the file. string file = SaveFile(fileuploader.PostedFile); if (!file.Equals("")) { if (File.Exists(file)) { lblInfo.Text = ""; string userBat = "\"" + @"C:\Users\Nathan\Documents\Visual Studio 2013\Projects\ClawBotManager\ClawBotManager\vexFiles\userUpload.bat" + "\""; ExecuteBatFile(userBat); } else { lblInfo.ForeColor = System.Drawing.Color.Red; lblInfo.Text = "Error uploading binary file!"; } } else { lblInfo.ForeColor = System.Drawing.Color.Red; lblInfo.Text = "Please upload only binary files!"; } } else { lblInfo.ForeColor = System.Drawing.Color.Red; lblInfo.Text = "Choose a file!"; } } string SaveFile(HttpPostedFile file)
17 | P a g e
{ // Specify the path to save the uploaded file to. string savePath = @"C:\Users\Nathan\Documents\Visual Studio 2013\Projects\ClawBotManager\ClawBotManager\vexFiles\"; string newFileName = "userProgram.bin"; if (!Directory.Exists(savePath)) { Directory.CreateDirectory(savePath); } // Get the name of the file to upload. string fileName = fileuploader.FileName; //if filename is binary file if (fileName.Contains(".")) { if (fileName.ToUpper().Split('.')[1].Equals("BIN")) { // Create the path and file name to check for duplicates. string pathToCheck = savePath + newFileName; // Check to see if a file already exists with the // same name as the file to upload. if (System.IO.File.Exists(pathToCheck)) { System.IO.File.Delete(pathToCheck); } // Append the name of the file to upload to the path. savePath += newFileName; // Call the SaveAs method to save the uploaded // file to the specified directory. fileuploader.SaveAs(savePath); return savePath; } else {
18 | P a g e
return ""; } } else { return ""; } } private void ExecuteBatFile(string batName) { // upload to vex //execute bat file which will upload the prog to the vex.. //thanks to PUrdue OS for the uploading java code which made this possible... ProcessStartInfo processInfo; Process process; processInfo = new ProcessStartInfo("cmd.exe", "/c " + batName); processInfo.CreateNoWindow = true; processInfo.UseShellExecute = false; // *** Redirect the output *** processInfo.RedirectStandardError = true; processInfo.RedirectStandardOutput = true; process = Process.Start(processInfo); //while (!process.StandardOutput.EndOfStream) //{ // lblInfo.Text = lblInfo.Text + process.StandardOutput.ReadLine() + System.Environment.NewLine; //} process.WaitForExit(); // *** Read the streams *** string output = process.StandardOutput.ReadToEnd().ToUpper(); string error = process.StandardError.ReadToEnd(); //exitCode = process.ExitCode; if (!string.IsNullOrEmpty(error) || output.Contains("EXCEPTION") || output.Contains("ERROR")) { lblInfo.ForeColor = System.Drawing.Color.Red; lblInfo.Text = "Problem uploading code!"; } else {
19 | P a g e
lblInfo.ForeColor = System.Drawing.Color.DarkOrange; lblInfo.Text = "Successfully uploaded!"; } process.Close(); } private void setControls(Boolean enabled) { btnarmDown.Visible = enabled; btnarmUp.Visible = enabled; btnLeft.Visible = enabled; btnRight.Visible = enabled; btnCloseClaw.Visible = enabled; btnOpenClaw.Visible = enabled; btnForward.Visible = enabled; btnReverse.Visible = enabled; btnRestore.Visible = enabled; btnUpload.Visible = enabled; fileuploader.Visible = enabled; } } } ii. Manual Control Operation in C #include "main.h" void operatorControl() { while (1) { int command = getchar(); //putchar(command); //echo command back used for testing.. if (command != -1) { switch (command) { case 119: //if command is "w" goforward motorSet(10, 75); motorSet(1, 75); motorSet(6, 0); motorSet(7, 0); delay(400);
20 | P a g e
break; case 97: //if command is "a" go left motorSet(10, 50); motorSet(1, -50); motorSet(6, 0); motorSet(7, 0); delay(275); break; case 100: //if command is "d" go right motorSet(10, -50); motorSet(1, 50); motorSet(6, 0); motorSet(7, 0); delay(275); break; case 115: //if command is "s" go reverse motorSet(10, -75); motorSet(1, -75); motorSet(6, 0); motorSet(7, 0); delay(400); break; case 111: //if command is "o" open claw motorSet(10, 0); motorSet(1, 0); motorSet(6, -50); motorSet(7, 0); delay(200); break; case 116: //if command is "t" close claw motorSet(10, 0); motorSet(1, 0); motorSet(6, 50); motorSet(7, 0); delay(200); break; case 117:
21 | P a g e
//if command is "u" lift arm motorSet(10, 0); motorSet(1, 0); motorSet(6, 0); motorSet(7, -50); delay(300); break; case 108: //if command is "l" lower arm motorSet(10, 0); motorSet(1, 0); motorSet(6, 0); motorSet(7, 20); delay(300); break; default: motorSet(10, 0); motorSet(1, 0); motorSet(6, 0); motorSet(7, 0); break; } motorSet(10, 0); motorSet(1, 0); motorSet(6, 0); motorSet(7, 0); } /* * JoyStick commands * */ /* if (joystickGetDigital(1, 5, JOY_UP)) { motorSet(6, 100); } else if (joystickGetDigital(1, 5, JOY_DOWN)) { motorSet(6, -100); } else { motorSet(6, 0); } if (joystickGetDigital(1, 6, JOY_UP)) {
22 | P a g e
motorSet(7, 100); } else if (joystickGetDigital(1, 6, JOY_DOWN)) { motorSet(7, -100); } else { motorSet(7, 0); } int joystick1 = joystickGetAnalog(1, 2); int joystick2 = joystickGetAnalog(1, 3); motorSet(10, joystick1); motorSet(1, joystick2); delay(20); */ } } iii. ClawBot Manager HTML
<%@ Page Title="" Language="C#" MasterPageFile="~/Default.Master" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="ClawBotManager.Default1" %> <asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server"> </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server"> <asp:ScriptManager runat="server"></asp:ScriptManager> <div class="row"> <asp:Label ID="lblConnectionErr" runat="server" Text="Cannot communicate with VEX controller unit!!" ForeColor="Red" Font-Size="X-Large" Visible="false"></asp:Label> <div class="col-md-8"> <div class="panel panel-info"> <div class="panel-heading"> <h4>Control ClawBot </h4> </div> <div class="panel-body text-center"> <asp:UpdatePanel ID="camPanel" runat="server" UpdateMode="Conditional">
23 | P a g e
<ContentTemplate> <img id="streamImg" src="http://192.168.10.116/img/video.mjpeg" /> <asp:Label ID="lblOutOfRange" runat="server" Text="The clawbot is out of range" ForeColor="Red" Visible="false"></asp:Label> </ContentTemplate> </asp:UpdatePanel> <br /> <br /> <asp:UpdatePanel ID="ctrlPanel" runat="server" UpdateMode="Conditional"> <ContentTemplate> <div class="row"> <div class="col-xs-4"> <table style="width: 25%;"> <tr> <td></td> <td> <button runat="server" type="button" id="btnForward" onserverclick="goForward" class="btn btn-default btn-lg"> <i class="fa fa-arrow-up"></i> </button> </td> <td></td> </tr> <tr> <td> <button runat="server" type="button" id="btnLeft" onserverclick="goLeft" class="btn btn-default btn-lg"> <i class="fa fa-arrow-left"></i> </button> </td> <td></td> <td> <button runat="server" type="button" id="btnRight" onserverclick="goRight" class="btn btn-default btn-lg"> <i class="fa fa-arrow-right"></i> </button> </td> </tr>
24 | P a g e
<tr> <td></td> <td> <button runat="server" type="button" id="btnReverse" onserverclick="goReverse" class="btn btn-default btn-lg"> <i class="fa fa-arrow-down"></i> </button> </td> <td></td> </tr> </table> </div> <div class="col-xs-4"> <table style="width: 25%;"> <tr> <td>Arm Up <button runat="server" type="button" id="btnarmUp" onserverclick="armUp" class="btn btn-default btn-lg"> <i class="fa fa-long-arrow-up"></i> </button> </td> <td> </td> <td>Close Claw <button runat="server" type="button" id="btnCloseClaw" onserverclick="clawClose" class="btn btn-default btn-lg"> <i class="fa fa-chevron-right"></i><i class="fa fa-chevron-left"></i> </button> </td> </tr> <tr> <td> <br /> </td> </tr> <tr> <td> <button runat="server" type="button" id="btnarmDown" onserverclick="armDown" class="btn btn-default btn-lg"> <i class="fa fa-long-arrow-down"></i>
25 | P a g e
</button> Arm Down </td> <td> </td> <td> <button runat="server" type="button" id="btnOpenClaw" onserverclick="clawOpen" class="btn btn-default btn-lg"> <i class="fa fa-chevron-left"></i><i class="fa fa-chevron-right"></i> </button> Open Claw </td> </tr> </table> </div> </div> </ContentTemplate> </asp:UpdatePanel> </div> </div> </div> <div class="col-md-4"> <div class="panel panel-info"> <div class="panel-heading"> <h4>Program ClawBot </h4> </div> <div class="panel-body text-center"> <h5>Made possible by <a href="http://purdueros.sourceforge.net/doc/">Purdue Robotics Operating System</a></h5> <h5>Use the PROS IDE to code and compile. Then upload your code here!</h5> <br /> <asp:UpdatePanel ID="prgrmPanel" runat="server" UpdateMode="Conditional"> <ContentTemplate> <asp:FileUpload ID="fileuploader" runat="server" /> <br /> <div class="row"> <div class="col-xs-5"> <button runat="server" id="btnUpload" type="button" onserverclick="UploadFile" class="btn btn-default btn-md"> Upload/Program
26 | P a g e
</button> </div> <div class="col-xs-5"> <button runat="server" id="btnRestore" type="button" onserverclick="RestoreDefault" class="btn btn-default btn-md"> Restore Default </button> </div> </div> <hr /> <asp:Label ID="lblInfo" runat="server"></asp:Label> </ContentTemplate> <Triggers> <asp:PostBackTrigger ControlID="btnUpload" /> </Triggers> </asp:UpdatePanel> <asp:UpdateProgress ID="UpdateProgress" runat="server" AssociatedUpdatePanelID="prgrmPanel"> <ProgressTemplate> Programming the VEX </ProgressTemplate> </asp:UpdateProgress> </div> </div> </div> </div> </asp:Content>