Lua Scripting (lua.mo)

Started by dmilligan, March 29, 2015, 04:44:07 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

garry23

Ok, I jumped in and tried adapting Walter's script. The function of the script is simply to take an image. But I can't seem to get it to work.

I hope some kind expert can nudge me in the right direction, as once I get this core script running, I feel I can make progress on more complex scripting.

-- Test Script

require('keys')

function main()
    keys:start()
menu.block(true)
  while menu.visible do
local key = keys:getkey()
if key == KEY.RATE then camera.shoot() end
  end

-- quit script
    menu.block(false)
    keys:stop()
end

keymenu = menu.new
{
    parent = "Audio",
    name = "Shoot",
    help = "Simply operates shutter",
    select = function(this) task.create(main) end,
}

Licaon_Kter


Quote from: garry23 on January 24, 2016, 09:50:50 AM
It truly would be fantastic is someone could write a simple (couple of pages) ML-focused intro to Lua scripting, ie showing how to do all the 'common' things we will be looking to do, eg: set up menu, get focus position, change exposure, move lens focus, take an image, drive other ML functionality from within a script, eg set ETTR etc etc.
You read some examples on the right here: https://davidmilligan.github.io/ml-lua/ too, right?


garry23

Yes...of course :-)

I've read and reread then many times.

I feel my weakest understanding is the basic syntax, ie how do you get DoF or move the lens etc.

I'll get there :-)

Cheers

Garry

dmilligan

When using keys:getkey(), you need to yield execution inside your loop (otherwise keys won't be able to process events). So inside your while loop add the line:

task.yield(100)

garry23

@dmilligan

Thanks for the hint and I've tried it two ways: but no luck :-(

-- Test Script

require('keys')


function main()
    keys:start()
menu.block(true)
  while menu.visible do
task.yield(100)
local key = keys:getkey()
-- task.yield(100) - tried it here as well
if key == KEY.RATE then camera.shoot() end
  end

-- quit script
    menu.block(false)
    keys:stop()
end

keymenu = menu.new
{
    parent = "Audio",
    name = "Shoot",
    help = "Simply operates shutter",
    select = function(this) task.create(main) end,
}


BTW this is why it would be helpful for someone in the know, to help kickstart the rest of us in the art of scripting.

I had looked at the Pong example and it didn't have the task.yield(100) business.

I truly am not looking for personal help as I know everyone is busy.

As I said, I'll just wait until a few more post their scripts and adapt anything I see useful to my project.

Cheers

Garry

Walter Schulz

I replaced .RATE with .INFO and it is working fine on 650D. Only one "yield" entry needed.

garry23

Walter

Does that imply you can't 'access' the rate button on the 5D3?

Walter Schulz

That would be wonderful because I don't own a 5D3.

garry23

Ok I just found out what has been happening.

With the script loaded (in the Audio parent menu) iy shows up OK.

If I toggle to the script submenu and press RATE nothing happens.

If I first press SET then RATE the script appears to function OK.

It's nuances like this that will mean that 'idiots' like me will meander towards scripts that work, ie our only way forward is to adapt others' scripts and experiment (and hope we don't brick our cameras :-))

Bottom line: now I can trigger a script I can focus on my task, ie an auto landscape bracketing script.

Thanks for your help.

Cheers

Garry

Totte

It's nice to finally have an official build with LUA included. Now I no longer have to wonder if the errors I encounter are from my own sketchy build and can instead concentrate on the LUA part.

I've experimented with camera.bulb(duration). The documentation says that duration is in seconds, but I soon discovered that it must indeed be in ms.

Even if I put a single camera.bulb(5000) statement inside a while loop there's still about 3 seconds before the next pic is taken with my 5D2. It is possible to fire off manual bulb exposures with at least 2s less delay between exposures with the same camera settings. Is this something that can be optimized in the camera.bulb() implementation or does the problem run deeper?

Thanks!
Totte

garry23

I hope one of the Lua experts can help with this simple script I am using to try and understand Lua.

-- Test Script

require('keys')


function main()
-- Close ML menu
menu.close()
    console.show()
print "move to macro end"
    key.wait()
-- Move lens to macro end
lens.focus(-10,3)
print "take picture"
    key.wait()
camera.shoot()
    print (lens.focal_length)
    print (lens.focal_distance)
print (lens.dof_near)
print (lens.dof_far)
print "Press any key to exit"
    key.wait()
    console.hide()
-- quit script
end

keymenu = menu.new
{
    parent = "Audio",
    name = "Shoot",
    help = "Simply operates shutter",
    select = function(this) task.create(main) end,
}


All the script does is first move the lens to the macro end, following a key press; then take a picture, following a key press; then display some info; then finish after a key press.

But I get strange results and when in the console I get 'loads' of other Lua reporting, eg about other scripts running.

What am I doing wrong?

Hope some kind person can 'educate me'  :)

Totte

Here's another script that is oh-so close. The idea is to switch between two series of settings while shooting and toggle this 'mode' with the joystick. The logic seems sound and it all works perfectly when the camera.shoot() statements are commented out and I just watch the camera settings change. When the camera.shoot() statements are included, it still works in principle but several shots are fired off before the key event is handled. This is very frustrating, as I would guess that the ability to handle key inputs would increase with longer task.yield() periods, yet this is not what I see for reasonable values of task.yield(). Any ideas?

For those of you who are LUA experts: Apologies for my mistreatment of the LUA language :P

Quoterequire('keys')

menu.new
{
  name = "MultiSeq",
  select = function() task.create(multiseq) end,
  depends_on = DEPENDS_ON.M_MODE,
}

multiseq = function()

  shutters0  = {   1/4 ,    1/8,   1/16 }
  apertures0 = {   8.0 ,    5.6,    4.0 }
  isos0      = {   100 ,    100,    100 }

  shutters1  = {  1/32 ,   1/64,  1/128 }
  apertures1 = {  16.0 ,   11.0,    8.0 }
  isos1      = {   200 ,    200,    200 }

  elementsin0 = 3
  elementsin1 = 3

  seq = 0
  k = nil
  i = 1

  keys:start()
  beep(1,500)

  while true do
    if seq == 0 then
      camera.shutter.value  = shutters0
      camera.aperture.value = apertures0
      --camera.iso.value      = isos0
      camera.shoot() 
      i = i+1
      if i>elementsin0 then
        i = 1
      end
    elseif seq == 1 then
      camera.shutter.value  = shutters1
      camera.aperture.value = apertures1
      --camera.iso.value      = isos1
      camera.shoot()
      i = i+1
      if i>elementsin1 then
        i = 1
      end
    else
      keys:stop()
      return
    end
   
   
    task.yield(1000)
    k = keys:getkey()

    if k==KEY.LEFT or k==KEY.RIGHT then
      if (seq == 0) then
        seq = 1
        beep(2)
      else
        seq = 0
        beep(1)
      end
      i = 1
    elseif k==KEY.SET or k==KEY.UP or k==KEY.DOWN then
      seq = 2
      beep(1, 1000)
    end

  end
end

dmilligan

Quote from: Totte on January 25, 2016, 02:11:44 PM
Is this something that can be optimized in the camera.bulb() implementation or does the problem run deeper?
All the Lua function does is simply call the underlying function in ML core.

Quote from: garry23 on January 25, 2016, 11:07:56 PM
But I get strange results and when in the console I get 'loads' of other Lua reporting, eg about other scripts running.
There is only one console, you do not have exclusive access to it. So anything else that is running: ML core, modules, and other scripts, might be writing there (at any given time there may be as many as a dozen or more ML tasks running).

garry23

@dmilligan

Thanks for clarifying the console.

May I ask one more question of you: If you look at my simple code, can you see why it wouldn't work.

For example, rather than go to the macro end, when the code runs it seems to go the macro end and then return to where the lens started.

An image isn't taken and the shutter picks up a half press focus, when I have back button set.

As I said: I don't understand as the code seems 'simple' to me.

dmilligan

You probably need to call camera.shoot with the should_af parameter to false (it defaults to true).

camera.shoot(64, false)

garry23

I'm afraid that didn't change anything.

Here is the function I call:

function main()
-- Close ML menu
menu.close()
    console.show()
print "move to macro end"
    key.wait()
-- Move lens to macro end
lens.focus(-10,3)
print "take picture"
    key.wait()
camera.shoot(64, false)
    print (lens.focal_length)
    print (lens.focal_distance)
print (lens.dof_near)
print (lens.dof_far)
print "Press any key to exit"
    key.wait()
    console.hide()
-- quit script
end


After the first key.wait, the lens doesn't move.

After the second key.wait an image is taken and the lens moves to the macro end then back to where it was.

Also the half press becomes active.

I'm mystified as the above code can't get much simpler.

Hope someone can divine what I'm doing wrong :-)

dmilligan


garry23

!!!!!!! I am now !!!!!!!!!!!!!!!!!!

But I still have a non-predicted response.

After the first wait, the lens correctly moves to the macro end.

After the next wait a picture is not taken and the lens moves backwards and forwards between the macro and infinity end.

I'm baffled.

dmilligan

The lens is moving because the camera is still trying to auto focus.

dmilligan

I think I found a bug.

Try

camera.shoot(64, 0)


In C there is no boolean data type, it's just zero (false) and non-zero (true) integers. In Lua there's a difference. In the Lua API function for camera.shoot I mixed these up:

static int luaCB_camera_shoot(lua_State * L)
{
    LUA_PARAM_INT_OPTIONAL(wait, 1, 64);
    LUA_PARAM_INT_OPTIONAL(should_af, 2, 1);
    int result = lens_take_picture(wait, should_af);
    lua_pushinteger(L, result);
    return 1;
}


should be:

static int luaCB_camera_shoot(lua_State * L)
{
    LUA_PARAM_INT_OPTIONAL(wait, 1, 64);
    LUA_PARAM_BOOL_OPTIONAL(should_af, 2, 1);
    int result = lens_take_picture(wait, should_af);
    lua_pushinteger(L, result);
    return 1;
}


the definition of those macros just for reference:

#define LUA_PARAM_INT_OPTIONAL(name, index, default) int name = (index <= lua_gettop(L) && (lua_isinteger(L, index) || lua_isnumber(L,index))) ? (lua_isinteger(L, index) ? lua_tointeger(L, index) : (int)lua_tonumber(L, index)) : default

#define LUA_PARAM_BOOL_OPTIONAL(name, index, default) int name = (index <= lua_gettop(L) && lua_isboolean(L, index)) ? lua_toboolean(L, index) : default

garry23

@dmilligan

:)

That fixed it: thank you.

I'm now confident to move to the coding the conditional logic in my script.

Once again thanks for your help.

BTW I hadn't read anywhere that Lua requires you to be in LV.

Cheers

Garry

Walter Schulz

Quote from: garry23 on January 26, 2016, 11:10:59 PMBTW I hadn't read anywhere that Lua requires you to be in LV.

That's mainly because it doesn't. There are functions/procedures only working in LV or in non-LV or in movie mode or ... See http://davidmilligan.github.io/ml-lua/modules/constants.html#DEPENDS_ON and http://davidmilligan.github.io/ml-lua/modules/constants.html#MODE
Example in recdelay.lua

dmilligan

It's a long standing ML limitation that we can only control focus in LV, and that control that we do have is very limited.

There's a note in the documentation for lens.focus: http://davidmilligan.github.io/ml-lua/modules/lens.html#focus

garry23

David/Walter

Once again, thanks for the prompt and to the point feedback.

It was my incompetence that I hadn't picked up on the LV 'sensitivity' to some ML functionality. I'll look at the documentation more carefully next time  ;)

I will also build some simple 'error' handling into the script, eg to ensure it doesn't run if not in LV.

BTW I assume if I call lv.start() it will switch on LV if LV is not enabled?

Once again, many thanks, and, because of your help, I hope to be publishing my first script very soon  :)

Finally, can someone explain the need for task.yield and when to use it.

dmilligan

Quote from: garry23 on January 27, 2016, 08:07:09 AM
Finally, can someone explain the need for task.yield and when to use it.
In a long running loop where you are polling or waiting for something to change and need to allow other things to execute rather than hogging the CPU and blocking event handlers.