CHDK Wiki
Line 387: Line 387:
 
*For "pre-focus" feature it was changed property number from 67 to 18
 
*For "pre-focus" feature it was changed property number from 67 to 18
 
*For "display off" feature it was changed button from "display" to "print" and it's clicked after shooting (in original it's clicking before)
 
*For "display off" feature it was changed button from "display" to "print" and it's clicked after shooting (in original it's clicking before)
  +
'''Some refinements'''
  +
  +
I modified slighlty the script to do the following:
  +
*Sanitize input parameters (make sure values are not negative)
  +
*Make endless shooting and fixed focus appear as optional parameters (@range x 0 1)
  +
*Replace get_prop(67/18) with get_focus_state(), which should be processor independent (and thus work with all cameras)
  +
The code follows. Please Fraser, if you are willing to embed these changes in your original scirpt feel free to put it at the top of the page; having many small variations of the same script won't help new users picking the right one :-)
  +
  +
<pre>
  +
--[[
  +
Author: Fraser McCrossan, with minor changes by Alfredo Pironti
  +
Tested on G9, A2000, should work on most cameras.
  +
  +
An accurate intervalometer script, with pre-focus and screen power off options.
  +
  +
Features:
  +
- input is frame interval plus total desired run-time (or "endless")
  +
- displays frame count, frame total and remaining time after each frame
  +
(in endless mode, displays frame count and elapsed time)
  +
- honours the "Display" button during frame delays (so you can
  +
get it running then turn off the display to save power)
  +
- can turn off the display a given number of frames after starting
  +
(might take a couple of frames longer to cycle to correct mode)
  +
- can pre-focus before starting then go to manual focus mode
  +
- use SET button to exit
  +
  +
See bottom of script for main loop.
  +
]]
  +
  +
--[[
  +
@title Time-lapse
  +
@param s Secs/frame
  +
@default s 5
  +
@param h Sequence hours
  +
@default h 0
  +
@param m Sequence minutes
  +
@default m 5
  +
@param e Endless?
  +
@default e 0
  +
@range e 0 1
  +
@param f Fix focus at start?
  +
@default f 0
  +
@range f 0 1
  +
@param d Display off frame 0=never
  +
@default d 0
  +
--]]
  +
  +
-- convert parameters into readable variable names
  +
secs_frame, hours, minutes, endless, focus_at_start, display_off_frame = s, h, m, (e == 1), (f == 1), d
  +
  +
-- sanitize parameters
  +
if secs_frame <= 0 then
  +
secs_frame = 1
  +
end
  +
if hours < 0 then
  +
hours = 0
  +
end
  +
if minutes <= 0 then
  +
minutes = 1
  +
end
  +
if display_off_frame < 0 then
  +
display_off_frame = 0
  +
end
  +
  +
props = require "propcase"
  +
  +
-- derive actual running parameters from the more human-friendly input
  +
-- parameters
  +
function calculate_parameters (seconds_per_frame, hours, minutes, start_ticks)
  +
local ticks_per_frame = 1000 * secs_frame -- ticks per frame
  +
local total_frames = (hours * 3600 + minutes * 60) / secs_frame -- total frames
  +
local end_ticks = start_ticks + total_frames * ticks_per_frame -- ticks at end of sequence
  +
return ticks_per_frame, total_frames, end_ticks
  +
end
  +
  +
function print_status (frame, total_frames, ticks_per_frame, end_ticks, endless)
  +
local free = get_jpg_count()
  +
if endless then
  +
local h, m, s = ticks_to_hms(frame * ticks_per_frame)
  +
print("#" .. frame .. ", " .. h .. "h " .. m .. "m " .. s .. "s")
  +
else
  +
local h, m, s = ticks_to_hms(end_ticks - get_tick_count())
  +
print(frame .. "/" .. total_frames .. ", " .. h .. "h" .. m .. "m" .. s .. "s/" .. free .. " left")
  +
end
  +
end
  +
  +
function ticks_to_hms (ticks)
  +
local secs = (ticks + 500) / 1000 -- round to nearest seconds
  +
local s = secs % 60
  +
secs = secs / 60
  +
local m = secs % 60
  +
local h = secs / 60
  +
return h, m, s
  +
end
  +
  +
-- sleep, but using wait_click(); return true if a key was pressed, else false
  +
function next_frame_sleep (frame, start_ticks, ticks_per_frame)
  +
-- this calculates the number of ticks between now and the time of
  +
-- the next frame
  +
local sleep_time = (start_ticks + frame * ticks_per_frame) - get_tick_count()
  +
if sleep_time < 1 then
  +
sleep_time = 1
  +
end
  +
wait_click(sleep_time)
  +
return not is_key("no_key")
  +
end
  +
  +
-- delay for the appropriate amount of time, but respond to
  +
-- the display key (allows turning off display to save power)
  +
-- return true if we should exit, else false
  +
function frame_delay (frame, start_ticks, ticks_per_frame)
  +
-- this returns true while a key has been pressed, and false if
  +
-- none
  +
while next_frame_sleep (frame, start_ticks, ticks_per_frame) do
  +
-- honour the display button
  +
if is_key("display") then
  +
click("display")
  +
end
  +
-- if set key is pressed, indicate that we should stop
  +
if is_key("set") then
  +
return true
  +
end
  +
end
  +
return false
  +
end
  +
  +
-- if the display mode is not the passed mode, click display and return true
  +
-- otherwise return false
  +
function seek_display_mode(mode)
  +
if get_prop(props.DISPLAY_MODE) == mode then
  +
return false
  +
else
  +
click "display"
  +
return true
  +
end
  +
end
  +
  +
-- switch to autofocus mode, pre-focus, then go to manual focus mode
  +
function pre_focus()
  +
local focused = false
  +
local try = 1
  +
while not focused and try <= 5 do
  +
print("Pre-focus attempt " .. try)
  +
press("shoot_half")
  +
sleep(2000)
  +
if get_focus_state() > 0 then
  +
focused = true
  +
set_aflock(1)
  +
end
  +
release("shoot_half")
  +
sleep(500)
  +
try = try + 1
  +
end
  +
return focused
  +
end
  +
  +
if focus_at_start then
  +
if not pre_focus() then
  +
print "Unable to reach pre-focus"
  +
end
  +
end
  +
  +
start_ticks = get_tick_count()
  +
  +
ticks_per_frame, total_frames, end_ticks = calculate_parameters(secs_frame, hours, minutes, start_ticks)
  +
  +
frame = 1
  +
original_display_mode = get_prop(props.DISPLAY_MODE)
  +
target_display_mode = 2 -- off
  +
  +
print "Press SET to exit"
  +
  +
while endless or frame <= total_frames do
  +
print_status(frame, total_frames, ticks_per_frame, end_ticks, endless)
  +
if display_off_frame > 0 and frame >= display_off_frame then
  +
seek_display_mode(target_display_mode)
  +
end
  +
shoot()
  +
if frame_delay(frame, start_ticks, ticks_per_frame) then
  +
print "User quit"
  +
break
  +
end
  +
frame = frame + 1
  +
end
  +
  +
-- restore display mode
  +
if display_off_frame > 0 then
  +
while seek_display_mode(original_display_mode) do
  +
sleep(1000)
  +
end
  +
end
  +
  +
-- restore focus mode
  +
set_aflock(0)
  +
</pre>
  +
  +
On the A2000, the script doesn't seem to turn off the display.
  +
  +
Another improvement I'd like to make is to avoid waiting in the last loop, if the time to the next shoot is after the ending time.
 
[[Category:Scripts|<<SCRIPT TITLE>>]]
 
[[Category:Scripts|<<SCRIPT TITLE>>]]
 
[[Category:Intervalometer]]
 
[[Category:Intervalometer]]

Revision as of 20:53, 4 April 2013

Accurate Intervalometer with power-saving and pre-focus

Written for/on: G9
Also works on: should work on any
Required CHDK build: any

This is yet another "accurate" intervalometer (that is, it uses get_tick_count to take frames at exact intervals rather than after specific delays, so small variances in shooting time don't affect the frame rate). Takes the frame delay (e.g. 5 seconds) and the shooting time (e.g. 1 hour 30 minutes), or "endless" to ignore the delay, the script will run until you press SET (or the shutter button) to stop it. For reasons outlined below, exit the script using SET, not the shutter button.

Extra features:

  • During the inter-frame delays you can use the Display button (to turn it off to save power).
  • The script can "pre-focus" then lock the focus; this slightly speeds up shooting time, and avoids annoying focus changes during shooting. Press SET to end the script early and restore auto-focus. If you interrupt the script using the shutter button, you'll need to turn the camera off and on to restore autofocus. (So don't do that.) To enable pre-focus, set the "Focus" option to "Start" (1). To disable, set it to "Every" (0).
  • The script can optionally turn the display off after a set number of frames, to save power; as above you can turn the screen on again temporarily to see progress, and the script will turn it off again. For example, setting "Display off frame" to 3, the camera will turn the display off after the third frame. (Possibly the fourth, depending on how many display modes it has to cycle through). Press SET to exit cleanly and restore the display. If you interrupt the script using the shutter button, you'll need to turn the display back on manually. Set "Display off frame" to 0 to disable turning off the display.

Script Code (save as "lapse.lua" to your /CHDK/SCRIPTS/ folder - note the .lua - this is a Lua script, not a uBasic script.)

--[[
Author: Fraser McCrossan
Tested on G9, should work on most cameras.

An accurate intervalometer script, with pre-focus and screen power off options.

Features:
 - input is frame interval plus total desired run-time (or "endless")
 - displays frame count, frame total and remaining time after each frame
   (in endless mode, displays frame count and elapsed time)
 - honours the "Display" button during frame delays (so you can
   get it running then turn off the display to save power)
 - can turn off the display a given number of frames after starting
   (might take a couple of frames longer to cycle to correct mode)
 - can pre-focus before starting then go to manual focus mode
 - use SET button to exit 

 See bottom of script for main loop.
]]

--[[
@title Time-lapse
@param s Secs/frame
@default s 5
@param h Sequence hours
@default h 0
@param m Sequence minutes
@default m 5
@param e Endless? 0=No 1=Yes
@default e 0
@param f Focus: 0=Every 1=Start
@default f 0
@param d Display off frame 0=never
@default d 0
--]]

-- convert parameters into readable variable names
secs_frame, hours, minutes, endless, focus_at_start, display_off_frame = s, h, m, (e > 0), (f > 0), d

props = require "propcase"

-- derive actual running parameters from the more human-friendly input
-- parameters
function calculate_parameters (seconds_per_frame, hours, minutes, start_ticks)
   local ticks_per_frame = 1000 * secs_frame -- ticks per frame
   local total_frames = (hours * 3600 + minutes * 60) / secs_frame -- total frames
   local end_ticks = start_ticks + total_frames * ticks_per_frame -- ticks at end of sequence
   return ticks_per_frame, total_frames, end_ticks
end

function print_status (frame, total_frames, ticks_per_frame, end_ticks, endless)
   local free = get_jpg_count()
   if endless then
      local h, m, s = ticks_to_hms(frame * ticks_per_frame)
      print("#" .. frame .. ", " .. h .. "h " .. m .. "m " .. s .. "s")
   else
      local h, m, s = ticks_to_hms(end_ticks - get_tick_count())
      print(frame .. "/" .. total_frames .. ", " .. h .. "h" .. m .. "m" .. s .. "s/" .. free .. " left")
   end
end

function ticks_to_hms (ticks)
   local secs = (ticks + 500) / 1000 -- round to nearest seconds
   local s = secs % 60
   secs = secs / 60
   local m = secs % 60
   local h = secs / 60
   return h, m, s
end

-- sleep, but using wait_click(); return true if a key was pressed, else false
function next_frame_sleep (frame, start_ticks, ticks_per_frame)
   -- this calculates the number of ticks between now and the time of
   -- the next frame
   local sleep_time = (start_ticks + frame * ticks_per_frame) - get_tick_count()
   if sleep_time < 1 then
      sleep_time = 1
   end
   wait_click(sleep_time)
   return not is_key("no_key")
end

-- delay for the appropriate amount of time, but respond to
-- the display key (allows turning off display to save power)
-- return true if we should exit, else false
function frame_delay (frame, start_ticks, ticks_per_frame)
   -- this returns true while a key has been pressed, and false if
   -- none
   while next_frame_sleep (frame, start_ticks, ticks_per_frame) do
      -- honour the display button
      if is_key("display") then
	 click("display")
      end
      -- if set key is pressed, indicate that we should stop
      if is_key("set") then
	 return true
      end
   end
   return false
end

-- if the display mode is not the passed mode, click display and return true
-- otherwise return false
function seek_display_mode(mode)
   if get_prop(props.DISPLAY_MODE) == mode then
      return false
   else
      click "display"
      return true
   end
end

-- switch to autofocus mode, pre-focus, then go to manual focus mode
function pre_focus()
   local focused = false
   local try = 1
   while not focused and try <= 5 do
      print("Pre-focus attempt " .. try)
      press("shoot_half")
      sleep(2000)
      if get_prop(67) > 0 then
	 focused = true
	 set_aflock(1)
      end
      release("shoot_half")
      sleep(500)
      try = try + 1
   end
   return focused
end

if focus_at_start then
   if not pre_focus() then
      print "Unable to reach pre-focus"
   end
end

start_ticks = get_tick_count()

ticks_per_frame, total_frames, end_ticks = calculate_parameters(secs_frame, hours, minutes, start_ticks)

frame = 1
original_display_mode = get_prop(props.DISPLAY_MODE)
target_display_mode = 2 -- off

print "Press SET to exit"

while endless or frame <= total_frames do
   print_status(frame, total_frames, ticks_per_frame, end_ticks, endless)
   if display_off_frame > 0 and frame >= display_off_frame then
      seek_display_mode(target_display_mode)
   end
   shoot()
   if frame_delay(frame, start_ticks, ticks_per_frame) then
      print "User quit"
      break
   end
   frame = frame + 1
end

-- restore display mode
if display_off_frame > 0 then
   while seek_display_mode(original_display_mode) do
      sleep(1000)
   end
end

-- restore focus mode
set_aflock(0)

--Joatca

For Digic III (e.g. A480) change the line:

      if get_prop(67) > 0 then

to:

      if get_prop(18) > 0 then

The above code mod also appears to work for the Digic IV processor in the G10 which will not pre-focus if get_prop is left set to the default value of 67.

For A480 don't configure the display to turn off as this will stop shooting and put the device into play mode. Instead insert the Audio/Video cable into the camera and leave the other end of the cable disconnected.

SX100 IS ,SX200 IS mod

Original script doesn't work on SX100,SX200 IS (Digic III) camera ("display off" and "pre-focus" features are not working).

Here is modified version for SX cameras:

--[[
Author: Fraser McCrossan
Modification for SX100 IS: Anar Ibragimoff

An accurate intervalometer script, with pre-focus and screen power off options.

Features:
 - input is frame interval plus total desired run-time (or "endless")
 - displays frame count, frame total and remaining time after each frame
   (in endless mode, displays frame count and elapsed time)
 - honours the "Print" button during frame delays (so you can
   get it running then turn off the display to save power)
 - can turn off the display a given number of frames after starting
   (might take a couple of frames longer to cycle to correct mode)
 - can pre-focus before starting then go to manual focus mode
 - use SET button to exit 

Additional notes:
 -  To use "display off" feature, you need to configure your camera 
    to turn display off on "Print" button (in standard camera's menu)
 -  For additional power save I'd recommend to turn off preview after shoots (in standard camera's menu)


 See bottom of script for main loop.
]]

--[[
@title Time-lapse
@param s Secs/frame
@default s 5
@param h Sequence hours
@default h 0
@param m Sequence minutes
@default m 5
@param e Endless? 0=No 1=Yes
@default e 0
@param f Focus: 0=Every 1=Start
@default f 0
@param d Display off frame 0=never
@default d 0
--]]

-- convert parameters into readable variable names
secs_frame, hours, minutes, endless, focus_at_start, display_off_frame = s, h, m, (e > 0), (f > 0), d

props = require "propcase"

-- derive actual running parameters from the more human-friendly input
-- parameters
function calculate_parameters (seconds_per_frame, hours, minutes, start_ticks)
   local ticks_per_frame = 1000 * secs_frame -- ticks per frame
   local total_frames = (hours * 3600 + minutes * 60) / secs_frame -- total frames
   local end_ticks = start_ticks + total_frames * ticks_per_frame -- ticks at end of sequence
   return ticks_per_frame, total_frames, end_ticks
end

function print_status (frame, total_frames, ticks_per_frame, end_ticks, endless)
   local free = get_jpg_count()
   if endless then
      local h, m, s = ticks_to_hms(frame * ticks_per_frame)
      print("#" .. frame .. ", " .. h .. "h " .. m .. "m " .. s .. "s")
   else
      local h, m, s = ticks_to_hms(end_ticks - get_tick_count())
      print(frame .. "/" .. total_frames .. ", " .. h .. "h" .. m .. "m" .. s .. "s/" .. free .. " left")
   end
end

function ticks_to_hms (ticks)
   local secs = (ticks + 500) / 1000 -- round to nearest seconds
   local s = secs % 60
   secs = secs / 60
   local m = secs % 60
   local h = secs / 60
   return h, m, s
end

-- sleep, but using wait_click(); return true if a key was pressed, else false
function next_frame_sleep (frame, start_ticks, ticks_per_frame)
   -- this calculates the number of ticks between now and the time of
   -- the next frame
   local sleep_time = (start_ticks + frame * ticks_per_frame) - get_tick_count()
   if sleep_time < 1 then
      sleep_time = 1
   end
   wait_click(sleep_time)
   return not is_key("no_key")
end

-- delay for the appropriate amount of time, but respond to
-- the display key (allows turning off display to save power)
-- return true if we should exit, else false
function frame_delay (frame, start_ticks, ticks_per_frame)
   -- this returns true while a key has been pressed, and false if
   -- none
   while next_frame_sleep (frame, start_ticks, ticks_per_frame) do
      -- honour the display button
      if is_key("print") then
	 click("print")
      end
      -- if set key is pressed, indicate that we should stop
      if is_key("set") then
	 return true
      end
   end
   return false
end

-- click "print" to turn on/off display
function seek_display_mode()
   click "print"
end

-- switch to autofocus mode, pre-focus, then go to manual focus mode
function pre_focus()
   local focused = false
   local try = 1
   while not focused and try <= 5 do
      print("Pre-focus attempt " .. try)
      press("shoot_half")
      sleep(2000)
      if get_prop(18) > 0 then
	 focused = true
	 set_aflock(1)
      end
      release("shoot_half")
      sleep(500)
      try = try + 1
   end
   return focused
end

if focus_at_start then
   if not pre_focus() then
      print "Unable to reach pre-focus"
   end
end

start_ticks = get_tick_count()

ticks_per_frame, total_frames, end_ticks = calculate_parameters(secs_frame, hours, minutes, start_ticks)

frame = 1

print "Press SET to exit"

while endless or frame <= total_frames do
   print_status(frame, total_frames, ticks_per_frame, end_ticks, endless)
   shoot()
   if display_off_frame > 0 and frame >= display_off_frame then
      seek_display_mode()
   end
   if frame_delay(frame, start_ticks, ticks_per_frame) then
      print "User quit"
      break
   end
   frame = frame + 1
end

-- restore display mode
if display_off_frame > 0 then
   seek_display_mode()
end

-- restore focus mode
set_aflock(0)

Notes:

  • To use "display off" feature, you need to configure your camera to turn display off on "Print" button (in standard camera's menu)
  • For additional power save I'd recommend to turn off preview after shoots (in standard camera's menu)
  • use the modified version for SX cameras for the S90

Modifications to original script:

  • For "pre-focus" feature it was changed property number from 67 to 18
  • For "display off" feature it was changed button from "display" to "print" and it's clicked after shooting (in original it's clicking before)

Some refinements

I modified slighlty the script to do the following:

  • Sanitize input parameters (make sure values are not negative)
  • Make endless shooting and fixed focus appear as optional parameters (@range x 0 1)
  • Replace get_prop(67/18) with get_focus_state(), which should be processor independent (and thus work with all cameras)

The code follows. Please Fraser, if you are willing to embed these changes in your original scirpt feel free to put it at the top of the page; having many small variations of the same script won't help new users picking the right one :-)

--[[
Author: Fraser McCrossan, with minor changes by Alfredo Pironti
Tested on G9, A2000, should work on most cameras.

An accurate intervalometer script, with pre-focus and screen power off options.

Features:
 - input is frame interval plus total desired run-time (or "endless")
 - displays frame count, frame total and remaining time after each frame
   (in endless mode, displays frame count and elapsed time)
 - honours the "Display" button during frame delays (so you can
   get it running then turn off the display to save power)
 - can turn off the display a given number of frames after starting
   (might take a couple of frames longer to cycle to correct mode)
 - can pre-focus before starting then go to manual focus mode
 - use SET button to exit 

 See bottom of script for main loop.
]]

--[[
@title Time-lapse
@param s Secs/frame
@default s 5
@param h Sequence hours
@default h 0
@param m Sequence minutes
@default m 5
@param e Endless?
@default e 0
@range e 0 1
@param f Fix focus at start?
@default f 0
@range f 0 1
@param d Display off frame 0=never
@default d 0
--]]

-- convert parameters into readable variable names
secs_frame, hours, minutes, endless, focus_at_start, display_off_frame = s, h, m, (e == 1), (f == 1), d

-- sanitize parameters
if secs_frame <= 0 then
	secs_frame = 1
end
if hours < 0 then
	hours = 0
end
if minutes <= 0 then
	minutes = 1
end
if display_off_frame < 0 then
	display_off_frame = 0
end

props = require "propcase"

-- derive actual running parameters from the more human-friendly input
-- parameters
function calculate_parameters (seconds_per_frame, hours, minutes, start_ticks)
   local ticks_per_frame = 1000 * secs_frame -- ticks per frame
   local total_frames = (hours * 3600 + minutes * 60) / secs_frame -- total frames
   local end_ticks = start_ticks + total_frames * ticks_per_frame -- ticks at end of sequence
   return ticks_per_frame, total_frames, end_ticks
end

function print_status (frame, total_frames, ticks_per_frame, end_ticks, endless)
   local free = get_jpg_count()
   if endless then
      local h, m, s = ticks_to_hms(frame * ticks_per_frame)
      print("#" .. frame .. ", " .. h .. "h " .. m .. "m " .. s .. "s")
   else
      local h, m, s = ticks_to_hms(end_ticks - get_tick_count())
      print(frame .. "/" .. total_frames .. ", " .. h .. "h" .. m .. "m" .. s .. "s/" .. free .. " left")
   end
end

function ticks_to_hms (ticks)
   local secs = (ticks + 500) / 1000 -- round to nearest seconds
   local s = secs % 60
   secs = secs / 60
   local m = secs % 60
   local h = secs / 60
   return h, m, s
end

-- sleep, but using wait_click(); return true if a key was pressed, else false
function next_frame_sleep (frame, start_ticks, ticks_per_frame)
   -- this calculates the number of ticks between now and the time of
   -- the next frame
   local sleep_time = (start_ticks + frame * ticks_per_frame) - get_tick_count()
   if sleep_time < 1 then
      sleep_time = 1
   end
   wait_click(sleep_time)
   return not is_key("no_key")
end

-- delay for the appropriate amount of time, but respond to
-- the display key (allows turning off display to save power)
-- return true if we should exit, else false
function frame_delay (frame, start_ticks, ticks_per_frame)
   -- this returns true while a key has been pressed, and false if
   -- none
   while next_frame_sleep (frame, start_ticks, ticks_per_frame) do
      -- honour the display button
      if is_key("display") then
	 click("display")
      end
      -- if set key is pressed, indicate that we should stop
      if is_key("set") then
	 return true
      end
   end
   return false
end

-- if the display mode is not the passed mode, click display and return true
-- otherwise return false
function seek_display_mode(mode)
   if get_prop(props.DISPLAY_MODE) == mode then
      return false
   else
      click "display"
      return true
   end
end

-- switch to autofocus mode, pre-focus, then go to manual focus mode
function pre_focus()
   local focused = false
   local try = 1
   while not focused and try <= 5 do
      print("Pre-focus attempt " .. try)
      press("shoot_half")
      sleep(2000)
      if get_focus_state() > 0 then
	 focused = true
	 set_aflock(1)
      end
      release("shoot_half")
      sleep(500)
      try = try + 1
   end
   return focused
end

if focus_at_start then
   if not pre_focus() then
      print "Unable to reach pre-focus"
   end
end

start_ticks = get_tick_count()

ticks_per_frame, total_frames, end_ticks = calculate_parameters(secs_frame, hours, minutes, start_ticks)

frame = 1
original_display_mode = get_prop(props.DISPLAY_MODE)
target_display_mode = 2 -- off

print "Press SET to exit"

while endless or frame <= total_frames do
   print_status(frame, total_frames, ticks_per_frame, end_ticks, endless)
   if display_off_frame > 0 and frame >= display_off_frame then
      seek_display_mode(target_display_mode)
   end
   shoot()
   if frame_delay(frame, start_ticks, ticks_per_frame) then
      print "User quit"
      break
   end
   frame = frame + 1
end

-- restore display mode
if display_off_frame > 0 then
   while seek_display_mode(original_display_mode) do
      sleep(1000)
   end
end

-- restore focus mode
set_aflock(0)

On the A2000, the script doesn't seem to turn off the display.

Another improvement I'd like to make is to avoid waiting in the last loop, if the time to the next shoot is after the ending time.