Pan Tilt Camera touchscreen Raspberry Pi

Camera Pan and Tilt control with TFT and Touchscreen

Here is an example of how to use a TFT screen to control the pan and tilt of a Raspberry Pi camera.

Git repository here
The code can be pulled down to your Raspberry Pi with;

pi@raspberrypi ~ $ git clone


There are a number of elements in place to get this working;

  • Detecting input events on the touchscreen.
  • The use of double buffering for the framebuffer.
  • Using fbcp(framebuffer copy) to copy camera image to back buffer. fbcp source has been integrated into the code above.
  • Updating back buffer with text and buttons.
  • Forking the actual process that starts recording.
  • Create a unique file name fore each recording.
  • Software PWM to control servers. (ServoBlaster)


The code has been well documented, so I will only cover imported snippets below.

Drawing buttons


The function below is used to draw the buttons and slider outlines to the display.

void drawButton(int x, int y, int w, int h, char *text, int backgroundColor, int foregroundColor);

x & y are the top left coordinates of the button.
w is width.
h is height.

The structure buttons  holds all button data.

struct buttons
int coords[5];
int currentPosition[4];
int timer;
int delta;
int oldScaledData[2];

Looking at these defined values will help you understand what is stored in coords[5]

//used for button coordinates
#define X 0             //Top left corner X position
#define Y 1             //Top left corner Y position
#define W 2             //Button width
#define H 3             //Button height
#define L 4             //Slider length


Using the values that are found in the above structure for the “PAN”button, we can easily draw a button using drawButton();


The coordinate values int he structure are;

        {       button[0].coords[X]=10,



We can also use drawButton() to draw the outline of the sliders. Just need to specify no text and have a black background. Below is what we can use to draw a slider outline around the “PAN” button;

                drawButton(button[0].coords[X]-1, button[0].coords[Y]-1,

This is what the above is doing;
Line 1: One less from X and Y position so that the slider appears outside the PAN button.
Line 2: Button 0 is PAN, so we use the width of the button plus the length of the slide. Add an extra 2 to display it outside of the button.
Line 3: Add two to height so the outline appears outside the PAN button.
Line 4: No text, red outline and black fill.

Keep Track of Sliding Buttons

button[0].delta is used to keep track of the sliding buttons and is used to update the current position (button[0].currentPosition[X]).

Has the Button Been Pressed?

In each loop, we check to see if there are any touch events are happening within any of the button areas.
Below is used to detected touch within the “PAN” button area.

                //Does the current X input fall between the current X position and the width of the button?
                //Does the current Y input fall between the current Y position and the height of the button?
                if((scaledX  >  button[0].currentPosition[X]  && scaledX < ( button[0].currentPosition[X]  + button[0].coords[W]))
                (scaledY >  button[0].coords[Y] && scaledY < (button[0].coords[Y]+button[0].coords[H])))

PiScreen TFT Raspberry Pi

Pan and Tilt

Servoblaster is used to provide PWM to control the servos. The code for this can be found in servo.c.
The servo angles are controled by writing a percentage value to /dev/servoblaster
Which can be replicated from the command prompt with;

pi@raspberrypi ~ $ echo 0=50% > /dev/servoblaster

To get the corresponding values from the button location as a percentage, we just need to device the button delta by the button slide length and height or width.

float panValue = (float)button[0].delta/ (button[0].coords[L]+button[0].coords[W]);
float tiltValue = (float)button[1].delta /(button[1].coords[L]+button[1].coords[H])

Capture Video

When we want to start capturing video, we spawn a new process. If we dont, our program will stop running while the video is being captured.
We also append the date and time to the file name so that each file is unqie and the last file recorded will not be overwritten.
Feel free to change the values in parmList[] to how you like the video to be recorded.

void videoCapture()
        char str[100];
        char timeAndDate[100];
        time_t now = time(NULL);
        struct tm *t = localtime(&now);

        //Create a string with the current time and date. This will be used to append to the file name
        strftime(timeAndDate, sizeof(timeAndDate)-1, "%Y%m%d%H%M%S", t);
        sprintf(str, "video-%s.h264", timeAndDate);

        //Parameter list used in raspivid
        char  *parmList[] = {"/opt/vc/bin/raspivid","-v","-t", "0","-rot","180","-h","720","-w","1280","-o", str, NULL};

        //Create child process that does the recording
        if (pid == 0)
                if ((pid = fork()) == -1)
                        perror("fork error");
                else if (pid == 0)
                        execv("/opt/vc/bin/raspivid", parmList);

Compile the code

The code in the git repository can be complied with;

pi@raspberrypi ~ $ gcc -o panTilt panTilt.c -I/opt/vc/include/ -I/opt/vc/include/interface/vmcs_host/linux -L/opt/vc/lib -lbcm_host -I/opt/vc/include/interface/vcos/pthreads

Further Reading

Programming for a Touchscreen on the Raspberry Pi
Controlling the GPIO on a Raspberry Pi with a Touchscreen
Pi-Pan, a Pan-Tilt Kit for Raspberry Pi Camera

Leave a Reply