Skip to main content

GAGA-1: 2,766 tedious photographs and a log file

I couldn't take the uBASIC code for controlling the GAGA-1 camera any longer and I rewrote the entire thing in the other language that CHDK supports: Lua. This has resulted in a much better program with additional functionality: a proper log file stored on the camera's SD card, reading of battery levels and internal temperatures and a simple routine to check that the camera has enough memory space for the projected flight time.

Last night I ran a test taking 10 pictures per minute with a 16Gb memory card. The result is a pair of drained Energizer Ultimate Lithium batteries, 2,766 tedious photographs out the back window of the house, and a log file indicating that the camera ran from 1704 to 0005 before failing. The camera actually took less than 10 pictures per minute taking a few seconds per image as the night wore on. The gap between cycles remained at 6 seconds.

So the camera ran for 7h01m on new batteries and took a picture every 9.1s on average.

The camera's log file begins:

20100911170411,GAGA Camera Control
20100911170411,Self-check started
20100911170411,Assert property (49) -32764 == -32764 (Not in manual mode)
20100911170411,Assert property (5) 0 == 0 (AF Assist Beam should be Off)
20100911170412,Assert property (6) 0 == 0 (Focus Mode should be Normal)
20100911170412,Assert property (8) 0 == 0 (AiAF Mode should be On)
20100911170412,Assert property (21) 0 == 0 (Auto Rotate should be Off)
20100911170412,Assert property (29) 0 == 0 (Bracket Mode should be None)
20100911170412,Assert property (57) 0 == 0 (Picture Mode should be Superfine)
20100911170412,Assert property (66) 0 == 0 (Date Stamp should be Off)
20100911170412,Assert property (95) 0 == 0 (Digital Zoom should be None)
20100911170412,Assert property (102) 0 == 0 (Drive Mode should be Single)
20100911170412,Assert property (133) 0 == 0 (Manual Focus Mode should be Off)
20100911170413,Assert property (143) 2 == 2 (Flash Mode should be Off)
20100911170413,Assert property (149) 100 == 100 (ISO Mode should be 100)
20100911170413,Assert property (218) 0 == 0 (Picture Size should be L)
20100911170413,Assert property (268) 0 == 0 (White Balance Mode should be Auto)
20100911170413,Assert 2010 > 2009 (Unexpected year)
20100911170413,Assert 17 > 6 (Hour appears too early)
20100911170413,Assert 17 < 20 (Hour appears too late)
20100911170413,Assert 3138 > 2700 (Batteries seem low)
20100911170413,Assert 5078 > 1800 (Insufficient card space)
20100911170413,Self-check complete
20100911170424,Starting picture capture
20100911170426,Picture 1 taken
20100911170426,Temperatures: 34, 34, 30
20100911170426,Battery level 3017
20100911170434,Picture 2 taken
20100911170434,Temperatures: 34, 34, 30
20100911170434,Battery level 2983
20100911170442,Picture 3 taken

The time stamp is YYYYMMDDhhmmss. The three temperatures are the optical components, the CCD and the battery compartment. The camera was warm when I started because I'd been playingwith it. The battery level is in mV.

The temperature peaked early on and then settled down to a steady warm glow: the camera was warm to the touch while running. This'll be a little different on the flight since the external temperature of the capsule will drop to -55C. Here's a chart showing the CCD and Battery temperatures:

The battery declined steadily throughout the run:



And here's the code for anyone who wants to try the same thing:

-- GAGA Camera Control Code
--
-- Copyright (c) 2010 John Graham-Cumming
--
-- Performs the following steps:
--
-- Performs a self-check
-- Waits for a predetermined amount of time
-- Enters loop doing the following:
-- Take a number of photographs in succession
-- Wait a predetermined amount of time

--[[
@title GAGA Camera Control

@param s Start-up delay (secs)
@default s 10

@param c Pictures per iteration
@default c 1

@param i Iteration delay (secs)
@default i 6

@param f Flight time (hrs)
@default f 3

]]

function stamp()
return string.format("%4d%02d%02d%02d%02d%02d",
get_time("Y"),
get_time("M"),
get_time("D"),
get_time("h"),
get_time("m"),
get_time("s"))
end

ok = 1

function log(m)
print(m)
l = io.open("A/gaga.log", "ab")
if ( l ~= nil ) then
l:write(string.format("%s,%s\n", stamp(), m))
l:close()
end
end

function assert_error(e)
play_sound(6)
er = string.format("ERROR: %s", e)
log( er )
ok = 0
end

function assert_prop(p, v, m)
pp = get_prop(p)
log( string.format("Assert property (%i) %i == %i (%s)", p, pp, v, m))
if ( pp ~= v ) then
assert_error(m)
end
end

function assert_eq(a, b, m)
log( string.format("Assert %i == %i (%s)", a, b, m))
if ( a ~= b ) then
assert_error(m)
end
end

function assert_gt(a, b, m)
log( string.format("Assert %i > %i (%s)", a, b, m))
if ( a <= b ) then
assert_error(m)
end
end

function assert_lt(a, b, m)
log( string.format("Assert %i < %i (%s)", a, b, m))
if ( a >= b ) then
assert_error(m)
end
end

-- The sleep function uses microseconds do the s and i need
-- to be converted

ns = (f * 60 * 60 * c) / i
s = s * 1000
i = i * 1000

log( "GAGA Camera Control" )

-- Now enter a self-check of the manual mode settings

log( "Self-check started" )

assert_prop( 49, -32764, "Not in manual mode" )
assert_prop( 5, 0, "AF Assist Beam should be Off" )
assert_prop( 6, 0, "Focus Mode should be Normal" )
assert_prop( 8, 0, "AiAF Mode should be On" )
assert_prop( 21, 0, "Auto Rotate should be Off" )
assert_prop( 29, 0, "Bracket Mode should be None" )
assert_prop( 57, 0, "Picture Mode should be Superfine" )
assert_prop( 66, 0, "Date Stamp should be Off" )
assert_prop( 95, 0, "Digital Zoom should be None" )
assert_prop( 102, 0, "Drive Mode should be Single" )
assert_prop( 133, 0, "Manual Focus Mode should be Off" )
assert_prop( 143, 2, "Flash Mode should be Off" )
assert_prop( 149, 100, "ISO Mode should be 100" )
assert_prop( 218, 0, "Picture Size should be L" )
assert_prop( 268, 0, "White Balance Mode should be Auto" )
assert_gt( get_time("Y"), 2009, "Unexpected year" )
assert_gt( get_time("h"), 6, "Hour appears too early" )
assert_lt( get_time("h"), 20, "Hour appears too late" )
assert_gt( get_vbatt(), 3000, "Batteries seem low" )
assert_gt( get_jpg_count(), ns, "Insufficient card space" )

log( "Self-check complete" )

if ( ok == 1 ) then
sleep(s)
log( "Starting picture capture" )

n = 0

while ( 1 ) do
tc = c
while ( tc > 0 ) do
shoot()
n = n + 1
log( string.format("Picture %i taken", n ))
tc = tc - 1
end
log( string.format("Temperatures: %i, %i, %i",
get_temperature(0), get_temperature(1), get_temperature(2) ))
log( string.format("Battery level %i", get_vbatt()))
sleep(i)
end
end

log( "Done" )

The only remaining worry was that the camera was showing the 'shake' symbol while taking pictures. This turned out to be simply because night was falling and I have the camera locked into manual mode at ISO 100 with no flash. The shake symbol was a warning of a low f-stop and long shutter open period. Will be a bit different in the ever sunny stratosphere.

Comments

Anonymous said…
What about the pictures? Anything cool like this? :D http://dnfitness.wordpress.com/2010/08/19/caught-on-webcam-whats-the-chance-of-that-happening-again/

Popular posts from this blog

Your last name contains invalid characters

My last name is "Graham-Cumming". But here's a typical form response when I enter it:


Does the web site have any idea how rude it is to claim that my last name contains invalid characters? Clearly not. What they actually meant is: our web site will not accept that hyphen in your last name. But do they say that? No, of course not. They decide to shove in my face the claim that there's something wrong with my name.

There's nothing wrong with my name, just as there's nothing wrong with someone whose first name is Jean-Marie, or someone whose last name is O'Reilly.

What is wrong is that way this is being handled. If the system can't cope with non-letters and spaces it needs to say that. How about the following error message:

Our system is unable to process last names that contain non-letters, please replace them with spaces.

Don't blame me for having a last name that your system doesn't like, whose fault is that? Saying "Your last name …

All the symmetrical watch faces (and code to generate them)

If you ever look at pictures of clocks and watches in advertising they are set to roughly 10:10 which is meant to be the most attractive (smiling!) position for the hands. They are actually set to 10:09.14 if the hands are truly symmetrical. CC BY 2.0image by Shinji
I wanted to know what all the possible symmetrical watch faces are and so I wrote some code using Processing. Here's the output (there's one watch face missing, 00:00 or 12:00, because it's very boring):



The key to writing this is to figure out the relationship between the hour and minute hands when the watch face is symmetrical. In an hour the minute hand moves through 360° and the hour hand moves through 30° (12 hours are shown on the watch face and 360/12 = 30).
The core loop inside the program is this:   for (int h = 0; h <= 12; h++) {
    float m = (360-30*float(h))*2/13;
    int s = round(60*(m-floor(m)));
    int col = h%6;
    int row = floor(h/6);
    draw_clock((r+f)*(2*col+1), (r+f)*(row*2+1), r, h, floor(m…

The Elevator Button Problem

User interface design is hard. It's hard because people perceive apparently simple things very differently. For example, take a look at this interface to an elevator:


From flickr

Now imagine the following situation. You are on the third floor of this building and you wish to go to the tenth. The elevator is on the fifth floor and there's an indicator that tells you where it is. Which button do you press?

Most people probably say: "press up" since they want to go up. Not long ago I watched someone do the opposite and questioned them about their behavior. They said: "well the elevator is on the fifth floor and I am on the third, so I want it to come down to me".

Much can be learnt about the design of user interfaces by considering this, apparently, simple interface. If you think about the elevator button problem you'll find that something so simple has hidden depths. How do people learn about elevator calling? What's the right amount of informati…