<< return to Pixycam.com

Moving the servos properly in my pan-tilt mechanism

I have made my own pan-tilt by supergluing two of those cheap 9g servos together and used another 9g servo simply as a 90 degree support (see picture below).

I have got pixy moving when it sees a yellow tennis ball, however it seems scared when it tries to look at the ball. Vertically, it is head-thrashing quite vigorously like at a death metal concert whilst maintaining correct height on average. Horizontally, it is very confused.

What I have attempted to do is combine the hello world (Arduino) example with the code for operating 2 servos found at
http://www.robotoid.com/appnotes/arduino-operating-two-servos.html.

The hello world example tells me that the centre detection positions of pixy are horizontally, 0 to about 320 (left to right) and vertically 0 to 199 (up to down), whereas testing the servos previously I found they point in my preferred way horizontally 180 to 0 (left to right) and vertically 30 to 130 (up to down). In an attempt to scale the pixy coordinates to approximately match the servos I included the following calcs in the part of the code where it tells the servo where to move to.

Vertical: servo y value will be = 30+pixy/2
Horizontal: servo x value will be = pixy/-2

Therefore, I have the following two lines of code:
servoVert.write(30+(pixy.blocks[j].y)/2);
servoHori.write((pixy.blocks[j].x)/-2);

The code on the robotoid site that I modified was:
servoLeft.write(0);
servoRight.write(180);

Maybe this modification is just totally the wrong way to code. I also realise that as Pixy turns, the coordinates that it detects will change. Maybe that is the source of the erraticism? I didn’t want to buy the Pixy pan-tilt mechanism yet because this is a challenge I wanted to do. Would somebody know how to fix this please. Maybe a whole different approach? Pixy is getting tired.

You can see in the full code below that I combined parts of the robotoid 2 servo code with Hello World.

// http://cmucam.org/projects/cmucam5/wiki/Hooking_up_Pixy_to_a_Microcontroller_(like_an_Arduino)
//
// It prints the detected blocks once per second because printing all of the
// blocks for all 50 frames per second would overwhelm the Arduino’s serial port.
//

#include <SPI.h>
#include <Pixy.h>

// This is the main Pixy object
Pixy pixy;

// **********************************************************************
//from http://www.robotoid.com/appnotes/arduino-operating-two-servos.html
#include <Servo.h>
Servo servoVert; // Define vertical servo
Servo servoHori; // Define horizontal servo
// **********************************************************************

void setup()
{

// **********************************************************************
//from http://www.robotoid.com/appnotes/arduino-operating-two-servos.html
servoVert.attach(10); // Set left servo to digital pin 10
servoHori.attach(9); // Set right servo to digital pin 9
// **********************************************************************

Serial.begin(9600);
Serial.print(“Starting…\n”);

pixy.init();
}

void loop()
{
static int i = -90;
int j;
uint16_t blocks;
char buf[32];

// grab blocks!
blocks = pixy.getBlocks();

// If there are detect blocks, print them!
if (blocks)
{
i++;

// **********************************************************************
//from http://www.robotoid.com/appnotes/arduino-operating-two-servos.html
// If there are detect blocks, move servos!
{
servoVert.write(30+(pixy.blocks[j].y)/2);
servoHori.write((pixy.blocks[j].x)/-2);
}
// **********************************************************************

    // do this (print) every 50 frames because printing every
// frame would bog down the Arduino
if (i%50==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();
  }
}

}
}

Hello Boyd,
Using the center pixel (160 horizontal and 100 vertical) is probably best because you want Pixy to look directly at your tennis ball, instead of to the side.

The pan/tilt example for Arduino uses two PD (proportional-derivative) control loops. These are great, but 2 things need to be correct for them to work well.

  1. The sign needs to be correct. In other words, when you calculate the error that goes into the PD calculation, will it send the servo away from where you want the servo to go (incorrect), or toward where you want the servo to go (correct). It sounds like maybe your horizontal servo has the wrong sign. You might try inverting the error. Something like error = -error.

  2. The Proportional and Derivative gains need to be well-adjusted. Try setting all of your gains to 0 for both the pan and tilt axes and then try slowly increasing the Proportional gains. The pan/tilt will move slowly, but at least it won’t vibrate (like what you describe the tilt motion doing). You can then try increasing the Proportional gain until you get the behavior you want.

This page has some good info on setting gains:

cmucam.org/projects/cmucam5/wiki/LEGO_Chase_Demo

See the section “Some notes on adjusting the PID gains”

Hope this helps!

Edward