EOPD – How to measure distance

In this post I will show you how to measure distance with the EOPD sensor. I will explain the math and give you some data and show you how it was analyzed. Equations for calculating distance as well as calibration constants will be presented. Sample code in LEGO Mindstorms NXT-G and NXC.

NXT-G EOPD Programs for LEGO Mindstorms 1.1
NXT-G EOPD Programs for LEGO Mindstorms 2.0
NXC EOPD Programs
Excel spreadsheet with EOPD Calculations

The EOPD Sensor, unlike the Ultrasonic sensor, does not measure distance directly. The EOPD Sensor is really a type of light sensor with one big difference; it only measures light that comes back from its own LED. Since the EOPD sensor ignores ambient light, there is one less variable that determines what the sensor value is.

If you think about the LEGO Light sensor, there are essentially three variables that determine the value:

  1. The color or shininess of the surface. Since the LED is illuminating the surface, the more light that comes back the higher the value. White high, black low.
  2. The distance to the surface. If the surface is closer, more of the light from the LED makes it back into the sensor element so you get a higher value. More about this later.
  3. And finally, the ambient light. This is especially true when the sensor is further away from the surface. In that case the illumination from the LED is usually relatively weak compared to the ambient light so the variation can be significant.

The EOPD sensor, on the other hand, is virtually immune to variation in ambient light. That means there are only two variables left in determining the EOPD sensor value, the shininess/color of the surface and the distance. This is very useful because if use the sensor in a situation where you can control one of these variables, then the sensor can be used to determine the other, and you don’t have to worry about the variation in lighting.

So how does one measure distance? We’ll the first thing we need to do is make sure that the nature of the surface is consistent. For example, if we make it work so that we can measure the distance to a white wall, then it won’t work well with a blue wall. That is because the blue wall will absorb a lot more light than the white wall and, in effect, appear further away. But once we work out the math it will be very easy to adjust from one type of wall to another. The other thing we need to make sure is that the surface is big enough. If we move the sensor far enough away and the whole cone of light is no longer striking the surface, then this will also throw off the distance calculation.

Let’s try to understand what really happens when an EOPD sensor faces a wall.

  1. Light comes out of the LED as a cone of light.
  2. This cone will then make a circle of light on the surface. Note, that the distance from the LED to the surface is not really what is important. Even though the light looks brighter on the wall when there is less distance, there is actually the same amount of light, it is just spread out over a larger area.
  3. Now the light on the surface will scatter in all directions and only some of that light will come back into the sensor element. So let’s imagine just a single point on the surface. If the EOPD sensor is a certain distance to surface, then you can image another cone from the point on the surface back to the sensor, this time to the sensor element. That’s the light that we are actually measuring, well actually that plus all the light from all the other points of light on the surface.

So let’s say we get a certain EOPD sensor value at certain distance. For example we might get a value of 250 at 2cm from the wall. So what happens when the distance doubles to 4 cm? Imagine that cone of light from the point on the surface going back to the sensor element. Now that cone makes a circle on the sensor cap that is twice the diameter of before. Since the area is proportional to the square of the diameter, that circle on the sensor is now four times bigger than before. That means only ¼ as much light is actually reaching the sensor element. Now repeat this for all the points of light on the surface and you can understand that the EOPD value goes down with the inverse of the square of the distance. If the distance goes to 6cm, then the circle on the sensor is now three times the diameter, thus 9 times bigger in area, thus the value should be 1/9 of the original value at 2cm.

Thus the sensor value should be something like this:

Where k is some constant that sets the scale of the value.

But what we want is the distance given the sensor value. With a little bit of algebra we can solve this for distance and get this:

Since the square root of k is just another constant, we will rename it to kScale and get rid of the radical. So now the formula is:

Okay, that’s the theory. The reality is really close but not exactly the same.

To set the constant(s) we will now get some sample data and enter them into a spreadsheet so we can analyze it and figure out what the ideal constant will be. Here is my test setup:

I used the program ViewEOPD and then I recorded the raw sensor value for each distance from 1 to 10 cm to a white LEGO brick wall, entered them into excel, and then graphed them so we can see what is going on.

CM    Raw   
1 973
2 975
3 668
4 447
5 319
6 235
7 181
8 143
9 114
10 95

There are two main things to observe in this graph, one is that it is non-linear, which is what we expected since the value is supposed to be the inverse of the square of the distance. The other thing is that the data at the beginning of the graph is clearly not consistent with the rest of the graph. There are two reasons why this is happening; one is that the analog sensor values on the NXT are limited to a range of 0 to 1023. The sensor is electronically limited to about a range of 0 to 1000. The other reason is that the sensor is so close at 1cm that the offset between the LED to the sensor element is preventing some of the light from getting in.

Our goal is to calculate the distance given the raw sensor value, so now we are going to do some analysis so that we can mathematically convert the raw sensor values into the distance. To that we are going to add a column takes the inverse of the square root of the raw sensor value:

CM    Raw    SquareRoot(Raw)   1/SquareRoot(Raw)
1 973 31.19294792 0.032058528
2 975 31.22498999 0.032025631
3 668 25.84569597 0.038691162
4 447 21.14237451 0.047298377
5 319 17.8605711 0.055989251
6 235 15.32970972 0.065232807
7 181 13.45362405 0.074329415
8 143 11.95826074 0.083624201
9 114 10.67707825 0.093658581
10 95 9.746794345 0.102597835

In this graph we can see that we have now made the data linear. The next goal is to scale it so that the linear range, at least from 3cm to 10cm, matches the actual distance. At 10cm the value was 0.102598 and at 3cm the value was 0.038691, which is difference of 0.063906. Since this represents a distance range of 70mm, if we want to convert this to mm then we will want to scale it by the constant 70/0.63906, which is about 1095. In other words, our first good attempt at getting a distance from the raw value should be with the kScale constant equal to 1095:

Let put this into the data and see how we do:

kScale: 1095.35
CM    Raw    / Sqrt(Raw)    Error
1 973 35.12 25.12
2 975 35.08 15.08
3 668 42.38 12.38
4 447 51.81 11.81
5 319 61.33 11.33
6 235 71.45 11.45
7 181 81.42 11.42
8 143 91.6 11.6
9 114 102.59 12.59
10 95 112.38 12.38

As you can see, in this table I have added one more column, the error between the calculated distance and the actual distance. By looking at the error we can see that it is very consistent. If we want to be consistently close to the actual distance then all we need to do is subtract the average error as well. Here is the new formula that includes the new kError term, which for this data should be set to around 12.

This is The Equation that we need to calculate a distance using the EOPD sensor.

So why do we need an error term? We are measuring the distance to the leading edge of the sensor but that is not actually where the sensor element is. The sensor element is inside the sensor case. Also, the light does not go straight onto the sensor element but first passes through the small lens, which I think also affects the distance calculation.

Here you can see the result from the program:

Calibrating made easy

Above I calibrated by doing some analysis on a spreadsheet and averaging many data points. That is actually more complicated than necessary. All you really need are two data points. You will need to record the EOPD sensor value for one point close to the surface and one point further away. Make sure the one that is near the surface is not too close; I would recommend at least 1 inch or 3cm. The one further away can be something like 10 inches or 20 cm or so. I used 10cm above. You will find that your distance calculation will be pretty good for the entire range but best near the end points of the range you used for calibration so it depends a little on what you need.

You can also pick any measuring units you want. I used millimeters but you can also use centimeters, inches, or LEGO units (aka studs).

Here are the four pieces of data you need:

distNear   This is the short distance for calibration. For example, 3 for 3cm or 1 for 1 inch. Note that the units you choose here will be the units you get out of the formula.
eopdNear   This is the raw EOPD value when the sensor is at distNear to the surface.
distFar   This is the far distance for calibration. Keep the units the same as distNear.
eopdFar   This is the raw EOPD value for this distance.

To calculate the kScale and kError constants you can use these equations:

For example, using my data above, I would use 30 for distNear, 668 for eopdNear, 100 for distFar, and 95 for eopdFar. That would give me a kScale of 1095.35 and kError of 12.38. These are slightly different than the values above because they only use two data points for the calibration.

Programming with the LEGO Mindstorms 2.0 Software

With the Mindstorms 2.0 software, you can take advantage of the floating point math including the square root function. With download for the NXT-G 2.0 programs you will find EOPDDist2.rbt. This program uses the two constants kScale and kError exactly as described above. If you want to need to adjust the calibration constants you can use the equations above.

Programming with the LEGO Mindstorms 1.0 Software

The 1.0 program is a little different because it does not support floating point math and all the math is done with integers. Since there is no square root function built in to the 1.0 software, the NXT-G EOPD sensor block has a special processed value where the square root has already been done for you. Specifically, this is what the Processed value looks like:

The reason that ten is multiplied in before the square root is to improve the resolution. To adapt this to our distance formula, we need to replace the radical term on the bottom with the processed value and modify the constant on top by multiplying it with the square root of 10. Thus the formula for the 1.0 software comes out like this:

With kScaleP equal to the kScale*sqrt(10). These calibration constants can also be calculated directly from the processed value using these equations:

For example, for my data above I had 30 for distNear, 81 for eopdProcNear, 100 for distFar, and 30 for eopdProcFar. This will give me a kScaleP of 3335 and kError of 11.

The attached program EOPDDist1 in the NXT-G 1.0 programs set implements this formula and displays the distance on the NXT screen. In this program you can adjust the kScaleP and kError using the equations above for your own surface or units.

Program in NXC

With NXC you can also take advantage of floating point math as well as have access to the square root function, assuming that you have a current version of NXC and LEGO firmware. If you need to install or upgrade your NXC installation, then you do so from here. The latest LEGO firmware that is available from LEGO is version 1.29. You can find that here.

In NXC the basic code to convert the EOPD value to millimeters is as follows:

#define kScale   1095.0
#define kError   12.0
task main()
  float dist;
  SetSensorHTEOPD(IN_1, false);
  while(true) {
    // Calculate distance
    dist = kScale/sqrt(SensorHTEOPD(IN_1))-kError;
    TextOut(0,LCD_LINE5,"Dist:       ");
    NumOut(6*5, LCD_LINE5, dist);

In the NXC set of files attached to this post, you will find two programs: ViewEOPDC.nxc and EOPDDistC.nxc.

Tags: , , ,

9 Responses to “EOPD – How to measure distance”

  1. [...] Filed under: Uncategorized — Xander @ 18:51 Gus Jansson of HiTechnic has written a nice article on how to use the HiTechnic EOPD sensor as a distance measuring [...]

  2. steffan says:

    I think i understand how the sensor works but im not sure how exaclty to program the EOPD sensor block that will allow me to use the sensor. I see in your programs you have the myblock but i would like to learn how to program it myself. it would be great if you could help.

  3. Gus says:

    Steffan, that is not a MyBlock. You need to download and install the EOPD sensor block from the HiTechnic downloads page. The EOPD sensor block gives you the processed as well as the raw output and lets you set the range.

  4. steffan says:

    ya just figured that out. before i downloaded the sensor block it kept showing up as a my block sorry.

  5. Vladimir says:

    Hi! I have NXT with firmware 1.05, how I can use float type in it? The firmware 1.29 isn’t work in my brick..

  6. Gus says:

    Your NXT does support the latest LEGO firmware. You can download from here:
    You can use either the LEGO Mindstorms software or something like BricxCC to download the firmware to your NXT.

    Even though this firmware supports floating point math, the LEGO Mindstorms 1.0 software does not. To use floating point math in your program you will either need to upgrade to the 2.0 LEGO Mindstorms software or switch to NXC.

  7. Vladimir says:

    Thanks a lot!

  8. GSRobo says:

    Hi I’ve got a problem because I dont Understand this programm. Can you make a Library so I can use it like a Ultrasonic Sensor ! Please
    Love this sensors, they are better than these other seonsors from LEGO NXT. But what if i cant use them because im a Big idiot!
    Thanks if you help me !

    LG GSRobo

  9. Gus says:

    You can’t use the EOPD sensor to measure distance as easily as the Ultrasonic sensor so I’m not sure if a driver or an NXT-G block will be the solution. If you are programming in NXT-G, then you really only need one math block together with the EOPD block to estimate distance. Put the math block after the EOPD block and pass in the Processed value from the EOPD block to the B input on the math block. Now set the math block to divide and put a constant in the A field. The amount of the constant will depend on the surface you are measure distance to so it will require some experimenting. Start with something like 1000 and see what you get. Write a program that displays this result on the NXT screen so you can easily see what you get for different distances.

Leave a Reply