Seiten

Montag, 27. Januar 2014

Lego Mindstorms EV3 Components: Infrared Sensor - Part 1

Now that we have demonstrated how to work with motors, the next component we will focus on is a sensor - the infrared sensor.

In this first part we will show how to use the ability of the sensor to find objects and recognize the distance between that object and the sensor. There are other functionalities like receiving commands from the infrared remote control, which we will focus on in later posts.

The used lejos version is 0.5.0-alpha like in our last postings as it is still the most current version (01/27/2014).

The robot

First, as always, we needed a new robot which uses the infrared sensor. Therefore I just enhanced the robot from the last episode a bit (so if you want to understand the source code in this posting it will help if you already have checked the two postings about using motors). I strengthened the basement between the two wheels, so that it wouldn't break because of the weight of the brick and other components. The brick is now no longer located directly between the wheels, but a bit more above. Additionally, I mounted the infrared sensor centered above / in front of the brick and plugged it into the sensor plug 2. The result looks like the following.



( could be a relative of disney's wall-e )

The parcours

As said, in this tutorial we will focus on the ability of the infrared sensor to locate objects and return the objects' distance.

The scenario I created for that purpose:
We have a walled zone (cage). The robot is placed anywhere in that cage and the robot will always move forwards until he is directly in front of a wall. He then will turn left (90°) and will again move forwards until he reaches the next wall.



The infrared sensor API

So, before looking at the code let's talk a bit about what classes and methods the api offers for the infrared sensor.

It's quite easy to use an infrared sensor. You can simply instantiate an object of the EV3InfraredSensor-class. The (slightly) harder part is to tell the program to use the functionality of the sensor to detect objects and return their distances - and react on the returned values of course. Therefore you need: RangeFinderAdaptor, RangeFeatureDetector and FeatureListener.

But it's not as hard as it might seem now.
The aim is to have a listener on the sensor, so that the it returns the distance of a recognized object in regular time intervals (let's say: return the object's distance every second).
We need a class, which implements the FeatureListener, to do that. In my opinion the name FeatureListener is a bit confusing.. "Feature" means the object that has been detected by the sensor. The class which implements it has to implement the method
public void featureDetected(final Feature feature, final FeatureDetector detector);
And this method is called in the given interval, so we react to the distance of the detected object here (we will see how that works in the code for the parcours).
But that implementing class is the last thing we will do.
The regular order for realizing our aim with the instantiated Sensor-object is:
  1. Instantiate a RangeFinderAdaptor-object and tell it in which mode the sensor is used
  2. Instantiate a RangeFeatureDetector-object and tell it: the interval of checking the object's distance and the maximum distance of objects. It also needs the (prior to this step) created RangeFinderAdaptor-object.
  3. Instantiate an object of the class which implements the FeatureListener
  4. Add the instantiated listener from step 3 to the RangeFeatureDetector-object from step 2.
That's it. So after the theory let's have a look at the finished plain code.

The code

We have two classes this time. The Main-Class (as always) and the class which implements the needed FeatureListener.

Let's start with the Main-Class:

import lejos.hardware.Button;
import lejos.hardware.motor.Motor;
import lejos.hardware.port.SensorPort;
import lejos.hardware.sensor.EV3IRSensor;
import lejos.robotics.RangeFinderAdaptor;
import lejos.robotics.navigation.DifferentialPilot;
import lejos.robotics.objectdetection.FeatureListener;
import lejos.robotics.objectdetection.RangeFeatureDetector;
import lejos.utility.Delay;

public class Main {

    protected final static double NINETY_DEGREES = 90.0;
    protected final static double PILOT_SPEED = 50.0;
    protected final static int PILOT_ACCELERATION = 25;
    protected final static float MAX_DISTANCE = 100.0f;
    protected final static int INTERVAL = 500;
    protected final static double WHEEL_DIAMETER = 30.0f;
    protected final static double DISTANCE_BETWEEN_WHEELS = 170.0;

    public static void main(String[] args) {

        final DifferentialPilot pilot = new DifferentialPilot(WHEEL_DIAMETER, DISTANCE_BETWEEN_WHEELS, Motor.C, Motor.B);
        final EV3IRSensor infraredSensor = new EV3IRSensor(SensorPort.S2);

        configurePilot(pilot);
        configureInfraredSensor(infraredSensor, pilot);

        //wait for the sensor to be completely initialized and start the robot
        Delay.msDelay(5000);
        System.out.println("    Starting!");
        pilot.forward();
        Button.waitForAnyPress();
    }

    private static void configureInfraredSensor(final EV3IRSensor infraredSensor, final DifferentialPilot pilot) {
        final RangeFinderAdaptor rangeFinderAdaptor = new RangeFinderAdaptor(infraredSensor.getDistanceMode());
        final RangeFeatureDetector rangeFeatureDetector = new RangeFeatureDetector(rangeFinderAdaptor, MAX_DISTANCE, INTERVAL);
        final FeatureListener detectedObjectListener = new DetectedObjectListener(pilot);
        rangeFeatureDetector.addListener(detectedObjectListener);
    }

    private static void configurePilot(final DifferentialPilot pilot) {
        pilot.setAcceleration(PILOT_ACCELERATION);
        pilot.setRotateSpeed(PILOT_SPEED);
        pilot.setTravelSpeed(PILOT_SPEED);
    }
}

The main-method is quite short and simple. In the first part we instantiate the pilot to control the wheels/motors and the infrared sensor. For more information on the pilot check the corresponding postings about using motors with the lejos api if you haven't done yet).
The EV3InfraredSensor-class only needs to know which plug it is plugged into to create a corresponding object.

After creating our needed pilot and sensor we need to configure them. Have a look at the configureInfraredSensor-method. That's were we realize the things described in the last paragraph.
  1. We create a RangeFinderAdaptor-object by telling the constructor in which mode the sensor should work.
  2. We create a RangeFeatureDetector and assign the RangeFinderAdaptor-object plus the maximum distance of objects and the interval where the sensor should check for objects.
  3. We create a FeatureListener-object which needs the pilot because we will control the pilot in it. We will see the implementation of the listener next.
  4. We assign the created listener to the RangeFeatureDetector so the featureDetected-method of the listener is called in the configured interval.
After configuring the sensor I set a delay of five seconds because the configuration needs some time. When I tried starting the pilot without a delay it came to weird reactions like the robot moving forwards and backwards some millimeters jerkily.
After the delay the robot will start moving forwards and the rest of the code is done in the listener, so let's have a look at it next. (Button.waitForAnyPress() is just used to let the program continue. Without that line the program would just end before the robot even started moving.)

The Listener-class:

import lejos.robotics.navigation.DifferentialPilot;
import lejos.robotics.objectdetection.Feature;
import lejos.robotics.objectdetection.FeatureDetector;
import lejos.robotics.objectdetection.FeatureListener;
import static org.rapidpm.ev3.infrared.Main.*;

public class DetectedObjectListener implements FeatureListener {

    private DifferentialPilot pilot;

    public DetectedObjectListener(final DifferentialPilot pilot) {
        this.pilot = pilot;
    }

    @Override
    public void featureDetected(final Feature feature, final FeatureDetector detector) {
        int range = (int)feature.getRangeReading().getRange();
        if(range <= 10){
            if(range <=2){
                System.exit(0);
            }
            pilot.stop();
            pilot.rotate(NINETY_DEGREES);
            pilot.forward();
        }
    }
}

We have a field for the pilot from the constructor which we will use in the featureDetected()-method which is called in the configured interval.
In that method we get the distance/range of a recognized object from the Feature-object (which represents the detected object).
If the range is greater than 10 (centimeters), nothing will happen. The robot will of course continue moving forward (remember that in the main-method we called pilot.forward() and told the program to wait for a button press to exit the program).
If the range is lower than 10, we know that the robot has reached a wall. So we tell the pilot to stop. After that we let the robot rotate by 90°. At last we tell the pilot to move forwards again. An exception to that behavior is the special case if the range is lower or equals 2 cm. If that is the case the program will exit. Why is that? Without that backdoor, the program would run until any button of the brick is pressed (remember the main-method). But instead of having to grab the robot and press a button we now can just hold any object directly in front of the infrared sensor and the program will exit.

The result

At the end I added some console output to the featureDetected-method to have some feedback during the execution of the program.

    @Override
    public void featureDetected(final Feature feature, final FeatureDetector detector) {
        int range = (int)feature.getRangeReading().getRange();
        if(range <= 10){
            if(range <=3){
                System.out.println("Recognized signal directly on front of me: exiting!");
                System.exit(0);
            }
            System.out.print("Reached wall! Stopping...");
            pilot.stop();
            System.out.println("done!");
            System.out.print("Rotating 90 degrees...");
            pilot.rotate(NINETY_DEGREES);
            System.out.println("done!");
            pilot.forward();
        } else {
            System.out.println("range: "+range);
        }
    }

And here is the result (watch on youtube for better quality):


Montag, 20. Januar 2014

IoT with Java8 and TinkerForge Part 2

One of the interesting features of TinkerForge is the possibility to put different elements like sensors, physical buttons, and more on a MasterBrick

This is what we want to do today.

The Barometer
Today we are using the Barometer-Bricklet. The Barometer Bricklet can be used to extend the features of Bricks by the capability to measure air pressure in range of 10 to 1200mbar with a resolution of 0.012mbar. The measurement is temperature compensated internally. The Bricklet is equipped with a MS5611-01BA01 sensor which is designed to be used as an altimeter, too.

At https://bitbucket.org/rapidpm/jaxenter.de-0012-iot-tinkerforge are all source codes you will need, including the TinkerForge API itself. I spoke with TinkerForge and we decided to put the API into maven. After we have done this, I will inform you. If you are interested, follow me on Twitter please ( @SvenRuppert )

The most interesting part for us today will be the presents of two sensors inside of one Bricklet.
How we can handle it and how we will get the data to the screen?

Connect to n - Sensor-units
To remember... To connect to a sensor you need an instance of the representing class. To get the value from the sensor you have to implement an ActionListener. Here the short example from my last blog about TinkerForge. (engl / ger)

import com.tinkerforge.BrickletTemperature;
import com.tinkerforge.IPConnection;
public class ExampleCallback {
  private static final String host = "localhost";
  private static final int port = 4223;
  private static final String UID = "dXj";
  public static void main(String args[]) throws Exception {
    IPConnection ipcon = new IPConnection();
    BrickletTemperature temp = new BrickletTemperature(UID, ipcon);
    ipcon.connect(host, port);
    temp.setTemperatureCallbackPeriod(1000);
    temp.addTemperatureListener(new
    BrickletTemperature.TemperatureListener() {
      public void temperature(short temperature) {
        System.out.println("Temperature: "
        + temperature/100.0 + " °C");
      }
    });
    ipcon.disconnect();
}
}
The same will be with the two sensor-units inside the Barometer-Bricklet. The class name will be BrickletBarometer, and you have to implement two ActionListeners. One for the air-pressure called AirPressureListener and one for the altitude called AltitudeListener.

public class ExampleCallback {
    private static final String host = "localhost";
    private static final int port = 4223;
    private static final String UID = "jY4";

    public static void main(String args[]) throws Exception {
        IPConnection ipcon = new IPConnection();
        BrickletBarometer b = new BrickletBarometer(UID, ipcon);
        ipcon.connect(host, port);
        b.setAirPressureCallbackPeriod(1000);
        b.setAltitudeCallbackPeriod(1000);
        b.addAirPressureListener(
                new BrickletBarometer.AirPressureListener() {
                    public void airPressure(int airPressure) {
                        System.out.println("Air Pressure: "
                                + airPressure / 1000.0 + " mbar");
                    }
                }
        );
        b.addAltitudeListener(new BrickletBarometer.AltitudeListener() {
            public void altitude(int altitude) {
                System.out.println("Altitude: " + altitude / 100.0 + " m");
            }
        });
        ipcon.disconnect();
    }
}
Connection to JavaFX
The connection to JavaFX could be simple. The basic steps are always the same. You have to start an Thread outside our JavaFX GUI Thread. Inside this thread you have to configure the sensor and inside the run()- method you have to add the action listener. All steps that are manipulating the GUI, you have to start again inside a Platform.runLater() Now, we have to sensor-units. This means that we are doing this twice. To reuse the code later, we are extracting it into an separate class. If we would do it for the temperature sensor we used last time, it will look like the following.

public class Temp implements Runnable {

  private String UID;
  private ObservableList seriesData;

  public Temp(final String UID, final XYChart.Series series) {
      this.UID = UID;
      this.seriesData = series.getData();
  }

  @Override
  public void run() {
      IPConnection ipcon = new IPConnection();
      BrickletTemperature temp = new BrickletTemperature(UID, ipcon);
      try {
          ipcon.connect(Barometer.host, Barometer.port);
          temp.setTemperatureCallbackPeriod(1000);
          temp.addTemperatureListener(new BrickletTemperature.TemperatureListener() {
              public void temperature(short temperature) {
                  Platform.runLater(new Runnable() {
                      @Override
                      public void run() {
                          final double temp = temperature / 100.0;
                          System.out.println("Temperature: " + temp + " °C");
                          final XYChart.Data data = new XYChart.Data(new Date(), temp);
                          seriesData.add(data);
       }
                  });
              }
          });
      } catch (IOException 
       | AlreadyConnectedException 
    | TimeoutException 
    | NotConnectedException e) {
          e.printStackTrace();
      }
  }
}
For the Barometer-Bricklet I was writing two classes. One for the airpressure and one for the altitude. Both are identically, with one difference. The implementation of the ActionListener. Every sensor will put his data to a separate LineChart.
 This implementation is not perfect, because we are not disconnecting from the sensor in the end, and for one Bricklet we have two representing classes. Both instances are in a different thread. But this is still running over a longer period. (at least a few days with my laptop) How to encapsulate this in better way we will see in one of my next posts.

public class Altitude implements Runnable {

    private String UID;
    private ObservableList seriesData;

    public Altitude(final String UID, final XYChart.Series series) {
        this.UID = UID;
        this.seriesData = series.getData();
    }

    @Override
    public void run() {
        IPConnection ipcon = new IPConnection();
        BrickletBarometer b = new BrickletBarometer(UID, ipcon);

        try {
            ipcon.connect(Barometer.host, Barometer.port);
            b.setAirPressureCallbackPeriod(1000);
            b.addAltitudeListener(new BrickletBarometer.AltitudeListener() {
                public void altitude(int altitude) {
                    System.out.println("Altitude: " + altitude / 100.0 + " m");
                    Platform.runLater(new Runnable() {
                        @Override
                        public void run() {
                            final double temp = altitude / 100.0;
                            final XYChart.Data data = new XYChart.Data(new Date(), temp);
                            seriesData.add(data);
                        }
                    });
                }
            });
        } catch (IOException | AlreadyConnectedException | TimeoutException | NotConnectedException e) {
            e.printStackTrace();
        }
    }
}

public class Airpressure implements Runnable {

    private String UID;
    private ObservableList seriesData;

    public Airpressure(final String UID, final XYChart.Series series) {
        this.UID = UID;
        this.seriesData = series.getData();
    }

    @Override
    public void run() {
        IPConnection ipcon = new IPConnection();
        BrickletBarometer b = new BrickletBarometer(UID, ipcon);

        try {
            ipcon.connect(Barometer.host, Barometer.port);
            b.setAirPressureCallbackPeriod(1000);
            b.addAirPressureListener(new BrickletBarometer.AirPressureListener() {
                public void airPressure(int airPressure) {
                    System.out.println("Air Pressure: " + airPressure / 1000.0 + " mbar");
                    Platform.runLater(new Runnable() {
                        @Override
                        public void run() {
                            final double temp = airPressure / 1000.0 ;
                            final XYChart.Data data = new XYChart.Data(new Date(), temp);
                            seriesData.add(data);
                        }
                    });
                }
            });
        } catch (IOException 
     | AlreadyConnectedException 
     | TimeoutException 
     | NotConnectedException e) {
            e.printStackTrace();
        }
    }
}
Putting all together we will get the following main.

public class Barometer extends Application {
    public static final String host = "localhost";
    public static final int port = 4223;


    public static void main(String args[]) throws Exception {
        launch(args);
    }

    public static XYChart.Series seriesTemp = new XYChart.Series();
    public static XYChart.Series seriesAirpressure = new XYChart.Series();
    public static XYChart.Series seriesAltitude = new XYChart.Series();

    @Override
    public void start(Stage stage) {
        stage.setTitle("Line Chart TinkerForge Sample");

        final VBox box = new VBox();
        seriesTemp.setName("Temp");
        seriesAirpressure.setName("Airpressure");
        seriesAltitude.setName("Altitude");

        final ObservableList boxChildren = box.getChildren();
        boxChildren.add(createLineChart("Temp", seriesTemp));
        boxChildren.add(createLineChart("Airpressure", seriesAirpressure));
        boxChildren.add(createLineChart("Altitude", seriesAltitude));

        Scene scene = new Scene(box, 2000, 1500);

        stage.setScene(scene);
        stage.show();
        Platform.runLater(new Temp("dXj", seriesTemp));
        Platform.runLater(new Airpressure("jY4", seriesAirpressure));
        Platform.runLater(new Altitude("jY4", seriesAltitude));
    }

    private LineChart createLineChart(final String chartName,final XYChart.Series series ){
        final DateAxis dateAxis = new DateAxis();
        dateAxis.setLabel("Time");
        final NumberAxis yAxis = new NumberAxis();

        final LineChart lineChart = new LineChart<>(dateAxis, yAxis);
        lineChart.setTitle(chartName);
        lineChart.getData().add(series);

        return lineChart;
    }
}

At https://bitbucket.org/rapidpm/jaxenter.de-0012-iot-tinkerforge are all source codes you will need, including the TinkerForge API itself. I spoke with TinkerForge and we decided to put the API into maven. After we have done this, I will inform you. If you are interested, follow me on Twitter please ( @SvenRuppert )

Short and simple.. as always .. But if we are using more sensors in a way like this, we will get performance problems. To solve this we are connecting different NoSQL systems soon. And we have to build the next version of JavaFX GUI-Elements... .... stay tuned.. and happy coding.

Mittwoch, 15. Januar 2014

Lego Mindstorms EV3 Components: Motors - Part 2

In the first article of the Mindstorms component series I showed the most basic way to control motors which are connected to the EV3-brick. We had a robot with 1 motor connected which made the robot move forwards and backwards and one smaller motor which let three razorblades rotate (for fun).
In this second part I will explain how to use the superior level of abstraction to control a robot with two motors (each motor moves one wheel). The lejos-crew calls these robots  "wheeled vehicles".

So, first I built such a vehicle as shown in these pictures:


(For the wheels I used the construction manual of the GRIPP3R-robot)

DifferentialPilot-class

As said before, the DifferentialPilot class from the lejos api represents the superior level of abstraction when communicating with the motors. You can use it when you have a robot with two motors connected to the brick where each motor controls an own wheel.

It offers different methods like travel(), steer() or arc() which will be used in the program for the robot.

The parcours

First, I thought of a little demonstration parcours for the new robot. It should contain simple movements for- and backwards, rotations and turns / circles. As a result the parcours consists of 3 parts:


So, the first part of the parcours is pretty simple, the robot will move in a rectangular shape until it is back in its initial position.


In the second part, the robot then will move 90° in a turn. After the turn it will then drive a 90° turn backwards after which the robot will be in the position indicated transparent in the picture.


At the end of the second part the robot will first move forwards a bit. Then it will move in a circle. After the circle has finished, the robot will rotate by 180° (and then look like transparent indication in the picture). Then the robot will move backwards until it is back in the initial position from the beginning of the parcours.

The code

Let's have a look at the plain code of the finished program first.

import lejos.hardware.motor.Motor;
import lejos.robotics.navigation.DifferentialPilot;

public class Main {
    public static void main(String[] args) {

        final DifferentialPilot pilot = new DifferentialPilot(30.0, 185.0, Motor.C, Motor.B);
        pilot.setAcceleration(200);
        pilot.setRotateSpeed(50.0);
        pilot.setTravelSpeed(50.0);

        pilot.travel(350.0);
        pilot.rotate(90.0);
        pilot.travel(190.0);
        pilot.rotate(90.0);
        pilot.travel(350.0);
        pilot.rotate(90.0);
        pilot.travel(190.0);
        pilot.rotate(90.0);

        pilot.steer(65.0, 90.0);
        pilot.steer(-65.0, 90.0);

        pilot.travel(175.0);
        pilot.arc(-100.0,-360.0);
        pilot.steer(200.0,180.0);
        pilot.travel(-175.0);

    }
}


At the beginning we instantiate a new instance of a DifferentialPilot and configure the wanted movement speeds. The used constructor takes four parameters:
  • wheel-diameter: The diameter of the wheel connected to the motor. The used wheel has a 30mm diameter.
  • track width: The distance between the centres of both wheels. In my case ~185mm.
  • left motor: The plug connection where the left motor is plugged in.
  • right motor: The plug connection where the right motor is plugged in.
The diameter of the wheels and the track width are needed by the api to know how long the motors must rotate to perform correct rotations etc.

In the next block we perform the first part of the parcours which is pretty trivial. The travel-method makes the robot move forwards for the given distance (350mm). Recognize, that the distance unit must be the same as used for wheel diameter and track width in the constructor. That method is a blocking operation, so the program will wait here until the movement has finished. After that, the robot will rotate (in place) by 90° to the left (-90° would be  90° right). This happens four times until the rectangular movement has finished and the robot is back in its initial position.

In the next block there are to steer-method calls.
The steer()-method takes two parameters:
  • turnRate: The ratio of the two wheels' speeds (Integer between -200 and +200)
  • angle: When the robot turned by this degrees, the steering will stop.
This needs some more explainations:
turnRate: If the value is positive you are configuring the left wheel, if it's negative you are configuring the right wheel. Let's look at some positive values:
0 - means, that both wheels will rotate at the same speed, which causes the robot to move forwards (no steering!)
100 - means, that the left wheel won't move.
200 - means, that the left wheel will do the exact opposite of the right wheel.

angle: you can enter a value between 0 und 360°, positive and negative. Positive values will rotate the brick to the left, negative values cause right rotations.

So, back to our two method-calls. The first call says: Make the left wheel move 0.65 * the speed of the right wheel. This will cause the robot to turn leftwards while moving. The robot will then move until it has turned by 90° to the left.
The second method call: The first parameter is negative, so we tell the RIGHT wheel to move at 0.65 * the speed of the LEFT wheel. The robot will move until the robot turned 90° to the left. Recognize, that the robot can only turn to the left by moving "backwards" because the right wheel rotates slower than the left wheel.

In the last block the motor travels some centimeters fowards. Then there is a new method called arc. This methods tells the robot to move in a circle. The two parameters are:
  • radius of the circle
  • angle: When the robot turned by this degrees, the steering will stop.
Both parameters may be positive or negative.
A positive radius means, that the circle centre should be on the left of the brick. A negative respectively means that the circle centre is on the right side of the brick.
A positive angle means that the robot will rotate to the left, a negative angle respectively right.

So, the arc-method-call says: Drive a circle. The circle center is on the right side of the brick and has a radius of 10cm. Drive that circle by rotating rightwards. The only possibility to do that, is by driving the circle forwards. A positive angle of 360° would have caused the robot to drive the circle by rotating to the left, which could only have been realized by moving backwards.
The next steer-method-call is easy: It says: The left wheel should do the opposite of the right wheel. The robot should move until it has turned by 180°. Maybe you recognized it: It's a simple 180° in-place rotation. So we could have used pilot.rotate(180) here, too.
The last travel()-call makes the robot move backwards the last centimeters until it is back in it's initial position.

That's it, at last I just refactored and added some Console-ouput to the program for comfort:

import lejos.hardware.motor.Motor;
import lejos.robotics.navigation.DifferentialPilot;

public class Main {

    final static double NINETY_DEGREES = 90.0;

    public static void main(String[] args) {

        final DifferentialPilot pilot = new DifferentialPilot(30.0, 185.0, Motor.C, Motor.B);
        pilot.setAcceleration(200);
        pilot.setRotateSpeed(50.0);
        pilot.setTravelSpeed(50.0);

        System.out.println("Configured speeds and starting the first part of the parcours.");
        travelRectangle(pilot, 350.0, 190.0);

        System.out.println("Starting the second part of the parcours.");
        driveTurns(pilot);

        System.out.println("Starting the third part of the parcours.");
        driveCircleAndBackToInitialPosition(pilot);

    }

    private static void driveCircleAndBackToInitialPosition(final DifferentialPilot pilot) {
        System.out.print("    Driving half the way...");
        pilot.travel(175.0);
        System.out.println("done!");
        System.out.print("    Driving the circle...");
        pilot.arc(-100.0,-360.0);
        System.out.println("done!");
        System.out.print("    Turning 180 degrees...");
        pilot.steer(200.0,180.0);
        System.out.println("done!");
        System.out.print("    Driving backwards to initial position...");
        pilot.travel(-175.0);
        System.out.println("done!");
    }

    private static void driveTurns(final DifferentialPilot pilot) {
        System.out.print("    Driving turn forwards...");
        pilot.steer(65.0, NINETY_DEGREES);
        System.out.println("done!");
        System.out.print("    Driving turn backwards...");
        pilot.steer(-65.0, NINETY_DEGREES);
        System.out.println("done!");
    }

    private static void travelRectangle(final DifferentialPilot pilot, final double rectLength, final double rectWidth) {
        travelRectangleEdgeAndRotate(pilot, rectLength);
        travelRectangleEdgeAndRotate(pilot, rectWidth);
        travelRectangleEdgeAndRotate(pilot, rectLength);
        travelRectangleEdgeAndRotate(pilot, rectWidth);
    }

    private static void travelRectangleEdgeAndRotate(final DifferentialPilot pilot, final double distance) {
        System.out.print("    Driving " + distance + " mm...");
        pilot.travel(distance);
        System.out.println("done!");
        System.out.print("    Rotating 90 degrees...");
        pilot.rotate(NINETY_DEGREES);
        System.out.println("done!");
    }
}
and here is the result:



It isn't 100% exact, but still quite satisfying. I think this is because the wheel diameter and the track width I gave the constructor aren't perfectly correct.

Montag, 13. Januar 2014

IoT with Java8 and TinkerForge Part 1

IoT is something cool, but I think you know it already.
Today I started with TinkerForge. TinkerForge is a german company that are building electronic elements. You can put them together like LEGO. This means, that you don´t need any special electronic stuff or knowledge.
And the best, you can code plain Java to use them.

But how we can start?

First of all, you need a MasterBrick and at minimumm one sensor. For my first experiment I am using the simple temperature sensor. After unpacking it I needed around 3 min to put all together. After this you can plug it into your USB port. Now the hardware part is ready.

To speak with this components you have to install two things.
First the usb-driver, that is used for the communication with the MasterBrick,
second the BrickViewr. With this you can check the installation, update the firmware and so on.

You will find the software for linux/osx/windows.

Hello IoT World: 

We will start with the first HelloWorld. Here with the Hello IoTWorld.
After you connected the MasterBrick with the USB-port you will see a blue light and the MasterBrick will be ready for communication.


Now we could start the BrickViewer to check the installation. The importand part is the UID from the sensor. With this we can connect it later. After you pressed the connect button, you can see all the informations.

At https://bitbucket.org/rapidpm/jaxenter.de-0012-iot-tinkerforge are all source codes you will need, including the TinkerForge API itself.
I spoke with TinkerForge and we decided to put the API into maven.

After we have done this, I will inform you. If you are interested, follow me on Twitter please ( @SvenRuppert )

The basic steps are quite simple to use this sensor.

  • create a IPConnection 
  • create an instance of the class BrickletTemperature 
  • configure the sensor 
  • add an ActionListener.

That is all.

import com.tinkerforge.BrickletTemperature;
import com.tinkerforge.IPConnection;

public class ExampleCallback {
    private static final String host = "localhost";
    private static final int port = 4223;
    private static final String UID = "dXj"; 
    public static void main(String args[]) throws Exception {
        IPConnection ipcon = new IPConnection(); 
        BrickletTemperature temp = new BrickletTemperature(UID, ipcon); 
        ipcon.connect(host, port); 
        temp.setTemperatureCallbackPeriod(1000);
        temp.addTemperatureListener(new 
          BrickletTemperature.TemperatureListener() {
            public void temperature(short temperature) {
                System.out.println("Temperature: " 
                   + temperature/100.0 + " °C");
            }
        });
        ipcon.disconnect();
    }
}
After this short example we could do our first javafx test. We want to check the temperature over some time and show this inside an LineChart.



Here we are... and please note, the DateAxis is from http://myjavafx.blogspot.de/2013/09/javafx-charts-display-date-values-on.html
 
 public class HelloTinkerForge extends Application {

    private static final String host = "localhost";
    private static final int port = 4223;
    private static final String UID = "dXj"; 


    public static void main(String args[]) throws Exception {
        launch(args);
    }

    public static XYChart.Series series;

    @Override
    public void start(Stage stage) {
        stage.setTitle("Line Chart TinkerForge Sample");
        final DateAxis dateAxis = new DateAxis();
        final NumberAxis yAxis = new NumberAxis();
        dateAxis.setLabel("Time of Temp");
        final LineChart lineChart 
           = new LineChart<>(dateAxis, yAxis);

        lineChart.setTitle("Temp Monitoring");

        series = new XYChart.Series();
        series.setName("My temps");
        final ObservableList seriesData = series.getData();

        lineChart.getData().add(series);
        Scene scene = new Scene(lineChart, 800, 600);
        stage.setScene(scene);
        stage.show();
        new Worker(seriesData).start();

    }

    public static class Worker extends Thread {
        final ObservableList seriesData;
        public Worker(final ObservableList seriesData) {
            setDaemon(true);
            setName("Thread Temp");
            this.seriesData = seriesData;
        }

        @Override
        public void run() {
            Platform.runLater(new Runnable() {
                @Override
                public void run() {
                    IPConnection ipcon = new IPConnection();
                    BrickletTemperature temp 
                        = new BrickletTemperature(UID, ipcon);
                    try {
                        ipcon.connect(host, port);
                        temp.setTemperatureCallbackPeriod(1000);
                        temp.addTemperatureListener(
                          new BrickletTemperature.TemperatureListener() {
                            public void temperature(short temperature) {
                                Platform.runLater(new Runnable() {
                                    @Override
                                    public void run() {
                                        final double temp 
                                           = temperature / 100.0;
                                        final int counter 
                                           = seriesData.size() + 1;
                                        final XYChart.Data data 
                                           = new XYChart.Data(
                                                 new Date(), temp);
                                        seriesData.add(data);
                                    }
                                });
                            }
                        });
                    } catch (IOException | 
                             AlreadyConnectedException | 
                             TimeoutException | 
                             NotConnectedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }
}

Short and simple.. Well this is a simple example, but the next step will be with more sensor-elements...
 stay tuned.. and happy coding.

Samstag, 11. Januar 2014

Lego Mindstorms EV3 Components: Motors - Part 1


With this posting I will start a series of articles where I explain which components/sensors are contained in the Lego Mindstorms EV3-set an how to work with them.

In this posting I will start with one of the most basic components - the motors. The Mindstorms-set includes three motors: two of the same size and a smaller one.

Both types work the same way and so they have the same api-methods.

I will build a simple program were I let the robot perform some movements to different directions.

Before we can start developing, we first need a robot which we will control with the program. I built a simple robot for that. It consists of only one single component connected to the brick: One of the bigger motors. There are two wheels plugged into the motor and two more wheels which aren't connected to the motor and just work as stabilization. Here are some pics:


( There are different ways at different abstract levels to control the motors, but I will use the most basic method by using the Motor-class directly in this first part. We couldn't use a more abstract method which enable features like driving turns or following paths because we only have a single motor connected to our robot here. So the robot can just move forwards and backwards. )

I plugged the motor into plug connection B on the brick.

So, now we are ready to develop the program for our new robot. I set up an IntelliJ-project as described in our posting about developing leJOS programs with IntelliJ on Windows.

First, here is the plain code which is quite easy to understand:

import lejos.hardware.motor.Motor;
import lejos.utility.Delay;

public class Main {
    public static void main(String[] args) {

        Motor.B.setAcceleration(200);
        Motor.B.setSpeed(90);
        Motor.B.rotate(360);
        Motor.B.setSpeed(180);
        Motor.B.rotate(360);
        Motor.B.setSpeed(360);
        Motor.B.rotate(360);
        Motor.B.backward();
        Delay.msDelay(3000);
        Motor.B.stop();

    }
}
What does that code do?
We address the motor in plug connection B via Motor.B. Then we set its acceleration to 200. The standard value is 6000 which means that the motor will accelerate by 6000 degrees per second per second. This is quite fast and so we lowered the value to 200 to get a smoother acceleration.
Then we set the speed of the motor to 90 degrees per second. After we "configured" the motor, we let it start rotating by 360 degrees. This operation is a blocking operation which means that the program will stop here until the motor rotated 360 degrees (which will be done after 4 seconds at the configured speed of 90 degrees per second).
After the motor rotated 360 degrees we double the speed to 180 degrees per second and let the motor rotate 360 degrees again. This time the motor will need half the time (2 seconds), of course.
After that the same happens again with a speed of 360 degrees per second.
Then, as the last part of the program, we call the backward-method. In contrast to the rotate-method, this method is non-blocking. That means, that the program will continue directly after calling that method, it won't wait till the backwards-movement is done (otherwise the motor wouldn't stop rotating anymore, there is no parameter for defining how long the motor should rotate). Recognize that there is also a rotate()-method with a second, boolean parameter. If you use that one with the boolean parameter = true the method becomes non-blocking like backward().
In the next line we tell the program to do nothing for 3 seconds, the motor will of course continue rotating (at the speed which was set as last = 360 degrees per second) during that time.
Then after these 3 seconds we let the motor stop und the program is at its end.

To get some feedback on what the robot is exactly doing through the program execution, we added some printlns to the console.

import lejos.hardware.motor.Motor;
import lejos.utility.Delay;

public class Main {
    public static void main(String[] args) {
        /*
        The standard value for acceleration is (6000 degrees per second) per second
        which results in a very jerky start when the motor starts rotating.
        To make the start smoother, the acceleration is set to a lower level.
         */
        Motor.B.setAcceleration(200);
        
        Motor.B.setSpeed(90);
        System.out.println("Set speed to 90 degrees per second.");
        System.out.print("Rotating 360 degrees...");
        Motor.B.rotate(360);
        System.out.println("done!");
        
        Motor.B.setSpeed(180);
        System.out.println("Set speed to 180 degrees per second.");
        System.out.print("Rotating 360 degrees...");
        Motor.B.rotate(360);
        System.out.println("done!");
        
        Motor.B.setSpeed(360);
        System.out.println("Set speed to 360 degrees per second...");
        System.out.print("Rotating 360 degrees...");
        Motor.B.rotate(360);
        System.out.println("done!");
        
        Motor.B.backward();
        System.out.print("Now rotating backwards for 3s");
        Delay.msDelay(3000);
        System.out.print("...3s are over...");
        Motor.B.stop();
        System.out.println("and stopped!");

    }
}
That code looks better now, but there's tons of duplicate code. So we put the code for setting different speeds and letting the motor rotate in a function.

import lejos.hardware.motor.Motor;
import lejos.utility.Delay;

public class Main {
    public static void main(String[] args) {
        /*
        The standard value for acceleration is (6000 degrees per second) per second
        which results in a very jerky start when the motor starts rotating.
        To make the start smoother, the acceleration is set to a lower level.
         */
        Motor.B.setAcceleration(200);

        rotateDegreesAtSpeed(360, 90);
        rotateDegreesAtSpeed(360, 180);
        rotateDegreesAtSpeed(360, 360);

        Motor.B.backward();
        System.out.print("Now rotating backwards for 3s");
        Delay.msDelay(3000);
        System.out.print("...3s are over...");
        Motor.B.stop();
        System.out.println("and stopped!");

    }

    private static void rotateDegreesAtSpeed(final int degreesToRotate, final int degreesPerSecond) {
        Motor.B.setSpeed(degreesPerSecond);
        System.out.println("Set speed to "+degreesPerSecond+ "degrees per second.");
        System.out.print("Rotating "+ degreesToRotate + "degrees...");
        Motor.B.rotate(degreesToRotate);
        System.out.println("done!");
    }
}

That was it. After transfering the program onto the brick (via WiFi) we executed the program. Here's a video of how the result looks like (console output readable in higher qualities).



Perfect. The next thing we did was extending the robot by a second motor - the smaller one. The result looked like the following:


So the second motor will make the three "razorblades" rotate ( some eyecandy :) ).
We put the second motor in plug connection A of the brick.

The aim for that second motor should be: The razorblades should always rotate the same speed, the first motor has.

So we extended our program. Here's the finished code:
import lejos.hardware.motor.Motor;
import lejos.utility.Delay;

public class Main {
    public static void main(String[] args) {

        final int ACCELERATION = 200;
        final int ONE_ROTATION = 360;
        /*
        The standard value for acceleration is (6000 degrees per second) per second
        which results in a very jerky start when the motor starts rotating.
        To make the start smoother, the acceleration is set to a lower level.
         */
        Motor.B.setAcceleration(ACCELERATION);
        Motor.A.setAcceleration(ACCELERATION);

        Motor.A.forward();
        rotateDegreesAtSpeed(ONE_ROTATION, 90);
        rotateDegreesAtSpeed(ONE_ROTATION, 180);
        rotateDegreesAtSpeed(ONE_ROTATION, 360);

        Motor.A.backward();
        System.out.println("Switched Motor A from forward to backward. Waiting for the direction change.");
        Delay.msDelay(2000);
        Motor.B.backward();

        System.out.print("Now rotating backwards for 3s");
        Delay.msDelay(3000);
        System.out.print("...3s are over...");
        Motor.B.stop();
        Motor.A.stop();
        System.out.println("and stopped!");

    }

    private static void rotateDegreesAtSpeed(final int degreesToRotate, final int degreesPerSecond) {
        Motor.A.setSpeed(degreesPerSecond);
        Motor.B.setSpeed(degreesPerSecond);
        System.out.println("Set speed of motors to "+degreesPerSecond+ " degrees per second.");
        System.out.print("Rotating "+ degreesToRotate + " degrees...");
        Motor.B.rotate(degreesToRotate);
        System.out.println("done!");
    }
}
At the beginning of the program we set the acceleration of motor A to 200, too. Then we call Motor.A.forward(), which is a non-blocking operation like the backward()-method. We added one line in the created function to set the speed for motor A which is the same as for motor B, of course. After the three function calls we first call bachwards() on motor A. This will make the motor stop as the first step, and then start rotating backwards in a second step. Recognize, that Motor.A.backward() will be called when motor B stopped rotating. To let the robot wait until motor A also stopped, we added a delay of two seconds. After these two seconds the robot will start turning backwards (motor B will rotate into the other direction). At the same time, motor A will start rotating in the other direction, too.
We will let the robot move backwards for three seconds and then stop both motors.

So, here is the final result:


In the next article I will use the DifferentialPilot-class, which is the superior level of abstraction for controlling the motors, to move a two-wheeled robot which can drive turns for example.

Freitag, 10. Januar 2014

FXController with CDI managed DynamicObjectAdapter - Part 1

Today I will show the first step how you can use a dynamic proxy for JavaFX Controller.
This we will need for the CDI support inside TestFX.. but this later..

During I was writing on my reflection shortcut together with Dr. Heinz Kabutz
(will be first available in german, later in english if asked for) I was thinking about his Newsletter
about "Object Adapter based on Dynamic Proxy".
Based on this we will now transform this into an CDI pattern for JavaFX Controller.

The basic target will be an decorator for an CDI environment, to switch between implementations of defined methods
of an controller. Ok, there is an decorator defined inside the CDI environment but with some hard limitations.

First of all, you have to define the decorator inside the beans.xml. I don´t like this.
If something will be changed you have to restart the container. And the definition is static.
The second I not like, is the usage of an decorator.

You have to annotate the class,
you have to inject the basic implementation
and you have to extend the basic implementation.

This is too much and the main disadvantage: you have to decide what decorator to use in the static context.

How to solve this?

Let´s start with the basic step. With the default methods in JDK8 you don´t need a basic Implementation class.
But you have an interface. Let´s say we have an interface called DemoLogic.

@CDINotMapped
public interface DemoLogic {

    public default int add(int a, int b){
        return a+b;
    }

    public default int sub(int a, int b){
        return a-b;
    }
}
Importand is the annotation, to exclude this from the default scope inside CDI. You will see it later why..

The next thing we want to have is an special implementation from the add method. This we will implement inside a class
called DemoLogicAdapter_A.

@CDINotMapped
public class DemoLogicAdapter_A implements DemoLogic{

    public int add(int a, int b){
        System.out.println("DemoLogicAdapter_A.add");
        return a+b + 100;
    }
}
Same here with the annotation. The good thing is, you really have to implement the changed method only.
No other delegator stuff.

Next we need, is something to decide dynamically if we want to use the original implementation or the special one.
This we will simulate with a singleton calles Context. This class with only one boolean attribute called original
is to simulate a decicion logic.
If the attribute is true, we are in context original otherwise we are inside the context customer specific.

@Singleton
public class Context {

    public boolean original = true;
}
Now we will use it like the developer will do it later in a high level way.
For this we write a jUnit Test to test this.
The test will do the following.
Inject the DemoLogic, call the method add and test if the original version was used.
After this switch the context by setting the attribut original to false.
Now get the demologic again and call the method add.
If all is all right we will get the customer specific result.

@RunWith(Arquillian.class)
public class DemoLogicTest {
    @Deployment
    public static JavaArchive createDeployment() {
        return ShrinkWrap.create(JavaArchive.class)
                .addPackages(true, "org.rapidpm.commons")
                .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
    }

    @Inject @DynamicDecoratorTest Instance demoLogic;
    @Inject Context context;
    @Test
    public void testDemoLogicOriginalTest() throws Exception {
        Assert.assertNotNull(demoLogic);
        final DemoLogic demoLogic1 = demoLogic.get();
        final int add = demoLogic1.add(1, 1);
        Assert.assertEquals(2,add);
        System.out.println("add = " + add);

        context.original = false;
        final DemoLogic demoLogic2 = demoLogic.get();
        final int addAdapted = demoLogic2.add(1, 1);
        Assert.assertEquals(102,addAdapted);
        System.out.println("addAdapted = " + addAdapted);
    }
}
I am using arquillian to have CDI support inside my jUnit Tests.
The annotation DynamicDecoratorTest is to separate this test from the rest of my tests.

You see the usage quite clear. The developer will only see the interface. He will use it like
he will do it as normal. No change to see! Let´s asume the context switch is done by the system,
hidden, so the the develper is not able to see it.
He will write code only with the thinking about the business logic to implement.

Afer we described what we want to have, we will implement the core.
To get an instance of the DemoLogic, we need a producer. We will call the class DemoLogicProducer.

public class DemoLogicProducer {

    @Inject Instance dynamicObjectAdapterFactoryInstance;

    @Inject Context context;

    @Produces @DynamicDecoratorTest
    public DemoLogic create(ManagedInstanceCreator instanceCreator){
        final DemoLogic demoLogic = instanceCreator.activateCDI(new DemoLogic() {});

        final DynamicObjectAdapterFactory dynamicObjectAdapterFactory = dynamicObjectAdapterFactoryInstance.get();

        final Object adapter;
        if (context.original){
            adapter = new Object();
        } else {
            adapter = instanceCreator.activateCDI(new DemoLogicAdapter_A());
        }

        return dynamicObjectAdapterFactory.adapt(demoLogic, DemoLogic.class, adapter);
    }
}
The basic what we are simulating here ist the switch between original and customer specific.
This will be more comfortable in the next post. (using a ContextResolver)
But to show the basic step this is made explicite simple.
If the attribute is true, use the original one otherwise use the customer specific.
Very simple.. Both instances are manually put inside the CDI environment.
This ist only to show that the adapter itself can be managed too.

The most importand step is the transparent wrapping with the DynamicObjectAdapterFactory.
The developer will not see this, until he is debugging ;-)

How this factory is working?
The factory is using the java.lang.reflect.Proxy from the JDK itself. An old but very usefull class.
In my case I will use this in side a CDI managed environment.

public class DynamicObjectAdapterFactory {

    @Inject Instance cdiInvocationHandlerInstance;

    public   T adapt(final Object adaptee,final Class target,final Object adapter) {

        final CDIInvocationHandler invocationHandler = cdiInvocationHandlerInstance
                .get()
                .adapter(adapter)
                .adaptee(adaptee);

        return (T) Proxy.newProxyInstance(
                target.getClassLoader(),
                new Class[]{target},
                invocationHandler
                );
    }

}
This means I will be able to inject, for example, the InvocationHandler.
This I need, because I need a managed InvocationHandler.
The usage of the Proxy is nothing complex. But the InvocationHandler is the final and importand step.

public class CDIInvocationHandler implements InvocationHandler {

    @Inject @CDILogger Logger logger;

    private Map adaptedMethods = new HashMap<>();

    private Object adapter;
    private Object adaptee;

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        if (adaptedMethods.isEmpty()){
            final Class adapterClass = adapter.getClass();
            Method[] methods = adapterClass.getDeclaredMethods();
            for (Method m : methods) {
                adaptedMethods.put(new MethodIdentifier(m), m);
            }
        }else{
            if (logger.isDebugEnabled()) {
                logger.debug("adaptedMethods is initialized..");
            }
        }
        try {
            Method other = adaptedMethods.get(new MethodIdentifier(method));
            if (other != null) {
                return other.invoke(adapter, args);
            } else {
                return method.invoke(adaptee, args);
            }
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        }
    }

    public CDIInvocationHandler adapter(final Object adapter) {
        this.adapter = adapter;
        return this;
    }

    public CDIInvocationHandler adaptee(final Object adaptee) {
        this.adaptee = adaptee;
        return this;
    }


}

public class MethodIdentifier {
    private final String name;
    private final Class[] parameters;

    public MethodIdentifier(Method m) {
        name = m.getName();
        parameters = m.getParameterTypes();
    }

    // we can save time by assuming that we only compare against
    // other MethodIdentifier objects
    public boolean equals(Object o) {
        MethodIdentifier mid = (MethodIdentifier) o;
        return name.equals(mid.name) &&
                Arrays.equals(parameters, mid.parameters);
    }

    public int hashCode() {
        return name.hashCode();
    }
}

The method invoke is called every time a method is called on the proxy. This is the place to decide which method will be called.
From the adapter we will get all methods and put them inside a HashMap. The key is based on method-name and attributes.
If a method is called with this key, we will get the adapter instance of this method from the map and
will call this instead of the original one.
If not key found, we will call the original nethod.
This is really simple!

This means you have everywhere CDI managed instances.
You have only to implement what you whant to change.
It is dynamic with every request.
No beans.xml must be edited.

You never need the decorator from CDI anymore. ;-)

Next step will be the integration iside an JavaFX controller.. and TestFX CDI Support

Freitag, 3. Januar 2014

TestFX internals explained

TestFX a small but powerful framework for JavaFX GUI Testing with jUnit.
How it is used and how it is working inside?

TDD for GUI development is for a lot of developers something that make them feeling uncomfortable.
Using jUnit for the testing of the GUI Elements is mostly not what you want to do.
But with TestFX it is quite simple to write short but reusable tests.

Let´s start with the project initialization. You need only a few entries in you pom.xml.
jUnit, hamcrest and testfx, that is it.. and nothing more.


    org.loadui
    testFx
    3.0.0 


    org.hamcrest
    hamcrest-all
    1.3


    junit
    junit
    4.11
    
        
            org.hamcrest
            hamcrest-core
        
    

After we added this entries to the pom.xml, we can start with the first jUnitTest using TestFX.
We will start with the traditional HelloWorld. The first step is the creation of a TestClass.
The TestClass must extend from GuiTest, a base class from the TestFX Framework.
This class is abstract and you have to implement the method protected Parent getRootNode()
This method must create the GUI element that you will test. I our example we want to test a simple button.

@Category(TestFX.class)
public class SimpleButtonTest extends GuiTest {
    @Override
    protected Parent getRootNode() {
        final Button btn = new Button();
        btn.setId("btn");
        btn.setText("Hello World");
        btn.setOnAction((actionEvent)-> btn.setText( "was clicked" ));
        return btn;
    }
}
You can see, that you don´t have to create a holder for your GUI element.
Now we can start with the first test itself.
The button will change the text from "Hello World" to "was clicked" if the user will click the button.
How we can test this?
As normal we have to write a test method annotated with the @Test from jUnit.
The first question will be, how to get the reference of the button?
For this you can use one of the service methods. With find and the id you will get the instance.

@Test
public void shouldClickButton(){
    final Button button = find( "#btn" );
    click(button);
    verifyThat( "#btn", hasText("was clicked") );
}
As you can see, we can start with the functional tests after we got the reference. Here we are simulating the click.
After this we are checking if the result is as expected.
Writing tests looks now like , writing the use case with methods organized with the builder pattern.
If you want to write your own check like hasText() you have to write it with the framework hamcrest.
But TestFX will provide a lot of default checks and test-steps. Mostly you don not need more.

But how TestFX is doing all this?
Starting with the test class GUITest, we know that we have to create the GUI element we want to test.
The class GUITest itself contains a lot of methods to describe the use case with
actions like click,drag,move,push, scroll, rightClick and so on.
But how the application is started? This will be done by the internal class TestFXApp inside GUITest.

public static class TestFxApp extends Application
{
    private static Scene scene = null;

    @Override
    public void start( Stage primaryStage ) throws Exception
    {
        primaryStage.initStyle(StageStyle.UNDECORATED);
        primaryStage.show();
        stageFuture.set( primaryStage );
    }

    public static void setRoot( Parent rootNode )
    {
        scene.setRoot( rootNode );
    }
}
Every developer that was writing the first few jUnit tests for an JavaFX application
came to the point where the JVM was telling something like
"please, only one instance of the JavaFX Application please"
How to deal with this?
The basic is quite simple. You have to start the application in one thread, save this as an singleton over all jUnit tests in one JVM.
After this, put every junit test method in one Callable and start them one after an other.
The first step will be done with the method setupStage, annotated with @Before.
Inside this there is a check if the singleton is already there or not. If not, it will be created. FXTestUtils.launchApp(TestFxApp.class);
After this the GUI element from getRootNode() will be placed in a new Runnable.

@Before
public void setupStage() throws Throwable{
    showNodeInStage();
}

private void showNodeInStage(){
    showNodeInStage(null);
}

private void showNodeInStage( final String stylesheet ){
    GuiTest.stylesheet = stylesheet;

    if( stage == null ){
        FXTestUtils.launchApp(TestFxApp.class);
        try{
            stage = targetWindow(stageFuture.get( 25,TimeUnit.SECONDS ) );
            FXTestUtils.bringToFront( stage );
        }catch( Exception e ) {
            throw new RuntimeException( "Unable to show stage", e );
        }
    }

    try{
        FXTestUtils.invokeAndWait( new Runnable(){
            @Override
            public void run(){
                Scene scene = SceneBuilder
                    .create()width( 600 ) height( 400 )
                    .root( getRootNode() ).build();

                if(stylesheet!=null) 
                    scene.getStylesheets().add(stylesheet);
                stage.setScene( scene );
            }
        }, 5 );
    }catch( Exception e ) {
        e.printStackTrace();
    }
}

That´s it. Quite simple and easy to use for a developer.
The good thing is, that TestFX is good usable in an CI environment.
You only have to configure jUnit if not already done.

But this is not the end.. I am working in the moment at the full CDI support inside
TestFX. We will see it in one of the next versions from TestFX. stay tuned...

If you have any ideas what we can improve.. let me know..

happy javafx testing