Friday, February 5, 2016

Building a small Arduino powered robot

It's time to play Arduino and Motor Shield

I received many weeks ago enough part to build a small arduino robot, and I have nos the time. Let's build it...

For this project I have no real objective. I just want to asseble an autonomous robot, avoiding wall or other object.

The parts

  • Arduino uno for control-command
  • Seeed motor shield V2 for power and simplifaction of command
  • An HC-SR04 ultra-sonic sensor for objects detection
  • A 9g servo motor for ultra sonic sensor rotation
  • battery  clip connector 9v to 2,1 power plug (see here to build or buy )
  • a chassi 2wd motor, with bolts and nuts, wheel, two small DC motor, a four battery pack AAA some wires and an end wheel
 

The assembly

Nothing very important to say here. Try to assemble, see what goes wrong, re assemble , what goes wrong and so on.


The only thing to say is that I make parts work separately first :
  • the HC-SR04 ultra-sonic sensor
  • then the servo 
  • then the motor shield
 And finally integrate. And at this point it does not work...  as usual ...
  • Motor shield use pin 8 to  13 to work 
  • AND servo (library) disable PWM for 9 and 10 pin

So it does not work. The solution is to change the pin mapping in motor shield libraries from 9,10 to 5,6 and connect them physicaly (not shown on this picture).
I saw this on a blog here. It works for me too ,but if you  try, you try at your own risks.

Servo

Library used : arduino  Servo
#include "Servo.h"
const int SERVO_CMD = 14;
void setup() {
     myServo.attach(SERVO_CMD);
}

and
myServo.write(angle);

MotorShield (Seeed v2)

Library used : seeed MotorDriver modified in  MotorDriver56 to use pwm 5,6 in place of 9 and 10

include "MotorDriver56.h"
void setup() {
      motordriver.init();
      motordriver.setSpeed(200,MOTORB);
      motordriver.setSpeed(200,MOTORA);
}
and
motordriver.goForward();
motordriver.goBackward();
motordriver.goLeft();
motordriver.goRight();
motordriver.stop();

typical use

motordriver.go${Action}();
delay(time);
motordriver.stop();

HC-SR04

use
   const int trigPin = 4;
   const int echoPin = 7;

and
   int calculateDistance(){ 
      digitalWrite(trigPin, LOW); 
      delayMicroseconds(2);
      // Sets the trigPin on HIGH state for 10 micro seconds
      digitalWrite(trigPin, HIGH);
      delayMicroseconds(10);
      digitalWrite(trigPin, LOW);

     // Reads the echoPin, returns the sound wave travel time in microseconds
      duration = pulseIn(echoPin, HIGH); 
      int distance = duration*0.034/2;
      return distance;
    }

The basic control / command


if (nothing front) {
   goFront()
} else if ( something left ) {
   goBackward()
   goRight()
} else {
   goBackward() 
   goLeft()
}

But ...

My small rover does not go straightaway.  The reasons ... motor are differents, the end wheel is not so good. Those two points cause deviations.

Next improvment 

  • the tail whell cause trajectory deviation. Need to change to a round ball, or use chains
  • add encoder measurement to have a better distance/movement  estimation
  • there's no sensor at back (securing goBackward() ) 
  • Use arduino interrupt

Ultimate goal

Transform this rover into sensor. I mean acquire distance measurement, send it via ESP8266 (wifi) to raspberry Pi.  And finally build a 3D map of the rover context.

Monday, February 1, 2016

Stream, Image processing,Java 8 and parallel

During last few days I decide to go further with Java 8 stream, lambda. As I currently work on differents projects set to Java 5 compatibility I does not have a lot of "material" for experiment.

Learn

So I began, as usual with google to find out example and/or tutorial.
I mainly found cases of studies starting with simple list, applying mapping, filtering and finally reducing.

Those examples are very usefull and well explain and were helpfull as starting point :

Apply

Now it time to try ourself.  I do not want to work with case of studies beacause I want to think about about the solution and find myself how solve with stream a given problem. And, I want to make something (I hope) usefull (almost for me...).
So which example ? A long time a ago, I worked on image processing, segmentation, morphology transformation,  skeletonisation, hough transform,  on color (TLS, RVB), gray level or binary images.
An image is a good client for my streaming example :
  • could be usefull
  • could be enough big to see parallel effect
  • you  could easily imagine how to apply a structuring element on an image stream

Imagine the stream

As I want to apply a structuring element 3x3, 5x5, nxn I think about :
  1. walking on a stream  of vectors building from original image. Those vectors has the same dimension as the structuring element.
  2. iterate on an Integer Stream of (height x width) of image for limit, that allow to build the target image
I give up the first solution beacause :
  • the memory foot print is four time the image size for a 3x3 kernel. 3 for stream + 1 for target.
  • the time for stream building is in excess and depend of the kernel size.

Stream coding

To do the second solution I have to :
  • iterate on a range [0 , heigh * width]
  • for each calculate the value resulting of kernel application
  • put it in the the resulting image.
I found to two way to implement this :

IntStream.range(0, (heigh * width)-1).forEach(n->{applyKernel(n)})
or
Stream.iterate(0, n -> n+1).limit(heigh * width) - 1).forEach(n-> {applyKernel(n)})

The applyKernel(int n) method is for  the target pixel resulting of kernel application ( for the pixel n)

To find the right way to implement,  I saw result time for the same image, the same number of time in the same machine, excluding the worst 2 cases for each. The winner is the first solution with 880 ms compare with 1000ms.

Why?  I think It's because IntStream is provide for this purpose exactly -ie providing an int range. Unlike Stream.iterate() with (plus) limit() is done to generate a stream by applying the given function on the seed. It's something that is more sophisticated. Another point could be that the limit method produce another stream(). So at the end I think there is more "mechanics" in the second solution that implie less speed.

Processing image

In this example to process image I
  • load it as a BufferedImage
  • convert it to gray (byte) 
  • filter it with an octagonal 
  • convert it to binary relying on DataBufferByte
  • 2 closing (dilate x 2 then erode x 2)
  • then edge detection 

Load image

File imageFile = ... 
BufferedImage img = ImageIO.read(imageFile);

Convert to byte gray

BufferedImage  grayImg= new BufferedImage(widht, heigh, BufferedImage.TYPE_BYTE_GRAY);
BufferedImageOp gsOp = new ColorConvertOp(
          imageToConvert.getColorModel().getColorSpace(),
          grayImg.getColorModel().getColorSpace(),null);
gsOp.filter(imageToConvert, grayImg);

Filter with Octagon kernel

It is the application of this kernel
|1,1,1|
|1,1,1|  divide by 9
|1,1,1|

It means that the resulting pixel is the average of  itself and the 8 pixels around it.
To do that I use the
byte[] imageAsByteArray =  ((DataBufferByte)image.getRaster().getDataBuffer()).getData();

Convert to binary

It means  iterate on gray scale byte[] and set resulting pixel to 0 or 255 depending of the imput value.
If the imput value is more than a threshold  the valur will be 255 else 0.

Closing

for erosion and dilatation I use a CROSS kernel
|false,true,false|
|true ,true, true|  
|false,true,false|

For dilatation I apply this  on binary image (255 is true, 0 is false) if the kernel application (logical OR) on the given image contexte return true then the result is 255 , 0 otherwhise.
For erosion this is the same kernel but the application use a logical AND.

The closing operator effect is filling small hole in image. The hole size fill up depend of the kernel size an the number of succesive erosion, dilatation.

Edge detection

On binary image I apply the laplacian square using multiplication.
|0, 1,0|
|1,-4, 1|  
|0, 1,0|

Stream and parallel

Now it's time to test parallel feature. I red a lot of bad thing about parallel but it seems that all those "problems" always appear in concurrent enviromnent. See :

The big deal is that stream allows nows to acheive those easily/instantly without need to use Thread or other framework, just add .parallel() and you got it.
How to use it in my example. I just do like that :


IntStream.range(0, (heigh * width)-1).parallel().forEach(n->{applyKernel(n)})

If you want to control the number of thread use (see here for more informations) :

ForkJoinPool forkJoinPool = new forkJoinPool(4);
... 
forkJoinPool.submit(() -> 
IntStream.range(0, (heigh * width)-1).parallel().forEach(n->{applyKernel(n)})
).get()

At the end the time is cut by 2 going from 880 ms to 430 ms to does erosion.
So nice and easy. So is there any problems around there ?

Well as I understand problem could come from :

Conclusion

I have now a better understanding on Java stream pro and cons.  Enough to think about Stream the next time I face an analoguoud context.