Canon DSLR and Linux

Well, in the past couple of days I got both a pleasant surprise and a bit of a let-down.

First, I discovered that sometime in the past year or two, the gphoto2 folks have been very busy with Canon DSLRs. They’re reasonably well supported (in spite of what appears to be a lack of any real support from Canon; it looks like they’ve been busy reverse engineering the USB commands). I can connect to my Canon Digital Rebel XT (aka 350D) and change its configuration settings. I can download images from the camera (well, okay, I could do that before via the mass storage interface, but now it works as a camera not a USB drive).

I also discovered it was pretty trivial to get my serial port cable to control two cameras independently with a little Perl:

 #!/usr/bin/perl

=head1 NAME - cable-release.pl

Use a serial port to control the Canon EOS cable release.

=head1 SYNOPSIS

canon-release.pl [--port=DEVICE] [--expose=SECONDS]
[--verbose|-v] [--quiet|-q] [--version|-V] [--help|-h]

=head1 DESCRIPTION

Some Canon EOS DSLRs use a cable release separate from the USB camera
control. Among these are the Canon 300D and 350D. Instruction may be
found on the internet for making these.

=cut

use Device::SerialPort;

use Getopt::Long qw(:config bundling noignore_case);
use Pod::Usage;

use constant DEF_MIRROR_LOCK => 2;

=head1 OPTIONS

=over 4

=item --port=DEVICE

Name of serial device for cable release. Defaults to /dev/ttyS0.

=item --mirror-lock[=SECONDS]

Assume mirror lock is enabled in camera. If specified, delay of
SECONDS will be allowed for mirror settling. Minimum delay is 2
seconds.

=item --expose=SECONDS

Expose for SECONDS. Default is 1 second.

=item --version

Print version information and exit.

=item --verbose

Increase verbosity (placeholder).

=item --quiet

Decrease verbosity (placeholder).

=item --help

Display documentation and exit.

=back

=cut

my $VERSION = 0.1;
my %opt;
$opt{port} = '/dev/ttyS0';
$opt{expose} = 1;
GetOptions('port=s' => \$opt{port},
'mirror-lock:i' => sub { $opt{mirror} = DEF_MIRROR_LOCK
if ($opt{mirror} <= DEF_MIRROR_LOCK); },
'expose=i' => \$opt{expose},
'version|V' => sub { print(&basename($0), " version $VERSION\n");
exit 0; },
'verbose|v' => sub { $opt{verbose}++; },
'quiet|q' => sub { $opt{verbose}--; },
'help|h' => sub { pod2usage(-exitstatus => 0, -verbose => 3); },
) or &pod2usage(-verbose => 0, -exitstatus => 1);

# Minimum mirror lock is really 2-seconds. Maybe less will work if I
# use usleep from Time::HiRes, but is is at least tens of
# milliseconds.
if (exists($opt{mirror})) {
$opt{mirror} = DEF_MIRROR_LOCK if (!$opt{mirror});
if ($opt{mirror} < 2) {
$opt{mirror} = 2;
}
}

my $port = new Device::SerialPort($opt{port}, $quiet)
or die("can't open $port: $!");
$port->rts_active(F);
$port->rts_active(T);
if ($opt{mirror}) {
sleep($opt{mirror}-1);
$port->rts_active(F);
sleep(1);
$port->rts_active(T);
}
sleep($opt{expose});
$port->rts_active(F);

I’ve got the home-made cables connected to a Keyspan 4-port USB-to-serial box which works just fine.

Alas, I’ve discovered two small issues that make this a less than perfect world. First, gphoto –capture-image always gives an error. The capture works just fine, but the error still happens. Since I would be using the cable release, that’s not really a big deal. But second, you can’t talk to two cameras simultaneously attached to the computer, even if they are different USB busses. The commands from gphoto2 always seem to go to the camera most recently attached. If you detach it, then they go back to the first (and only) camera. This is a showstopper for completely automated control of multiple cameras.

In the good news category, this is at least no worse than using Canon’s EOS Capture utility since it can only control one camera at a time, also.