ASE 0.8 Alpha Released

I just finished releasing version 0.8 alpha. The most significant changes in this release are:

  • À la carte interpreter installation. which drops the installation size from 4.3MB to 900kB. With all interpreters installed, ASE now takes 7.9MB.
  • User scripts are now stored on the SD card and persisted across reinstallations of ASE. This should also make it easier to copy scripts to the device from a host computer or the web.
Visit the ASE project page to download the new APK. To install interpreters, click Menu, Help, then follow the directions under the InstallingInterpreters wiki page.

Solving Car Talk Puzzlers with Python

If you're not familiar with Car Talk, it's a horrible talk radio show hosted by Tom and Ray Magliozzi (aka Click and Clack the Tappet brothers). Every week there is a new puzzler and every so often it's math oriented. After hearing this week's mathy puzzler, I thought it would be fun to dig into the archives (2009 and 2008) and try solving a few of them in Python. Here's what I came up with:

# 2008-10-20 The Perfect Square Dance!
import itertools, math

for numbers in itertools.permutations(range(1, 19)):
for a, b in zip(numbers[::2], numbers[1::2]):
sqrt = math.sqrt(a + b)
if not str(sqrt).endswith('.0'):
break
if a == 1:
sallys_partner = b
elif b == 1:
sallys_partner = a
else:
print 'Sally danced with %d' % sallys_partner
break

# 2008-10-27 One is the Magic Number
print ''.join(str(n) for n in xrange(0, 1000000)).count('1')

# 2008-12-08 It's Math Time!
for ab in xrange(10, 100):
cab = ab ** 2
if str(cab)[1:] == str(ab):
print cab
break

# 2009-05-26 Equate This!
from __future__ import division # Avoids truncation.
import random

numbers = [2, 3, 4, 5]
operations = ['*', '**', '+', '-', '/']

while True:
random.shuffle(numbers)
random.shuffle(operations)
equation = ''
for i, number in enumerate(numbers):
equation += str(number)
if i < len(numbers) - 1:
equation += operations[i]
result = eval(equation)
if result == 26:
print equation
break

# 2009-06-08 Number One
print len([n for n in xrange(0, 1000000) if '1' not in str(n)])
I'd like to see someone good with Ruby, Perl, or Lua do the same so we can compare solutions.

Scripting on Android

Today I released a project I've been working on for some time. You may remember a couple earlier posts where I got Python and Lua working on Android. I've wrapped up those hacks into a nice Android application called Android Scripting Environment (ASE).

But wait, there's more! See the official blog post on the Google Open Source Blog and the project page for details. Further updates will be publish here with the "ase" tag.

Logitech Pan/Tilt Python C Extension

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.

#include <Python.h>
#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);
}
And here is the associated setup.py script to build it:
from distutils.core import Extension
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])
To get this to build and run on Ubuntu, I had to:
  • 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 as pantilt.c.
  • Execute python setup.py install
Finally, here's a sample usage of the pantilt module:
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.

Ubuntu Jaunty Wireless and RT61PCI

I upgraded to Jaunty yesterday and again had to struggle with my wireless. This time, it wasn't necessary to install a new kernel module. Instead, I just needed to remove Network Manager and set up wpa_supplicant. Here's my new /etc/network/interfaces that I configured for my WPA2 PSK AES TLA network.

auto wlan0
iface wlan0 inet dhcp
wpa-driver wext
wpa-conf managed
wpa-ssid myssid
wpa-ap-scan 1
wpa-proto RSN
wpa-pairwise CCMP
wpa-group CCMP
wpa-key-mgmt WPA-PSK
wpa-psk mypsk
With that, all I needed to do was sudo /etc/init.d/networking restart.