Let's Make Robots!

Face Tracking with Processing and Arduino

I was wondering if anyone can help me with my code. So I am using my camera on my macbook pro. In processing, the tracking software works almost perfectly, I am using opencv. Then through serial the coordinates of my face are supposed to be translated to servo commands and sent to the arduino. I am getting movement with the servo, but it is only jitters. Any help is well appreciated. 

Processing Code:

 

import hypermedia.video.*;

import java.awt.Rectangle;

import processing.serial.*;        

 

 

int gx = 15;

int gy = 35;

int spos=90;

 

Serial port; 

 

OpenCV opencv;

 

// contrast/brightness values

int contrast_value    = 0;

int brightness_value  = 0;

 

 

 

void setup() {

 

    size( 320, 240 );

 

    opencv = new OpenCV( this );

    opencv.capture( width, height );                   // open video stream

    opencv.cascade( OpenCV.CASCADE_FRONTALFACE_ALT );  // load detection description, here-> front face detection : "haarcascade_frontalface_alt.xml"

 

    // print usage

    println( "Drag mouse on X-axis inside this sketch window to change contrast" );

    println( "Drag mouse on Y-axis inside this sketch window to change brightness" );

 

 println(Serial.list());

 port = new Serial(this, Serial.list()[1], 9600);

}

 

 

public void stop() {

    opencv.stop();

    super.stop();

}

 

 

 

void draw() {

 

    // grab a new frame

    // and convert to gray

    opencv.read();

    opencv.convert( RGB );

    opencv.contrast( contrast_value );

    opencv.brightness( brightness_value );

 

    // proceed detection

    Rectangle[] faces = opencv.detect( 1.2, 2, OpenCV.HAAR_DO_CANNY_PRUNING, 40, 40 );

 

    // display the image

    image( opencv.image(), 0, 0 );

 

    // draw face area(s)

    noFill();

    stroke(255,1,1);

    for( int i=0; i<faces.length; i++ ) {

        rect( faces[i].x, faces[i].y, faces[i].width, faces[i].height ); 

    }

    for( int i=0; i<faces.length; i++ ) {

        update( faces[i].x); 

    }

 

}

 

 

 

/**

 * Changes contrast/brigthness values

 */

void mouseDragged() {

    contrast_value   = (int) map( mouseX, 0, width, -128, 128 );

    brightness_value = (int) map( mouseY, 0, width, -128, 128 );

}

void update(int x) 

{

  //Calculate servo postion from mouseX

  spos= x/30;

 

  //Output the servo position ( from 0 to 180)

  port.write(spos + "a"); 

    gx = x/80;

  gy = 100-x/120;

}

 

 

Arduino Code:

 

#include <Servo.h>

 

Servo neck;

 

int xPos=0;

int yPos = 0;

 

void setup()  {

  Serial.begin(9600);

  neck.attach(9);

}

 

void loop()  {

  if(Serial.available() >0)  {

    xPos=Serial.read();

    yPos=Serial.read();

  }

  int xServo = map(xPos, 0, 320, 20, 70);

  int yServo = map(yPos, 0, 240, 20, 70);

  neck.write(xServo);

  Serial.println("testing....");  

 

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Is it possible that you are transmitting ASCII from processing, and trying to apply an ASCII code for say 12 instead of the binary value for 12?

if the servo is jittering back and forth then you may be over corecting in your code. Try adjusting the servo position by smaller amounts.

Then I would upload the example servo sweep code just to verify that it not the servo that has the problem.

 

// Sweep
// by BARRAGAN <http://barraganstudio.com
// This example code is in the public domain.


#include <Servo.h> 
 
Servo myservo;  // create servo object to control a servo 
                // a maximum of eight servo objects can be created 
 
int pos = 0;    // variable to store the servo position 
 
void setup() 
{ 
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object 
} 
 
 
void loop() 
{ 
  for(pos = 0; pos < 180; pos += 1)  // goes from 0 degrees to 180 degrees 
  {                                  // in steps of 1 degree 
    myservo.write(pos);              // tell servo to go to position in variable 'pos' 
    delay(15);                       // waits 15ms for the servo to reach the position 
  } 
  for(pos = 180; pos>=1; pos-=1)     // goes from 180 degrees to 0 degrees 
  {                                
    myservo.write(pos);              // tell servo to go to position in variable 'pos' 
    delay(15);                       // waits 15ms for the servo to reach the position 
  } 
} 

I uploaded the code and there is no problem with the servo. I know this for sure because I used two servos and I had the same problem with both.

Then it’s your program that needs a bit of tuning. The problem might be that you are updating the servos too often. One thing you might try is to store the last servo position in a variable and if the new position is the same as the old one, don’t update the servo position, else do a neck.write

When I try and look at the serial mointor while I am running the processing program, I get an error from arduino saying "processing.app.SerialException: Serial port '/dev/tty.usbmodemfd121' already in use."

So is there any other way I can check it out what the variable is reading while the processing program is running?

I think that you misunderstand me. Use your original program and do the reading from the serial as you are doing. But before you send the new servo position with the neck.write, check the new value against the stored value and if they are different, then change the servo position. Else just read the next value from the serial and do another compare…

The first question might be, how are you powering your servo? If your relaying on the USB power, that might not be enough. So either add a different power source for the servo or try adding 9V to the Arduino power jack.

You might also add a delay(20); after the neck.write command to give the servo time to reach the position.

Now while testing it would be smart to print the value for xServo to see that you get the correct values.

 

Thank you for the fast reply,

I added the 9v, didnt change the outcome. I added the 20 milisecond delay, it is less "jittery" but it still doesnt accomplish the actual face tracking. I also added the serial print command for xServo, but I cant watch it because it intervers with the proccessing code. 

 

serial write , insted of print :) sounds like a cool project