Skip to content

Instantly share code, notes, and snippets.

@pigeonhill pigeonhill/M3 Brackets.lua
Last active Aug 15, 2019

Embed
What would you like to do?
M3 Focus & Exposure Bracketing
--[[
@title M3 Bracketing: Focus & Exposure
@chdk_version 1.4
#mode = 0 "Mode" {Off X2INF Min2INF}
#bracket = 0 "Exposure bracket?" {None ZN4 ZN3 ZN2 ZN2+2 ISO1600}
#infinity = 3 "Infinity focus" [2 4]
#overlap = 15 "Overlap (um)" [5 30]
#sleep_time = 2 "Delay (s)"
#bookends = 1 "Bookends?" {No Yes}
#screen_off = 0 "Screen off?" {No Yes}
#nudge = 10 "Nudge distance (mm)" [10 30]
#t = 0 "Lens Thickness (mm)"
#lens = 0 "Get lens name?" {No Yes}
Release 1.15
Note: only tested on EFM lenses
photography.grayheron.net
--]] capmode = require("capmode")
bi = get_buildinfo()
if (bi.platform ~= "m3") then error('Only runs on M3') end
press("shoot_half")
repeat sleep(10) until get_shooting()
dof = get_dofinfo()
f = dof.focal_length -- in microns
F = f / 1000 -- focal length in mm
s = get_tv96()
av = get_av96()
release("shoot_half")
repeat sleep(10) until (not get_shooting())
n = av96_to_aperture(get_user_av96()) -- N*1000
H = (f / 1000 + (f * f) / ((n * overlap))) -- in mm
steps = 1
function get_focus_distance_upper()
local x = -1
if (bi.platsub == "101a") then
x = peek(0x00244916, 2)
elseif (bi.platsub == "120f") then
x = peek(0x0024495A, 2)
else
error('Not 101a or 120f')
end
return x
end
function lens_name()
local get_lens_name_fn = 0xfc2f3fd5
if (bi.platsub == "101a") then get_lens_name_fn = 0xfc2f3fc3 end
if call_event_proc('System.Create') == -1 then error('Unknown Error') end
local ppname = call_event_proc('AllocateMemory', 8)
if ppname == -1 or ppname == 0 then error('Unknown Error') end
local plen = ppname + 4
poke(ppname, 0)
poke(plen, 0)
local status = call_func_ptr(get_lens_name_fn, ppname, plen)
local pname = peek(ppname)
local len = peek(plen)
call_event_proc('FreeMemory', ppname)
if ppname == -1 or ppname == 0 then error('Unknown Error') end
local i = 0
local t = {}
while i < len do
local c = peek(pname + i, 1)
if c == 0 then break end
table.insert(t, string.char(c))
i = i + 1
end
local name = table.concat(t)
return name
end
function restore()
set_tv96_direct(s)
set_av96_direct(av)
press("shoot_half")
repeat sleep(10) until get_shooting()
sleep(100)
release("shoot_half")
repeat sleep(10) until (not get_shooting())
if current_focus_mode ~= 1 then set_mf(0) end
if (current_mode ~= "M") then capmode.set(current_mode) end
set_lcd_display(1)
exit_alt()
end
function get_focus_distance_lower()
local x = -1
if (bi.platsub == "101a") then
x = peek(0x00244918, 2)
elseif (bi.platsub == "120f") then
x = peek(0x0024495C, 2)
else
error('Not 101a or 120f')
end
return x
end
function set_up()
current_focus_mode = get_focus_mode()
current_mode = capmode.get_name()
if current_focus_mode ~= 1 then set_mf(1) end
s = get_tv96()
av = get_av96()
if (current_mode ~= "M") then capmode.set("M") end
set_tv96_direct(s)
set_av96_direct(av)
press("shoot_half")
repeat sleep(10) until get_shooting()
sleep(1000)
release("shoot_half")
repeat sleep(10) until (not get_shooting())
return true
end
function refocus_to(xx) -- returns requested focus distance in cm
local current_x = get_focus_distance_lower() -- ie focus distance of current step that includes current_x
local steps_total = 0
local last_step_count = steps_total
if xx < current_x then return -1 end -- don't use
local last_x = current_x
while current_x < xx do
call_event_proc("EFLensCom.MoveFocus", steps, 1) -- move towards infinity
steps_total = steps_total + steps
sleep(25) -- for system to catch up
current_x = get_focus_distance_lower()
if (current_x ~= last_x) and (current_x < xx) then -- just went through an intermediate step change, ie not yet reached the step that covers xx
last_x = current_x
last_step_count = steps_total -- close enough
end
end
-- now fine tune position
local steps_back = ((current_x - xx) * (steps_total - last_step_count)) / (current_x - last_x)
steps_back = steps_back/steps
if steps_back ~= 0 then
for i = 1, steps_back do call_event_proc("EFLensCom.MoveFocus", -steps, 1) end
end
sleep(25) -- for system to catch up
return xx
end
function myshoot()
local prevcnt = hook_shoot.count()
local rawprevcnt = hook_raw.count()
press 'shoot_full_only'
repeat sleep(10) until prevcnt ~= hook_shoot.count()
release 'shoot_full_only'
repeat sleep(10) until rawprevcnt ~= hook_raw.count()
end
function X_bracket()
press("shoot_half")
repeat sleep(10) until (get_shooting())
set_tv96_direct(s)
if bracket == 0 then
myshoot()
elseif bracket == 1 then
myshoot()
set_tv96_direct(s - 96 * 4)
myshoot()
elseif bracket == 2 then
myshoot()
set_tv96_direct(s - 96 * 3)
myshoot()
elseif bracket == 3 then
myshoot()
set_tv96_direct(s - 96 * 2)
myshoot()
elseif bracket == 4 then
myshoot()
set_tv96_direct(s - 96 * 2)
myshoot()
set_tv96_direct(s - 96 * 4)
myshoot()
elseif bracket == 5 then
local iso = get_iso_mode()
set_iso_mode(100)
myshoot()
set_iso_mode(1600)
myshoot()
set_iso_mode(iso)
end
set_tv96_direct(s)
release("shoot_half")
repeat sleep(10) until (not get_shooting())
end
function bookend()
set_tv96_direct(960)
set_av96_direct(640)
local ecnt = get_exp_count()
shoot()
set_tv96_direct(s)
set_av96_direct(av)
repeat sleep(10) until (get_exp_count() ~= ecnt)
end
-- Main Section
if lens == 1 then
print(lens_name())
return
end
if lens_name() == "EF-M11-22mm f/4-5.6 IS STM" then
-- add other lenses as required, ie replace the following for your lens
-- 300 is the lens max magnification x 1000
-- 22000 is the lens maximun zoom, or the prime, focal length in microns
-- 150 is the lens minimum focus distance (mm)
m = (300 * f) / (22000)
t = (F * (1000 + m) * (1000 + m))
t = 150 - t / (1000 * m) -- this is an estimate of the spilt thin lens thickness (mm)
-- elseif lens_name() == "your lens" then
-- m = (300*f)/(22000)
-- t = (F*(1000+m)*(1000+m))
-- t = 150 - t/(1000*m)
end
if screen_off == 1 then set_lcd_display(0) end
set_up()
if bookends == 1 then bookend() end
if mode == 0 then
X_bracket()
if bookends == 1 then bookend() end
restore()
return
end
if mode == 2 then
call_event_proc("EFLensCom.FocusSearchNear")
sleep(50)
end
sleep(sleep_time * 1000)
x = get_focus_distance_lower() -- current x estimate in cm
u = x * 10 - F - t -- distance from split thin lens 'front principal' in mm
print(x .. "cm")
X_bracket()
while (u < H / 3) do -- capture the focus brackets up to H/3
new_u = (2 * F * F - 3 * F * u + H * u) / (F + H - 2 * u) -- estimate position of next focus bracket in mm. From 'Ins & Out of Focus' by Merklinger
if new_u - u < nudge then new_u = u + nudge end
u = new_u
x = (u + F + t) / 10
print(refocus_to(x) .. "cm")
X_bracket()
end
if u < H then
print(refocus_to((F + t + H) / 10) .. "cm")
X_bracket()
print(refocus_to(3 * (F + t + H) / 10) .. "cm")
X_bracket()
end
if bookends == 1 then bookend() end
restore()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.