Have you ever seen the movies where people control robot just by waving hands?
Maybe it is not too complex to do it yourself.
In this project, I am going show you how to use PHPoC to control Pan-Tilt via hand gesture.

Demo



Hardware components:

PHPoC Blue × 1
Grove Gesture Sensor × 1
Pan-Tilt Kit × 1
PHPoC Grove Expansion Board × 1
PHPoC PWM & Sensor Expansion Board × 1
Battery Holder × 1 ( I used battery to supply external voltage source for Pan-Tilt motors)


Wiring

+ Stack PHPoC- Grove Expansion board and PHPoC- PWM & Sensor Expansion board to PHPoC Blue
+ Connect Gesture Sensor to PHPoC Blue via I2C interface
+ Connect two Pan-Tilt motors to PHPoC Blue via HT0 and HT1 connectors
+ Connect external source (battery holder) to PHPoC- PWM & Sensor Expansion board

The sensor and servo motors can be directly wired to PHPoC Blue, but here I used PHPoC expansion boards for neat-looking wiring.

Click image for larger version  Name:	1.jpg Views:	19 Size:	38.7 KB ID:	588

Click image for larger version  Name:	2.jpg Views:	7 Size:	39.6 KB ID:	589

Click image for larger version  Name:	3.jpg Views:	10 Size:	32.8 KB ID:	590


Data Flow

Gesture sensor ---> PHPoC ---> Pan-Tilt motors

The data flow is simple: PHPoC continuously reads data from gesture sensor and sends the command to Pan-Tilt motors.

For demonstration in this project, I only retrieve four different hand gestures (right, left, up, down). Note that the sensor allows more gestures to be recognized, so it could be much more fun if you can use other gestures to control robot. Based on detected gestures, PHPoC will send the command to control the servo motors on Pan-Tilt, makes the direction of Pan-Tilt changes accordingly.

Source Code

Source code includes two files:

gesture_PAJ7620.php: This file contains library for Grove gesture sensor.

PHP Code:
<?php


include_once "/lib/sd_340.php";

// PHPoC I2C ID
define ("I2C_ID",   0);

// Define command value for exchanging data with PHPoC
define("CMD_LEFT"1);
define("CMD_RIGHT"2);
define("CMD_DOWN"3);
define("CMD_UP"4);


define ("PAJ7620_ADDR_BASE",   0x00);
define ("PAJ7620_REGITER_BANK_SEL",   (PAJ7620_ADDR_BASE 0xEF));  

// Device ID
define ("PAJ7620_ID",  0x73);

// Register bank 0
define ("PAJ7620_ADDR_SUSPEND_CMD",         (PAJ7620_ADDR_BASE 0x3));  
define ("PAJ7620_ADDR_GES_PS_DET_MASK_0",   (PAJ7620_ADDR_BASE 0x41));  
define ("PAJ7620_ADDR_GES_PS_DET_MASK_1",   (PAJ7620_ADDR_BASE 0x42));  
define ("PAJ7620_ADDR_GES_PS_DET_FLAG_0",   (PAJ7620_ADDR_BASE 0x43));  
define ("PAJ7620_ADDR_GES_PS_DET_FLAG_1",   (PAJ7620_ADDR_BASE 0x44));  
define ("PAJ7620_ADDR_STATE_INDICATOR",      (PAJ7620_ADDR_BASE 0x45));  
define ("PAJ7620_ADDR_PS_HIGH_THRESHOLD",   (PAJ7620_ADDR_BASE 0x69));
define ("PAJ7620_ADDR_PS_LOW_THRESHOLD",   (PAJ7620_ADDR_BASE 0x6A));  
define ("PAJ7620_ADDR_PS_APPROACH_STATE",   (PAJ7620_ADDR_BASE 0x6B));
define ("PAJ7620_ADDR_PS_RAW_DATA",         (PAJ7620_ADDR_BASE 0x6C));

// Register bank 1
define ("PAJ7620_ADDR_PS_GAIN",               (PAJ7620_ADDR_BASE 0x44));
define ("PAJ7620_ADDR_IDLE_S1_STEP_0",      (PAJ7620_ADDR_BASE 0x67));  
define ("PAJ7620_ADDR_IDLE_S1_STEP_1",      (PAJ7620_ADDR_BASE 0x68));  
define ("PAJ7620_ADDR_IDLE_S2_STEP_0",      (PAJ7620_ADDR_BASE 0x69));  
define ("PAJ7620_ADDR_IDLE_S2_STEP_1",      (PAJ7620_ADDR_BASE 0x6A));  
define ("PAJ7620_ADDR_OP_TO_S1_STEP_0",      (PAJ7620_ADDR_BASE 0x6B));  
define ("PAJ7620_ADDR_OP_TO_S1_STEP_1",      (PAJ7620_ADDR_BASE 0x6C));  
define ("PAJ7620_ADDR_OP_TO_S2_STEP_0",      (PAJ7620_ADDR_BASE 0x6D));  
define ("PAJ7620_ADDR_OP_TO_S2_STEP_1",      (PAJ7620_ADDR_BASE 0x6E));
define ("PAJ7620_ADDR_OPERATION_ENABLE",   (PAJ7620_ADDR_BASE 0x72));  


define ("PAJ7620_BANK0",   0x00);
define ("PAJ7620_BANK1",   0x01);


define ("PAJ7620_I2C_WAKEUP",   0x01);
define ("PAJ7620_I2C_SUSPEND",   0x00);


define ("PAJ7620_ENABLE",      0x01);
define ("PAJ7620_DISABLE",      0x00);


define ("GES_RIGHT_FLAG",         0x01);
define ("GES_LEFT_FLAG",         0x02);
define ("GES_UP_FLAG",            0x04);
define ("GES_DOWN_FLAG",         0x08);
define ("GES_FORWARD_FLAG",         0x10);
define ("GES_BACKWARD_FLAG",      0x20);
define ("GES_CLOCKWISE_FLAG",      0x40);
define ("GES_COUNT_CLOCKWISE_FLAG",   0x80);
define ("GES_WAVE_FLAG",         0x01);

define ("BANK0",   0);
define ("BANK1",   1);

define ("GES_REACTION_TIME",   500);        
define ("GES_ENTRY_TIME",      800);  
define ("GES_QUIT_TIME",      1000);

function 
paj7620_write_reg($addr$cmd)
{
   
i2c_write(I2C_ID, ($addr&0xFF)|(($cmd&0xFF)<<8),2);
}

function 
init_register()
{
   
paj7620_write_reg(0xEF,0x00);
   
paj7620_write_reg(0x32,0x29);
   
paj7620_write_reg(0x33,0x01);
   
paj7620_write_reg(0x34,0x00);
   
paj7620_write_reg(0x35,0x01);
   
paj7620_write_reg(0x36,0x00);
   
paj7620_write_reg(0x37,0x07);
   
paj7620_write_reg(0x38,0x17);
   
paj7620_write_reg(0x39,0x06);
   
paj7620_write_reg(0x3A,0x12);
   
paj7620_write_reg(0x3F,0x00);
   
paj7620_write_reg(0x40,0x02);
   
paj7620_write_reg(0x41,0xFF);
   
paj7620_write_reg(0x42,0x01);
   
paj7620_write_reg(0x46,0x2D);
   
paj7620_write_reg(0x47,0x0F);
   
paj7620_write_reg(0x48,0x3C);
   
paj7620_write_reg(0x49,0x00);
   
paj7620_write_reg(0x4A,0x1E);
   
paj7620_write_reg(0x4B,0x00);
   
paj7620_write_reg(0x4C,0x20);
   
paj7620_write_reg(0x4D,0x00);
   
paj7620_write_reg(0x4E,0x1A);
   
paj7620_write_reg(0x4F,0x14);
   
paj7620_write_reg(0x50,0x00);
   
paj7620_write_reg(0x51,0x10);
   
paj7620_write_reg(0x52,0x00);
   
paj7620_write_reg(0x5C,0x02);
   
paj7620_write_reg(0x5D,0x00);
   
paj7620_write_reg(0x5E,0x10);
   
paj7620_write_reg(0x5F,0x3F);
   
paj7620_write_reg(0x60,0x27);
   
paj7620_write_reg(0x61,0x28);
   
paj7620_write_reg(0x62,0x00);
   
paj7620_write_reg(0x63,0x03);
   
paj7620_write_reg(0x64,0xF7);
   
paj7620_write_reg(0x65,0x03);
   
paj7620_write_reg(0x66,0xD9);
   
paj7620_write_reg(0x67,0x03);
   
paj7620_write_reg(0x68,0x01);
   
paj7620_write_reg(0x69,0xC8);
   
paj7620_write_reg(0x6A,0x40);
   
paj7620_write_reg(0x6D,0x04);
   
paj7620_write_reg(0x6E,0x00);
   
paj7620_write_reg(0x6F,0x00);
   
paj7620_write_reg(0x70,0x80);
   
paj7620_write_reg(0x71,0x00);
   
paj7620_write_reg(0x72,0x00);
   
paj7620_write_reg(0x73,0x00);
   
paj7620_write_reg(0x74,0xF0);
   
paj7620_write_reg(0x75,0x00);
   
paj7620_write_reg(0x80,0x42);
   
paj7620_write_reg(0x81,0x44);
   
paj7620_write_reg(0x82,0x04);
   
paj7620_write_reg(0x83,0x20);
   
paj7620_write_reg(0x84,0x20);
   
paj7620_write_reg(0x85,0x00);
   
paj7620_write_reg(0x86,0x10);
   
paj7620_write_reg(0x87,0x00);
   
paj7620_write_reg(0x88,0x05);
   
paj7620_write_reg(0x89,0x18);
   
paj7620_write_reg(0x8A,0x10);
   
paj7620_write_reg(0x8B,0x01);
   
paj7620_write_reg(0x8C,0x37);
   
paj7620_write_reg(0x8D,0x00);
   
paj7620_write_reg(0x8E,0xF0);
   
paj7620_write_reg(0x8F,0x81);
   
paj7620_write_reg(0x90,0x06);
   
paj7620_write_reg(0x91,0x06);
   
paj7620_write_reg(0x92,0x1E);
   
paj7620_write_reg(0x93,0x0D);
   
paj7620_write_reg(0x94,0x0A);
   
paj7620_write_reg(0x95,0x0A);
   
paj7620_write_reg(0x96,0x0C);
   
paj7620_write_reg(0x97,0x05);
   
paj7620_write_reg(0x98,0x0A);
   
paj7620_write_reg(0x99,0x41);
   
paj7620_write_reg(0x9A,0x14);
   
paj7620_write_reg(0x9B,0x0A);
   
paj7620_write_reg(0x9C,0x3F);
   
paj7620_write_reg(0x9D,0x33);
   
paj7620_write_reg(0x9E,0xAE);
   
paj7620_write_reg(0x9F,0xF9);
   
paj7620_write_reg(0xA0,0x48);
   
paj7620_write_reg(0xA1,0x13);
   
paj7620_write_reg(0xA2,0x10);
   
paj7620_write_reg(0xA3,0x08);
   
paj7620_write_reg(0xA4,0x30);
   
paj7620_write_reg(0xA5,0x19);
   
paj7620_write_reg(0xA6,0x10);
   
paj7620_write_reg(0xA7,0x08);
   
paj7620_write_reg(0xA8,0x24);
   
paj7620_write_reg(0xA9,0x04);
   
paj7620_write_reg(0xAA,0x1E);
   
paj7620_write_reg(0xAB,0x1E);
   
paj7620_write_reg(0xCC,0x19);
   
paj7620_write_reg(0xCD,0x0B);
   
paj7620_write_reg(0xCE,0x13);
   
paj7620_write_reg(0xCF,0x64);
   
paj7620_write_reg(0xD0,0x21);
   
paj7620_write_reg(0xD1,0x0F);
   
paj7620_write_reg(0xD2,0x88);
   
paj7620_write_reg(0xE0,0x01);
   
paj7620_write_reg(0xE1,0x04);
   
paj7620_write_reg(0xE2,0x41);
   
paj7620_write_reg(0xE3,0xD6);
   
paj7620_write_reg(0xE4,0x00);
   
paj7620_write_reg(0xE5,0x0C);
   
paj7620_write_reg(0xE6,0x0A);
   
paj7620_write_reg(0xE7,0x00);
   
paj7620_write_reg(0xE8,0x00);
   
paj7620_write_reg(0xE9,0x00);
   
paj7620_write_reg(0xEE,0x07);
   
paj7620_write_reg(0xEF,0x01);
   
paj7620_write_reg(0x00,0x1E);
   
paj7620_write_reg(0x01,0x1E);
   
paj7620_write_reg(0x02,0x0F);
   
paj7620_write_reg(0x03,0x10);
   
paj7620_write_reg(0x04,0x02);
   
paj7620_write_reg(0x05,0x00);
   
paj7620_write_reg(0x06,0xB0);
   
paj7620_write_reg(0x07,0x04);
   
paj7620_write_reg(0x08,0x0D);
   
paj7620_write_reg(0x09,0x0E);
   
paj7620_write_reg(0x0A,0x9C);
   
paj7620_write_reg(0x0B,0x04);
   
paj7620_write_reg(0x0C,0x05);
   
paj7620_write_reg(0x0D,0x0F);
   
paj7620_write_reg(0x0E,0x02);
   
paj7620_write_reg(0x0F,0x12);
   
paj7620_write_reg(0x10,0x02);
   
paj7620_write_reg(0x11,0x02);
   
paj7620_write_reg(0x12,0x00);
   
paj7620_write_reg(0x13,0x01);
   
paj7620_write_reg(0x14,0x05);
   
paj7620_write_reg(0x15,0x07);
   
paj7620_write_reg(0x16,0x05);
   
paj7620_write_reg(0x17,0x07);
   
paj7620_write_reg(0x18,0x01);
   
paj7620_write_reg(0x19,0x04);
   
paj7620_write_reg(0x1A,0x05);
   
paj7620_write_reg(0x1B,0x0C);
   
paj7620_write_reg(0x1C,0x2A);
   
paj7620_write_reg(0x1D,0x01);
   
paj7620_write_reg(0x1E,0x00);
   
paj7620_write_reg(0x21,0x00);
   
paj7620_write_reg(0x22,0x00);
   
paj7620_write_reg(0x23,0x00);
   
paj7620_write_reg(0x25,0x01);
   
paj7620_write_reg(0x26,0x00);
   
paj7620_write_reg(0x27,0x39);
   
paj7620_write_reg(0x28,0x7F);
   
paj7620_write_reg(0x29,0x08);
   
paj7620_write_reg(0x30,0x03);
   
paj7620_write_reg(0x31,0x00);
   
paj7620_write_reg(0x32,0x1A);
   
paj7620_write_reg(0x33,0x1A);
   
paj7620_write_reg(0x34,0x07);
   
paj7620_write_reg(0x35,0x07);
   
paj7620_write_reg(0x36,0x01);
   
paj7620_write_reg(0x37,0xFF);
   
paj7620_write_reg(0x38,0x36);
   
paj7620_write_reg(0x39,0x07);
   
paj7620_write_reg(0x3A,0x00);
   
paj7620_write_reg(0x3E,0xFF);
   
paj7620_write_reg(0x3F,0x00);
   
paj7620_write_reg(0x40,0x77);
   
paj7620_write_reg(0x41,0x40);
   
paj7620_write_reg(0x42,0x00);
   
paj7620_write_reg(0x43,0x30);
   
paj7620_write_reg(0x44,0xA0);
   
paj7620_write_reg(0x45,0x5C);
   
paj7620_write_reg(0x46,0x00);
   
paj7620_write_reg(0x47,0x00);
   
paj7620_write_reg(0x48,0x58);
   
paj7620_write_reg(0x4A,0x1E);
   
paj7620_write_reg(0x4B,0x1E);
   
paj7620_write_reg(0x4C,0x00);
   
paj7620_write_reg(0x4D,0x00);
   
paj7620_write_reg(0x4E,0xA0);
   
paj7620_write_reg(0x4F,0x80);
   
paj7620_write_reg(0x50,0x00);
   
paj7620_write_reg(0x51,0x00);
   
paj7620_write_reg(0x52,0x00);
   
paj7620_write_reg(0x53,0x00);
   
paj7620_write_reg(0x54,0x00);
   
paj7620_write_reg(0x57,0x80);
   
paj7620_write_reg(0x59,0x10);
   
paj7620_write_reg(0x5A,0x08);
   
paj7620_write_reg(0x5B,0x94);
   
paj7620_write_reg(0x5C,0xE8);
   
paj7620_write_reg(0x5D,0x08);
   
paj7620_write_reg(0x5E,0x3D);
   
paj7620_write_reg(0x5F,0x99);
   
paj7620_write_reg(0x60,0x45);
   
paj7620_write_reg(0x61,0x40);
   
paj7620_write_reg(0x63,0x2D);
   
paj7620_write_reg(0x64,0x02);
   
paj7620_write_reg(0x65,0x96);
   
paj7620_write_reg(0x66,0x00);
   
paj7620_write_reg(0x67,0x97);
   
paj7620_write_reg(0x68,0x01);
   
paj7620_write_reg(0x69,0xCD);
   
paj7620_write_reg(0x6A,0x01);
   
paj7620_write_reg(0x6B,0xB0);
   
paj7620_write_reg(0x6C,0x04);
   
paj7620_write_reg(0x6D,0x2C);
   
paj7620_write_reg(0x6E,0x01);
   
paj7620_write_reg(0x6F,0x32);
   
paj7620_write_reg(0x71,0x00);
   
paj7620_write_reg(0x72,0x01);
   
paj7620_write_reg(0x73,0x35);
   
paj7620_write_reg(0x74,0x00);
   
paj7620_write_reg(0x75,0x33);
   
paj7620_write_reg(0x76,0x31);
   
paj7620_write_reg(0x77,0x01);
   
paj7620_write_reg(0x7C,0x84);
   
paj7620_write_reg(0x7D,0x03);
   
paj7620_write_reg(0x7E,0x01);
}

function 
paj7620_read_reg($addr, &$data)
{
   
i2c_write(I2C_ID$addr&0xFF1);
   
i2c_read(I2C_ID$data1);
   return 
0;
}

function 
paj7620_select_bank($bank)
{
    switch(
$bank){
      case 
BANK0:
         
paj7620_write_reg(PAJ7620_REGITER_BANK_SELPAJ7620_BANK0);
         break;
      case 
BANK1:
         
paj7620_write_reg(PAJ7620_REGITER_BANK_SELPAJ7620_BANK1);
         break;
      default:
         break;
   }
}

function 
PAJ7620_init()
{
   
$i 0;

   
$data0 0;
   
$data1 0;

   
usleep(700);  
   
//Wait 700us for PAJ7620U2 to be stabilized  

   
i2c_setup(I2C_IDPAJ7620_ID);
   
paj7620_select_bank(BANK0);

   
paj7620_read_reg(0$data0);  
   
paj7620_read_reg(1$data1);

   if ( (
$data0 != 0x20 ) || ($data1 != 0x76) )
   {
      return 
0xff;
   }

   
init_register();

   
paj7620_select_bank(BANK0);  

   return 
0;
}


function 
get_gesture()
{
   
$data 0;
   
$data1 0;

   
paj7620_read_reg(0x43$data);            

   switch (
$data)      
   {      
      case 
GES_RIGHT_FLAG:
         
usleep(GES_ENTRY_TIME);
         
paj7620_read_reg(0x43$data);
         if(
$data == GES_FORWARD_FLAG)
         {
            echo 
"Forward \r\n";
            
usleep(GES_QUIT_TIME);
         }
         else if(
$data == GES_BACKWARD_FLAG)
         {
            echo 
"Backward \r\n";
            
usleep(GES_QUIT_TIME);
         }
         else
         {
            echo 
"Right \r\n";
            return 
CMD_RIGHT;
         }          
         break;
      case 
GES_LEFT_FLAG:
         
usleep(GES_ENTRY_TIME);
         
paj7620_read_reg(0x43$data);
         if(
$data == GES_FORWARD_FLAG)
         {
            echo 
"Forward \r\n";
            
usleep(GES_QUIT_TIME);
         }
         else if(
$data == GES_BACKWARD_FLAG)
         {
            echo 
"Backward \r\n";
            
usleep(GES_QUIT_TIME);
         }
         else
         {
            echo 
"Left \r\n";
            return 
CMD_LEFT;
         }          
         break;
      case 
GES_UP_FLAG:
         
usleep(GES_ENTRY_TIME);
         
paj7620_read_reg(0x43$data);
         if(
$data == GES_FORWARD_FLAG)
         {
            echo 
"Forward \r\n";
            
usleep(GES_QUIT_TIME);
         }
         else if(
$data == GES_BACKWARD_FLAG)
         {
            echo 
"Backward \r\n";
            
usleep(GES_QUIT_TIME);
         }
         else
         {
            echo 
"Up \r\n";
            return 
CMD_UP;
         }          
         break;
      case 
GES_DOWN_FLAG:
         
usleep(GES_ENTRY_TIME);
         
paj7620_read_reg(0x43$data);
         if(
$data == GES_FORWARD_FLAG)
         {
            echo 
"Forward \r\n";
            
usleep(GES_QUIT_TIME);
         }
         else if(
$data == GES_BACKWARD_FLAG)
         {
            echo 
"Backward \r\n";
            
usleep(GES_QUIT_TIME);
         }
         else
         {
            echo 
"Down \r\n";
            return 
CMD_DOWN;
         }          
         break;

      default:
         
paj7620_read_reg(0x43$data1);
         if (
$data1 == GES_WAVE_FLAG)
         {
            echo 
"Wave \r\n";
         }
         break;
   }
   return 
0;
}

?>

task0.php: This file contains main program for PHPoC.
PHP Code:
<?php

include "gesture_PAJ7620.php";
define("PWM_PERIOD"20000);
define("WIDTH_MIN"771);
define("WIDTH_MAX"2193);

function 
servo_set_angle($id$angle)
{            
    
$width WIDTH_MIN + (int)round((WIDTH_MAX WIDTH_MIN) * $angle 180.0);
    if((
$width >= WIDTH_MIN) && ($width <= WIDTH_MAX))
        
ht_pwm_width($id$widthPWM_PERIOD);
}

// Angles of two motor (degree)
$angles = array(0,0);
$angle_max =  array(18090);
$angle_min =  array( 00);
$pwm = array(01); // HT0 control lef_right motor, HT1 control up_down motor
$degree_step 90;
i2c_scan(0);
PAJ7620_init();

ht_pwm_setup($pwm[0], 0PWM_PERIOD"us");
ht_pwm_setup($pwm[1], 0PWM_PERIOD"us");


servo_set_angle($pwm[0], 90);
servo_set_angle($pwm[1], 0);

while(
1)
{
   
sleep(1);

  
$cmd get_gesture();
  if(
$cmd==0)
     continue;

   switch (
$cmd)
   {
      case 
CMD_LEFT:
         
$angles[0]  += $degree_step;
         break;
      case 
CMD_RIGHT:
         
$angles[0]  -= $degree_step;
         break;
      case 
CMD_DOWN:
         
$angles[1]  -= $degree_step;
         break;
      case 
CMD_UP:
         
$angles[1]  += $degree_step;
         break;
      default:
         break;
   }

        for(
$i 0$i <2$i++)
        {        
            if(
$angles[$i] > $angle_max[$i])
                
$angles[$i] = $angle_max[$i];
            else if(
$angles[$i] < $angle_min[$i])
                
$angles[$i] = $angle_min[$i];

            
servo_set_angle($pwm[$i], $angles[$i]);
        }

}

?>