<< return to Pixycam.com

Question about running Pan/Tilt onboard Pixy

My basic question is when the Pixy runs the Pan/Tilt program instead of the default, is there any way of pulling from the pins whether or not the pixy sees the object? I want the pixy to handle the PD and gimbal control and simply tell my microcontroller if it sees the object at all.

The above is the TL;DR ^, below is just some context.

To give a little more context (because I’m always open to ideas), I’m using a propeller board instead of an arduino, and although I’ve managed to get the two communicating over SPI, it seems as thought my ability to reliably see the object is finicky. Part of the reason it is or isn’t able to see blocks depends on the loop time, and each loop iteration sometimes takes vastly different amounts of time to run (between 10-35ms, even though it should not be able to run faster than 20ms (50Hz)). If I run each loop using a “pause(15);” at the end, it seems to work better than if I use “pause(20);” or any other time that I’ve tried for that matter - faster or slower! If I use an empty while loop at the end of each main loop iteration to wait until 20ms has passed, it works even worse.

Furthermore, I have to dedicate resources (an extra cog and pins) on the propeller chip that I would prefer to just have the pixy handle and therefore not bog down my microcontroller.

Any insights as to how I can pull whether the object is seen mid pan tilt program run or as to why my acquisition of the object location is unreliable would be greatly appreciated.

Hello John,
The pan/tilt demo is just supposed to be a way to test the pan/tilt mechanism, and it wasn’t intended to communicate over SPI, or other serial interface, although this is something we might consider.

It sounds like maybe getting the communications working better might be worthwhile. What about detecting new frames, the two start codes back-to-back? Can you reliably detect these?

Edward

I agree with the working on communications suggestion. I have managed to improve things slightly by working on the loop timing. An example of the type of capturing of the object is attached (and attempted to be inline) below.

!signal_reliability_example.PNG!

What this shows is the time in ms (y-axis) between captures of blocks. This data is (unfortunately due to communication limitations) transmitted every 50ms (from a different core of the processor, so it is not interfering with this loop), so there are certainly missing data points in between, but for the most part, this should be rather descriptive. As you can see, there are periods where the propeller board is able to read a block every 31 ms, and sometimes at 71 ms at regular intervals. This leads me to suspect there is a framing issue with communication. Furthermore, if the Pixy gets a new block at 50hz, there should be new data every ~20ms, not 31.

I included my main loop for the pixy to see if that helps you understand my implementation.

  while(1){
    pixy_get_block(1);
    if(blockCount){ //if block found, assign errors
      xErr = (int) (-blocks[0].x+319/2);
      yErr = (int) (-blocks[0].y+199/2);
      camTimer = (int) (CNT-timer)/80000; //record time since last block seen in ms
      timer = CNT; //record clock cycle at which last block was seen
      pause(10);
    }
    if((CNT-timer)/80000>1000){ //if the amount of time since the object was last seen > 1s, reset position to 0.
      xErr = 0;
      yErr = 0;
      panPID.Reset();
      tiltPID.Reset();
    }          
    if((CNT-constTransTimer)/80000>50){  //If 50ms have elapsed, calculate loops and transmit data
      PanOut = panPID.Calculate( xErr, 0, 1); //calculate pwm for servos
      TiltOut = tiltPID.Calculate( -yErr, 0, 1);
      constTransTimer = CNT;
      camUpdate = 1; //Tell other core to send current data.
    }    

  //Control servo gimbals (map pitch and roll imu values to pwm*8 for servos)
  Servo32_Set(PIN_MOTOR_AUX1,PanOut+8000);
  Servo32_Set(PIN_MOTOR_AUX2,TiltOut+8000);      
  }

Hello John,
I’m not sure what is happening with your SPI communications. I agree that 31ms is a weird number. It’s half of 60ms, so if for whatever reason, 1/3 of the frames were being missed, you’d get an average of 30ms between frames. Since SPI is a master/slave link, it is also possible to get any framerate out of Pixy, if the SPI reads are delayed, for example. This might explain the 31ms. I’m just speculating.

Do you have an Arduino you can use to compare against?

Edward

So I tried it with sending all data (instead of 1/3 or 1/4) and I was able to get a good sample to show you, so the following graphs are with all data (no aliasing).

First I tested the camera using the arduino. The data was very clean and is shown in the figure below. (x axis is sample number, y axis is ms between detected blocks for all graphs)

CORRECTION: This first graph shows Hz on the y-axis. The next 2 are in ms on the y-axis.

!ArduinoSignalQuality.png!

Here is the same test using the current parallax code as I have it (and is shown in my code in reply above).

!ParallaxPortSignalQuality.png!

Lastly, I figured I’d test an older version of the code to see how well that one works in comparison. I changed it because the old version had limited timing control. This version of the main loop for running the Pixy is shown below.

while(1){
pixyTimer = CNT;
pixy_get_block(5);
if(blockCount){
xErrs[xyErrsPlace] = (int) (blocks[0].x-319/2);
yErrs[xyErrsPlace] = (int) (-blocks[0].y+199/2);
xErr = 0;
yErr = 0;
for(char i = 0; i<numCamSamples; i++){
xErr ++= xErrs[i];
yErr += yErrs[i];
}
xyErrsPlace+++;
if(xyErrsPlace == numCamSamples)
xyErrsPlace = 0;
dataCNT++;
noDataCNT = 0;
camTimer = (int) (CNT)/80000;
camUpdate = 1;
}

else if(noDataCNT>10){
    memset(xErrs,0,sizeof(xErrs));
    memset(yErrs,0,sizeof(yErrs));
    xErr = 0;
    yErr = 0;
}
else{
  dataCNT = 0;
    noDataCNT++;
}
loopCnt++;

if(loopCnt == 3){
    loopCnt = 0;
}
pause(15);

}

The result from this version was much better (though still not quite as good as with the arduino) and is shown below:

!ParallaxPortSignalQuality_v2.png!

Between these 2 versions, none of the functions called for communicating with the pixy were changed.

Wow, that’s a lot of data! One thing I don’t understand though is the 50ish milliseconds between frames with the Arduino. If you run the hello_world example, it indicates 50 frames per second from Pixy.

Edward

Sorry, but that was an error. I added a correction to my message saying that for that graph specifically which is that it is not 50 ms, but 50hz, so it is actually 20ms between messages. The other 2 graphs are correct in that the y-axis for those graphs is in ms.