Skip to content

Instantly share code, notes, and snippets.

@pigeonhill
Last active July 15, 2022 15:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pigeonhill/3656fce88badb50d258995a48840d326 to your computer and use it in GitHub Desktop.
Save pigeonhill/3656fce88badb50d258995a48840d326 to your computer and use it in GitHub Desktop.
Thin Lens Functionalised Focus
--[[
@title TLFF
@chdk_version 1.6
#log = 0 "Log?" {Off On}
Notes:
* This test script only runs on the M3, M10 or M100 with the XIMR version of CHDK. But note, not tested on the M100.
* Go to https://drive.google.com/drive/folders/1drk1xi6kMMIeF5xSqXgnpjGCffF8CVkd?usp=sharing for XIMR builds
*
* The script is a proof of principle of using a thin lens approximation to estimate focus distance from the sensor plane
Release 0.51 ALPHA
photography.grayheron.net
July 2022
--]]
bi = get_buildinfo()
set_exit_key("down") -- change as required
set_console_autoredraw(1)
set_console_layout(0,0,45,3)
focus_count = -999
reset_lens = false
INF = 999000 -- infinity trap
count = 0
U = 0
-- Check a couple of things first
if not ((bi.platform == "m3") or (bi.platform == "m10") or (bi.platform == "m100")) then
print("Doesn't run on this Cam")
sleep(3000)
return
end
if get_gui_screen_width() ~= 360 then
print("Need an XIMR build")
sleep(3000)
return
end
-- Functions --
function units(xx) -- pretty print of focus distance
local xr =""
if xx:int() > 5000 then
xr=(xx/1000):tostr(1).."m"
elseif xx:int() > 1000 then
xr=(xx/10):tostr(0).."cm"
else
xr=(xx):tostr(0).."mm"
end
return xr
end
function get_focus_distance_lower() -- returns lower focus distance in mm, but note 'accuracy' is 1cm from Canon
local x=-1
if (bi.platform=="m3") and (bi.platsub=="101a") then
x=peek(0x00244918, 2)
elseif (bi.platform=="m3") and (bi.platsub=="120f") then
x=peek(0x0024495C, 2)
elseif (bi.platform=="m3") and (bi.platsub=="121a") then
x=peek(0x0024495C, 2)
elseif (bi.platform=="m10") then -- same address in 110d, 110f, 110g
x=peek(0x00272018, 2)
elseif (bi.platform=="m100") and (bi.platsub=="100a") then
x=peek(0x001FC7FC, 2)
else
print('Wrong platform')
end
if x == -1 then return -1 else return x*10 end -- in mm
end
function get_focus_distance_upper() -- returns upper focus distance in mm, but note 'accuracy' is 1cm from Canon
local x=-1
if (bi.platform=="m3") and (bi.platsub=="101a") then
x=peek(0x00244916, 2)
elseif (bi.platform=="m3") and (bi.platsub=="120f") then
x=peek(0x0024495A, 2)
elseif (bi.platform=="m3") and (bi.platsub=="121a") then
x=peek(0x0024495A, 2)
elseif (bi.platform=="m10") then -- same address in 110d, 110f, 110g
x=peek(0x00272016, 2)
elseif (bi.platform=="m100") and (bi.platsub=="100a") then
x=peek(0x001FC7FA, 2)
else
print('Wrong platform')
end
if x == -1 then return -1 else return x*10 end
end
function lens_name() -- does what it says
local pname = 0
if (bi.platform=="m3") then
if (bi.platsub == "101a") then
pname = 0x00244969
else
pname = 0x002449ad
end
elseif (bi.platform=="m10") then
pname = 0x272065
elseif (bi.platform=="m100") and (bi.platsub == "100a") then
pname = 0x1FC84E
end
local len = peek(pname-1,1)
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 lens_cal() -- called at the start and when focal length changes: sets lens to MFD
call_event_proc('InitializeAdjustmentSystem')
temp = call_event_proc('GetEFLensFocusPositionWithLensCom')
repeat
temp = call_event_proc('GetEFLensFocusPositionWithLensCom')
call_event_proc("EFLensCom.FocusSearchFar")
sleep(20)
until temp == call_event_proc('GetEFLensFocusPositionWithLensCom') -- make sure we are at 'infinity'
repeat -- to find some useful data
call_event_proc("EFLensCom.MoveFocus", -1, 1)
sleep(20)
until get_focus_distance_lower() < 81000
xc = get_focus_distance_lower() -- Canon lower focus distance 'infinity' start
sleep(20)
far_count = call_event_proc('GetEFLensFocusPositionWithLensCom')
print("far count:"..far_count)
temp = call_event_proc('GetEFLensFocusPositionWithLensCom')
repeat
temp = call_event_proc('GetEFLensFocusPositionWithLensCom')
call_event_proc("EFLensCom.FocusSearchNear")
sleep(10)
until temp == call_event_proc('GetEFLensFocusPositionWithLensCom') -- make sure we are at MFD
near_count = call_event_proc('GetEFLensFocusPositionWithLensCom')
MFD = fmath.new(get_focus_distance_lower(),1)
k = (MFD*(MFD-4*F)):sqrt()
total_count = far_count - near_count -- lens max number of steps at the current focal length
reset_lens = false
print("FL = "..F:int())
print("Total count = "..total_count)
-- Use the following to log focus against counts
if log == 1 then
print_screen(1)
print("--")
print("FL= "..F:int().."mm")
print("Stepper Motor Counts")
for j = 1, total_count do
print(j)
end
print("TLFF distances (mm)")
for j = 1, total_count do
x = TL_focus_pos(j)
print(x:int())
end
print("--")
print_screen(0)
end
end
function TL_focus_pos(nn) -- functioalised estimate of focus from the stepper motor position
local a = fmath.new(get_focus_distance_lower(),1)
local b = fmath.new(get_focus_distance_upper(),1)
local c = ((2*a*b)/(a+b)):int()
local d = MFD
-- use a, b or c to 'scale'' the basic functional form
return (total_count*MFD - 2*F*nn)/(total_count-nn) - (a*nn)/(total_count)
end
function set_up()
dof = get_dofinfo()
F = fmath.new(dof.focal_length,1000) -- focal length in mm (real)
end
function lens_info()
if lens_name() == "EF-M11-22mm f/4-5.6 IS STM" then -- calculate lens thickness from manufacturer's data
return true
elseif lens_name() == "EF-M28mm f/3.5 MACRO IS STM" then
return true
elseif lens_name() == "EF-M55-200mm f/4.5-6.3 IS STM" then
return true
elseif lens_name() == "EF-M18-55mm f/3.5-5.6 IS STM" then
return true
elseif lens_name() == "EF-M15-45mm f/3.5-6.3 IS STM" then
return true
else -- lens not recognised
return false
end
end
function check_focus()
dof = get_dofinfo()
dirty = false
local test_count = call_event_proc('GetEFLensFocusPositionWithLensCom')
local test_n = fmath.new(av96_to_aperture(get_user_av96()),1000)
local test_F = fmath.new(dof.focal_length,1000)
if test_F ~= F then -- recalibrate lens and update focus position
dirty = true
reset_lens = true
elseif test_count ~= focus_count then -- update focus position
dirty = true
end
F = test_F
focus_count = test_count
end
function update() -- update focus position estimate in the console
count = call_event_proc('GetEFLensFocusPositionWithLensCom') - near_count
x = TL_focus_pos(count)
if x:int() < INF and count <= total_count then
print(units(x)..",Lower = "..get_focus_distance_lower()..",Upper = "..get_focus_distance_upper()..",count = "..count)
else
print("oo")
end
end
-- Main Section --
if lens_info() == false then -- then don't use
print("Can't use for now")
sleep(3000)
return
end
call_event_proc('FA.Create') -- assume only need to call this once
sleep(100)
set_up()
lens_cal()
finish = false
repeat -- stay here
check_focus()
if reset_lens then lens_cal() end -- focal length changed so recalibrate lens
if screen_needs_refresh() then dirty = true end
if dirty then update() end
sleep(100) -- adjust a required
until finish -- exit via pressing ALT exit button
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment