TCPCom Module
 
TCP With The Lego EV3 Robot
 

 

The Lego EV3 robot runs a full-featured Linux system. With the SD card from the leJOS for EV3 distribution, you have access to the Linux file system using SSH and standard Java programs can be executed. The leJOS framework contains a rich Java library in the lejos package that supports the Lego robot hardware. You can also use the EV3JLib-based SD card and a fully object-oriented Java und Python library is added, but the standard leJOS package is still available without modification. Our distribution also contains the TCPCom package for Java and Python, so no addition installation is needed to make the event-based socket library work on the EV3.

Since the EV3 can be considered as a standard Linux system like any PC, the examples on the previous TCPCom demonstration sites can easily be adapted to run on the EV3. Probably the most exciting issue for you is a TCP communication between two (or several) EV3 robots.

EV3-to-PC Communication using the leJOS Framework

To keep the learning curve smooth, you start by implementing just another echo server on the EV3. There is nothing new about the TCPCom related code, but you show the state on the EV3 display.

Java server on EV3:

import lejos.hardware.lcd.LCD;
import lejos.hardware.Sound;
import lejos.hardware.Button;
import ch.aplu.tcpcom.*;

public class EchoServerRaw implements TCPServerListener
{
  private TCPServer server;

  public EchoServerRaw()
  {
    int port = 5000;
    server = new TCPServer(port);
    server.addTCPServerListener(this);
    LCD.drawString("Start Echo Server", 0, 1);
    Sound.beepSequenceUp();
    Button.waitForAnyPress();
    Sound.beepSequence();
    server.terminate();
  }
  
  public void onStateChanged(String state, String msg)
  {
    if (state.equals(TCPServer.LISTENING))
    {
      LCD.clear(2);
      LCD.drawString("Listening", 0, 2);
    }
    else if (state.equals(TCPServer.CONNECTED))
    {
      LCD.clear(2);
      LCD.drawString("Connected", 0, 2);
    }
    else if (state.equals(TCPServer.MESSAGE))
    {
      LCD.clear(4);
      LCD.drawString(msg, 0, 4);
      server.sendMessage(msg);
    }
  }

    
  public static void main(String[] args)
  {
    new EchoServerRaw();
  }
}


On the PC side, you can run the same echo clients in Java or Python as presented for the PC-to-PC communication here. If you run the EV3 over a Bluetooth link, you use the IP address 10.0.0.1, but you may also connect the EV3 via WLAN to an access point (hot spot) and use the second IP address shown on the EV3 display.

 

EV3-to-PC Communication using the EV3JLib Framework

With our EV3JLib-based SD card, you can program in typical Java-style because the robot is modelled as an instance of the LegoRobot class. Consult the corresponding Web site for more information about the library design and how to install the card.

Java echo server on EV3 (developed under Netbeans/Eclipse/BluJ and downloaded via BrickTransfer):

// EchoServer.java
// Echo server

import ch.aplu.ev3.*;
import ch.aplu.tcpcom.*;

public class EchoServer implements TCPServerListener
{
  private TCPServer server;
  private LegoRobot robot;

  public EchoServer()
  {
    robot = new LegoRobot();
    robot.drawString("Start Echo Server", 0, 1);
    int port = 5000;
    server = new TCPServer(port);
    server.addTCPServerListener(this);
    while (!robot.isEscapeHit())
      continue;
    server.terminate();
  }

  public void onStateChanged(String state, String msg)
  {
    if (state.equals(TCPServer.LISTENING))
      robot.drawString("Listening", 0, 2);
    else if (state.equals(TCPServer.CONNECTED))
      robot.drawString("Connected", 0, 2);
    else if (state.equals(TCPServer.MESSAGE))
    {
      robot.drawString(msg, 0, 4);
      server.sendMessage(msg);
    }
  }

  public static void main(String[] args)
  {
    new EchoServer();
  }
}


By using our EV3Lib-based SD card, you also add the support for the Python language on the EV3, but you must use the TigerJython IDE to develop Python programs either for the autonomous or remote mode. The library design to use the robot hardware and the TCP communication is identical, so it is easy to port programs from Java to Python and vice versa. As an example, here the echo server with exactly the same features as above, but written in Python.

Python echo server on EV3 (developed and downloaded under TigerJython):

from ev3robot import *

def onStateChanged(state, msg):
    if state == TCPServer.LISTENING:
        robot.drawString("Listening", 0, 2)
    elif state == TCPServer.CONNECTED:
        robot.drawString("Connected", 0, 2)
    elif state == TCPServer.MESSAGE:
        robot.drawString(msg, 0, 4)
        server.sendMessage(msg)
 
robot = LegoRobot()
robot.drawString("Start Echo Server", 0, 1)
port = 5000
server = TCPServer(port, stateChanged = onStateChanged)
while not robot.isEscapeHit():
    continue
server.terminate()     
robot.exit()

As clients you may use the same as above.

 

EV3-to-PC Communication for Remote Measurement Systems

Client-server communications over TCP/IP play an important role in measuring and control technology. Often a measuring instrument or a robot is far away from a command center and the measurement and control data are transmitted via TCP/IP. Here you are using a Raspberry Pi that acts as interface between the measuring sensors and the Internet, and sends the measurement data to a remote recording station. In this demonstration, only the light intensity of a light sensor (the EV3 color sensor) is reported.

The server program is very simple: In the measuring loop you call periodically ls.getValue() to read the current light intensity. Subsequently the value is transferred to the client and displayed on the EV3 display. By pressing the Escape key, the server program terminated.

Java measurement server on EV3 (using the EV3JLib framework):

// LightServer.java

import ch.aplu.ev3.*;
import lejos.hardware.lcd.LCD;
import ch.aplu.tcpcom.*;

public class LightServer implements TCPServerListener
{
  private final long period = 100000000L;
  private TCPServer server;

  public LightServer()
  {
    LegoRobot robot = new LegoRobot();
    LightSensor ls = new LightSensor(SensorPort.S1);
    robot.addPart(ls);
    int port = 5000;
    server = new TCPServer(port);
    server.addTCPServerListener(this);
    LCD.drawString("Start Light Server", 0, 1);

    while (!robot.isEscapeHit())
    {  
      long startTime = System.nanoTime();
      int v = ls.getValue();
      server.sendMessage("" + v);
      LCD.clear(3);
      LCD.drawString("Light value: " + v, 0, 3);
      while (System.nanoTime() - startTime < period)
        Tools.delay(1);
    }
    server.terminate();
    robot.exit();
  }

  public void onStateChanged(String state, String msg)
  {
    if (state.equals(TCPServer.LISTENING))
    {
      LCD.clear(2);
      LCD.drawString("Listening", 0, 2);
    }
    else if (state.equals(TCPServer.CONNECTED))
    {
      LCD.clear(2);
      LCD.drawString("Connected", 0, 2);
    }
  }

  public static void main(String[] args)
  {
    new LightServer();
  }
} 

The client can use the abundance of any programming language and treat the measuring values in any way, including graphics display, for example in Java the GPanel class from the ch.aplu.util package.

Java measurement client on PC:

import ch.aplu.tcpcom.*;
import ch.aplu.util.*;

public class EV3LightClient implements TCPClientListener
{
  private GPanel gp;
  private double t = 0;

  public EV3LightClient()
  {
    gp = new GPanel(0, 10, 0, 1000);
    drawGrid();

    String host = "10.0.1.1";
    int port = 5000;
    TCPClient client = new TCPClient(host, port);
    boolean success = client.connect();
    if (!success)
    {
      gp.title("Connection failed");
      return;
    }
    client.addTCPClientListener(this);
    gp.title("Connection established");
  }

  public void onStateChanged(String state, String msg)
  {
    if (state.equals(TCPClient.MESSAGE))
    {
      int v = Integer.parseInt(msg);
      if (t == 0)
        gp.pos(0, v);
      else
        gp.draw(t, v);
      t += 0.1;
      if (t > 10)
      {
        t = 0;
        gp.clear();
        drawGrid();
      }
    }
    else if (state.equals(TCPClient.DISCONNECTED))
      gp.title("Disconnected");
  }

  private void drawGrid()
  {
    for (int t = 0; t <= 10; t += 1)
      gp.line(t, 0, t, 1000);
    for (int y = 0; y <= 1000; y += 100)
      gp.line(0, y, 10, y);
  }

  public static void main(String[] args)
  {
    new EV3LightClient();
  }
}

Execute the program locally using WebStart (not yet active).

tcpcomev3


EV3-to-EV3 Communication

Probably the most exiting robotic application using TCP communication is the exchange of information between two (or several) robots in real-time. A typical scenario are moving robots that move on the same track with one or several passing places. The program must ensure that there is no collision (as we already did on the Pi2Go site.)

Here we demonstrate the communication between two robots in a someone more colorful scenario where we consider the robots to act like humans in a conversation. The robots ANNA and BOB talks by emitting some beeps of different frequencies and duration. Like in a courteous dialog each of them speaks for some arbitrary length of time while the partner keeps silent and listens. Then the situation is interchanged.

Unlike in the previous examples where the EV3 can be accessed over Bluetooth PAN, it is now necessary that a WLAN dongle is inserted. If you do not have WLAN access via a router, you can run a WLAN hot spot app with any modern smartphone. The phone does not need to be connected to the Internet.

Start the EV3 and use the WiFi menu option to select the access point (AP) and enter the router's WPA security password. Reboot the EV3 and the IP address obtained from the router's DHCP is displayed under the Bluetooth PAN address 10.0.1.1. To check the connection you can connect to the same access point with your notebook and perform a ping operation.

The demonstration is based on the leJOS framework and the TCPCom library. A more elaborated version with button support and state information shown on the EV3 display is part of the TCPCom distribution. It is up to you to create a more realistic (and intelligent) dialog between ANNA and BOB with spoken sentences taken from sound clips stored in the EV3 file system.

Java server on EV3 (ANNA):

import lejos.hardware.Sound;
import ch.aplu.tcpcom.*;

public class Anna implements TCPServerListener
{
  private TCPServer server;
  private boolean isWaiting = true;

  public Anna()
  {
    int port = 5000;
    server = new TCPServer(port);
    server.addTCPServerListener(this);
    Sound.beepSequenceUp();
    while (true)
    { 
      while (isWaiting)
        continue;
      speak(1000);
      isWaiting = true;
      delay(1000);  
      server.sendMessage("done");
    }  
  }
  
  private void speak(int freq)
  {
    int n = 1 + (int)(5 * Math.random());
      for (int i = 0; i < n; i++)
      {
        Sound.playTone(freq, 500);
        delay(100);
      }
  }
  
  private void delay(int duration)
  {
    try
    {
      Thread.sleep(duration);
    }  
    catch (InterruptedException ex)
    {
    }
  }
  
  public void onStateChanged(String state, String msg)
  {
    if (state.equals(TCPServer.MESSAGE))
       isWaiting = false;
  }

    
  public static void main(String[] args)
  {
    new Anna();
  }
}

To stop the program, press the Down+Enter buttons.

Java client on EV3 (BOB):

import lejos.hardware.Sound;
import ch.aplu.tcpcom.*;

public class Bob implements TCPClientListener
{
  private TCPClient client;
  private boolean isWaiting = true;

  public Bob()
  {
    String host = "192.168.0.17"; // ANNA
    int port = 5000;
    client = new TCPClient(host, port);
    client.addTCPClientListener(this);
    Sound.beepSequenceUp();
    client.connect();
    client.sendMessage("done");
    while (true)
    {
      while (isWaiting)
         delay(100);
      speak(500);
      isWaiting = true;
      delay(1000);
      client.sendMessage("done");
    }
  }

  private void speak(int freq)
  {
    int n = 1 + (int)(5 * Math.random());
    for (int i = 0; i < n; i++)
    {
      Sound.playTone(freq, 100);
      delay(50);
    }
  }

  private void delay(int duration)
  {
    try
    {
      Thread.sleep(duration);
    }
    catch (InterruptedException ex)
    {
    }
  }

  public void onStateChanged(String state, String msg)
  {
    if (state.equals(TCPClient.MESSAGE))
      isWaiting = false;
  }

  public static void main(String[] args)
  {
    new Bob();
  }
}

To stop the program, press the Down+Enter buttons. For the Python version the TigerJython IDE is used and the BrickGate server must be started.

tcpcom-talk

 

To demonstrate a simple EV3-to-EV3 communication with Python, we use again the prototype of all client/server scenarios, the echo server application. On one EV3 you download and start the echo server shown above in the EV3-to-PC section. But instead of using a PC client, the other EV3 is now playing the role of the echo client.

Python echo client on EV3 (developed and downloaded under TigerJython):

from ev3robot import *
import time

def onStateChanged(state, msg):
    if state == TCPClient.MESSAGE:
        robot.drawString(msg, 0, 4)
    elif state == TCPClient.CONNECTED:
        robot.drawString("Connected", 0, 2)
    elif state == TCPClient.DISCONNECTED:
        robot.drawString("Disconnected", 0, 2)
 
robot = LegoRobot()
robot.drawString("Echo Client", 0, 1)
host = "192.168.0.17"
port = 5000
client = TCPClient(host, port, stateChanged = onStateChanged)
if client.connect():
    robot.drawString("Connected", 0, 2)
else:
    robot.drawString("Connection failed", 0, 2)
n = 0
while not robot.isEscapeHit():
    client.sendMessage(str(n))
    n += 1
    time.sleep(0.1)
client.disconnect()     
robot.exit()

To stop the program, press the Escape button.