Behavior readRawValues with colorSensor enabled

This is where you talk about the NXJ software itself, installation issues, and programming talk.

Moderators: roger, 99jonathan, imaqine

Behavior readRawValues with colorSensor enabled

Postby Stone » Tue Nov 06, 2012 7:40 pm

Hi,
I am making a coin sorter, and have been writing some code for it.
After some testing and debugging I found some strange behaviors in the execution.

I will first explain the purpose of the method which behaves strange before showing down my code, results and errors.

So I've made a method for scanning the RGB values of a coin. The method is called when a coin is detected, and will be executed untill the coin is completly scanned.
Here is a picture of my basic coin scanner:

Image

I'll post here the code of my class I made, but you only have to see to the method 'ScanCoin'.

Code: Select all

public class CoinSensor
{
   final int BOUNDARY_VALUE;
   SensorPort port;
   
   public CoinSensor(SensorPort p)
   {
      this.port = p;
      port.enableColorSensor();
      port.setType(SensorConstants.TYPE_COLORFULL);
      BOUNDARY_VALUE = 200;
   }
   
   public boolean coinIsDetected()
   {
      
   }
   
   public void scanCoin(Coin coin)
   {
      boolean coinIsScanned = false;
      int actualDegree, degree = -1;
      int returnedValue;
      final int ARRAY_LENGTH = 3;
      int[] RGBvalues = new int[4];
      
      Motor.A.resetTachoCount();
      Motor.A.forward();
      
      while(!coinIsScanned)
      {
         actualDegree = Motor.A.getTachoCount();
         
         if(actualDegree > degree)
         {
            returnedValue = port.readRawValues(RGBvalues);
         
            if(RGBvalues[0] > BOUNDARY_VALUE || RGBvalues[0] == 0)
            {
               try
               {
                  if(RGBvalues[0] == 0)
                  {
                     for(int i = 0; i < ARRAY_LENGTH; i++) coin.RGBvalues[actualDegree][i] = -50;
                  }

                  if(returnedValue < 0)
                  {
                     for(int i = 0; i < ARRAY_LENGTH; i++) coin.RGBvalues[actualDegree][i] = -100;
                  }
                  if(RGBvalues[0] != 0 && returnedValue > 0)
                  {
                     for(int i = 0; i < ARRAY_LENGTH; i++) coin.RGBvalues[actualDegree][i] = (short) RGBvalues[i];
                  }
               }
               catch(ArrayIndexOutOfBoundsException exception)
               {
                  coinIsScanned = true;
               }
            }
            else
            {
               coinIsScanned = true;
            }
            degree = actualDegree;   
         }
      }
   }
}


So the method let the coin move under the colorsensor. And every time that the motor has turned 1 degree, the sensorport will read the RGB values from the coin.
The multiple if-instructions I wrote for debugging my program.

And as you can see in my results, there are a few errors which occurs.
First of all, the method 'readRawValues' sometimes doesn't fill the given array with RGB values.
Second, when the motor speed is verry low, the method 'readRawValues' returns verry much an error (equals to value -1).
Then, when the motor has an average speed, the method 'readRawValues' needs a long time for scanning the RGB values.
And last, when the motor speed is high, no errors occures!

Here is the url to my excel document with my results, it maybe better for downloading it rather than viewing online.
https://docs.google.com/open?id=0B1zd8u803341b0ZLNjR3OU5wUWc
The document has three tabs, each with the results of one specified motor speed.

First of all, thank you for reading this all.
And please reply if you know the origin of this behavior. Ask me for more information if some things weren't clear.

Gratz, Stone!
Stone
New User
 
Posts: 14
Joined: Tue Apr 10, 2012 4:29 pm
Location: Belgium

Re: Behavior readRawValues with colorSensor enabled

Postby gloomyandy » Tue Nov 06, 2012 11:00 pm

What version of leJOS are you using?

Are you using the standard Lego color sensor is is that a HiTechnics color sensors? I assume it is a Lego sensor?

Have you tried your test with fresh batteries?

Are you running this code directly on the NXT or is it running on a PC using the leJOS PC side code?

Using an array out of bounds exception to exit the loop is probably not very good practice. Why not simply test the value in actualDegree against the size of the array?

Are you assuming that this code will result in actualDegree always being one degree greater than before, this may not always be the case, in which case you will end up skipping entries in your array of results.

You probably should check the value of returnedValue before using the values in RGBValues, if returnedValues is ever less than 0 then the contents of RGBValues will be invalid.

Your current program is rather complex. It looks like you may be getting errors from the color sensor, but it is hard to be sure. To test this you may want to write a simpler program that simply sets up the sensor port and then loops calling readRawValues and checks the return for an error condition and counts the number of good and bad reads over a period of say a minute. If you have access to more then one color sensor you could try the same program with each sensor to see how they compare. If you do get errors, please post your test code and I will try the same program on my own color sensor.
User avatar
gloomyandy
leJOS Team Member
 
Posts: 3004
Joined: Fri Sep 28, 2007 2:06 pm
Location: UK

Re: Behavior readRawValues with colorSensor enabled

Postby Stone » Wed Nov 07, 2012 9:52 am

Hi, I answered your questions and I hope you will now have a better view on my problem.

What version of leJOS are you using?

I have leJos 9.1 firmware

Are you using the standard Lego color sensor is is that a HiTechnics color sensors? I assume it is a Lego sensor?

Yes, it is a Lego sensor

Have you tried your test with fresh batteries?

Yes, I did several tests and some of them were with fresh batteries. But I don't think the results I get depends on the battery level.

Are you running this code directly on the NXT or is it running on a PC using the leJOS PC side code?

The code is completely running on the NXT. After collecting the results in an array, they will be send with the Datalogger to my pc.

Using an array out of bounds exception to exit the loop is probably not very good practice. Why not simply test the value in actualDegree against the size of the array?

Actually the only thing which had to be in the try instruction is:
Code: Select all
try
               {
                     for(int i = 0; i < ARRAY_LENGTH; i++) coin.RGBvalues[actualDegree][i] = (short) RGBvalues[i];
               }
               catch(ArrayIndexOutOfBoundsException exception)
               {
                  coinIsScanned = true;
               }

I thought that it would be better that I did this with exception handling. Because normally when the coin is scanned correctly, the array will be never out of bounds. Else the if-instruction will be executed like 300 times and will always return true.

Are you assuming that this code will result in actualDegree always being one degree greater than before, this may not always be the case, in which case you will end up skipping entries in your array of results.

My purpose is to fill the array with as much as possible arrays of RGB values. I know that it could skip some elements, so I will have some arrays with 0's in the array (I hope it doen't sound confusing when I am talking about 2-dimensional arrays). But I also don't want that an element of the array will be overwrited when it had already some values (I don't want duplicates). So that's the reason why I first check that actualDegree > degree.

You probably should check the value of returnedValue before using the values in RGBValues, if returnedValues is ever less than 0 then the contents of RGBValues will be invalid.

Yes sure. But this program is designed to see where errors occure. With all the if-instructions, I can afterwards see when the method 'readRawValues' returned an error, or acted strange. For example, if the RGB values of an array are -100 in my results, I can see that the returned value was -1. (I don't know if you actually downloaded my excel file, but if you did you could see that I put the values in a graph so you can easily see when the program acts. Btw, in google it looks awfull so i would rather download it).

Your current program is rather complex. It looks like you may be getting errors from the color sensor, but it is hard to be sure. To test this you may want to write a simpler program that simply sets up the sensor port and then loops calling readRawValues and checks the return for an error condition and counts the number of good and bad reads over a period of say a minute. If you have access to more then one color sensor you could try the same program with each sensor to see how they compare. If you do get errors, please post your test code and I will try the same program on my own color sensor.

Well I think that when I would just only call the method 'readRawValues', there will be no errors. The whole strange thing about my program is that it looks like the behavior of the method 'readRawValues' depends on the speed of my motor. When the motor has a speed of 200, the program works like it should be and no errors occur. But when the motor turns very slow, the method 'readrawValues' return many times an error. And when the motor speed is 50, it turns out that the method does a long time before returning. This is not my conclusion of one test, but from several tests. In the excel file you should take a look to the first 30 values of each test. I wrote some text next to it so you can easily understand these values.

Gratz, Stone
Stone
New User
 
Posts: 14
Joined: Tue Apr 10, 2012 4:29 pm
Location: Belgium

Re: Behavior readRawValues with colorSensor enabled

Postby gloomyandy » Wed Nov 07, 2012 11:24 am

The problem with your current test is that it there are several things happening at once. The speed of the motor is impacting the rate at which you sample the sensor. This makes it hard to work out if it is the motor running that is causing the problem or the sample rate change. Writing a simple test program will allow you to separate these two things (and will also establish if the sensor is working correctly). So I would write the simple test program (as I described), if that works fine, try adding delays (to change the sample rate), if that works fine try running the motor at the same time with various speeds and see if that causes errors. The other advantage of this sort of test is that it means that myself or the other developers can try your simple test program without having to build anything or have any coins etc. If you want people to help you then make it easy for them...
User avatar
gloomyandy
leJOS Team Member
 
Posts: 3004
Joined: Fri Sep 28, 2007 2:06 pm
Location: UK

Re: Behavior readRawValues with colorSensor enabled

Postby Stone » Wed Nov 07, 2012 4:13 pm

Thanks for responding Andy. You're right. It was maybe stupid to show a piece of my own program, and not just only the thing which isn't working properly.
I will quick write some tests and post the results on the forum. It is maybe better to start a new topic, because in this topic I shared a lot of information where the most people don't care about.
Btw, how can I easily show some tables with data on the forum, without posting a link to my documents elsewhere?

I got just some few more questions. About the exception handling thing, was is better to do it in my way as I explained it? Or is is it still better to use if-instructions?
And has the battery level much influence on the execution of a program?

Gratz Stone
Stone
New User
 
Posts: 14
Joined: Tue Apr 10, 2012 4:29 pm
Location: Belgium

Re: Behavior readRawValues with colorSensor enabled

Postby gloomyandy » Wed Nov 07, 2012 4:38 pm

For the exception thing I would search the internet for opinions on that. I think generally it is not considered good practice to use exception handling for things are not really exceptional. One of the problems is that doing things in this way makes it very hard to work out what it is that you really intended, also there is a danger when using something like this that you may accidentally catch the wrong exception. So for instance in this code you intend to catch actualDegrees being greater than your array size, but the exception handler would also trigger if you had an error in your code that resulted in mis indexing say RGBValues, I realize that in this case this is very unlikely to happen, but code has the habit of growing more complex and you could end up masking a genuine error. I think it is also better to use simple code like the if statement first, and worry about performance issues when they become a problem.

As to the battery issue, the reason I asked you about that was that you have a situation here where using the motor in different ways seems to trigger a problem. One thing that motor usage will cause is a drop in the battery voltage, this could have an impact on the color sensor and cause it to go into an error state. If the problem did not show up with fresh batteries, but did with old ones then this may have pointed to an issue like this...

I think it is fine to continue using this thread for your new test program results.

Sorry I don't have a better way for you to post tables etc. The code tag may help as it uses a fixed pitch font.

Andy
User avatar
gloomyandy
leJOS Team Member
 
Posts: 3004
Joined: Fri Sep 28, 2007 2:06 pm
Location: UK

Re: Behavior readRawValues with colorSensor enabled

Postby Stone » Wed Nov 07, 2012 6:44 pm

I all figured it out how the method 'readRawValues' behaves. I will describe this in several lines. I will not post my code because I adjusted my program several times to get all the information I needed. The results are not based on only one test, but at least 10 different tests and thousands of values. And I did my experiments with full loaded batteries (rechargeable, 1.2v).

-If the elapsed time between 2 calls of the method is between [80 -115] milliseconds, the method will return no error BUT there occurs a fault! The given array which it has to fill will not be filled with RGB's

-The next time that the method is called (after the fault occurs), it will return an error (-1) and it takes 178ms to return. This is always the case no matter what else happens.

-The third time that the method is called (after the fault occurs), it will again return -1 and now it takes 180ms to return. This is also always the case.

-The fourth time that the method is called (after the fault occurs), the returned value depends on the previous call. When the elapsed time between the third and fourth call is between [80 - 115]ms then the method will again return -1, and the array will not be filled (return time is again 180ms). Else the method will act normal. So if there is again a fault after the third call, it will not repeat this cycle but just add oen more error.


Conclusion:
-There is a fault when the time between 2 calls of the method is between [80 - 115] milliseconds
-When a fault occurs, there will be 3 arrays of RGB's incorrect (all 0) and there will be returned only 2 times an error (-1).
-The method-return-time is very long when a fault occurs, once 178ms and once 180ms. So in total 358ms!
-When the elapsed time between calls after the first three calls is good, the method against act normal. Else there will be add as much errors as faults that occur.

I hope it is a bit clear. So now we know exactly when the method returns an error. But there is still the question why it is. If there is someone with a bit more knowledge of how ARM's or this color sensor works who could answer this question?

Gratz, Stone
Stone
New User
 
Posts: 14
Joined: Tue Apr 10, 2012 4:29 pm
Location: Belgium

Re: Behavior readRawValues with colorSensor enabled

Postby gloomyandy » Wed Nov 07, 2012 9:28 pm

Hi,
if you can post a simple test program (no need for it to log the results, just count the number of error cases), then I will try the same thing with my color sensor. That way we will know if it is a problem with your sensor or a more general issue.

The long read times after an error are to be expected as the sensor will need to be reset and initialized. This is a time consuming and relatively complex process hence the delay.

Also is there a reason why you are using the SensorPort class directly rather than accessing the sensor via the ColorSensor class?

Andy
User avatar
gloomyandy
leJOS Team Member
 
Posts: 3004
Joined: Fri Sep 28, 2007 2:06 pm
Location: UK

Re: Behavior readRawValues with colorSensor enabled

Postby Stone » Thu Nov 08, 2012 6:22 am

I have 2 simple test programs I will post here.

The first program wil raise the time between 2 method calls. From 0 to 300ms. My result was 35 (errors in the interval [80 - 115] probably.
Code: Select all
import lejos.nxt.LCD;
import lejos.nxt.SensorConstants;
import lejos.nxt.SensorPort;
import lejos.nxt.Sound;
import lejos.util.Datalogger;
import lejos.util.Stopwatch;
import java.lang.Math;

/*
 * This program will test the 'readRawValues' when the time of calling is rising from 1 to 300
 */

public class Test2 {


   public static void main(String[] args) throws InterruptedException {
      int[] rgbValues = new int[4];
      int returnedValue;
      int timeElapsed;
      int returnedValueWasError=0;
      int randomTime;
      
      Stopwatch s1 = new Stopwatch();
      Stopwatch s2 = new Stopwatch();
      
      SensorPort.S1.enableColorSensor();
      SensorPort.S1.setType(SensorConstants.TYPE_COLORFULL);
      
      for(int i=0; i < 300; i++)
      {
         s2.reset();
         while(s2.elapsed() < i);
            
         returnedValue = SensorPort.S1.readValues(rgbValues);

         if(returnedValue < 0) returnedValueWasError++;
         
      }
      LCD.drawString("times that error occured:", 0, 0);
      LCD.drawInt(returnedValueWasError, 0, 1);
      
      Sound.playTone(600, 10000, 100);
      Thread.sleep(10000);
      

   }

}


And the second one will generate a random time between 2 calls ( [0 - 200]ms ). My last result was 232 but can varies from test to test.
Code: Select all
import lejos.nxt.LCD;
import lejos.nxt.SensorConstants;
import lejos.nxt.SensorPort;
import lejos.nxt.Sound;
import lejos.util.Datalogger;
import lejos.util.Stopwatch;
import java.lang.Math;

/*
 * This program will test the 'readRawValues' when the time of calling depends on a random time between [0 - 200]ms
 */

public class Test3 {


   public static void main(String[] args) throws InterruptedException {
      int[] rgbValues = new int[4];
      int returnedValue;
      int timeElapsed;
      int returnedValueWasError=0;
      int randomTime;
      
      Stopwatch s1 = new Stopwatch();
      Stopwatch s2 = new Stopwatch();
      
      SensorPort.S1.enableColorSensor();
      SensorPort.S1.setType(SensorConstants.TYPE_COLORFULL);
      
      for(int i=0; i < 1000; i++)
      {
         s2.reset();
         randomTime = (int) (Math.random()*200);
         while(s2.elapsed() < randomTime);
            
         returnedValue = SensorPort.S1.readValues(rgbValues);

         if(returnedValue < 0) returnedValueWasError++;
         
      }
      LCD.drawString("times that error occured:", 0, 0);
      LCD.drawInt(returnedValueWasError, 0, 1);
      
      Sound.playTone(600, 10000, 100);
      Thread.sleep(10000);
      

   }

}



And I use the sensorport instead of the colorSensor because the colorSensor makes an object of the class Color that I don't need, and it will call the method getColorId() which I also don't need. I'm trying to make my program as fast as possible as it will become complex.
Stone
New User
 
Posts: 14
Joined: Tue Apr 10, 2012 4:29 pm
Location: Belgium

Re: Behavior readRawValues with colorSensor enabled

Postby gloomyandy » Thu Nov 08, 2012 12:31 pm

Hi,
Thanks for the test programs I will give them a try as soon as I can.

As I said before, it is often best to take the simple approach and only get into optimizing things when you find there is actually a problem. Did you establish that using the ColorSensor class actually gave you a performance problem? No idea of your background so you may already be familiar with this topic, but if not you may want to google "premature optimization", there are a lot of interesting articles and papers about the idea. Calling getRawColor should not result in a call to getColorId.

Andy
User avatar
gloomyandy
leJOS Team Member
 
Posts: 3004
Joined: Fri Sep 28, 2007 2:06 pm
Location: UK

Re: Behavior readRawValues with colorSensor enabled

Postby Stone » Thu Nov 08, 2012 1:27 pm

I read some information about 'premature optimization' and maybe I'm making it hard for myself to create my own methods so that the design is not anymore that clean. I'm studying engineer (my second year) so I haven't yet seen a lot of ICT (actually only some object-orientated java).
I just tested my delay program, but now I created a colorSensor object and used the getColor method. Instead of comparing (returnedValue > 0) I tested if the returned Color had zero-values. And that was the case! I had now 36 errors, so also that method is affected by the elapsed time between two calls.
Maybe I didn't aswered your question thorough, but I hadn't that much time this morning. The basic reason that I came on the idea to use the method readRawValues instead of getColor was that, if I used getColor and putted the returned object in an array, I would have an array filled with colors. But in this way my brick was quickly out of memory (when an array is analysed, I let it point to a null reference).
But when I use the readRawValues, I cast the returned values to short and then put them in an array.
(I know I could also cast the returned RGB's from the Color object to short and them put them in an array but this makes it more complex and confusing).
And indeed, I was wrong with the fact that getRawColor() method doesn't call the getColorId() method.

Gratz , Stone
Stone
New User
 
Posts: 14
Joined: Tue Apr 10, 2012 4:29 pm
Location: Belgium

Re: Behavior readRawValues with colorSensor enabled

Postby gloomyandy » Sun Nov 11, 2012 1:33 pm

Hi,
I've run your test program on my sensor and am seeing the same results. Looking closer at what is going on and it would seem that the sequence...
readSensor
delay 100 ms
read Sensor
is triggering the device into a reset. Without getting into a lot of detail this is because the hardware signals generated by the above sequence are pretty much identical to those used to reset the device. At the moment I can see no way to stop this from happening other than to avoid having a delay of between 80 and 120 ms between two read requests.

I'll continue to look into this but for now I would suggest that you change your code to have a separate thread that basically reads the sensor at a higher than 100ms sample rate over and over again and to store this into a variable using synchronized methods. Then change your current code so that instead of calling the sensor read routine simply grab the most recent sample from the sensor (again using a synchronized method).

Andy
User avatar
gloomyandy
leJOS Team Member
 
Posts: 3004
Joined: Fri Sep 28, 2007 2:06 pm
Location: UK


Return to NXJ Software

Who is online

Users browsing this forum: No registered users and 3 guests

more stuff