I just started learning C++ in earnest about a month ago. This weekend I felt like I knew enough to start looking at Python C extensions, so I wrote one to control the pan and tilt functions of my Logitech Orbit. I used this camera previously for my OLPC telepresence project.
There's already a similar module out there, called lpantilt, that does this using Cython. But, I wanted to take a crack at it myself and do it with straight C.
There's already a similar module out there, called lpantilt, that does this using Cython. But, I wanted to take a crack at it myself and do it with straight C.
#include <Python.h>And here is the associated
#include <errno.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include "linux/videodev2.h"
#include "uvcvideo.h"
static int pantilt(int pan, int tilt, int reset) {
struct v4l2_ext_control xctrls[2];
struct v4l2_ext_controls ctrls;
if (reset) {
xctrls[0].id = V4L2_CID_PAN_RESET;
xctrls[0].value = 1;
xctrls[1].id = V4L2_CID_TILT_RESET;
xctrls[1].value = 1;
} else {
xctrls[0].id = V4L2_CID_PAN_RELATIVE;
xctrls[0].value = pan;
xctrls[1].id = V4L2_CID_TILT_RELATIVE;
xctrls[1].value = tilt;
}
ctrls.count = 2;
ctrls.controls = xctrls;
int fd;
if (-1 == (fd = open("/dev/video0", O_RDWR))) {
PyErr_SetString(PyExc_IOError, "Couldn't open /dev/video0.");
return 0;
}
if (-1 == ioctl(fd, VIDIOC_S_EXT_CTRLS, &ctrls)) {
PyErr_SetString(PyExc_IOError, "ioctl failed.");
return 0;
}
if (-1 == close(fd)) {
PyErr_SetString(PyExc_IOError, "Failed to close /dev/video0.");
return 0;
}
return 1;
}
static PyObject* pantilt_reset(PyObject* self, PyObject* args) {
if (!PyArg_ParseTuple(args, "")) {
return NULL;
}
if (!pantilt(0, 0, 1)) {
return NULL;
}
Py_RETURN_NONE;
}
static PyObject* pantilt_pantilt(PyObject* self, PyObject* args) {
int pan;
int tilt;
if (!PyArg_ParseTuple(args, "ii", &pan, &tilt)) {
return NULL;
}
if (!pantilt(pan * 64, tilt * 64, 0)) {
return NULL;
}
Py_RETURN_NONE;
}
static PyMethodDef PantiltMethods[] = {
{"pantilt", pantilt_pantilt, METH_VARARGS, "Set relative pan and tilt of the camera."},
{"reset", pantilt_reset, METH_VARARGS, "Reset the pan and tilt of the camera."},
{NULL, NULL, 0, NULL}
};
PyMODINIT_FUNC initpantilt(void) {
(void) Py_InitModule("pantilt", PantiltMethods);
}
setup.py
script to build it:from distutils.core import ExtensionTo get this to build and run on Ubuntu, I had to:
from distutils.core import setup
m = Extension('pantilt', sources=['pantilt.c'])
setup(name='pantilt',
version='1.0',
description='Control pan and tilt of supported webcams.',
ext_modules=[m])
- Download and install libwebcam.
- Execute
uvcdynctrl -i logitech.xml
(logitech.xml
can be found in the source for libwebcam). - Install the
linux-source-*
package and extract the/usr/src/linux-source*.tar.bz2
to disk. - Copy
uvcvideo.h
in to the same directory aspantilt.c
. - Execute
python setup.py install
import pantilt, time
pantilt.reset() # Reset the pan and tilt to the origin.
time.sleep(1)
pantilt.pantilt(10, 0) # Increase relative pan by 10 degrees.
pantilt.pantilt(0, 10) # Increase relative tilt by 10 degrees.