<< return to Pixycam.com

getBlocks(false) - Still taking way too long - Why?

Hello Everyone,

I am quite impressed with my Pixy2. I am doing testing with a stepper driven XY table and arduino mega which tracks objects above it and follows them. It’s working but getBlacks() limits my step rate to 60 steps per second while tracking. That is incredibly slow on a 800 step per revolution stepper driver. I have cheated this by not updating the getBlocks as often but that also makes it run quite jittery.

From my searching this is a known situation. When you call “pixy.ccc.getBlocks();” it will automatically wait until the next frame from the camera is available by default. I have also read on this forum that if you call “pixy.ccc.getBlocks(false);” it will not wait and return the prior data if nothing new is available. This is exactly what I want but it doesn’t seem to work. Whether I use the “false” statement or not seems to have absolutely zero effect.

Am I misunderstanding how to do this correctly? Thank you! - Brad

I have included the code that runs very slow. Hopefully I formatted it correctly.

#include <Pixy2.h>

// This is the main Pixy object
Pixy2 pixy;

// Define stepper motor connections and steps per revolution:
#define dirPin 2
#define stepPin 3
#define dirPiny 4
#define stepPiny 5

int Speed = 700;
int i = 0;

void setup()
{
  //  Serial.begin(115200);
  //  Serial.print("Starting...\n");

  pixy.init();
  pixy.changeProg("color_connected_components");

  // Declare pins as output for stepper driver:
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
  pinMode(stepPiny, OUTPUT);
  pinMode(dirPiny, OUTPUT);
}

void loop()
{
    // grab blocks!
    pixy.ccc.getBlocks(false);

  // If there are detect blocks, print them and check location!
  if (pixy.ccc.numBlocks)
  {
    //    Serial.print (pixy.ccc.blocks[0].m_x);
    //   Serial.println();
    if (pixy.ccc.blocks[0].m_x < 150) //get x coordinate of block 0 and check its location from center
    {
      digitalWrite(dirPin, LOW);
      digitalWrite(stepPin, HIGH);
      delayMicroseconds(Speed);
      digitalWrite(stepPin, LOW);
      delayMicroseconds(Speed);

    }
    if (pixy.ccc.blocks[0].m_x > 165)
    {
      digitalWrite(dirPin, HIGH);
      digitalWrite(stepPin, HIGH);
      delayMicroseconds(Speed);
      digitalWrite(stepPin, LOW);
      delayMicroseconds(Speed);
    }
    if (pixy.ccc.blocks[0].m_y < 96) //get y coordinate of block 0 and check its location from center
    {
      digitalWrite(dirPiny, LOW);
      digitalWrite(stepPiny, HIGH);
      delayMicroseconds(Speed);
      digitalWrite(stepPiny, LOW);
      delayMicroseconds(Speed);

    }
    if (pixy.ccc.blocks[0].m_y > 111)
    {
      digitalWrite(dirPiny, HIGH);
      digitalWrite(stepPiny, HIGH);
      delayMicroseconds(Speed);
      digitalWrite(stepPiny, LOW);
      delayMicroseconds(Speed);

    }
  }
  //  delay(100);
}

Hi Brad,

I’m not sure what’s going on here, but I wonder if the program isn’t looping a ton while it’s waiting for new blocks to arrive? Assuming pixy.ccc.getBlocks(false) is actually executing as intended, it will return immediately when no new blocks are present, which will iterate through the next chunk of your code (the if statements with associated delayMicroseconds calls) very quickly.

Try commenting out the delayMicroseconds calls and see if anything changes. Just a hunch…

Cheers,
Jesse

Thank you for the reply freed.

I cannot remove those delays as the microsecond delays are the actual pulses which initiate a step on our stepper driver/motor. If there is not delay then it is not a pulse. It makes no difference if I change those values anyway as I have tried.

I can cheat and make it work kind of correctly by putting the getblocks portion in an if statement that only runs every 20-50 loops. Then the machine comes to life and runs quite fast but stutters every 20-50 steps when the whole code waits on the next frame. Here is an example of the cheat I am referring to.

If (i >= 20)
{
pixy.ccc.getBlocks(false);
i=0;
}
i++;

I am self taught so please excuse my methods if they are unorthodox or inefficient.

Since adding this statement speeds up the machine dramatically (it goes from a crawl to a pace so rapid it shakes the table when it starts and stops) I can see no other possibility than that the false statement as I have implemented it in my arduino code does not work. I am adding code and operations to the code but it is running faster…so it is definitely not just giving me the most recent frame when I use pixy.ccc.getBlocks(false).

Am I using this correctly? Does it only work in Java? Do I need to update my Pixy2?

Thanks all

Has anyone else tested the time that pixy.ccc.getBlocks(false); takes?

I’m just trying to figure out if I am implementing it incorrectly or if it just doesn’t work as it is supposed to.

Thanks
Everyone

@edge can you weigh in here?

Does anyone have a possible work around? I would like to get the most recent location of the object on the screen and keep moving toward it one step with each loop of the code. I can’t think of any way of updating the position without the code coming to a complete halt while it waits for the next frame. This prevent smooth motion and it also could cause quite a bit of additional wear and tear on the stepper system as well with all or the abrupt stopping.

Should I be considering a different camera?

Thanks all
Brad

Hello,
If you call getBlocks with false, getBlocks may return a PIXY_RESULT_BUSY (a negative value) meaning that the next block hasn’t come in yet. I’m not sure what will happen if you don’t take this into account.

Why do you not want to wait for the next frame? You code seems to only be using the Pixy data, so i seems like it would make sense to wait.

Help me understand what you are trying to do and maybe I can help you understand the best path forward.

Edward

Thank you for the reply edge! Here is the problem in a nut shell - we are using the same arduino to drive a stepper. So the code must loop at a speed high enough to move the stepper. Let’s say for example looping at 800hz (800 steps per rev - 1 full rotation per second). This is easy for the arduino to accomplish. As soon as I call getBlocks it drops down to as slow as 60hz loops because I am stuck waiting for the next frame. Even if I don’t call get blocks every loop it still gets drastically slowed down for that single step when I do call it because it is waiting on the next frame. What I would like to do is just get the position value that is currently available. I don’t care if it is 10ms old.

As far as I can tell there is no way to use the pixy without occasionally having single loops that take up to 16ms. That is much to slow to operate the stepper in the same code. In the real world it means my stepper is limited to one revolution every 13 seconds if I am asking for the most recent location each loop of the code.

If instead of waiting for the next frame the pixy2 just returned the current location data it would operate flawlessly.

Hopefully that makes the situation clearer. I seriously appreciate the help!

Brad

Again, I don’t think you are doing it correctly. In your code you have

if (pixy.ccc.numBlocks)

and only if this is true do you do anything useful. This condition will only be true I believe if Pixy was able to get block data.

Why don’t you do something like

result = pixy.ccc.getBlocks(false);

if (result<0)
< run stepper motor >
else
< handle block data >

Hope this helps

Edward

1 Like

I will try that thank you! It sounds like I may have been using it improperly which would be great news.

So when the code gets to:

result = pixy.ccc.getBlocks(false);

It won’t wait for the next frame before moving to the next line of arduino code? If so that should solve it.

Thanks
Brad

getBlocks(false) will not block for long – less than 1 millisecond.

I tried to implement the code as suggested but I still have the same issue. If I call getBlocks each loop it runs insanely slowly.

#include <Pixy2.h>

// This is the main Pixy object
Pixy2 pixy;

// Define stepper motor connections and steps per revolution:
#define dirPin 2
#define stepPin 3
#define dirPiny 4
#define stepPiny 5

int Speed = 500;
int result = 0;

void setup()
{
  //  Serial.begin(115200);
  //  Serial.print("Starting...\n");

  pixy.init();
  pixy.changeProg("color_connected_components");

  // Declare pins as output for stepper driver:
  pinMode(stepPin, OUTPUT);
  pinMode(dirPin, OUTPUT);
  pinMode(stepPiny, OUTPUT);
  pinMode(dirPiny, OUTPUT);
}

void loop()
{
  // grab blocks!
  result = pixy.ccc.getBlocks(false);

  if (result > 0)
  {

    if (pixy.ccc.blocks[0].m_x < 150) //get x coordinate of block 0 and check its location from center
    {
      digitalWrite(dirPin, LOW  );
      digitalWrite(stepPin, HIGH);
      delayMicroseconds(Speed);
      digitalWrite(stepPin, LOW);
      delayMicroseconds(Speed);

    }
    if (pixy.ccc.blocks[0].m_x > 165)
    {
      digitalWrite(dirPin, HIGH);
      digitalWrite(stepPin, HIGH);
      delayMicroseconds(Speed);
      digitalWrite(stepPin, LOW);
      delayMicroseconds(Speed);
    }
    if (pixy.ccc.blocks[0].m_y < 96) //get y coordinate of block 0 and check its location from center
    {
      digitalWrite(dirPiny, LOW);
      digitalWrite(stepPiny, HIGH);
      delayMicroseconds(Speed);
      digitalWrite(stepPiny, LOW);
      delayMicroseconds(Speed);

    }
    if (pixy.ccc.blocks[0].m_y > 111)
    {
      digitalWrite(dirPiny, HIGH);
      digitalWrite(stepPiny, HIGH);
      delayMicroseconds(Speed);
      digitalWrite(stepPiny, LOW);
      delayMicroseconds(Speed);

    }
  }
}

Am I still doing this wrong?

Thank you
Brad

Hello,
Your code looks good to me. You might call millis() to determine if it’s as slow as you suspect.

https://www.arduino.cc/reference/en/language/functions/time/millis/

But you aren’t taking advantage of “doing x while waiting for the next frame”. You are just doing something when you get frame data (when result>0).

Edward

Yes I noticed this after my last posting and I changed that

if (result > 0)

To

if (pixy.ccc.numBlocks > 0)

Which should run at an uninhibited speed as long as blocks are present. But nope…still runs just as slow. I am going to write up a super basic program that just times getBlocks with the false or default parameters. I still think that pixy.ccc.getBlocks(false) simply does not work. That would explain every issue I have had.

Has anyone used pixy.ccc.getBlocks(false)? Am I using it correctly to modify the “wait” feature? Nothing changes in terms of how the code functions when the false is used, which seems odd.

I won’t be able to test this until tomorrow unfortunately.

I got it working!

I did not quite understand your suggestion Edge but I think I have implemented it correctly now.

void loop()
{
  // grab blocks!
  result = pixy.ccc.getBlocks(false);

  if (result < 0) //no new postion data so move steppers based on prior location data
  {

    if (targetX < 150) //get x coordinate of block 0 and check its location from center
    {
      digitalWrite(dirPin, LOW  );
      digitalWrite(stepPin, HIGH);
      delayMicroseconds(Speed);
      digitalWrite(stepPin, LOW);
      delayMicroseconds(Speed);
    }
    if (targetX > 165)
    {
      digitalWrite(dirPin, HIGH);
      digitalWrite(stepPin, HIGH);
      delayMicroseconds(Speed);
      digitalWrite(stepPin, LOW);
      delayMicroseconds(Speed);
    }
    if (targetY < 96) //get y coordinate of block 0 and check its location from center
    {
      digitalWrite(dirPiny, LOW);
      digitalWrite(stepPiny, HIGH);
      delayMicroseconds(Speed);
      digitalWrite(stepPiny, LOW);
      delayMicroseconds(Speed);
    }
    if (targetY > 111)
    {
      digitalWrite(dirPiny, HIGH);
      digitalWrite(stepPiny, HIGH);
      delayMicroseconds(Speed);
      digitalWrite(stepPiny, LOW);
      delayMicroseconds(Speed);
    }
  }
  else //update location of target based on new data from Pixy
  {
    targetX = pixy.ccc.blocks[0].m_x;
    targetY = pixy.ccc.blocks[0].m_y;
  }
}

My best guess is that when I was checking locations with pixy.ccc.blocks[0].m_x that it was returning an error when no new location data existed. So saving location data to a variable and only updating it when new data arrives solves the problem. I think lol

Whatever the problem was it is working now as intended. Thank you all for the assistance!

Brad

1 Like

It’s an advanced piece of code and it looks great :slight_smile: Congrats on getting it working!

Edward

What I did not fully understand is that it returns the same value for no target and no new data. I assumed that it would give me the most recent data. So I need to save the one instance where new data is present and then do stuff with it. It does still cause some issues when I am trying to determine if there is no target, but I can make sure that it waits 20ms before verifying that there is no target.

If this understanding is incorrect please let me know but it seems to work when I code it with that assumption.

Thanks
Brad

If you pass in false for the wait argument, it returns 0 for no targets and returns PIXY_RESULT_BUSY (-2) if there is no new data. (and it returns the number of detected targets if it detects objects for that frame.)

Hope this helps.

Edward

1 Like

Thank you edge, that is hugely helpful. With that information I can simply check for a return of 0 to indicate no targets present. That will make things much easier. This is a great community!

1 Like