Pan and Tilt control for the Raspberry Pi Camera

I was fortunate enough to get access to a prototype of Pi-Pan from www.mindsensors.com during their kickstarter.
The kickstarter has finished and they reached their goal.   However they will be selling Pi-Pan from www.mindsensors.com at a future date.


Pi-Pan provides Pan and tilt movements for your Raspberry Pi Camera.
Pi-Pan can pan 180 degrees (from left to right) and tilt 110 degrees (top to bottom).

Pi-Pan comes with two servos, a controller board, screws, a mount and instructions.  It also comes with some python code that shows how the device can be operated.

(The controller board in the image below is a prototype and the production board will be a lot smaller.)

pipan-opt pipan2-opt pipanparts-opt

 

Pi-pan is well made and and feels solid once assembled, which only takes 5 minutes. There is also a mount which can be used to mount Pi-Pan on a case or other objects. I mounted mine directly on the Pi-Pan controller board for now.

PWM is required to drive the servos and the sample code uses Servoblaster which works very well. I also used Servoblaster in my code below.

OpenElectronics also has a light module (Pi-Light) which can be mounted on the front of the Pi camera to improve lighting and there is also a case in the works.

 

PiPan Case PiPan Light

The code below is what I used to control Pi-pan


/*
##########################################################################################
A program to control Pi-pan.

Pi-Pan details;
www.kickstarter.com/projects/1842571016/pi-pan-a-pan-tilt-for-raspberry-pi-camera
www.openelectrons.com

Copyright (C) 2013 Mark Williams
www.ozzmaker.com

Reqires Serverblaster
If the servos do not move, check that they have been defined correctly below.
##########################################################################################

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/

#include <stdio.h>

#include <string.h>
#include <sys/time.h>
#include <termios.h>
#include <stdlib.h>
#include <signal.h>

#define TILT_SERVO 5
#define PAN_SERVO 6

static struct termios g_old_kbd_mode;
FILE *fp;

// detect key press
static int kbhit(void){
    struct timeval timeout;
    fd_set read_handles;
    int status;

    // check stdin (fd 0) for activity
    FD_ZERO(&read_handles);
    FD_SET(0, &read_handles);
    timeout.tv_sec = timeout.tv_usec = 0;
    status = select(0 + 1, &read_handles, NULL, NULL, &timeout);
    return status;
}

// put the things as they were befor leave..!!!
static void old_attr(void){
    tcsetattr(0, TCSANOW, &g_old_kbd_mode);
}

void  INThandler(int sig)
{
	fclose(fp);
        signal(sig, SIG_IGN);
        exit(0);
}

void servoblaster(int server, int  pulseWidth){
	   fprintf(fp, "%i=%i\n",server,pulseWidth);
	   fflush(fp);
}

// main function
int main( void ){

    char ch;
    static char init;
    struct termios new_kbd_mode;
    int tilt=150;
    int pan=150;

    fp = fopen("/dev/servoblaster", "w");
    if (fp == NULL) {
        printf("Error opening file\n");
        exit(0);
    }

    if(init)
        return;
    // put keyboard (stdin, actually) in raw, unbuffered mode
    tcgetattr(0, &g_old_kbd_mode);
    memcpy(&new_kbd_mode, &g_old_kbd_mode, sizeof(struct termios));

    new_kbd_mode.c_lflag &= ~(ICANON | ECHO);
    new_kbd_mode.c_cc[VTIME] = 0;
    new_kbd_mode.c_cc[VMIN] = 1;
    tcsetattr(0, TCSANOW, &new_kbd_mode);
    atexit(old_attr);

    // stat Pi-pan in its neutral position
    servoblaster(TILT_SERVO,150);
    servoblaster(PAN_SERVO,150);

    printf("\n\n\nUse 'w','s','a' and 'd' keys to conrol the movement of Pi-pan.\n");
    printf("The spacebar will reset Pi-pan to its  neutral position.\n");
    printf("\n\n");

    while (!kbhit()){
        // getting the pressed key...
        ch = getchar();
	switch (ch){
	case 's':
		printf("Down\n");
		tilt++;
		if (tilt>180)tilt=180;
		servoblaster(TILT_SERVO,tilt);
		break;
	case 'w':
		printf("Up\n");
		tilt--;
		if (tilt<80)tilt=80; 		servoblaster(TILT_SERVO,tilt); 		break; 	case 'a': 		printf("Left\n"); 		pan++; 		if (pan>200)pan=200;
		servoblaster(PAN_SERVO,pan);
		break;
	case 'd':
		printf("Right\n");
		pan--;
		if (pan<50)pan=50;
		servoblaster(PAN_SERVO,pan);
		break;
	case ' ':
		printf("Reset\n");
		tilt=150;
		pan=150;
		servoblaster(TILT_SERVO,tilt);
		servoblaster(PAN_SERVO,pan);
		break;
        }
    }
}