High Altitude Balloon Part 1: Cameras
For my high altitude balloon launch, I wanted to send up something a little cheaper than a $400 GoPro camera in the event that I can't locate the balloon when it comes back to earth! So I found a much cheaper alternative that gave me the same level of customization but at a fraction of the price... old Canon cameras running the Canon Hack Development Kit CHDK
For $50 I was able to score two Canon AS1000 point and shoot cameras off eBay and loaded two 64GB flash cards with the latest stable CHDK package (1.41 as of the time of this post)
One camera will be my "still photos" camera and the other will be the "video camera". One of the excellent features of CHDK is the scripting feature. You can copy LUA scripts to the memory card and have them execute a series of functions on the camera. In this case I want the cameras to immediately start recording video once powered on or shooting photos every 5 seconds once powered on.
I found it tricky to install CHDK on the 64GB SD Card I had purchased and found out my cameras were manufactuered in 2008. Everytime I inserted the card to try and format it on the camera it just complained with "Memory Card Error". So after a little digging I found that I could partition the cards in linux, copy the CHDK files on to them and then the cameras would be happy.
First I used GParted in Ubuntu to create the first partition at 16MB as a FAT16 boot partition. After I confirmed the changes I right clicked the partition, went to "Manage Flags" and set this partition as a boo partition. This allows the camera to load up CHDK everytime on power and I don't have to manually activate it each time. Then I created a second partition as FAT32 that took up the rest of the space on the memory card. Here's what my GParted screen looked like after everything was finalized:
Then I had to copy the CHDK files to the camera. I downloaded the latest stable version of CHDK, 1.41 and extracted it on my laptop. Then I copied the DISKBOOT.BIN and PS.F12 files to the first boot patition. Then I copied the CHDK folder to the second partiton. Here are screenshots of each folder and what they should look like:
Finally I ejected the Memory card and write protected the card with the little plastic tab on the side. This step is important! It's what tells the camera to load from the boot partition. Now when you power on the camera the CHDK splashscreen will show after about 3 seconds.
Here's the lua script for continuous still shots of the camera for as long as the battery lasts or until the memory card fills up
--[[ High Altitude Balloon Camera script for Canon AS1100, still photos
@title Balloon Camera
@param i Shot Interval
@default i 5
@range i 1 60
@param d Display
@default d 0
@values d 0 1
--]]
props = require("propcase")
set_console_layout(1 ,1, 60, 15 )
print_screen(-1)
print("HAB Camera")
print(os.date())
sleep(1000)
local is_record, is_video, mode_number
is_record, is_video, mode_number = get_mode()
mode_number = bitand(mode_number, 0xFF)
if (mode_number ~= 2) then
print("!!! WRONG MODE "..mode_number.." !!!")
print("!!! WRONG MODE "..mode_number.." !!!")
print("!!! WRONG MODE "..mode_number.." !!!")
print("Set P mode and restart camera")
sleep(10000)
post_levent_to_ui('PressPowerButton')
end
-- conf.subj_dist_override_koef = SD_OVERRIDE_INFINITY
if (get_config_value(108) ~= 2) then
print("Enabling distance override")
set_config_value(108, 2)
sleep(500)
end
if (is_record == false) then
print("Switching to photo capture")
set_record(1)
while (get_mode() == false) do sleep(100) end
sleep(1000)
end
print("Setting AF-Lock")
set_aflock(1)
set_prop(props.AF_LOCK, 1)
sleep(1000)
print("Setting focus to infinity")
set_focus(60000)
sleep(3000)
local image_count = 0
print("---")
while(true)
do
if ((image_count == 3) and (d == 0)) then
print("Turning off display...")
sleep(3000)
set_lcd_display(0)
sleep(1000)
end
image_count = image_count + 1
local battery_voltage = get_vbatt()
local temperature = get_temperature(0)
local disk_kb = get_free_disk_space()
local disk_mb = disk_kb / 1024
print("Time: "..os.date())
print("Battery: "..battery_voltage.." mV")
print("Temp: "..temperature.." C")
print("Space: "..disk_mb.." MB")
if (disk_mb < 10) then
print("Out of disk space!")
break
end
print("Image: "..image_count)
press("shoot_half")
repeat sleep(50) until get_shooting() == true
local av = get_av96()
local sv = get_sv96()
local tv = get_tv96()
local bv = get_bv96()
local fc = get_focus()
print("Exposure: AV="..av.." SV="..sv.." TV="..tv.." BV="..bv)
print("Focus: "..fc)
press("shoot_full")
sleep(500)
release("shoot_full")
repeat sleep(50) until get_shooting() == false
release("shoot_half")
print("File: "..get_exp_count());
print("---")
sleep(i * 1000)
end
print("Power down")
post_levent_to_ui('PressPowerButton')
This is the video recording script and it allows you to:
- turn the display on & off by pressing the DISP button or down button,
- halt the script by pressing the MENU button
- restart recording by pressing the SET button.
- zoom in & out by moving the cameras zoom lever
- refocus by "half pressing" the shutter button
- It works on cameras with and without a dedicated video button.
Save it to your SD card with a .lua extension (e.g. vid_ext.lua).
--[[
********************************
Licence: GPL
(c) msl 2012 - 2014
********************************
@title Extended Video r2
@param a Auto (re)start
@default a 1
@range a 0 1
@param b Time in s 0=max
@default b 0
@range b 0 1800
]]
function StartStopVideo()
local rec, vid = get_mode()
local vid_button = get_video_button()
if rec and vid and vid_button == 0 then
press("shoot_full")
sleep(300)
release("shoot_full")
elseif rec and vid_button == 1 then
click("video")
end
end
function restore()
if get_movie_status() == 4 then StartStopVideo() end
cls()
set_console_layout(0,0,25,5)
set_console_autoredraw(1)
end
restart = a
record_time = b
BL=0
TC=false
time_start = 0
time_now = 0
set_console_layout(9,1,39,6)
if restart==1 then
cls()
print("Automatic Video (Re)Start")
if record_time > 0 then print("record time:", record_time, "s") end
sleep(2000)
end
set_console_autoredraw(0)
repeat
if TC == false and record_time > 0 then
time_start = get_tick_count()
TC = true
end
cls()
if restart ~= 1 then print("[SET] Start/Stop Video") end
print("[DISP] On/Off Backlight")
print("[ZOOM] Zooming")
print("[MENU] End")
console_redraw()
wait_click(900)
if is_key("display") or is_key("down") then
set_backlight(BL)
if BL == 1 then BL=0 else BL=1 end
elseif is_key("set") and restart ~= 1 then StartStopVideo()
elseif is_key("shoot_half") then set_aflock(1)
elseif is_key("zoom_in") then press("zoom_in") while is_pressed("zoom_in") do sleep(20) end release("zoom_in")
elseif is_key("zoom_out") then press("zoom_out") while is_pressed("zoom_out") do sleep(20) end release("zoom_out")
end
if TC and record_time > 0 then
if get_tick_count() - time_start >= record_time * 1000 + 2000 then
StartStopVideo() -- stop video
TC = false
end
end
status = get_movie_status()
if (status < 4 or status > 4) and restart == 1 then
StartStopVideo()
cls()
print("Start recording")
console_redraw()
sleep(5000)
if BL == 1 then set_backlight(0) end
end
until is_key("menu")
restore()