set a button to a focus distance (for hyperfocal scenaris)

Started by knoodrake, October 28, 2016, 09:59:14 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

garry23

I think you are right and believe David told be about that a while ago  ;D

a1ex

Quote from: garry23 on November 03, 2016, 06:27:37 PM
I wonder if the problem is related to it being called inside event.keypress call?

Correct. It's running under Canon's GUI task, so a msleep there will prevent Canon code from switching the GUI mode. Therefore, the event handler must be short (similar to an interrupt in embedded systems, or to a button handler in GUI frameworks - you can't use delays there either without locking up the entire thing while waiting).

To my knowledge, the way to implement this is to send a message to some other task from the event handler. Canon code uses semaphores (for binary messages), message queues (for more complex messages) or event flags (e.g. for waiting for a number of events which may happen in any order). There's no API exposed in Lua for those things yet.

Dirty way (usually good enough if you don't need real-time response): global variable and polling.

knoodrake

Thanks @a1ex !

Dirty way (usually good enough if you don't need real-time response): global variable and polling.


I'm absolutely not used to dev on real small hardware such as a dslr (java dev). Pooling won't do much harm in term of CPU (battery life) ? if it's like 500ms ? I guess not ?..

a1ex

I think you can use 100ms or 200ms with very little impact on battery power and overall performance. Even 50 should give good results when you need it.

You can estimate the power draw from the Debug menu (not very exact, but still useful).

garry23

@a1ex

Sorry to be stupid, but by polling do you mean like this?

lv.start()
repeat
dummy = 0
msleep(100)
until lv.enabled
move() -- to HFD position
lv.stop()


If so, the above doesn't work  :(

knoodrake

I think he means that the lv.start() should be done outside the event handler ( which I see as a "UI Thread" from my java mind :) )
So the idea would be that the keypress event just set a flag to says we want to start LiveView.

Somewhere else, we have a loop that checks every Xms if the flag is set. If so, we can start LV because we are within another "thread" (or whatever is called this Canon GUI Context ).

I hope I'm right up to this point :)

One thing I don't get, is how to start the "pooling" ? From my understanding I can't just write startPooling() at the end of the file, it won't be executed. On the other end, the only other "starting point" I have are camera events.. ( lens event, button event, ... )
I don't know how to "pool" automatically from the script loading ?

knoodrake

I think I may have understood but the exact opposite: start LV in the event handler context. Works ok, but we have to "wait" by checking (polling) if LV is on outside of the event handler (the opposite of what I said in my previous post).

Anyway, that doesn't change the problem: how to start the "pooling" elsewhere ?

garry23

I'll 'just' stick to the script only working IF liveview is on  ;)

--[[
Script to illustrate the use of key modification
Version 0.4 (should work on all ML enabled cameras with the Lua module)
Shows the use of a modified key approach using an AF lens auto positioned to the HFD
Garry George Nov 2016
http://photography.grayheron.net/
For the HFD functionality must be in LV and in AF mode, and lens must report distance
Also make sure ML DoF set up as you require it, eg diffraction on
Also for the fastest move position lens at infinity end, ie macro end moves are slower
This version of the script does no error checking ;-)
--]]

-- Declare globals

mod_button_1 = KEY.MENU -- key to modify
mod_button_2 = KEY.INFO -- key to indicate mod mode requested
last_key_pressed = 999 -- used to reset mod_button pairing

-- Choose buttons of your choice, eg KEY.RATE, KEY.UP, KEY.INFO or KEY.PLAY.
-- See http://davidmilligan.github.io/ml-lua/modules/constants.html for key constants

function move()
if lens.focus_distance ~= 0 and lens.af then -- lens is OK
if lens.dof_far ~= lens.dof_near then -- ok to move
if lens.focus_distance < lens.hyperfocal then
repeat
lens.focus(-1,1,false)
until lens.focus_distance >= lens.hyperfocal
else
repeat
lens.focus(1,1,false)
until lens.focus_distance <= lens.hyperfocal
repeat -- ensures lens is positioned with a bias towards INF
lens.focus(-1,1,false)
until lens.focus_distance >= lens.hyperfocal
end
else
beep (3, 200 , 500)  -- warning message
display.notify_box("Check aperture", 3000)
end
else
beep (3, 200 , 500)  -- warning message
display.notify_box("Check lens settings", 3000)
end
end

function test4mod(key)
if keymenu.submenu["Turn On/Off"].value == "Off" then
return true -- all keys work as normal
elseif key == mod_button_1 and last_key_pressed == mod_button_1 then -- use moded key as normal
last_key_pressed = 999 -- reset
return true
    elseif key == mod_button_2 and last_key_pressed == mod_button_1 then -- use moded key in modified way
-- ****************** Place modified code here ************
last_key_pressed = 999 -- reset
move() -- to HFD position
-- ****************** Place modified code here ************
return false -- steal key press
elseif key == mod_button_1 then -- first press of modified key in new sequence
last_key_pressed = mod_button_1
return false -- steal key press
else
return true -- use all non-moded buttons in an unmodified way
end
end

event.keypress = test4mod

keymenu = menu.new
{
parent = "Shoot",
name = "HFD",
help = "Moves lens to HFD focus distance",
depends_on = DEPENDS_ON.LIVEVIEW,
submenu =
{
{
name = "Turn On/Off",
help = "Switches the script on/off",
choices = {"On","Off"},
}
}
}

a1ex

https://en.wikipedia.org/wiki/Polling_(computer_science)
https://en.wikipedia.org/wiki/Pooling_(resource_management)
https://en.wikipedia.org/wiki/Busy_waiting

;)

What you write at the end of the file will be executed during initialization. So, if you place your main loop there, it may block other scripts from loading.

You can start a background task (task.create), or you can use the shoot_task hook (called pretty often, with no guarantees about the timing, but it's a ML task, so you can use it for this purpose).

Tasks are a scarce resource on some cameras, so the second method may give less headache when running on other cameras.

Note that moving the focus ring is also an activity that takes a while, so you shouldn't do it from the GUI event handler either.

knoodrake


garry23

@knoodrake

I looked at using the seconds_clock (arg) event, called every second, but it didn't seem to work.

I looked for the event module in the Lua code, but couldn't find any reference to event handling: so maybe these bits of Lua aren't enabled yet.

Keep us all plugged into you experiments  ;)

knoodrake

@garry23 I just happened to do something that seems to work, and with seconds_clock as well ! It takes at worst 0.99999s to kick in, but that seems to do the trick.
If already in LV, stays in LV, if not, goes back in LV off.

HFDRequested = false
LVWasAlreadyOn = true

event.seconds_clock = function (arg)
if HFDRequested and lv.enabled then
HFDRequested = false
move()
if not LVWasAlreadyOn then
lv.stop()
end
end
return true
end

event.keypress = function(key)
if keymenu.submenu["Turn On/Off"].value == "Off" then
  return true -- key works as normal
elseif key == hfd then
HFDRequested = true
  if not lv.enabled then
LVWasAlreadyOn = false
lv.start()
  end
return false -- steal the button push
end
end


knoodrake

Note: I did not tried yet with shoot_task because I have yet to understand what it is (is that a generic event that is fired for various unrelated things ? )
EDIT: Also, not yet investigated the tasks

garry23

@knoodrake

I realised my idea of using event.seconds_clock would work, after a saw I had coded in an error.

Anyway, here is my latest version of the HFD script, which uses the modified key approach, so I don't 'lose' a key, and some additional error checking:

--[[
Script to illustrate the use of key modification
Version 0.5 (should work on all ML enabled cameras with the Lua module)
Shows the use of a modified key approach using an AF lens auto positioned to the HFD
Garry George Nov 2016
http://photography.grayheron.net/
For the HFD functionality must be in AF mode and lens must report distance
Script handles LV, ie LV doesn't need to be on'
Also make sure ML DoF set up as you require it, eg diffraction on
Also for the fastest move position lens at infinity end, ie macro end moves are slower
This version of the script does no error checking ;-)
--]]

-- Declare some globals

mod_button_1 = KEY.MENU -- key to modify
mod_button_2 = KEY.INFO -- key to indicate mod mode requested
last_key_pressed = 999 -- used to reset mod_button pairing
hfd_move_requested = false
lv_already_on = false

-- Choose buttons of your choice, eg KEY.RATE, KEY.UP, KEY.INFO or KEY.PLAY.
-- See http://davidmilligan.github.io/ml-lua/modules/constants.html for key constants

function check_lens_ready() -- just in case
if hfd_move_menu.submenu["Turn On/Off"].value == "On" then-- check lens is ready to be moved
if lens.focus_distance ~= 0 and lens.af then -- lens is OK
repeat
msleep(100)
until lens.focus(0,1,false)
end
end
end

function move()
if lens.focus_distance ~= 0 and lens.af then -- lens is OK
if lens.dof_far ~= lens.dof_near then -- ok to move
if lens.focus_distance < lens.hyperfocal then
repeat
lens.focus(-1,1,false)
until lens.focus_distance >= lens.hyperfocal
else
repeat
lens.focus(1,1,false)
until lens.focus_distance <= lens.hyperfocal
repeat -- ensures lens is positioned with a bias towards INF
lens.focus(-1,1,false)
until lens.focus_distance >= lens.hyperfocal
end
else
beep (3, 200 , 500)  -- warning message
display.notify_box("Check aperture", 3000)
end
else
beep (3, 200 , 500)  -- warning message
display.notify_box("Check lens settings", 3000)
end
end

function test4mod(key)
if hfd_move_menu.submenu["Turn On/Off"].value == "Off" then
return true -- all keys work as normal
elseif key == mod_button_1 and last_key_pressed == mod_button_1 then -- use moded key as normal
last_key_pressed = 999 -- reset
return true
    elseif key == mod_button_2 and last_key_pressed == mod_button_1 then -- use moded key in modified way
-- ****************** Place modified flag requests here ************
last_key_pressed = 999 -- reset
hfd_move_requested = true -- flag HFD move requested
if lv.enabled then lv_already_on = true else lv_already_on = false end
-- ****************** Place modified flag requests here ************
return false -- steal key press
elseif key == mod_button_1 then -- first press of modified key in new sequence
last_key_pressed = mod_button_1
return false -- steal key press
else
return true -- use all non-moded buttons in an unmodified way
end
end

function check_requests(arg)
if hfd_move_requested == true then -- handle lv and lens move
hfd_move_requested = false -- reset flag
if not lv_already_on then lv.start() end
check_lens_ready() -- just in case it isn't'
move() -- lens to HFD position
if not lv_already_on then lv.stop() end
end
end

event.keypress = test4mod
event.seconds_clock = check_requests

hfd_move_menu = menu.new
{
parent = "Shoot",
name = "HFD",
help = "Moves lens to HFD focus distance",
submenu =
{
{
name = "Turn On/Off",
help = "Switches the script on/off",
choices = {"On","Off"},
}
}
}

a1ex

Nice.

The only problem that may appear is if your seconds_clock handler takes more than one second to run - this will cause other handlers not to get called at every second. Currently the side effects are minor (probably throwing off the battery level estimations if it happens a lot), but others might rely on this hook getting called once per second.

Therefore, I recommend using the shoot_task hook instead. The rest of the code can stay unchanged.

garry23

@A1ex

One thought I had was asking you or David to put in a variable seconds_clock event handler, or one, at say, 0.5 seconds.

I'm afraid I'm stumped on using the shoot_hook approach, would you be so kind to show me how I would do it.

Cheers

Garry

a1ex


garry23


garry23

@A1ex

I forgot to ask, if you don't return a bool when calling a lua event handler, does it have an consequences.

In my code I don't return anything.

a1ex

The return value is used to allow (true) or block (false) other routines (from other modules/scripts) that might run after this event. Their order is currently somewhat hardcoded (it depends on the order in which the modules are loaded - alphabetically - and then, the Lua module dispatches the event to the scripts - I think it's in the order they are started).

If you don't return anything, Lua assumes nil, which evaluates to true. So, it should do the right thing.

Blocking other CBRs makes sense for keys, for example (you handled some key and you don't want other feature, or Canon code, to reuse the same key).

garry23

@A1ex

Thanks: fully understood.

I'll insert a 'return false' IF my HFD move is used.

Cheers

Garry

knoodrake

@garry23 @a1ex

Cool, thanks a lot to you both  :)
Now that I discovered all the potential and easiness of scripting my camera, I want to do so many things (well, my last Idea was to play GoT theme song in camera beeps, maybe not the best nor the most useful idea )

A last question @a1ex if I may; Are there many interesting things the picoc modules API allows that are not exposed/possible in Lua ? And most importantly, is there a nice API doc for the module api somewhere, something as nice as this lua one https://davidmilligan.github.io/ml-lua/  ?

I just found the doxygen doc, some chaotic wiki pages, and pieces of advice scattered around the forum.

garry23

@knoodrake

I'm looking forward to seeing/using your work.

I share all my Lua scripts, but I note that not many others seem to  :o

All my working scripts are here: https://gist.github.com/pigeonhill

Maybe you should share yours via github?

Cheers

Garry

knoodrake

@garry23 I already checked your scripts  :P ( LE Simulation interested me a lot for instance, since my new lens doesn't take my ND1000 )

As for me, I love ML ever since I discovered DualISO, but it was here the very first time I tried to do anything :)
I'll make sure to share if (more likely when) I do anything else !

garry23

@knoodrake

My all singing script is: https://gist.github.com/pigeonhill/e008f051681885bc6ff84de637cb1d8e

This includes LE mode.

I may well add the multi-mode key approach to that and embedded HFD positioning  ;)