<< return to Pixycam.com

Missing block every 6 loop iterations.

I have a fairly simple application. I’m printing my object’s X position to an LCD screen. My block is clear and well-resolved. My loop takes around 60ms to iterate. If there is no block detected, I want an error message. However, I get a lot of iterations where blocks=0 erroneously. Specifically, every sixth loop I get two loops where blocks=0. This seems to be very consistent. This makes implementing an error message difficult.

I could implement a conditional so that it would take three consecutive blocks == 0 loops to trigger the error message, but that doesn’t really solve the problem of why I’m getting two faulty blocks every six loops. Does anyone have any ideas?

Hello David,
Are you using Arduino?

If so, you are calling getBlocks(), which will return 0 if there are either no blocks detected or no new blocks for the current frame. So you may be getting 0 because no new blocks are available for the current frame. This can be confusing. One workaround is to put a delay in your program so that your call to getBlocks will always result in new frame data. Delaying 20 ms is guaranteed to do this, but it may be less depending on the update rate of your loop. This thread has some similar information:

http://cmucam.org/boards/9/topics/5734?r=5758#message-5758

Hope this helps!

Edward

Hi Edward,

Yes, I’m calling getBlocks() on an Arduino. I knew about the blocks=0 issue. That’s why I stated that my loop is taking around 60ms to iterate. Even when blocks=0, the loop takes at least 50ms to come around again.

Thanks,
David

Hello David,
How are you measuring the loop timing?

Edward

I’m using a breakpoint. I’ve gotten my loop time down to about 50ms now, but it takes time to do all of my operations. I’m writing to buffers, printing to LCD, and performing calculations. Looping faster than 20ms is definitely not my issue.

Maybe I should mention that I went in and commented out the serial printing of CS and reorder errors. There were a lot of them. I wouldn’t think that’s what’s causing blocks to read zero though.

Hello David,
If you are getting lots of the the checksum and reordering errors, I’m wondering what’s causing those. It means that data isn’t being delivered 100% reliably. Are you using I2C or SPI? If you are using SPI, are you using the Arduino cable that came with your Pixy?

Edward

I’m using UART, though the same thing was happening with SPI on the factory cable throughout development. Every so often I’d get a run without checksum and reorder errors, but there was no rhyme or reason as to why. I’d post my code, but it’s proprietary.

Hello David,
Hmm, like I said, these errors tend to be very rare. What kind of Arduino are you using?

Edward

It’s a Mega 2560, and in my experience the errors are far from rare. I’ll go ahead and post a version of my main detection loop.

@void READ_BLOCK_DATA() {
while (Adaptd == true) {

	if (i == 0) {
		TFT_BL_ON;
		bmpFile = SD.open(__Gsbmp_files[6]);      ///////////////////////////THIS SELECTS THE .bmp FILE TO OPEN. CHANGE THE INDEX NUMBER.
		if (!bmpFile) { Serial.println("didnt find image"); while (1); }   ////This loads the measurement screen/////////
		if (!bmpReadHeader(bmpFile)) { Serial.println("bad bmp"); return; } ////This loads the measurement screen/////////
		bmpdraw(bmpFile, 0, 0); ////This loads the measurement screen/////////
		bmpFile.close(); ////This loads the measurement screen/////////
		Serial.println("Now taking measurements! (uncomment serial print lines to see)");
		++i;
	}
	BUTTON_STUFF();
	blocks = pixy.getBlocks();
	W = pixy.blocks[0].width;
	H = pixy.blocks[0].height;
	x = pixy.blocks[0].x;

	inchpos = InPix*(-(160.0 - x));   //Converts to inches using empirically found inches per pixel
	Output.add(inchpos);   // appends output to running median buffer
	MedianOut = f_round(Output.getMedian(), 3);
	float hashpos = f_round((MedianOut / 0.064), 2);  //inches divided by inches per hashmark = hashmarks
	dotpos = -(hashpos * 14) + 160;//POSITION INDICATOR DOT//
	if (blocks && x > 0 && x < 320) {
		if (W <= (StdWidth + widthpad2) && W >= (StdWidth - widthpad2) && H > 150) { //****GOT SOME GOOD BLOCKS!
			ledgreen();
			if (abs(lastdot - dotpos) >= 2) { //////////////////////POSITION INDICATOR DOT///////////////////////////       
				Tft.fillCircle(152, lastdot, 20, BLACK);
				q = 0;
			}
			if (q == 0 || q %20 == 0 && dotpos >= 6 && dotpos <= 313 ) {  //q = 0 means that there is either a new value to write or that the measurements have started or restarted. This inproves speed by not writing the value to the screen at every loop.
				Tft.fillCircle(152, dotpos, 12, WHITE);   //Draws the circle at the new location
				Tft.drawTriangle(152 - 6, dotpos - 10, 152 - 6, dotpos + 10, 152 + 12, dotpos, RED);  //(int poX1, int poY1, int poX2, int poY2, int poX3, int poY3, INT16U color)
			}
			lastdot = dotpos;

			if (outFormat == 0) {/////////////////////////////////////////////////HASHMARKS MODE (2 decimals) ///////////////////////////	
				
				dtostrf(hashpos, 5, 2, stringval);  //Transpose hashpos into string format. //dtostrf(floatVar, minStringWidthIncDecimalPoint, numVarsAfterDecimal, charBuf);	
				stringval[5] = 0;   //make sure buffer is null-terminated to prevent buffer overflow
				if (abs(lasthashpos - hashpos) >= 0.01) {
					Tft.drawString(laststringval, 70, 215, 5, BLACK);  //screen overwrite if new value different from last
					q = 0;
				}
				if (q == 0 || q % 20 == 0) { //q = 0 means that there is either a new value to write or that the measurements have started or restarted. This inproves speed by not writing the value to the screen at every loop.
					Tft.drawString("Hashmarks:", 30, 182, 2, WHITE);
					Tft.drawString(stringval, 70, 215, 5, WHITE);   //print output to screen
				}
				lasthashpos = hashpos;   //Save hashpos for next comparison to determine if screen overwrite needed
				dtostrf(hashpos, 5, 2, laststringval);//Save string value for next overwrite
				laststringval[5] = 0;   //make sure buffer is null-terminated to prevent buffer overflow
			}

			else {  //////////////////////////////////////////////////////////INCHES MODE (3 decimals) ////////////////////////////////////
				dtostrf(MedianOut, 6, 3, stringvalin); //Transpose inhpos into string format. //dtostrf(floatVar, minStringWidthIncDecimalPoint, numVarsAfterDecimal, charBuf);
				stringvalin[6] = 0;   //make sure buffer is null-terminated to prevent buffer overflow
				if (abs(MedianOut - lastinchpos) >= 0.001) {
					Tft.drawString(laststringvalin, 70, 215, 4, BLACK); //screen overwrite if new value different from last
					q = 0;
				}
				if (q == 0 || q % 20 == 0) { //q = 0 means that there is either a new value to write or that the measurements have started or restarted. This improves speed by not writing the value to the screen at every loop.
					Tft.drawString("Inches:", 30, 165, 2, WHITE);
					Tft.drawString(stringvalin, 70, 215, 4, WHITE);
				}
				lastinchpos = MedianOut; //Save inchpos for next comparison to determine if screen overwrite needed
				dtostrf(MedianOut, 6, 3, laststringvalin);//Save string value for next overwrite
				laststringvalin[6] = 0;   //make sure buffer is null-terminated to prevent buffer overflow
			}
		}
		else {   //  no good blocks :(
			ERROR();
		}
		//SerialOut();   ///print bocks to seial for debug
		//Serial.println(millis());      //for debug
		i++;
		g = 0;
		++q;   ////iterate q to stop new readouts from being printed to screen unless they are new
	}
	else {
		delay(D);
		g++;
		if (g >= 7) {  //block disappearance detector: if blocks == 0 for 7 consecutive loops, then the block has disappeared from view faster than the camera could react. 
			x = 281;  //forces "RANGE" error. x updates appropriately on next loop.
			g = 0;
			ERROR();
		}
	}
	PayloadSendit();
}

}@

Hello David,
Thanks for the code, but let’s try to investigate why you are getting so many errors, OK? This is definitely not normal.

Here’s what I think is happening. With UART communication, flow control is not supported with Arduino (or Pixy). This means that you need to be reading (polling) constantly, or you need to set up a interrupt to buffer data coming in so you don’t overrun. If you do overrun, the lost data will result in an error. The SPI and I2C there the flow control is built-in.

Can you run the hello_world example on your Arduino Mega 2560 with the supplied Arduino cable? Do you get errors when you run this demo? (you shouldn’t)

Edward

Edward,

Hello_world runs just fine with the supplied cable and over UART. It also works with the custom wiring harness I’m currently using. The errors don’t seem to crop up until my main loop reaches a certain level of complexity. Floating-point calculations, string transcriptions, and LCD screen writes add to the time it takes my loop to iterate. Although I can’t identify any particular cause, and I’ve never seen a single change to my code affect the condition noticeably, I do suspect it’s a timing issue.

As stated, I get the same number of errors over SPI as I’m getting over UART. So I’m not sure UART is the problem. If you have an idea for an interrupt though, I’d be willing to try it out.

David

Hello David,
If there are ways to disable sections of your code, it might help you shed light on which sections are causing errors. We can then get a better idea of the cause based on these clues. I’ll also ask around here and see if anyone has any suggestions of things to try.

Edward

I’ve already gone through hundreds of versions of my loop, and I’ve never seen a single change to my code affect the condition noticeably. I’ll see if I can’t take another approach though, and I’ll let you know if I find anything. Thanks.