Skip navigation

community

0

There comes a time in every roboticists life when using distance sensors and light sensors just isn't enough. While navigating a micromouse maze or following a line might be achievable using rather simple electronics, if you want to build robots which interact with people and their surroundings in a more general way, using cameras and image processing is one approach you could take. In this blog post I'll go through the basics of getting OpenCV (the defacto library for computer vision) up and running, and give you some ideas about what to do next and where to look for commonly used algorithms.

 

For downloading and installing OpenCV see their wiki here - http://opencv.willowgarage.com/wiki/InstallGuide

 

Capturing Video

 

The first step to developing computer vision algorithms is getting access to the source of video. This can be taken from either a camera or a video. A video source is very handy when you are programming away and don't want to waste time running the robot, but ultimately you will want to run your program using a camera. Below is the code for extracting video from a video/camera.

 

/* video_stream.cpp */
#include <opencv/cv.h>
#include <opencv/highgui.h>

using namespace cv;

int
main() {    
     /* Take images from the default camera */
    
     VideoCapture cam(0);

     /* Create a window called stream which autosizes */

     namedWindow("stream", CV_WINDOW_AUTOSIZE);

     while
(true) {         
          /* Create a matrix to hold the image data */

          Mat img;

          /* Extract an image from the camera and place into the matrix */
         
          cam >> img;

          /* Show the image on the window named stream */

          imshow("stream", img);         

          /* Wait for 30ms and if a key is pressed, place the
               ascii value of the key into variable ch       */
         
          char
ch = waitKey(30);
    
          /* If ESC was pressed then break out of the while loop */
         
          if
(ch == 27) break;
     }
    
     return
0;
}

 

To compile the code above you need to link it with the cv and highgui libraries (in linux type "g++ video_stream.cpp -lcv -lhighgui -o video_stream")

When running this example you should see a window called stream with the video input playing (in my case thats a camera looking at me )

Screenshot-1.png

Processing Video

 

Now that we have a nice video stream it is time to do some actual image processing. A nice and simple OpenCV function to use is Canny which performs edge detection on an image. The next program will have 2 windows, one showing the original video stream and the second showing the edges. To do this there are a few steps:

  1. Create a new window to display the edges
  2. Create a new matrix to store the matrix data
  3. Convert the image to grayscale for the Canny function (because it only accepts single channel images whereas colour images have 3 channels)
  4. Apply the Canny function to get edge data
  5. Show the edge data on the window.
 
1:
/* video_stream.cpp */
2:
#include <opencv/cv.h>
3:
#include <opencv/highgui.h>
4:

5:
using namespace cv;
6:

7:
int main() {
8:
     /* Take images from the source */
9:
     //VideoCapture src("/home/h/video.avi"); // Video file

10:
     VideoCapture src(0); // Default camera

11:

12:
     /* Create windows */
13:
     namedWindow("stream", CV_WINDOW_AUTOSIZE);
14:
     namedWindow("edges", CV_WINDOW_AUTOSIZE);
15:

16:
     while(true) {
17:
          /* Create matrices to hold the image and edge data */
18:
          Mat img, edges;
19:

20:
          /* Extract an image from the camera and place into the matrix */
21:
          src >> img;
22:

23:
          /* If image empty then break out of while loop */
24:
          if(img.empty()) break;
25:

26:
          /* Convert the image to grayscale and temporarily store in edge matrix */
27:
          cvtColor(img, edges, CV_BGR2GRAY);
28:

29:
          /* Find the edges and place in edge matrix
30:
             1st arg is the source matrix, 2nd arg is the destination matrix
31:
             3rd arg is the lower threshold, 4th arg is the upper threshold
32:
             Thresholds are used in the Canny algorithm to detect lines */
33:
          Canny(edges, edges, 10, 100);
34:

35:
          /* Show the images */
36:
          imshow("stream", img);
37:
          imshow("edges", edges);
38:
         

39:
          /* Wait for 30ms and if a key is pressed, place the
40:
               ascii value of the key into variable ch */

41:
          char ch = waitKey(30);
42:
    

43:
          /* If ESC was pressed then break out of the while loop */
44:
          if(ch == 27) break;
45:
     }
46:
     return 0;
47:
}

 

The code above is compiled in the same way as before. Upon running the program this is what I see:

edges.png

It's clear that edge detection might have some nice uses in text processing as it captures quite well the text outlines in the image.

 

Tweaking Parameters Easily

 

One last thing I want to show is the use of trackbars in OpenCV. Usually when working with image processing your algorithms will depend on many different parameters (e.g. the edge detection algorithm we just used required 2 threshold parameters). It's extremely useful to be able to change these values at runtime to tweak and tune until things are processed just right. This can be done in OpenCV using track bars which are basically sliders which are used to alter the value of a variable inside you program whilst it is running. Here's what we have to do:

  1. Create a window to display the trackbars in
  2. Create variables for the trackbars
  3. Create the trackbars and reference both the variables they control and the windows they are to be displayed in
  4. Place the variables into the paramater lists of our Canny function

 

Here is the code:

 
1:
/* video_stream.cpp */
2:
#include <opencv/cv.h>
3:
#include <opencv/highgui.h>
4:

5:
using namespace cv;
6:

7:
int main() {
8:
     /* Take images from the source */
9:
     //VideoCapture src("/home/h/video.avi"); // Video file

10:
     VideoCapture src(0); // Default camera

11:

12:
     /* Create windows */
13:
     namedWindow("stream", CV_WINDOW_AUTOSIZE);
14:
     namedWindow("edges", CV_WINDOW_AUTOSIZE);
15:
     namedWindow("trackbars", CV_WINDOW_AUTOSIZE);
16:

17:
     /* Create the variables and the trackbars, referencing the "trackbars"
18:
        window in which the trackbars should be shown */

19:
     int lowerThres = 10;
20:
     createTrackbar("LowerThres", "trackbars", &lowerThres, 255);  // 255 is the max value of the trackbars
21:
     int upperThres = 100;
22:
     createTrackbar("UpperThres", "trackbars", &upperThres, 255);

23:

24:
     while(true) {
25:
          /* Create matrices to hold the image and edge data */
26:
          Mat img, edges;
27:

28:
          /* Extract an image from the camera and place into the matrix */
29:
          src >> img;
30:

31:
          /* If image empty then break out of while loop */
32:
          if(img.empty()) break;
33:

34:
          /* Convert the image to grayscale and temporarily store in edge matrix */
35:
          cvtColor(img, edges, CV_BGR2GRAY);
36:

37:
          /* Find the edges and place in edge matrix */
38:
          /* 1st arg is the source matrix, 2nd arg is the destination matrix */
39:
          /* 3rd arg is the lower threshold, 4th arg is the upper threshold */
40:
          /* Thresholds are used in the Canny algorithm to detect lines */
41:
          Canny(edges, edges, lowerThres, upperThres);
42:

43:
          /* Show the images */
44:
          imshow("stream", img);
45:
          imshow("edges", edges);
46:

47:
          /* Wait for 30ms and if a key is pressed, place the
48:
               ascii value of the key into variable ch */

49:
          char ch = waitKey(30);
50:
    

51:
          /* If ESC was pressed then break out of the while loop */
52:
          if(ch == 27) break;
53:
     }
54:
     return 0;
55:
}

Here is what I see when running that code and tweaking it so that my hand is shown clearly against the background:

hand-edge.jpg

What's Next

So yeah that's it for today! You should now be able to try out other things for yourself like face/object recognition, blob-tracking or stereo-vision. If you do, post them on here! Here's a cool video on a hot-topic in research at the moment called SLAM (simultaneous localization and mapping):

 

OpenCV has functions for things like that! You can find them in the OpenCV documentation here - http://opencv.willowgarage.com/documentation/cpp/index.html


Stay tuned and there'll be some more interesting things on OpenCV as we are using it in our robot this year for localization.

0

Boo... Where have you all gone?

Posted by sfirth Oct 13, 2010

Hello

 

Have you broken up?  Haven't heard from any of you for ages.

 

Myself and a very 'high up' colleague are visiting Imperial on 20th Oct afternoon, are any of you free for a chat to see what we can do to help you with

projects/ideas/support?

 

Sam

0

A quick demonstration of the motor encoder so far.

 

 

 

 

A demo of PID motor control.

The motor is controlled by an Arduino, which uses a PID library for a nice feedback loop - http://www.arduino.cc/playground/Code...

The computer serves as just a screen and a keyboard, to display the current speed, and change the target speed.

1

Localization Beacons

Posted by harry.eakins Jan 10, 2010

We are designing a camera + light-source based localization system to let our robot localise itself in the Eurobot arena - see our other blog post for more details http://www.element-14.com/community/groups/mew-imperial-college/blog/2009/11/22/localization

 

One job is to make the light-sources, or beacons. Here are some things we considered:

 

  • 3 beacons, 1 must have 180degree illumination, the other two 90 degrees.
  • Red worked better in tests.
  • Must fit in 80x80x160mm volume.
  • Bottom has hook Velcro.
  • Light must come from the same position horizontally no matter where in field of illumination the observer is (but vertical displacement doesn't matter)
  • Shielding from lights on the horizon is desirable - the
  • Flashing LEDs, frequency adjustable. Between 1-100Hz

 

One of the problems, is that normal LEDs have quite a small angle of illumination - typically 30-60 degrees. We require up to 180 degrees. Our initial idea was a traffic light style beacon:

beaconFront.JPG
Unlike a traffic light however, each of the lights will point in a different direction. Their fields of illumination will overlap to ensure that all of the arena is covered.
beaconTop.JPG
The robot, when navigating the arena, will then use its camera to find where each of the three beacons are, and use a little bit of maths to find out its current position.
beaconArena.JPG

Change of Plan!

 

Well, while this might have worked, we found another high power LED with an angle of 165 degrees! - http://uk.farnell.com/avago-technologies/asmt-jr30-ars01/led-3w-red-80lm/dp/171839. So we are going to try using these instead.

 

The new LEDs are surface mount packages which is a problem, since we only have experience and equipment to solder through-hole components. In order to solder these, we are going to build a soldering oven! Like this one - http://www.seattlerobotics.org/encoder/200006/oven_art.htm. We have ordered a Toaster Oven from Amazon - http://www.amazon.co.uk/Sabichi-83913-Mini-Oven/dp/B000L1KHYM/ref=sr_1_1?ie=UTF8&s=kitchen&qid=1263052699&sr=8-1 and some solderpaste from Farnell - http://uk.farnell.com/edsyn/cr44/solder-paste-in-syringe/dp/876768?Ntt=876768. We're pretty excited about getting this thing started!

 

Another thing you need for surface mounting is PCB. You can't use breadboard or strip board, you must design a Printed Circuit Board and get it made. So we used Cadsoft's Eagle software - http://www.cadsoftusa.com/

The library for this LED couldn't be found on the internet, so we made our own, and it is attached to this blog post. Feel free to use it, but as I haven't used it yet... I can't promise it's quality!

The first board is this:

beacon-brd.png

And the corresponding schematic:

beacon-schem.png

 

Actually I think I might change it to only have 1 LED per board... 3x3W LEDs seems a bit excessive! The board and the LED should be here by next Tuesday.

0

Motor Encoder - Part 1

Posted by harry.eakins Jan 8, 2010

Essential to our progress now is creating a drive system which has some sort of feedback. Currently we can control the power supplied to each of the motors, but this is not enough to know how fast the they are moving. Factors effecting speed, other than power dissipated in the motor, are friction on the wheels (the wheels may slip) and torque required (e.g. going up hill will be slower than on a flat surface). While it might be possible to measure all of these various factors, feed the data into a mathematical model of the drive system and get it to calculate an estimate for the speed, it's not the easiest or most sensible approach. Measuring the speed directly, however, is much simpler and more effective!

 

To do this, we are going to build an optical encoder on each of the motors. Information about what encoders are and how they work can be found here:

http://www.societyofrobots.com/sensors_encoder.shtml

 

IMG_2148.JPG

The motors we use are from MFA (can be found here - http://www.cornwallmodelboats.co.uk/acatalog/geared_motors.html). The motor output is geared down to give higher torque at a lower speed (our gear ratio is 50:1). Since we want a relatively high resolution encoder, it makes sense to try to measure rotational speed closest to the output of the motor (before the gearbox) since this is where the highest speeds are. So we took off the red cap and had a look inside.

IMG_2152.JPG

The gear connected to the motor output shaft isn't very accessible to use as an encoder wheel so we found a similar gear and set out mounting it onto the gearbox. This would give us another gear outside of the motor which could be more easily used as an encoder disk. First we cut some holes in a piece of stripboard and cut it to shape, so that it would fit nicely on the gearbox mount.

IMG_2157.JPG

Then we drilled another hole in the stripboard and used a nut and bolt to attach one of the cogs we had. The fit was perfect! The green cog spun rapidly as the output shaft turned slowly. Plus it already had 4 holes in which meant no modification was necessary to make it into an encoder wheel - the slots were already there. We drilled another hole into the stripboard to allow light to pass to the sensor when we mount it.

IMG_2159.JPG


The sensors were taken from an old ball mice. These things are invaluable for encoder phototransistors! Here is the datasheet for the ones I found in the mouse - http://www.allproducts.com/ee/kantek/31-dual_phototransistor-l.jpg. Notice it has 2 phototransistors in the one package. This means it can not only measure the speed of the motor, but also the direction (using something called quadrature, see this for more explanation - http://www.eehomepage.com/report.php?report=20080225). The mice also have matching IR LEDs so we took those off to use in our encoder too. See the black package with the blue line (in front of the encoder wheel)?

IMG_2167.JPG

The leads for on the LED and phototransister were very short, so we soldered some longer wires onto them. The wires were stiff single core ones, so it allowed us to alter the position of the chips with ease - very handy when experimenting. The other end of the wires we soldered onto the strip board.

IMG_2168.JPG

Here's a pic of the other side. You can see the LED mounted and positioned to shine through a hole on the gear when it passes. Notice that the phototransistor package is black. This black plastic is actually transparent to IR light so it will still hit the phototransistor inside. The light which humans can see however will not get through. This serves to reduce the interference from other light sources.

IMG_2171.JPG

Another cool trick when working with IR is to use a camera to know if it is actually shining. Our eyes can't see IR, but the CCD sensors in cameras can pick it up. Look at the middle of the LED in this picture, and you can see a bright pink/purple dot. This is IR light!

IMG_2174.JPG

More coming up in a few days. Stay tuned!

1

Happy New Year

Posted by sfirth Jan 4, 2010

Just to wish you all a Happy 2010.

 

Kind regards


Sam

0

Mechanical Team Progress

Posted by mm.soloviev Nov 25, 2009
This week we have begun manufacturing parts for the robot, having finalised the design. The Chassis and outriggers are now complete (6mm Aluminium sheet), and the entire chassis will be assembled next week once the ball transfer units (like a byro with a 19mm ball) have arrived. Part of the fruit picking apparatus is now also complete, and the rest should be finished next week. It is entirely possible, therefore, that the new robot will be capable of moving itself and picking oranges in next week's meeting, which should be pretty exciting!
3

Localization

Posted by oliver.mattos Nov 22, 2009

It's important for the robot to know where it is within the playing board.  Once you know where you are and which way you're heading, you have no problems of crashing into any fixed things in the play area, like hitting walls etc.  Also, with a simple "follow a route" algorithm, which stays on track by using a good localization method, it's pretty simple to pick up a lot of points while totally ignoring the other robot or any or the more advanced game techniques.

 

Having established that we need effective localization, we are now designing and building it - below I describe how our current ideas are developing.

 

Our plan is to use visible or infrared lights on the fixed beacons.  These lights will flash or change colour to make them easier for us to track and seperate them from the other lights around the arena, which could be considerably brighter than ours.  We found that with most webcams the dynamic range of the colours in the image is pretty narrow - for example a very bright light like the sun appears exactly the same colour as a white wall (ie. both #FFFFFF, the brightest white the camera can represent).  This was a problem for us because lots of other things in the arena would be detected since they were the same colour as light sources.  Also, the camera blurred fast moving lights into lines, which again makes detection hard.

 

To compensate for this we modified the linux driver for the camera to reduce the exposure control dramatically (to about 1 16,000th of the original exposure time per frame) so the image only showed light sources and the rest of the image as black.  this had a nice side effect of getting rid of all the blur as well.

webcam-diagram.GIF