This program that allows you to control a robot over the internet (or at least your home wifi) from a web browser. The EV3 leJOS 0.5.0 release makes it trivial to write internet-aware programs on the EV3 as it supports the full Java networking library. I used the NanoHTTPD Java class which packages a simple web server in one Java file. Read on!

An EV3 with a wifi adapter brings the power of internet-accessible robots to your Lego set. Once the EV3 is connected to your wifi network you can write leJOS programs that use the Java networking libraries to communicate with any host. One practical application is to run a web server on your EV3 brick and link it to a leJOS program to control your robot. Now you can control your robot from any internet-connected device; a phone, a tablet or your PC.

Writing a web server is not a trivial task; while the HTTP protocol is very simple, but there are a lot of corner-cases to consider to get a web server that will work with every browser. Luckily there are many freely available Java implementations of web servers available. I chose the NanoHTTPD implementation; it packages a fully functional web-server in a single Java class file which is perfect to incorporate into your leJOS programs. I modified the web server code to intercept button presses for a simple web page GUI to control the direction and movement of the robot.

ASIDE: The Apache web server is a very powerful freely available package for Linux computers, and powers many of the web sites on the Internet. But Apache is overkill for a home-robotics web server. NanoHTTPD is far better suited to running on a device like the EV3.

NewImage

What’s involved?

There are a few steps involved to getting the web server code set up on the EV3, but once you’ve done this once you can skip these steps and jump straight to step 12 to start the web server each time.

  1. Insert a wifi adapter in your EV3.
  2. Power up the EV3 and make note of the IP address assigned (let’s call it YOURIPADDRESS)
  3. Import the NanoWebserver project into Eclipse.
  4. Modify the IP address in the web server_build.xml file ev3.host property to the IP address from step 2.
  5. Build a differential-drive robot with the motors on ports A and D of the EV3.
  6. Right-click on the web server_build.xml file, select Run As… Ant Build.
  7. The code should build and upload to your EV3.
  8. Download the www.tar.gz file below.
  9. Open your Terminal (on a Mac) or use a file transfer program on a PC to copy the www.tar.gz file to the EV3 in the directory /home/lejos/programs. For example, on a Mac you would type scp www.tar.gz root@YOURIPADDRESS:/home/lejos/programs
  10. Log into the EV3 using ssh and cd to /home/lejos/programs
  11. Extract the www.tar.gz file: tar xzvf www.tar.gz. This should create a www directory containing the index.html and png image files for the buttons on the web page.
  12. In a terminal window on your EV3 type: cd /home/lejos/programs; jrun -jar SimpleWebServer.jar -h YOURIPADDRESS -d /home/lejos/programs/www
  13. You will see the web server starting up; in takes about 20 second to initialise.
  14. Go to a web browser on your PC and in the address field enter YOURIPADDRESS. You should see the web page displayed. If not check the debug output on the command terminal from the EV3.
  15. Click the buttons to make your robot move!

Setting up a web server on your EV3

The NanoHTTPD server comes with a sample web server program that can run unmodified on the EV3. You will need an EV3 with a wifi adapter – be aware that the IP address of the wifi adapter will likely change each time you restart your EV3.

Web server Eclipse Project

I packaged my Eclipse project in a zip file (NanoWebserver.zip) which is broken down into these class files:

  • DebugServer.java (optional) – a simple web server that returns a web page containing the header and parameter details of the HTTP request. Very handy for debugging.
  • HelloServer.java (optional) – a Hello World server that generates the HTML code and a form in Java.
  • InternalRewrite.java (required) – rewriting rules used by the NanoHTTPD.
  • NanoHTTPD.java (required) – the core class for handling the HTTP protocol.
  • ServerRunner.java (required) – used by NanoHTTPD.
  • SimpleWebServer (required) – the main web server class. This is the program you will run on the EV3. I added the handleParameters() method to control the robot (see below for details).
  • WebServerPlugin.java (required) – used by NanoHTTPD.
  • WebServerPluginInfo.java (required) – used by NanoHTTPD.

I created three build files as follows:

  • debugserver_build.xml – builds the DebugServer.java to a jar file named DebugServer.jar and copies it onto the EV3 in the directory /home/lejos/programs. It will show up in the Programs menu in leJOS on your EV3, or you can run it from the command line.
  • helloserver_build.xml – builds the HelloServer.java class to a jar file named HelloServer.jar.
  • webserver_build.xml – builds the SimpleWebServer.java class to a jar file named SimpleWebServer.jar. This is the file we will use to control the robot.

You can download the NanoWebserver.zip file above and then unzip it and import it into Eclipse to get started.

Creating a web page

I created a simple web page to display the button icons. It is named index.html and looks as follows:

<html>
<head><title>LEGO EV3 Robot Control</title>
<script> 
function action(type) {
var xmlhttp;
if (window.XMLHttpRequest) {
 // code for IE7+, Firefox, Chrome, Opera, Safari
 xmlhttp=new XMLHttpRequest();
 } else {
 // code for IE6, IE5
 xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
 }
xmlhttp.open("GET","index.html?action="+type,true);
xmlhttp.send();
}
</script>
<noscript>Sorry, your browser does not support JavaScript!</noscript>
</head>
<body> 
<div style="text-align:center"> 
<h1>Lego EV3 Robot Control</h1> 
<button type="button" onclick="action('up')"><img src="up.png"></button>
<br>
<button type="button" onclick="action('left')"><img src="left.png"></button>
<button type="button" onclick="action('stop')"><img src="close.png"></button>
<button type="button" onclick="action('right')"><img src="right.png"></button>
<br>
<button type="button" onclick="action('back')"><img src="down.png"></button>
<br>
<button type="button" onclick="action('plus')"><img src="plus.png"></button>
<button type="button" onclick="action('minus')"><img src="minus.png"></button>
</div>
<hr>
2014 Mark Crosbie <a href="http://thinkbricks.net">http://thinkbricks.net</a>
</body>
</html>

The web page refers to the png files which I downloaded from IconFinder.com. The web contents will live in /home/lejos/programs/www on the EV3 (though you can move it to another location). I’ve packaged the www directory as a gzip’d tar file: www.tar.gz. Copy this file onto your EV3 in /home/lejos/programs and untar it there.

Handling the web requests

The modification I made to the SimpleWebServer.java class is to add a handleParameters() method that intercepts the HTTP request and extracts two parameters; action and speed. The action parameter corresponds to the name of the button pressed (e.g. “up” or “plus”) and the speed parameter is used to set the motor speed.

// Handle the parameters passed to the request to see if we control the robot
void handleParameters(IHTTPSession session, Map<String, String> header, Map<String, String> parms) {

   String uri = session.getUri();
   System.out.println(session.getMethod() + " '" + uri + "' ");

   if(parms.containsKey("speed")) {
       speed = Integer.parseInt(parms.get("speed"));
       System.out.println("Speed set to " + speed);
   }

   // see if the action and speed parameters are given
   if(parms.containsKey("action")) {
      String action = parms.get("action");
      System.out.println("Action = " + action);

      leftMotor.setSpeed(speed);
      rightMotor.setSpeed(speed);

      switch(action) {
        case "up":
        leftMotor.forward();
        rightMotor.forward();
        break;

        case "back":
        leftMotor.backward();
        rightMotor.backward();
        break;

        case "left":
        leftMotor.backward();
        rightMotor.forward();
        break;

        case "right":
        leftMotor.forward();
        rightMotor.backward();
        break;

        case "stop":
        leftMotor.stop();
        rightMotor.stop();
        break;

        case "plus":
        speed += 60;
        if(speed > 1440)
        speed = 1440;

        leftMotor.setSpeed(speed);
        rightMotor.setSpeed(speed);
        System.out.println("Speed is now " + speed);
        break;

        case "minus":
        speed -= 60;
        if(speed <= 60)
          speed = 60;

        leftMotor.setSpeed(speed);
        rightMotor.setSpeed(speed);
        System.out.println("Speed is now " + speed);
        break;

        default: System.out.println("Unknown");
      }
   }
}

The code is not very complicated – it takes the header and parameters from the HTTP session and looks for the value of the “action” parameter if it is set.