Sunday, September 12, 2010

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.

1 comment:

chanux 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/