motion tracking camera using servos

I'm trying to make a motion tracking camera using a CMUcam5 Pixy with servos controlled by the arduino rather than the pixy itself.

The pixy works by finding groups of pixels of the same color and drawing a box around it. It then gives values for the center in x,y coordinates called "pixy.blocks[j].x" and "pixy.blocks[j].y". I'm starting with the x axis only first. The pixy gives x coordinate from 0 to 319 pixels so I'm first scaling them to -90 to 90 degrees and then trying to add that scaled value to the servo's position variable which starts at 90.

For example, let's say the box is left of center at 80 pixels, it gets scaled to -45 which is added to the servo position at home (90). The servo (nicknamed xaxis) should move as if you said xaxis.write (45).

Instead the servo wants to jump to one of its limits and stay there. I have also tried to program it such that it simply adds or subtracts a number to the position variable depending on whether the tracked object is left or right of center, but small numbers make it track way too slowly and large numbers make it overshoot back and forth.

Does anyone have an idea of how to get the camera to track smoothly?

here's my current code;

#include <Servo.h>
Servo yaxis;
Servo xaxis;  
#include <SPI.h>  
#include <Pixy.h>
int xpos = 90;
// This is the main Pixy object 
Pixy pixy;

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

  yaxis.attach (9);
  xaxis.attach (10);

  pixy.init();
}

void loop()
{ 
  static int i = 0;
  int j;
  uint16_t blocks;
  char buf[32];   
  int  x= ((pixy.blocks[j].x*.5625)-90); // scale pixels to +/- 90 degrees
  
  // grab blocks!
  blocks = pixy.getBlocks();
  
  // If there are detect blocks, print them!
  if (blocks)
  {
    i++;
    
    // do this (print) every 20 frames because printing every
    // frame would bog down the Arduino
    if (i%20==0)
    {
      
      sprintf(buf, "Detected %d:\n", blocks);
      Serial.print(buf); 
      for (j=0; j<blocks; j++)
      {
        sprintf(buf, "  block %d: ", j);
        Serial.print(buf); 
        pixy.blocks[j].print();    // prints x and y coordinates of blocks
      
        xpos+=x;                    // change servo position variable
        xaxis.write (xpos);       //move servo to position
        
        }

      }
    }
  }
  int j;
  uint16_t blocks;
  char buf[32];   
  int  x= ((pixy.blocks[j].x*.5625)-90);

Tell me about the value of j

AWOL:

Tell me about the value of j

j is just the number of objects that the camera is picking up. I'm only working with one object so j is just 1.

When does 'j' get the value 1?

It looks like you are processing every block and moving the servo as if each was the only block found. That would move the servo very quickly if multiple blocks were detected. Pick one. The largest? The one closest to the center?

Also note: Unless the camera has a 180-degree field of view you are greatly overestimating how far the camera should move. Figure out the actual angle of view and use that instead of +/- 90.

johnwasser:
Unless the camera has a 180-degree field of view you are greatly overestimating how far the camera should move. Figure out the actual angle of view and use that instead of +/- 90.

That was the problem, thanks! The camera has a field of view of only 105 degrees so I changed it to that and that fixed it. It was still overshooting a bit so I reduced it by half and that has helped it's tracking a lot.

Raxius,

I am trying to do something very similar to you. Would you mind posting your most updated functional code?

I tried using your old code and modifying the

int x= ((pixy.blocks[j].x*.5625)-90);

line of it however the servo would still jump to one side and stay there.

Any help would be greatly appreciated.