Friday, December 11, 2009

unable to enumerate usb device

Today on an Ubuntu Karmic Koala machine, we plugged in a Canon camera and got a bunch of "unable to enumerate usb device" messages when we looked at dmesg. Turns out it was a bad cable. So check that first if you get that message.

Wednesday, December 09, 2009

Disable mouse or touchpad in xorg

Update: Apparently figuring out how to disable x input devices like mice, keyboards and touch pads is hard to find on the search engines, so I'm updating the post to make it more findable. (This post was originally called "Ubuntu karmic: 3dconnexion Space Navigator and xorg", but I just helped a friend of mine disable his EEE PC's elantech touch pad, and realized that the solution is general purpose.)

My friend always uses an external mouse with his laptop, and accidentally brushes the touch pad when he's typing. So he wanted to find a way to shut off the touch pad.

In Ubuntu Karmic Koala (9.10), xorg now autodetects my 3dConnexion Space Navigator and uses its events for mouse X and Y, which is not what I want.

I just discovered xinput, though, which is extremely cool. Thanks Philip Langdale and Frederic Lepied for writing it!

root@lg1:~# xinput list
"3Dconnexion SpaceNavigator" id=9 [XExtensionPointer]
Type is MOUSE
Num_buttons is 5
Num_axes is 6
Mode is Relative
Motion_buffer is 256
Axis 0 :
Min_value is -1
Max_value is -1
Resolution is 1
Axis 1 :
Min_value is -1
Max_value is -1
Resolution is 1
Axis 2 :
Min_value is -1
Max_value is -1
Resolution is 1
Axis 3 :
Min_value is -1
Max_value is -1
Resolution is 1
Axis 4 :
Min_value is -1
Max_value is -1
Resolution is 1
Axis 5 :
Min_value is -1
Max_value is -1
Resolution is 1

root@lg1:~# xinput list-props "3Dconnexion SpaceNavigator"
Device '3Dconnexion SpaceNavigator':
Device Enabled (93): 1
Evdev Reopen Attempts (227): 10
Evdev Axis Inversion (228): 0, 0
Evdev Axis Calibration (229):
Evdev Axes Swap (230): 0
Evdev Middle Button Emulation (231): 2
Evdev Middle Button Timeout (232): 50
Evdev Wheel Emulation (233): 0
Evdev Wheel Emulation Axes (234): 0, 0, 4, 5
Evdev Wheel Emulation Inertia (235): 10
Evdev Wheel Emulation Timeout (236): 200
Evdev Wheel Emulation Button (237): 4
Evdev Drag Lock Buttons (238): 0

root@lg1:~# xinput get-feedbacks "3Dconnexion SpaceNavigator"
1 feedback class
PtrFeedbackClass id=0
accelNum is 2
accelDenom is 1
threshold is 4

root@lg1:~# xinput set-ptr-feedback "3Dconnexion SpaceNavigator" 4 8 1 # very sensitive X pointer
root@lg1:~# xinput set-ptr-feedback "3Dconnexion SpaceNavigator" 4 1 8 # much less sensitive.

The threshold parameter doesn't seem to do anything.

Ah, here's the magic to make it stop influencing the pointer:

root@lg1:~# xinput set-int-prop "3Dconnexion SpaceNavigator" 93 8 0 # property 93 from list-props

Also works as:

root@lg1:~# xinput set-int-prop "3Dconnexion SpaceNavigator" "Device Enabled" 8 0
root@lg1:~# xinput set-int-prop "3Dconnexion SpaceNavigator" "Device Enabled" 8 1 # reenable

Unfortunately, I don't see any way to re-zero if it drifts (often happens when they're cold or hot or brand new), or turn on the LED. Here's C code to do it, though:

#include <sys/ioctl.h>
#include <error.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <linux/input.h>

main(int argc, char **argv) {

int fd;
int retval;
struct input_event ev; /* the event */

if (argc != 3) {
printf("Usage: %s device 1|0\n", argv[0]);

if ((fd = open(argv[1], O_WRONLY)) < 0) {
perror("opening the file you specified");

ev.type = EV_LED;
ev.code = LED_MISC;
ev.value = (argv[2][0] == '1') ? 1:0;
write(fd, &ev, sizeof(struct input_event));

Tuesday, November 24, 2009

Dell mini 10 with ubuntu jaunty xorg crash: stolenbase

Good grief. Did a dist-upgrade on the Dell mini 10, and now xorg is broken again. Something about a stolenbase in Xorg.0.log.

Thanks to this blog for the fix:

sudo apt-get remove --purge psb-kernel-source
sudo apt-get install psb-kernel-source

Since when did I become a full time distro installer?

Monday, November 23, 2009

Ubuntu Karmic: install -pae kernel breaks nvidia driver

Since I have > 3GB of RAM, I installed linux-image-generic-pae so that I could access up to 16GB on my Karmic Koala install. Note that installing a new kernel doesn't choose it as the default in grub (which is actually now grub2). So in /etc/default/grub I set GRUB_DEFAULT=saved so that it'd remember my choice, and then rebooted and hit SHIFT during the (very brief) grub blip to pull up the menu and choose the new kernel, which it then remembers.

Unfortunately, that broke my nvidia driver: when I rebooted into the kernel, the text login screen just flickered as xorg restarted constantly. This is due to 2 bugs:

Summary: I had to

apt-get remove --purge linux-headers-2.6.31-15

And then, when I did an

apt-get install linux-headers-2.6.31-15-pae

it automatically rebuilt (successfully) the nvidia.ko.

Saturday, November 21, 2009

Asus EEE pc 900 frequency scaling

I just got Ubuntu Jaunty running on this cursed EEE 900, and noticed it was running hot. But I just turned on CPU frequency scaling, so now the machine can automatically slow itself down from 900mhz to as low as 112mhz.

Right click on the menu bar and click "Add to panel", then select "CPU Frequency Scaling Monitor". When I first did this, it complained "CPU Frequency scaling unsupported". Turns out the celeron needs a particular kernel module installed for that to work. Here's my source for this fix, translated from Italian.

sudo apt-get install cpufrequtils sysfsutils
sudo modprobe p4_clockmod

Then add p4_clockmod to your /etc/modules with your favorite text editor or by:

sudo bash
echo p4_clockmod >>/etc/modules

Asus EEE pc 900 linux howto

(Update: linked to my post on frequency scaling down at the bottom).

Wow, I can't believe how many hours I've spent trying to make Linux work on this EEE 900. Our 900A seems to be okay, but ubunty karmic is completely broken with the 900, and hardy is seriously deficient. I tried eeebuntu, moblin, and I don't even remember what other distros. All failed miserably. Here's how I got Jaunty to work reliably with the VESA video driver.

The main problem is the xserver-xorg-video-intel driver, which locks up quickly after (or during) boot. For some reason, the i915 just seems to cause everybody huge headaches. And unfortunately, switching to the (slower) vesa xorg driver in many distros (such as Karmic Koala) causes it to lose video sync and be even more unfixable, since then the VTs (alt-F1, etc.) won't work.

Ubuntu Jaunty is the only thing that even comes close to working for me. It installs okay, and uses the vesa video driver, but has the standard trouble with the mind-rendingly awful netbook-launcher, which has plagued every netbook install I've ever tried. netbook-launcher sucks in a big way. It tries to be fancy by using OpenGL for visual effects, but in doing so either breaks video drivers or just eats up 100% CPU all the time.

Worse, Jaunty has a bug when turning it off that leaves you without a working window manager. System... Preferences... Switch Desktop Mode turns it off, and everything looks great, but as soon as you restart, you'll get a blank desktop with no menu bar, task bar, or gnome menus. Here's how to fix it, summarizing from the above link. (The above link also has ideas about what to do if you've already switched and are in that broken state).

To shut off netbook-launcher and get back to the normal gnome menus in Jaunty UNR, first switch to "Classic" mode from System... Preferences... Switch Desktop Mode. Everything should look great, but it'll break if you logout or restart now. To make sure the gnome menus load the next time, open System... Preferences... Startup Applications. Make sure UNR Launcher and Maximus are unchecked. Now click "Add" and create a "GNOME Panel" entry, running the command "gnome-panel" (no path needed). Add another called "GNOME Window Manager", running command "gnome-wm".

That should do it! You'll be limited to 800x600, instead of the native 1024x600, and of course the VESA video won't be as fast as a working accelerated driver would be. If that bothers you, feel free to spend a few days downloading and installing distros that'll break the machine entirely. Then reinstall Jaunty and reapply this fix, and you'll appreciate the suboptimal yet stable performance. Youtube and hulu work with flashplugin-nonfree, although not so much in HD or fullscreen modes.

Next up, enabling CPU frequency scaling to extend battery life.

Wednesday, November 11, 2009

Carmichael orrery

It occurs to me that it ought to be possible to demonstrate pseudoprimality with a purely mechanical device.

For instance, we could demonstrate 2^560%561 with 560 2:1 (or equivalently, 35 65536:1) gear amplifications followed by a 1:561 reduction, and rotate the input shaft once to see the output gear rest at 1. Of course, 2^560 ~ 3.8E168, so you'd have to turn the crank fairly hard.

You could also do a single 65536:1:561 train cranked n times for individual 65536n (mod 561) reductions, and repeat 35 iterations for 65536^35%561.

That would provide a (false) Fermat witness of 2. Simile for the other integers < 561. Not very interesting so far, but perhaps there's something more elegant.

Thursday, November 05, 2009

Math and music

If you represent the notes in the musical scale as the numbers 0 to 11 (0=A, 1=A#, 2=B, etc.), then the wheel of fifths is merely the multiples of 7 modulo 12. Likewise, the wheel of fourths is 5 mod 12. For some reason, the internets appear to be silent on this relationship.

Monday, November 02, 2009

Capturing sound in Linux using a USB headset (Plantronics DA40)

I picked up a Plantronics DA40 USB headset today and figured out how to capture .wav files to disk and play them back through the headset.

There are lots of other options, but I like this one because it's USB and I could use it with any Linux system, whereas if I used the native souncard, I'd probably have to do more per-machine troubleshooting. dmesg showed that it was detected okay:

[14563.672694] input: Plantronics DA40 Adapter as /devices/pci0000:00/0000:00:1d.3/usb4/4-2/4-2:1.3/input/input6
[14563.728138] input,hidraw3: USB HID v1.00 Device [Plantronics DA40 Adapter] on usb-0000:00:1d.3-2
[14563.909787] usbcore: registered new interface driver snd-usb-audio

Usually the mic comes muted by default, so I pulled up alsamixer to check. It came up with my native sound card first. So I ran "alsamixer -c 1" to try it with the second card, and that was indeed the DA40. Hitting TAB let met toggle between record and playback settings.

In the playback tab, there's a Mic option. You want to mute that ("m"), since that just loops the mic back through the speakers. On the Capture tab, there's a "Mic" field, and that's the one that actually sets the mic gain.

To record, I ran:

arecord -r 44100 -f S16_LE -D hw:1,0 foo.wav

(Hit control-c to end capture.) hw:1,0 let me record from card 1, the second sound card. It refused to record at its default setting of 8000Hz, so the 44100 and S16_LE were necessary. Then I was able to play back foo.wav with:

mplayer -ao alsa:device=hw=1.0 foo.wav

So far so good. Next, I wanted to know how much deviation I was getting (was the gain turned up enough?) so I downloaded a nifty, very old program called Wavesurfer, available as a statically linked binary:

I selected a "waveform" panel and loaded up foo.wav, and could see that I was only getting around +-500 units max (out of +-32767). In File... Preferences... Sound I/O, I set the Input and Output device to /dev/dsp1 (which I believe is the OSS version of the second sound card). Now I can record and playback from wavesurfer. I used alsamixer to tweak the Mic setting (remember to use the Record tab!) until I got +-10000 or so on my recordings. Anything over +-1000 would probably have been fine.

(BTW, wavesurfer will also show you nifty spectrograms, from which I learned a lot about the human voice.)

Here's a trivial script to start arecord recording in the background, and another script to kill it when you've had enough.


arecord -r 44100 -f S16_LE -D hw:1,0 /tmp/recording-in-progress.wav &
echo Recording. Wrote arecord pid of $ARECORD_PID to /tmp/
echo $ARECORD_PID > /tmp/


kill "`cat /tmp/`"

Tuesday, October 27, 2009

Machine Monastery

I've been reading 365 Tomorrows, and I like the idea of flash fiction. Here's a story that popped into my head while deep cleaning my carpets:

Cynthia was reluctant when it came time to leave the Machine Monastery. Nobody had predicted that machines would be Buddhists. Crazed killers, perhaps. Indifferent to humanity, perhaps. Cold calculators, almost certainly.

She had learned the tactile pleasures of sanding the walnut sides of an imperfect jewelry box she had made herself with hand tools. The visual pleasure of brushing a finish with a wet edge.

The empty contentedness of sweeping a floor. The ragged exhaustion of breaking out old concrete sidewalks with a sledgehammer and hauling them to a skip. The gleam of a toilet scrubbed clean.

The machines had done all these things, mostly better than humans could, and had found the same peace from their lessons. Cynthia would go back to her life in the city, where her finance skills would pay the bills, and where machine and human craftsmen continue to do their jobs with the labor-saving tools that made mass production cheap. But perhaps in the summer she would take another vacation to the mountains east of town, away from the noise, and rejuvenate with the joys of manual labor.

Tuesday, October 13, 2009

Ubuntu 8.04 (Hardy LTS) on HP EliteBook 8530w

Trying to boot the laptop with my 8.04 live CD, it hangs with a message "BUG: soft lockup - CPU#0 stuck for 11s". Hit F6 at the ubuntu boot screen and edit the boot params: remove "splash" and "quiet", and add "acpi=off".

Friday, September 25, 2009

Shopbot joinery

I tried my first joinery on the shopbot today. It's a concept for a sideboard to foot joint for a bed. I recessed the post 1/8" deeper than the plywood to give it a sense of depth when assembled, but I'm still deciding whether I like the effect. Maybe with a very gentle roundover on the post edges.

Here are my Sketchup, PartWorks and Shopbot partfiles. The partfiles are written for a 1/4" bit.

The raised sections of the post need a little rounding off at the tip to accommodate the 1/4" radius in the mating part; I should probably fix that in the sketchup model before I do any more of those. Also, in partworks, I relieved the plywood path by 0.030" so it had enough clearance to fit. I like how the fit came out with that amount of clearance.

Friday, September 04, 2009

squid reverse proxy (aka website accelerator) on ubuntu hardy

We had a bunch of machines all hitting the same URLs on, so we put up a squid reverse proxy on so that would get served and cached by

sudo apt-get install squid squid-cgi # squid-cgi enables the cache manager web interface

Edit /etc/squid/squid.conf. It's very well documented, and we only had to modify a few lines from the default ubuntu hardy config:

Allow other local machines to use our cache:

acl our_networks src
http_access allow our_networks

instead of the default of:

http_access allow localhost

Have the cache listen on port 80 and forward all requests to

http_port 80
cache_peer parent 80 0 no-query originserver

In our case, we wanted to cache pages that included "GET parameters" in the URL, such as (which is something you should only do in special cases):

# enable logging of the full URL, so you can see what's going on (though it's a potential privacy risk to your users)
strip_query_terms off

Comment out the lines that exclude cgi-bin and GET parameter URLs from being cached:

#acl QUERY urlpath_regex cgi-bin \?
#cache deny QUERY

Then we went to: http://localhost/cgi-bin/cachemgr.cgi to see how well our cache was working (blank login and password by default).

After doing an "/etc/init.d/squid restart", we found that we could hit and get, as expected.

Saturday, August 22, 2009

Dell Mini 10 slow with Ubuntu Netbook Remix

The Ubuntu Netbook Remix worked great with my Dell Mini 10, but the menu panel was horribly slow. Turns out it's just the "netbook-launcher" process itself, which eats up 100% CPU for some reason.

Fixing the problem is easy: go back to the traditional ubuntu menus with System... Preferences... Main Menu. (Updating to psb graphics also fixed the problem.)

Accelerated video on Dell Mini 10 with Ubuntu Netbook Remix

Update 4: Wow, this netbook sucks, mainly due to the intel graphics. (I've also had a miserable time with my other intel netbooks). The driver broke again, so I've been using it with the painfully slow vesa driver, which at least makes it stable.

Update 3: The netbook-launcher process is horribly slow when using non-accelerated graphics. If you just want to fix that without bothering with the accelerated graphics hack, just disable the netbook launcher.

Update 2: A magic incantation in xorg.conf fixes the lockups:

Option "AccelMethod" "EXA"
Option "DRI" "off"
Option "MigrationHeuristic" "greedy"

Update: I'm getting frequent system freezes. I suspect it's the video driver, so I'm going to downgrade back to the VESA driver and see if it improves.

After the install, I only got 800x576 video in xorg, using the non-accelerated VESA driver.

Based on these instructions, I added the Poulsbo graphics drivers:

Edit /etc/apt/sources.list (for example, by running "sudo gedit /etc/apt/sources.list") and add these two lines to the file:

deb jaunty main
deb-src jaunty main


sudo apt-key adv --keyserver --recv-keys C6598A30
sudo apt-get update
sudo apt-get install xserver-xorg-video-psb
sudo apt-get install poulsbo-driver-2d poulsbo-driver-3d

Rebooting, I got errors about "First SDVO output reported failure to sync or input is not trainded!!!" and "This driver currently needs DRM to operate." This bug report suggests that it has to do with the kernel version. The suggested fix worked:

apt-get install psb-kernel-source

Wednesday, August 05, 2009

Behavioral Confirmation (and behavioral compensation) part II

I found a much better discussion of behavioral confirmation on Google Books: The Social Construction of Reality, pp. 395-399.

Behavioral Confirmation happens when your expectations about how someone will act actually cause them to act that way. Sociologists have performed a bunch of clever experiments to prove that this is a real and significant effect. Here's how the author describes one experimental setup:

"Fifty-one male and fifty-one female undergraduates at the University of Minnesota participated, for extra course credit, in what had been described as a study of the "processes by which people become acquainted with each other." These individuals interacted in male-female dyads in a getting-acquainted situation in which they could hear but not see each other( a telephone conversation). Before initiating the conversation, the male member of each dyad received a Polaroid snapshot of his female interaction partner. These photographs, which had been prepared in advance and assigned at random to dyads, identified the target as either physically attractive (attractive-target condition) or physically unattractive (unattractive-target condition). Each dyad engaged in a ten-minute unstructured telephone conversation that was tape-recorded. Each participant's voice was recorded on a separate channel of the tape. In order to assess the extent to which the actions of the female targets provided behavioral confirmation of the male perceivers' stereotypes, twelve observer-judges listened to the tape recordings of the getting-acquainted conversations. The observer-judges were unaware of the experimental hypotheses and knew nothing of the actual or perceived physical attractiveness of the individual whom they heard on the tapes. They heard only those tape tracks containing the female participants' voices. Nine other observer-judges listened to and rated only the male perceivers' voices."

Not only did the judges find that the men treated the women differently based on the mens' biases, but the women unconsciously conformed to those biases!

Analysis of the observer-judges' ratings of the tape recordings of the conversations indicated that female targets who (unbeknown to them) were perceived to be physically attractive (as a consequence of random assignment to the attractive-target experimental condition) actually came to behave in a friendly, likeable, and sociable manner. This behavioral confirmation was discernible even by outside observer-judges who knew nothing of the actual or perceived physical attractiveness of the target individuals.

In this demonstration of behavioral confirmation in social interaction, the "beautiful" people became "good" people, not because they necessarily possessed the socially valued dispositions that had been attribuvted to them, but because the actions of the perceivers, which were based on their stereotyped beliefs, had erroneously confirmed and validated these attributions.

As the author, Mark Snyder, puts it: "They treated their targets as sociable or unsociable persons, and, indeed, these targets came to behave in a sociable or unsociable fashion."

Sunday, July 26, 2009

Phoebe in Wonderland

Great movie! And it's one of the rare movies that it satisfies the Bechdel Test.

Friday, July 17, 2009

Move the cursor from the command line in fvwm using FvwmCommand

In the holodeck, I sometimes forget to move the mouse pointer to the corner of the screen before I unplug the keyboard. Here's how to do it remotely if you use fvwm (or fvwm2) as your window manager:

$ ssh whatever

$ export DISPLAY=:0.0

$ FvwmCommand 'CursorMove -100 -100'

Note that the quotes are important; otherwise it gets confused about the -.

Tuesday, June 23, 2009

Tiny fonts with xorg (incorrect DPI)

Lots of monitors are totally screwed up in the way they report their sizes to your video card. So it's quite common to have insanely large or insanely tiny fonts for some graphical apps in linux.

Here's how I just fixed that on an Ubuntu Linux machine:

As root, edit /etc/X11/xorg.conf. In the "Section "Device"" part of the file that has your video card settings, put this so it won't try to get the DPI from the monitor:

Option "UseEdidDpi" "off"

Then, in the "Section "Monitor"", I added this line:

DisplaySize 508 286

That makes my 1920x1080 display use 96x96 dpi, a good common value.

This thread in the Arch linux forums lists this formula for the DisplaySize: displaysize = (/DPI-Desired)*25.4. So (1920/96)*25.4 = 508.

Save the file, restart X with control-alt-backspace, and see if it works.

ubuntu and

If applications complain about not being able to find, you should "sudo apt-get install libmotif3". (Hey, that rhymes)

Sunday, June 21, 2009

Sketchup bed design

Trying out ideas for a bed that would look nice, yet be easy to make on the shopbot. I'm thinking the curves could be simple v-groove engraved, and everything but the posts could be pre-finished cabinet plywood. It'd be neat to engrave some tasteful scrollwork on the faces too, just because it's so easy to do.

Here's the sketchup file: bed.skp.

Friday, June 19, 2009

Shopbot router tool bit holder

Today I built a really simple holder for my shopbot bits and collets. And here are the source files I used to build it: It includes the sketchup model, .dxf, PartWorks V2 .crv file that generated the toolpath, and the .sbp shopbot partfile itself.

It's astounding how bad this workflow is. There are plenty of opportunities to make mistakes with each of the 4 different file formats, and every time I make a change to the sketchup file, I have to manually regenerate each of the following steps and try to remember what settings I used. Plus, each of the 3 programs has bugs that create headaches at best and dangerous situations and ruined parts during manufacturing at worst.

So the bugs need to get fixed regardless. Then there are two ways to make the process better: make the workflow shorter, so that at least there's a single UI for each of the steps, or make the tools more modular and configurable so that you can automate the process of stringing them together.

The former approach reminds me of "integrated development environments" for writing software, such as Microsoft's Visual Studio. Everything comes with a slick user interface, and debugging, compiling and project management are all built in. The downside is that you're stuck with that package of tools, and automating big tasks like rebuilding a huge software product don't usually work very well.

The latter approach reminds me of using Makefiles to build software. You have to do some work up front to define how the parts of your project get built. But once you've done that correctly, typing "make" is sufficient to automatically rebuild any parts of the project that have changed. Big software projects almost always use this approach, in my experience.

The latter approach is the one I'd prefer in this case. There are three distinct parts to manufacturing a part on a CNC machine like this: making the 3d model, defining the toolpaths (what type of cutting bit to use, what what type of cut to make, feed rates, etc.), and executing that toolpath on your particular machine. Each of those can be relatively independent and should be interchangeable. And ideally, they'd all be available as Free software.

So someday, I'd like to be able to build my part in Free Sketchup, look at the Free toolpath generator's idea of how to cut it, tweak a settings file to fix anything I don't like, and then do a quick check on my Shopbot Simulator to make sure it'll cut the way I expect. And then when I have to tweak some part of the model, I can just run "make" and get all the derivative files generated automatically.

Wednesday, June 17, 2009

Shopbot aluminum feeds & speeds

11 March 2010 update:

One note about cutting metal on the shopbot: I'm always careful to empty the dust collector before I start cutting. Don't want hot metal shavings flying into a cloud of wood dust!

Wow, cutting fluid really makes a difference. Today I cut some 1/4" 6-series aluminum plate with a 1/4" 2-flute carbide end mill. After each pass, I'd raise the head, vacuum out the chips and put a little stream of A-9 Aluminum Cutting Fluid all along the groove.

Here's what I got away with:

- 1/4" 2-flute carbide end mill (short bit -- I think it's a 1.25" flute length bit)
- 6000RPM
- 0.3 IPS (so 0.0015" chip load per flute)
- 0.060" depth of cut per pass

I found it helpful to do a dry pass to start at 0.010" depth, to outline where the groove would be and leave me a little channel for fluid for the first pass. It also showed me that my workpiece wasn't very flat with respect to the tool... :/

This chart proved handy. On some of my earlier runs, I was really pushing the recommended chip load limits.

(9 July update with more numbers)

I got some new, shorter end mills. The 1/4" 3-flute didn't sound great at the settings I liked before, so I turned down the depth-of-cut to 0.010 again (yargh):

UPDATE: ignore this set of numbers; after getting 0.050 or so into the material, the mills kept loading up. Sigh, back to the conservative numbers.

3-flute solid carbide end mill
10,000 rpm
1 ips
0.010" depth of cut
okay, a little whiny

4-flute solid carbide end mill
10,000 rpm
1 ips = 0.0015" chip load
0.010" depth of cut
very nice

4-flute solid carbide end mill
10,000 rpm
1 ips
0.020" depth of cut
not bad

4-flute solid carbide end mill
10,000 rpm
1 ips
0.030" depth of cut
a little whiny but not bad; eventually loaded up badly

4-flute solid carbide end mill
10,000 rpm
0.3 ips
0.030" depth of cut
much whinier, at 1/3 the feed rate!

4-flute solid carbide end mill
10,000 rpm
1 ips
0.050" depth of cut
whiny, then loaded up with material

4-flute solid carbide end mill
10,000 rpm
1 ips
0.020" depth of cut
this seems to be sustainable, but keep an eye on it

(Updated to fix ipm numbers)

We have a Shopbot PRS Alpha with a 2HP HSD spindle at work, and I've been experimenting with cutting aluminum on it. Here are my latest results:

All were short passes across the face of a 1/2" 6061 T6 aluminum plate (so watch for heat buildup for actual tasks). Note that the 6-series behaves MUCH differently from 5-series aluminum. I need to experiment more, but I think 5052 will be much better to mill on a shopbot than 6061.

Summary of max feed rates I felt comfortable with:

3-flute 1/4" solid carbide end mill:
6000 rpm
0.020" depth of cut
0.30 ips = 18 ipm = 0.001" per flute

1-flute onsrud spiral 1/4" cutter, 1.25" cut length.
I think I bought too long a bit so it chatters:

1.25" 2-edge face cutter:
3000 rpm
0.005" depth
0.1 ips = 6 ipm = 0.001" per flute

2-flute 1/2" TiCN-coated solid carbide end mill:
12000 rpm
0.03" depth of cut
0.40 ips = 24 ipm = 0.001" per flute


3-flute 1/4" solid carbide end mill

3000 rpm
0.020" depth of cut
0.050 ips = 3 ipm = 0.000333" per flute
works good

3000 rpm
0.040" depth of cut
0.050 ips = 3 ipm
sounds bad; I think it's loading up

6000 rpm
0.020" depth of cut
0.10 ips = 6 ipm
seems okay

6000 rpm
0.020" depth of cut
0.20 ips = 12 ipm = 0.000666" per flute
seems okay

6000 rpm
0.020" depth of cut
0.30 ips = 18 ipm = 0.001" per flute
also okay

6000 rpm
0.020" depth of cut
0.30 ips = 18 ipm = 0.001" per flute
also okay

12000 rpm
0.020" depth of cut
0.60 ips = 36 ipm = 0.001" per flute
some vibration, maybe okay

18000 rpm
0.020" depth of cut
0.90 ips = 54 ipm = 0.001" per flute
tends to screech. do I smell something burning?

1-flute onsrud spiral 1/4" cutter, 1.25" cut length:

3000 rpm
0.020" depth of cut
0.050 ips = 3 ipm = 0.001" per flute
screechy chatter

6000 rpm
0.020" depth of cut
0.050 ips = 3 ipm = 0.0005" per flute
chatter twice as loud

12000 rpm
0.020" depth of cut
0.050 ips = 3 ipm = 0.00025" per flute
now sounds like "bizzity bizzity bizzity..."

18000 rpm
0.020" depth of cut
0.050 ips = 3 ipm = 0.000?" per flute
same but faster

12000 rpm
0.010" depth of cut
0.050 ips = 3 ipm = 0.00025" per flute
same but higher pitched

1.25" 2-edge face cutter:

3000 rpm
0.005" depth
0.05 ips = 3 ipm = 0.0005" per flute
not bad

3000 rpm
0.005" depth
0.1 ips = 6 ipm = 0.001" per flute
not bad. nice rainbow finish!

3000 rpm
0.010" depth
0.1 ips = 6 ipm = 0.001" per flute
some chatter but not bad.

6000 rpm
0.010" depth
0.2 ips = 12 ipm = 0.001" per flute
bigger c-shaped chips. occasional grindy noises

2-flute 1/2" tin-coated solid carbide end mill:

3000 rpm
0.020" depth of cut
0.050 ips = 3 ipm = 0.0005" per flute
quiet but unhappy screeches

6000 rpm
0.010" depth of cut
0.050 ips = 3 ipm = 0.00025" per flute
seems pretty happy

6000 rpm
0.010" depth of cut
0.10 ips = 6 ipm = 0.0005" per flute
starting to have some vibration

6000 rpm
0.010" depth of cut
0.20 ips = 12 ipm = 0.001" per flute
not bad

12000 rpm
0.010" depth of cut
0.40 ips = 24 ipm = 0.001" per flute
not bad

12000 rpm
0.015" depth of cut
0.40 ips = 24 ipm = 0.001" per flute
still not too bad

12000 rpm
0.03" depth of cut
0.40 ips = 24 ipm = 0.001" per flute
still okay

12000 rpm
0.05" depth of cut
0.40 ips = 24 ipm = 0.001" per flute
tends to whistle and vibrate

Sunday, June 14, 2009

Simple collapsible product photography rig

Here's an easy table saw project that breaks down into a set of flat panels for storage and transport.


- 1 plastic light panel as a flash diffuser, available at your local hardware store or TAP plastics
- a 2 foot by 4 foot piece of white flexible plastic from TAP for the continuous backdrop
- (optional) 2 foot by 4 foot piece of adhesive-backed anti-reflective black flocking material, to stick on the back of the white plastic, making the backdrop black/white reversible
- about 2 feet by 5 feet of 3/4" cabinet-grade plywood

Table saw blades are about 1/8" thick, which is perfect to create the slots for the diffuser panels. I cut a slot about 1/4" deep to hold the upright piece of plywood. That slot has to be just the right width in order to hold the upright rigid. If you want something more secure, it's easy to cut two 1" wide, 2 foot long strips and put them on either side of the slot to effectively make it much deeper.

I used solid birch for the top and front slots that hold the backdrop in place, but plywood would work just as well.

Saturday, June 06, 2009

Determinant sudoku

Some friends of mine have trouble finding sufficiently difficult sudoku puzzles to keep them occupied. So one day while daydreaming I came up with Determinant Sudoku, in which you take the determinant of each square within a valid sudoku and make a super-square in which no row or column repeats a determinant.

In base-4 sudoku, such a Determinant Sudoku is a grid of 12x12 numbers, not too much larger than a base-10 ordinary sudoku. But I wasn't sure if any valid base-4 Determinant Sudoku actually existed, so I wrote a program to help me check.

I did manage to construct a valid base-4 Determinant Sudoku, but I'm not sure how many others exist.

Here is the source code to enumerate all base-4 sudoku and print their determinants, and I've copied the comment header below which includes more explanation and the base-4 determinant sudoku I found:

// This program enumerates all the base-4 sudoku and calculates
// their determinants.
// The idea is this: start with base-4 sudoku, so that you get
// 2x2 squares which have the numbers 0,1,2,3 with none repeated.
// Create a 2x2 grid of those 2x2 squares, so that each row and column
// has the numbers 0,1,2,3. (Ordinary sudoku, but 4x4 instead of 9x9).
// Here's an example of a valid base-4 sudoku:
// 01 23
// 23 01
// 10 32
// 32 10
// There appear to be 288 distint base-4 sudoku, without removing isomorphisms.
// My idea was to take the determinant of each of those 2x2 matrices and create
// a "determinant sudoku".
// In matrix math, the determinant of
// a b
// c d
// is a*d - b*c.
// There are six possible determinants of the 2x2 blocks.
// To construct a base-4 determinant-sudoku, make a 3x3 grid of 4x4 base-4
// sudoku blocks. There will be six rows and six columns of 2x2 squares.
// How many base-4 determinant-sudoku blocks exist?
// This program almost answers that question, but not quite.
// Of the 288 base-4 sudoku, 168 have the same determinant, leaving 120
// base-4 sudoku that could contribute to a base-4 determinant-sudoku.
// I constructed one base-4 determinant-sudoku by hand:
// 01 23 | 01 32 | 02 31
// 23 01 | 32 01 | 31 02
// | |
// 10 32 | 10 23 | 20 13
// 32 10 | 23 10 | 13 20
// ----------------------
// 01 32 | 02 31 | 01 23
// 32 01 | 31 02 | 23 01
// | |
// 10 23 | 20 13 | 10 32
// 23 10 | 13 20 | 32 10
// ----------------------
// 02 31 | 01 23 | 01 32
// 31 02 | 23 01 | 32 01
// | |
// 20 13 | 10 32 | 10 23
// 13 20 | 32 10 | 23 10
// Determinants:
// -2 2 -3 3 -6 6
// 2 -2 3 -3 6 -6
// -3 3 -6 6 -2 2
// 3 -3 6 -6 2 -2
// -6 6 -2 2 -3 3
// 6 -6 2 -2 3 -3
// Each 4x4 block is a valid base-4 sudoku. And the 6x6 grid of 2x2 blocks
// has no repeated determinants in any row or column.
// (This base-4 determinant sudoku isn't very nice, since it repeats the
// same 3 base-4 sudoku 3 times each.)
// So the question remains open: how many base-4 determinant sudoku are there?

Tuesday, June 02, 2009

Drill holes in objects using sketchup

If you've ever used sketchup for woodworking, you've probably noticed that it's a pain to drill holes in your workpieces. You have to create a circle, type in its diameter, then use the push/pull tool to push the hole through to the other side. Unfortunately, you can't make the hole a component, either, since it won't intersect right unless you explode it first.

So here's a ruby extension for drilling holes with a single click. Save the below code to a file called "drill.rb" in your Plugins/ directory. Open sketchup, go to Window... Preferences, click Extensions, and enable "Ruby Script Examples". Then you may need to restart sketchup to see the Plugins dropdown. Select "drill", type a hole diameter in the VCB and then hit enter. It'll save that value until you change it. Now click on a face on a 3d object to drill a hole through it.

# Hacked together from the linetool example by Jason E. Holt
# Copyright 2005-2008, Google, Inc.

# This software is provided as an example of using the Ruby interface
# to SketchUp.

# Permission to use, copy, modify, and distribute this software for
# any purpose and without fee is hereby granted, provided that the above
# copyright notice appear in all copies.


require 'sketchup.rb'

class Drill

@@drill_diameter = 1

# This is the standard Ruby initialize method that is called when you create
# a new object.
def initialize

def draw(view)
Sketchup::set_status_text "DIAMETER", SB_VCB_LABEL
Sketchup::set_status_text @@drill_diameter.to_s, SB_VCB_VALUE

# The activate method is called by SketchUp when the tool is first selected.
# it is a good place to put most of your initialization
def activate
Sketchup::set_status_text "DIAMETER", SB_VCB_LABEL
Sketchup::set_status_text @@drill_diameter.to_s, SB_VCB_VALUE

# The onLButtonDOwn method is called when the user presses the left mouse button.
def onLButtonDown(flags, x, y, view)
center_ip =
center_ip.pick view, x, y
face = center_ip.face

center = center_ip.position
normal = face.normal

if ( face )
circle = view.model.entities.add_circle center, normal, @@drill_diameter / 2.0

other_entities = face.all_connected

reversed_normal = normal.reverse

circleface = nil

# This seems lame. add_circle seems to add it as a face, but then I have
# to go looking for that face.
for other in other_entities
if other.typename == "Face" and other.classify_point(center) == 1
#UI.messagebox("found myself :/")
circleface = other

# Find a face opposite the one they clicked in
for other in other_entities

#UI.messagebox("type is " + other.typename)

if other.typename == "Face"
if reversed_normal.samedirection? other.normal
#UI.messagebox "found it!"

point_on_other_face = center.project_to_plane other.plane
if other.classify_point(point_on_other_face) == 1
#UI.messagebox "yes, point projects onto other face."
pushpull_distance = point_on_other_face.vector_to(center).length

#UI.messagebox "nope, doesn't project"
#UI.messagebox "nope"


UI.messagebox "Drilling only works on faces"

def onUserText(text, view)

# The user may type in something that we can't parse as a length
# so we set up some exception handling to trap that
value = text.to_l
# Error parsing the text
puts "Cannot convert #{text} to a Diameter"
value = nil
Sketchup::set_status_text "", SB_VCB_VALUE
return if !value

@@drill_diameter = value

end # class Drill

# This functions is just a shortcut for selecting the new tool
def drill
end"PlugIns").add_item("Drill") {

Friday, May 29, 2009

On Indianapolis

Wow, so Indy is actually a really fun city. It's big without feeling as cramped as cities like SF. If you ever travel to within 100 miles of Indianapolis, you are required to stop at Yats on College St. and try the amazingly cheap, amazingly good creole food. Seriously, what a cool place.

Friday, May 22, 2009

Skip every other frame with mencoder

Recently I sped up a video by dropping every other frame. Here's how to do it with mencoder: multiply the original video's framerate by 2, then specify the same fps as the original for the output fps. So mencoder starts by "playing" the original video at 2x speed, then has to drop every other frame to work with the "lower" frame rate:

mencoder -fps 60 -ofps 30 -ovc lavc -oac copy in.avi -o out.avi

Sunday, May 17, 2009

Android: millisecond resolution time

The only mention I could find of time in the android docs was android.text.format.Time. It has a tomillis() function that returns things in units of milliseconds, but the time only increments in values of 1 second, so that's pretty useless.

These guys mention android.os.SystemClock, which works for me:

package com.example.benchmark;

import android.os.Bundle;
import android.widget.TextView;
import java.util.Formatter;
import android.os.SystemClock;

public class BenchmarkActivity extends Activity
/** Called when the activity is first created. */
public void onCreate(Bundle savedInstanceState)

long before = SystemClock.uptimeMillis();

long i, j=0;
for(i=0; i<23456780; i++) j+=i;

long after = SystemClock.uptimeMillis();

long millis = after - before;

Formatter f = new Formatter();

String foo = f.format("%d", millis).toString();

TextView tv = new TextView(this);


Android: "ant install" complains about INSTALL_FAILED_ALREADY_EXISTS

The android docs about writing apps without eclipse say to run "ant install" to upload an app to the emulator that's currently running. What they don't tell you is that after you've tweaked your code and recompiled, running "ant install" again will complain that the application is already installed. You could use the virtual phone's Settings... Applications... Manage Applications... [click on your app]... Uninstall each time, but that sucks. There appears to be an "ant uninstall" command, but that doesn't actually remove the app on my emulator.

What they should have mentioned is that you can merely run "ant reinstall".

(The other thing the docs suck at is making it clear what classes are in what versions of the API. So for example, android.text.format.Time wasn't found when I picked --target 1 (the original API), and I had to start a new "hello, world" app with --target 3 before it'd work. Very frustrating for a new android developer).

Wednesday, May 06, 2009

Behavioral confirmation

I was astounded to hear about this principle years ago, but could never remember the name. Apparently it's also called "expectancy confirmation". It takes a second to realize what's so amazing about the idea: when you expect somebody to behave a certain way, not only will you treat them differently, but *they'll subconsciously help you confirm your bias*. So expecting somebody to lie to you makes them more likely to actually do so!

For such a mind-blowing principle, it's documented really poorly online. The book search result was the closest thing I could find.

Tuesday, May 05, 2009

Enable external monitor on a thinkpad t41 for older ubuntu linux

In newer ubuntu distros, the t41 laptops seem to do the right thing, but in this old feisty release I couldn't figure out how to turn on the external monitor. This did the trick:

aticonfig --enable-monitor=crt1

Friday, May 01, 2009

Ubuntu "a camera has been detected" dialog checkbox "always perform this action" doesn't work

Whenever ubuntu detects that you've plugged in a camera, it opens an annoying dialog box. It's sad that this bug still hasn't been fixed, since it's been known for so long. But here's what to do, as reported by hammer89 in this bug. I'm posting it here to make it easier to find:

Open a terminal and type gconf-editor ... then in the list on the left navigate to / --> desktop --> gnome --> volume_manager --> prompts... then change the value for "camera_import_photos" to "1"

It's amazing how many hits I've gotten on my "fix gutsy" post. It seems that lots of bug fixes don't get good visibility, so little public services like this are actually pretty useful.

Friday, April 24, 2009

fix broken ubuntu gutsy apt-get sources.list

I couldn't find any docs about what to do with my broken gutsy install now that the apt repositories have all stopped carrying gutsy. "Drop what you're doing and reinstall with hardy" is not an okay answer this afternoon. So here's the solution.

Obsolete releases get moved to, so here's my working /etc/apt/sources.list:

deb gutsy main restricted universe multiverse
deb-src gutsy main restricted universe multiverse

deb gutsy-updates main restricted universe multiverse
deb-src gutsy-updates main restricted universe multiverse

deb gutsy-security main restricted universe multiverse
deb-src gutsy-security main restricted universe multiverse

Use with caution of course.

Daydream in blue

I love university radio stations! The clear channel stations suck -- it's all repeats of a couple of popular songs. But the local university station almost always has something I haven't heard before.

The other day they played Daydreamin' by Lupe Fiasco. And it turns out to be one of those songs with a fascinating past.

The Encyclopedia of Record tells us it was first recorded in 1968 as Daydream by The Wallace Collection.

I, Monster has a nice take on it.

The Pharcyde's She Said (with Fuzz Face from Portishead, naturally) rocks.

The Beta Band called theirs Squares.

Maybe later I'll look up some of the other songs in the wikipedia article.

Tuesday, April 21, 2009

Write a text format protobuf in python

The protobuf docs aren't clear on this, but I found the magic incantation in one of the tests.

To create a text format (ascii printable) protocol buffer using the python interface,

from google.protobuf import text_format


Thursday, April 16, 2009

Comparing images pixel for pixel on the linux command line

There's an old file format called ppm that stores an image as a very simple, very large text file. Unfortunately, there are several types of ppm images, without even getting into the pgm and pbm images which form the rest of the pnm family of image formats.

The Wikipedia netpbm article gives more details on how the family of formats work.

The P3 ppm (sometimes called "ascii ppm" or "plain ppm") image is most useful. It's surprisingly simple, and I've often implemented it by hand in C when I got sick of trying to make an image library work and just needed to get pixels into an image. It's also useful for pixel-by-pixel comparisons:

Let's say you have two images, a.png and b.png, and you want to know if the pixels differ at all between the two images. You could use gimp to subtract them and then tweak the histogram to hilight the differences, but it's slow going.

Instead, you can convert them to P3 ppm files and use diff to compare:

(-compress none tells the ImageMagick convert utility to produce a P3 ppm)
$ convert a.jpg -compress none a.ppm
$ convert b.jpg -compress none b.ppm
$ diff a.ppm b.ppm > differences
$ head differences
< 58 61 58 58 61 58 58 60 58 58 60 58
> 58 60 58 58 60 58 58 60 58 58 60 58

So, 13000 lines into the files, we see that a 61 has become a 60, and that it does so again the next pixel over. (These files have lines with 4 pixels each. In the above output, a.ppm had (rgb values) (58,61,68), (58,61,68), (58,60,58), (58,60,58), for example. So b.ppm differed by a single bit in the green channel in two adjacent pixels.)

Sunday, April 12, 2009


Supermax prisons have always struck me as evil institutions. This New Yorker article on solitary confinement is subjective, but also offers various pieces of research to support its claims.

I've often been inclined to write letters to inmates in solitary, although I hesitate to reveal my street address. Maybe someone could set up an email-to-snail-mail gateway like this one, but free, and people could volunteer to write to inmates. I wonder how much it would help.

Saturday, April 11, 2009

Shared google reader items

I think b has the right idea about using a shared google reader page to share links instead of creating a new blog post for each one.

Friday, April 10, 2009

Gatto + Gilbert

I've long been a fan of John Taylor Gatto. He talks a lot about the education system, but also about what he calls networks vs. communities.

And why does society now gravitate toward networks instead of community? I think Dan Gilbert has the answer there: we avoid commitment, even though it makes us less happy. And it does so in general, not just in the network/community sense.

I'm hopeful that society will learn from this and develop healthy ways of accepting commitment without discarding flexibility and choice. But I'm not sure that Gatto's communities will re-emerge.

Maybe there's something new that we'll stumble upon that will help us feel less lonely. I hope so, because I think the lack of it is corrosive.

Self-haters donate more

Another fascinating study at the overcoming bias blog: people are less charitable when they feel they're more moral.

Classic engineering mistakes

I like this list of classic mistakes in engineering projects. Here's the author's summary (see the original article for description):

1. Undermined motivation

2. Weak personnel

3. Uncontrolled problem employees

4. Heroics

5. Adding people to a late project

6. Noisy, crowded offices

7. Friction between developers and customers

8. Unrealistic expectations

9. Lack of effective project sponsorship

10. Lack of stakeholder buy-in

11. Lack of user input

12. Politics placed over substance

13. Wishful thinking

14. Overly optimistic schedules

16. Insufficient risk management

17. Contractor failure Insufficient planning

18. Abandonment of planning under pressure

19. Wasted time during the fuzzy front end

20. Shortchanged upstream activities

21. Inadequate design

22. Shortchanged quality assurance

23. Insufficient management controls

24. Premature or too frequent convergence

25. Omitting necessary tasks from estimates

26. Planning to catch up later

27. Code-like-hell programming

28. Requirements gold-plating

29. Feature creep

30. Developer gold-plating

31. Push me, pull me negotiation

32. Research-oriented development

33. Silver-bullet syndrome

34. Overestimated savings from new tools or methods

35. Switching tools in the middle of a project

36. Lack of automated source-code control

Wednesday, April 08, 2009

Dealing with impossible crises

I like this article on Dealing with impossible crises. The author's summary:

  • Calm down, smile and remain polite to maintain any chance of success
  • Become a human being rather than a faceless number
  • Be persistent to grind away the brick wall
  • Be prepared to lose to expand your freedom of thought and action
  • Be clear about your objective so you can be flexible about how to achieve it
  • Find who can, since often the first person you speak to cannot help
  • Take an active part in making things happen more efficiently
  • Make the other person feel good about helping you so that they are more likely to help you
  • Don’t relax this stance until it’s over, it’s easy to snatch defeat from the jaws of victory.

Thursday, April 02, 2009

Laman and Lemuel are dead

If you're one of those people who knows about the Book of Mormon and also Rosencrans and Guildenstern are Dead, then seriously, what's wrong with you? Nevertheless, you'll enjoy
Laman and Lemuel are Dead.

Friday, March 27, 2009

The dark side of autism

"The monster inside my son" is kind of mind blowing. It's about an autistic kid who basically goes crazy after about 18.

Sunday, March 22, 2009

Beautiful short film: "World Builder"

This film about a man building a virtual world is beautiful and well executed.

Friday, March 20, 2009

Ironic homage to skateboarding

At the Kaiser clinic in Mountain View, California, there's a delightfully nostagic sculpture of a youngster playing marbles, skateboard at his side. And the metal stubs installed on the edge of the ledge next to the sculpture? There to block skateboarders from doing boardslides. Apparently only old-fashioned skateboarding is commemorable.

Classic talk by Hamming: "You and Your Research"

I thought this talk about how to do Nobel-prize quality research was pretty insightful.

Thursday, March 12, 2009

The Done Manifesto

I like the spirit of the Done Manifesto.

Tuesday, March 10, 2009

Old color photos

I love these old color photographs. I always try to imagine old times in real life color instead of sepia, but I don't usually do it very well. These photos really make it easier to connect with my grandparents' generation.

Wednesday, March 04, 2009

Pepper sprayed for politeness

A canadian man asked a border guard to say please, and got pepper sprayed instead. Regardless of whether the guard should have been more polite, he shouldn't have harmed this guy.

If a police authority can't agree with someone, then there's a whole legal system for determining what's right and wrong, and that system is designed to dispense justice without cruelty. Allowing officers to inflict pain on someone for /not following orders/ sets up the officer himself as a dictator who not only decides what's right and wrong, but dispenses cruel and unusual punishment that the courts wouldn't even be able to.

Thursday, February 26, 2009

Winning the cold war

Gosper tells the story of one of the old minicomputers in the computer history museum, built during the cold war. The Soviets were trying to keep up technologically, and managed to acquire this particular model through devious and circuitous routes. They proceeded to reverse engineer it and build thousands of duplicates on their own, making it the dominant computer of its kind in the USSR.

The US government discovered this and thoroughly chastized the manufacturer for allowing this technological breach.

However, Gosper asserts that the architecture and instruction set were such a loss that the machine set the soviets back further than if they had designed their own machine from scratch, and that the manufacturer instead should have been given a medal for thier indirect assistance to the western world.

Monday, February 23, 2009

Is legalization of marijuana an astroturf by big tobacco?

I see stories on digg and reddit almost daily about how wonderful it'd be if we legalized marijuana. I tend to support it out of libertarian sensibilities, but I'm suspicious about the sheer volume and variety of things I see supporting it online.

I'm sure there are plenty of people who support it, and perhaps the elite posters on digg and reddit just happen to be in that camp. But I can't help suspecting that Big Tobacco sees this as their exit strategy from the increasingly unpopular tobacco industry domestically. Anyone have any evidence for or against that hypothesis?

Sunday, February 15, 2009

Over 50% of the world population in the middle class

This article in The Economist is really remarkable! I had no idea so many people in the world were doing so well. The associated statistics are also quite remarkable.

Saturday, February 14, 2009

The opposite of happiness is boredom

From 31 laws of fun:

Timothy Ferris: "What is the opposite of happiness? Sadness? No. Just as love and hate are two sides of the same coin, so are happiness and sadness... The opposite of love is indifference, and the opposite of happiness is - here's the clincher - boredom... The question you should be asking isn't 'What do I want?' or 'What are my goals?' but 'What would excite me?'... Living like a millionaire requires doing interesting things and not just owning enviable things."

Tuesday, February 10, 2009

Why walmart doesn't suck. Also, on careers.

I've had this vague sense for a while, but this article gives some concrete facts in favor of Walmart. Another winner from the NY Post!

And on an unrelated note, I ran across this Kurt Vonnegut quote recently, and it struck me as amusingly true:

“If you can do a half-assed job of anything, you're a one-eyed man in a kingdom of the blind.”

Tuesday, January 27, 2009


I like this description of Wabi-sabi. It describes the approach I've taken to my projects lately; I don't let myself get hung up on imperfections. Each of my projects has blemishes, and that is how they should be.

Sunday, January 25, 2009

Love my Dewalt planer!

Thank you, Dewalt! Right after I got my DW735 planer, I decided it'd be a good idea to plane some wood with countersunk nails in it, and managed to take a couple of chips out of the blades, which means that I now get three little raised ridges on everything I plane. So today I remembered to buy a set of replacement blades, although I was dreading the replacement process, since I'd heard it's really painful to get them aligned properly.

It turns out that replacing the blades is a delightfully easy and elegantly designed process. A single allen wrench is all that's required, and it came with the tool, in its own holder. The process of disassembly and replacement is obviously something they put a lot of thought into: everything's easy to reach and simple to remove. There was almost no dust inside the machine at all. And the allen wrench even has magnets on the handle for lifting out the blades and guards. The whole process is alignment-free; the blades have slots that fit squarely over pins on the shaft.

The best part? The blades are reversible. Whereas a lot of companies go to great lengths to make big profits on replacement parts, Dewalt essentially included a replacement set with the tool.

That rocks! That's the kind of quality that makes me willing to spend twice the price of a cheaper tool. We've spent thousands of dollars on Dewalt tools at work, and it's all been worth it. Well done.

Tuesday, January 20, 2009

Obama's inagural address

Here's the text of the speech. Lots of grand ideas and stirring words, but I really like that he said this: "we reject as false the choice between our safety and our ideals".

Saturday, January 17, 2009

Belkin routers suck

The other day I lauded Turtle Wax for their response to one of my blog posts about their suboptimal product packaging, and mentioned the evil that is astroturfing. And today I read that a
Belkin employee was caught using mechanical turk operators to astroturf positive reviews for a crappy Belkin router. Boo for Belkin.

Tuesday, January 13, 2009

A 4-color proof

"A four color proof", a parody of "A Boy Named Sue" by Johnny Cash.
Dedicated to Appel, Haken and Koch, with thanks to Hilarie Orman.
Released into the public domain, January 13 2008.

Well my daddy left home when I was three
And he didn't leave much for ma and me
Just a few conjectures and an empty bottle of booze.
Now, I don't blame him cause he run and hid
But the meanest thing he ever did
Was to leave us with a 4-color sketch, unproved.

Well he must a' thought it quite a joke
And it got a lot of laughs from a lot of folks
It seems I had to prove my whole life through.
Some gal would giggle and I'd get red
And some guy'd laugh and I'd bust his head,
I tell ya, it aint easy writin' a 4-color proof.

Well, I grew up quick and I grew up mean,
My predicates got hard and my insights keen,
I'd roam from town to town to seem aloof.
But I made a vow to the moon and stars
That I'd search the journals and seminars,
And kill that man who gave me that awful proof.

Well, it was in Atlanta in March '08
And I'd just hit town and was feeling irate,
so I thought I'd hit G4G and see what's new.
At an old card table, on a fractal rug,
Dealin' puzzles, lookin' smug,
Sat the dirty, mangy dog that claimed that proof.

Well, I knew that snake was my own sweet dad,
From a worn-out picture that my mother'd had,
And I knew that frumpy coat and his ugly tie.
He was big and bent and gray and old,
and I looked at him and my blood ran cold
And I said: "How do you do? 4-color's true!
Now you gonna die!"

Well I hit him hard right between the eyes,
with a manuscript, about 10 feet high,
With nineteen hundred thirty-six cases proved.
And I showed him the code, and the bill I owed,
For the twelve hundred hours of time I'd stole'd,
And said "Just read that through and stay unmoved!"

I tell ya, there'd been longer proofs,
But I really can't remember whose
It read like a dictionary and strained the eye.
I heard him laugh and then I heard him cuss,
He went for his pen and I pulled mine first
He stood there lookin at me and I saw him smile.

And he said: "Son, this world is rough
And to make it in math he's gotta be tough
And I knew I wouldn't be there to help ya along.
So I give ya that sketch and I said goodbye,
I knew you'd have to get tough or die
And it's that theorem that helped to make you strong."

And he said: "My sketch was one hell of a blight,
And I know you hate me and you've got the right
To graduate now, and I wouldn't blame you if you do.
But you ought to thank me, before you go,
For the vectors in the plane and the snarks that you show,
Cause it's my faulty proof that got you through.

I got all choked up and I threw down my proof
And I cited his work and he gave me my due
And I came away with a different point of view.
And I think about him, every now and then
Every time I try, and every time I win
And if I ever have a son, I think I'm gonna have him prove,
FLT or Goldbach, or anything but 4-color cycling! I still hate that proof!

Monday, January 12, 2009

Turtle Wax rocks :)

Marc, a rep from Turtle Wax, left a comment on yesterday's rant about poor product packaging. I really respect a couple of the things he said:

  • He acknowledged that he works for the company, and
  • He acknowledged that a defect exists.

That alone is praiseworthy, even if they had decided not to fix it. But apparently they do have a fix in the works, and he even gave a timeline. That rocks.

Astroturfing is an insidious practice that society isn't really prepared to handle yet. So I'm glad when companies take the high road and respond honestly instead of ignoring their customers or being deceptive. Thanks, Marc!

Sunday, January 11, 2009

Also, turtle wax sucks.

I must really sound like a curmudgeon sometimes, with all this complaining. Stupid product tricks do make me grumpy, but they also mystify me: why do premium brands sully their reputation with silly, preventable mistakes? Is it a random fluke? Price competition from cheap brands? Complacency? Mediocrity that accumulates as a company ages?

I bought some Turtle Wax to use on my cast iron tool worktables. Here's a company that's over 60 years old, whose product probably hasn't had to change much over that time. It came in a little tub with an applicator on top. Great.

Except that it's virtually impossible to get the yellow lid off without taking off the lid to the tub, and the tub is so flimsy that as the lid flies off, you end up with a handful of wax, and a gooped up lid attached to the lid holding the applicator safely inside. Seriously, wtf?

Did nobody at Turtle, Inc. ever actually think to try their product? Did environmental DDT contamination cause statistically thinner shells over time?

Even Sawstop didn't get it right with their $5000 cabinet saw. Reviews called it the finest saw they'd ever used, but both of the ones we got at work had some stupid missing or incorrect pieces or something.

Laguna LT14 bandsaw sucks

We just got a bandsaw at work, a $1600 Laguna LT14 SEL. We could have gotten a much cheaper unit from the likes of Jet or Grizzly, but we figured it's worth a premium price to get a tool that's elegant, high quality and reliable.

Presumably Laguna knows their customers expect a premium tool. So it totally mystifies me that setting up the saw for 110v took me several hours and multiple trips to the hardware store.

Seriously, though. This is woodworking; people care about brand names, and they talk to their friends. Laguna makes a lot of different types of tools, so they stand to make a lot of sales when they impress a customer with a quality product. We bought ours because one of the guys in the group recently bought a 16" bandsaw from them. So it's mind-rendingly stupid to ship a product that's $10 and a few hours of QA short of working correctly.

Now, the website specs only list the saw as working at 220v. But the manual shows both of the 14" models as supporting 110v as well, although it doesn't say anything about how to select between the two. Also, the unit doesn't ship with a plug. That sent me on hardware store trip #1, where I spent half an hour purchasing a $4 part. Here's an idea: if people are spending $1000 more than they have to on your product, their time is probably worth a lot to them, so don't waste it.

I consulted the motor housing, which does actually describe how to rewire for 110v. Now, a nice piece of equipment would have a block of screw terminals so that all it takes is a screwdriver to reconfigure it. But no, all the wires were spliced. So I got to spend an hour looking for wire nuts, then looking for my soldering iron, in order to resplice the wires according to the instructions on the motor.

Finally we try to turn it on, and get nothing but a buzz. We notice that the box the switch is in also mentions 110v vs. 220v, but someone at the factory has blacked out the 110v text with a permanent marker. Right on the side of the saw, just about at eye level. So much for La Bella Forma.

So, I consult the interwebs. According to their forums, you have to call up their tech support and order a 110v switch box if you want to use the saw at 110v. A $100 switch. A $100 switch that has lots of unused terminals inside for safety switches that disable power when the panels are open, unused because this model doesn't have panel switches.

This is exactly the kind of nonsense I was trying to avoid buy spending extra on a nice tool. If you're only making $2 profit on each unit, I can understand why your manual might not be totally correct and why you didn't spend the time and money to fix the errors that inevitably happen during manufacturing. That's not to say that anyone should actually spend hundreds or thousands of dollars on a half-baked product, but at least the manufacturer has an excuse for shoddy workmanship.

But seriously, $1600 and you didn't even get the (staple-bound, fresh-off-the-inkjet printer) manual right? You couldn't even be bothered to ask if I'd like the correct power switch or the right kind of power plug? Astounding.

Friday, January 09, 2009

Leap of Faith

Here's a delightful 1-minute CGI film called Leap of Faith.

Thursday, January 08, 2009

Engineering is plumbing, not math

Engineering is much more like plumbing than math.

As a programmer, being productive rarely involves finding new O(log(n)) algorithms. Adding new features and even optimizing for performance has much more to do with trying to figure out how to turn a vector of scoped_ptr<FooFactory>& into const ThreadableFooInstanceWrapper* tuples, regardless of whether the change actually affects the underlying algorithm in a nontrivial way.

My coworker pointed out that this tendency isn't limited to computer science. Modern digital devices come with slick programming interfaces, accessed over buses like I2C, SPI and CAN. All the datasheets have timing diagrams down to the individual bit levels for these standard, widely used interfaces, and at some point you'll get to hook up a logic analyzer to the lines and pull out the diagram to see why your commands don't seem to be affecting the chip. Oh, also, it needs 3 different power supply rails, and the following 6 very specific capacitors placed within 1cm of the power pins, before it'll do anything at all.

The semantic thing you're trying to get the chip to do -- turn off output B, enable automatic black level correction, or set the refresh rate -- is utterly straightforward. But hooking up the plumbing correctly so you can tell it that takes up a huge amount of the development time.

Mechanical engineering has that nature too: brackets, matching up bolt patterns between standard parts, sourcing a flange button head cap screw instead of the ordinary button head cap screw because the head is 2mm shorter and clears the bolts on the other leg of the L bracket.

When faced with a big project, an engineer's first impulse is to throw away what looks like a big mess of plumbing and start reinventing the core machine. That's almost always the wrong thing to do. Expect to spend at least half your time on plumbing by the time the system ships.

I suspect that engineering would benefit from a more explicit focus on plumbing skills. Yes, it's good if a programmer can break quicksort down into little pieces, but how many times have you had to implement quicksort? Okay, now how many times have you spent an hour trying to figure out how to get a new C++ library to work because the author didn't give any example code, and you didn't know which kinds of objects had to be initialized and in what order just to get the library initialized properly?

How much time have you spent pulling data from one source into a data structure so you can stuff it into a different data source in a slightly different format? Maybe CS departments need a Software Plumbing Research Group figuring out how to cut down on all the manual plumbing we have to do, and teaching classes on how to quickly rig up conduits between AJAX data sources and STL data structures used by C++ libraries.

And if you're on the designing end of a system, it suggests that before you write the detailed document for all the clever algorithms at the core of your system, you should write up some very straightforward recipes, with lots of ready-to-compile, complete examples (no pseudocode!) for how to build, use, and safely change what you've built. Make sure to copy and paste the examples into a clean environment and make sure it builds as advertised.

Stop assuming that algorithms are the important part and treating the plumbing as an afterthought, and you'll spend less time being frustrated at how hard it is to reach the semantics to make your tweaks. The plumbing's there; deal with it. And realize that your ability to hack the plumbing efficiently (or simplify it without crippling the system) is a big part of your overall productivity as an engineer.