Programmatic focus control and absolute/relative focus position

Started by sl0w0rm, March 30, 2013, 07:35:14 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.


These tests didn't attempt to model dynamic behavior in any way, so 500ms is fine. The hysteresis is probably mechanical backlash (just a guess).

100/2.8 still has large difference between the two directions, but different: this time, the focus position counter appears to catch up when the lens returns back to macro end.

35/2 looks very clean (as does 100/2.8 in the first test, on the areas that overlap).


The Extradelay in Lens.focus() has been set to 500 ms.

You can find here the repeatability tests for the 35mm f/2 IS

and the first one for the zoom EF17-40mm F/4 L USM @ 40mm

I will retry the test of the 100mm Macro IS, but with 500ms delay, Lv will probably shut down I am afraid : I will try to dim Lv display,...


Quote from: BBA on November 18, 2016, 07:36:13 PM
I will retry the test of the 100mm Macro IS, but with 500ms delay, Lv will probably shut down I am afraid

Press some key every now and then to wake it up (just make sure it won't have side effects, such as autofocusing or exiting LiveView).

35/2 repeatability:

17-40/4 @ 40:


This morning, I had time to do the 2 repeatability tests with the EF 17-40mm f/4 L USM @ 40mm with a rest time between them (to be sure, as I don't know about the temperature of the friction surfaces) :

and do a first try with the EF 50mm f/1.8 II : I think it went in an infinite loop with the first loop on lens.focus command (step-size=3) as there is nothing in the log file:

The 100mm will need more time.


17-40 has some small surprises on repeatability side:

For 50/1.8, I think there are no limit switches at the end, so this condition is detected only by noticing the motor no longer advances (or its current increases above some threshold). This matches the focus hunting noises made by this lens. The same focus error is reported when you try to stop the focus ring with your hand, or if the lens ring gets a little stuck for some reason.

The retry mechanism from ML currently checks whether focus_pos gets changed after each focus command (and if there's no change, it allows 2 retries). On 24/2.8, this is well-behaved. On 50/1.8, I assume the motor is trying to drive the focus ring past its limit, and the encoder just goes back and forth (because of those retries), therefore reporting changes in focus_pos (which confuses my algorithm and allows it to retry over and over).

With this retry mechanism, I'm trying to cover 3 issues:
- PROP_LV_FOCUS_DONE reporting error during normal movements (without reaching the limits); in this case, retrying the focus command in the same direction usually works; without the retry mechanism, some lenses have issues such as stopping a focus stack for no apparent reason
- lens refusing to go back with small steps after reaching a limit switch (after going back one small step, the limit switch is still active, so even if the movement was successful, PROP_LV_FOCUS_DONE reports error)
- when reaching the limit, the last step executed may be smaller than usual, and PROP_LV_FOCUS_DONE reports error even though the focus ring was moved (although not by one full step, because the limit was reached). In this case, I want a focus stack to take the last picture, even if that step was smaller, without reporting error (and I want an error to be reported for the next focus attempt in the same direction, if any). In other words, I want this half-complete motion to be considered a successful one (see this issue).

Maybe I should also check the focus direction of each command somehow before allowing retries.

Can we assume positive correlation between focus command, focus_pos and focus distance (or at least between the first two)? I remember reports about some third party lenses that moved in opposite direction (though I don't remember exact models).

We also need some focus tests (e.g. in api_test.lua) that cover the above cases. The test script that created the above logs checks for #2 at one of the ends. For #3, one could focus at one end with step size 3, then go back with step size 2, then forward with step size 3, forcing the last step to be incomplete (thus turning a seemingly random issue into a deterministic one). #1 is tricky, as it requires user actions that are not exactly friendly to the focusing mechanism (or, a lens with poor mechanical condition, that reports false errors very often).


Many thanks for those informations as well as the very interesting paper on the Kalman filter (I would like to look at closely).

The next test for the 100mm Macro IS was difficult to get done. During the first run, the position counter and focus distance were stuck on the first values for the whole length of he file. I had to try and find out what went wrong. I think there are false electrical contacts. I still don't know where actually (a Gray encoder ?). Maybe this lens needs servicing.

Anyway, I could finally get a correct run (but the results for this lens will have to be taken with greater care given the troubles we have had with it) :


It doesn't look that bad, but I'm also wondering what's going on. Anyone else having this lens?


After some homework, here are the 2 first test results for the 17-40 @ 17mm :

I have tested the 50mmf/1.8 II after commenting out the first loop and turning the "front barrel" to mechanical end (macro):
Note : this lens does not report the distance to ML
Note : when reaching the infinity mechanical end, the sound changes from louder to fainter indicating the motor does not work anymore; only the mechanical end protection (micro switch?) maybe.
I have left it working a few times at the mechanical end.
I guess the position conter counts and stops counting when the end protection enters in action because the same position should have been repeated more often.
The step length varies but there is no focus distance reported.


Quoteonly the mechanical end protection (micro switch?) maybe.

There's no such thing on 50/1.8 II as far as I could tell. When my 50/1.8 was still functional, I remember the motor trying to force the ring past its limit, and just hunting there.

Does the loop stop when reaching the end, or it just stays in some infinite loop?

The step count difference between the two attempts (1275 vs 1424) is pretty high. If it was repeatable, we could estimate the focus distance from this counter, as long as the lens is moved only from software and we know one of the limits (maybe with the lens equation, which I don't fully understand yet, but your experiment looked quite linear).


Does the loop stop when reaching the end, or it just stays in some infinite loop?
It stays in some infinite loop. As the lens is moving, it is possible to see when the end is reached. The sound changed too. I left it continue a little while and then switched the camera off.
The step count difference between the two attempts (1275 vs 1424) is pretty high
I wonder: as far as I can remember (Youtube video ?), the piezo electric motor present in this lens is not a ring motor which would directly move the helicoïdal lens barrel without intermediate piece. Moreover there are other external moving parts as the protruding lens, the manual focusing ring in front that is rotating : more friction ?
I wonder if this is not only an electronical counter not related to the actual position of the lens barrel.
but your experiment looked quite linear
I think I am misleading people with that picture: the red and yellow are only my attempts to adjust a straight line via the least squares method (linear regression); the only measured points correspond to the steps of the decreasing blue stair function.
I know what happened : this picture has been plotted against the number of steps (step-size=1) ! so, with the assumption that the step length was constant (at that time (july), I had not yet used the position counter : I just counted the number of steps); as the length step decreases towards the infinity end, the curve gets "compressed". My apologies  :-[ !!! I am working on another comparison picture.
Note : I only used the "thin lenses" formula : 1/p + 1/p' = 1/f where p, p' and f are in the same unit (mm), p is the focus distance, p' the image distance = distance from lens optical center to the sensor and f the focal distance.

Here are the results of the last test of the 17-40@17mm:

I have tested @ 28mm (in between):

If you like, I can also test an EF 70-200 f/2.8 L IS II USM (quite a wonderful one)...I have never dared to put it in test  :-\ .


Quote from: BBA on November 21, 2016, 05:22:00 PM
the piezo electric motor present in this lens

The 50/1.8 II has a simple DC motor (see p15) and an optical encoder (p18-20).

In AF mode, I would expect the encoder to be in sync with the focus ring position (even if you turn the focus ring manually and you hear the motor turning forcefully; be careful if you want to try that, as you can damage the focusing mechanism).

Quote from: BBA on November 21, 2016, 05:22:00 PM
If you like, I can also test an EF 70-200 f/2.8 L IS II USM (quite a wonderful one)...I have never dared to put it in test  :-\ .

Why not?

Quote from: BBA on November 21, 2016, 01:00:29 PM
17-40 @ 17mm

Quote from: BBA on November 21, 2016, 05:22:00 PM
@ 28mm (in between)

It focuses faster at 17mm, right?


For information purposes, here is a comparison chart between the stairs functions obtained:
- in function of the actual position counter value with actual varying steps (red)
- in function of the number of steps as if the step length were constant(blue).


X axis : position counter during the scan (the scan starts at macro mechanical end = 0) (in sub-steps)
This lens has many sub-steps : about 14426 sub-steps for about 3866 steps.

Y axis : focus distance in the image field (absolute value in mm)( the thin lenses formula has been used to project distances from the object field to the image field)

BLACK points : the same Y scale has used to display the step length in sub-steps. The scaling formula is : displayed_length = 110 + step_length*10. The values have a visual trend : go down from the macro end to a minimum and then, a little upwards near infinity end. The reason (if any) is not known.There are many outliers especially near infinity end (unknown reason heretoo).

RED points : The focus distance in the image field is displayed in function of the actual position counter values : at infinity, the distance between the focal lens centre and the sensor is equal to the lens focal length = 100mm. The position counter value giving the position of the focal distance is not known.

RED curve : it is possible to ask LibreOffice to calculate automatically a trend curve : a 2d degree polynomial has been chosen : the formula and the regression coefficient (least squares fitting) have been displayed near the curve. Actually, the curve should be forced to pass on the point (x,y) where x = lens focus image ( in french = n° du sub-step correspondant à la distance focale image) , and y = lens focal distance ( in french = distance focale image de l'objectif) but as written above, the position counter value corresponding to the focal distance is not known. Note : the coefficients of x and x2 seem tiny but the values of x and x2 are big !

BLUE points : for comparison purposes, the focus distance in the image field is displayed as if the step-length was constant from macro to infinity end (which it is not the case : see black points above) : the mean value of the step length has been calculated and taken as constant step length.

BLUE curve : a 2d degree polynomial curve has been fitted to the points automatically.
The curvature/concavity of the blue curve is less then the curvature of the red one.


Here are still the results of a few tests:

1)Last repeatability tests for the EF 17-40 @ 28mm

2) First test for EF70-200mm f/2.8L IS II USM @ 70mm  ;)
(after a run with the same values at all steps) Next time I will switch console on !

Thanks for the disassembly paper of the 50mm 1.8 II !
The DC motor + optical encoder are there with a lot of little gears !
There is not so much mechanical backlash though...


Trying to get a linear graph.

If I understand the thin lens equation, when the subject is at infinity, the image distance is equal to focal length.

When focusing towards macro, the image distance increases, and therefore, the lens must be moved a little far away from the sensor in order to keep the subject in focus.

If we assume the linear lens movement is proportional to the focus_pos counter, we should get a linear graph if we plot the image distance (instead of the focus distance). I'm just going to distort the axis (so the plot will show image distance, but the axis labels will show focus distance).

The Y axis transformation should be something like 1 / (1/f - 1/o), where f is focal length and o is focus distance (object distance in the above link).

I've played a bit with the focal length in the above formula, and if I use 200mm instead of the real value of 100mm, the graph is pretty much linear.

Is this because the thin lens equation doesn't quite apply here, or I'm just misunderstanding the whole thing and, and that linear graph was pure luck?

The 24/2.8 STM also gives a more linear plot with twice the actual focal length in the thin lens formula.

For 70-200/2.8 II, it's a tie.

For 35/2, 2*f looks better, and 3*f looks even better:

The 17-40/4 looks best when linearized with f=80mm, at all focal lengths.

Food for thought:

1. Assuming we can find a good linearization transform (e.g. by choosing the "fake focal length" to minimize linear fit errors or similar), which is a better approximation for the actual focus distance? The linear regression line, or the line connecting the center points of the horizontal segments in the above graphs?

This can be answered by somebody who can set up a test environment with known focus distances (e.g. a linear axis of a CNC machine or similar, that can be moved at known distances). One needs to get a log similar to the previous ones, with an extra column: the real focus distance.

2. Most lenses can focus past the infinity, and this is visible in the above graphs as well. Can we find the real infinity focus point without actually using a distant object to focus on? (assuming the focus distance markers are calibrated from factory).

These are probably nitpicks, not sure how useful they are in practice.


I am not a specialist in optics but I will try to help. If you think I am wrong, don't hesitate to tell it !
For an authorized advice, I would ask help from specialists our community...or from academic people...

As you know, real lenses are complex optical instruments.
For me, the thin lenses formula is to be considered as a simplified but convenient transform from the object field to another field not far from the image field ; in that meaning, the transform can be used with different parameters (like another focal lens value), and adapted according to our best needs.
I also thought of the  « focus breathing », where the « apparent » focal distance changes when the focus distance changes....Cine lenses avoid that problem, but most picture lenses don't when they use inner focus. In this case, even if the lens has only one focal distance in it's name, it is only valid when focusing to infinity.

But one must take care of the fact that this simplified model can lead to errors depending on what we want to infer from it and with which precision.

For instance, the actual object distance will be an approximate without calibration as a1ex explains it in his previous (#63) post.

Anyway, I think there will always be an uncertainty relative to the precision of the actual position of the hardware, even if the software has done it's job. This is true if we can only work in open loop (cf. focus backlash, motor errors...) and will always limit precision.

All depends on what the community wants to do. Is it:
1) positioning the lens at a given target position
2) focus stacking
3) display more/very accurate current focus distances in Lv

For each choice:
1) positioning the lens at a given target position
- If the target position is determined through auto focusing and if we just want to go back to that target, the position counter is just sufficient. The precision may go from one step to maybe one half of a step (step-size=1) (which is to be converted to the object field).
- If the target position is given by the object distance, IMHO, it will be difficult, at least without calibrating the lens.
2) focus stacking
The Canon focus_distance can be used to build a continuous function of the position counter (this may be a step forward over the discontinuous stair function available now). According to DOF calculations, the position of the shots needed can be calculated. Then we have to move the focus position to each of the calculated positions as in 1) above.
3) display more/very accurate current focus distances in Lv
Display more accurate focus distance may be possible (not near infinity), but very accurate display will need a lens calibration as a1ex explained in his previous post.



I'm away from home at the moment, but watching your developments with much interest.

As I alluded to before, as a stills (non-macro) photographer, this feature would be a nice to have, but non essential for me.

My Lua landscape bracketing scripts operate with a move from here-2-here rationale, ie FP2Inf, FP2HFD or FPa2FPb, and based on checking that overlap from the ML DoF variabes, eg DoF-near and -far.

As I overlap the focus brackets, being a few% out is not that critical.

Thus, I wonder, if the lens repeatably or linearalization gets 'better' between focus points, ie rather than trying to drive the lens over the entire possible movement capability.

Just a thought?




I have been following this thread with great interest, but there is something that has been worrying me from the beginning; perhaps I have not understood the target of this study, or perhaps I have not understood how all this works.

On one side we have the focusing distance, as reported by the encoder in the lens; this distance is used to inform a field in the EXIF data, so the user knows the focusing distance. On the other hand we have some commands to move the lens back and forth, and a counter that stores the current position of the lens; these commands are used by the camera to focus the lens on a subject. And now we are trying to find a method to match the focusing distance to the lens position, so we can (for example) tell the lens to move the focus to a specific distance.

What I was wondering is whether that function does even exist at all.

When the camera focuses, it uses the info from the AF sensors to determine if the subject is focused, how far from being focused it is, and what direction must move the lens to gain focus. With this information, the camera sends some commands to the lens, the lens moves the focus, and the camera checks the focus again. In this process, the focusing distance is not needed at all; in fact, the focusing distance reported is way coarser than the focusing abilities of the lens, and some lenses does not even report any focusing distance.

My thought is that if I was Canon, I would not bother to make any connection between the focusing distance and the focusing steps, because the camera does not need it: as far as I know, there is no official method (buttons, menus, PPTP, ...) to tell the camera to focus to a specific distance, and the AF does not need it either.

If I had to implement a method to move the focus to a specific distance, I think I would employ a trial-and-error approach: check focusing distance, move lens a large step, check focusing distance again, move lens a small step, ... All the info gathered in this thread can probably be used to speed up this process (for example, with a look-up table with some values from known lenses). But I do not think we can obtain a function to determine the lens position from the desired focusing distance.

Just my two cents (or perhaps a clueless comment).


That's correct - autofocus doesn't care about focus distance. Another example: my 18-55 II kit lens no longer reports focus distance properly (it's stuck at some value), yet this hasn't interfered with autofocus.

I guess the focus distance info is just for EXIF. It can be used for corrections such as vignetting, but these depend on the focus distance as well. In particular, on a 24/2.8 STM mounted on full frame, the focus distance and the aperture make a big difference in the vignette pattern.

Quote from: eduperez on November 24, 2016, 01:22:05 PM
And now we are trying to find a method to match the focusing distance to the lens position.
What I was wondering is whether that function does even exist at all.

Probably not. We are creating one from scratch.

The result would be just a higher precision in the focus distance indicator, or when moving to a specific focus distance. It might also add some rough focus distance indication to the lenses that don't have one.

Whether this will be useful in practice, I don't know.

In the process, we have also found some bugs in the focus backend, and fixed some of them. This is useful, right?

Also, we can now record focus positions and later return to them, with fewer constrains. Previously, we were able to do so only if we moved the lens in single steps of the same size (and even then, the position errors would accumulate, resulting in drift). With the fine position counter, we can probably return to saved focus points no matter how we move the lens, as long as the encoder records the movement (autofocus, or by sending focus commands of any size/speed. It's still not perfect - some lenses will lose the position during manual focus.

In other words, nitpicks :P

Walter Schulz

According to Canon focus distance is used by E-TTL II.
But I never tested through if and in which respect results differ between lenses with/without encoders.


There were "problems" with the EF70-200 f2.8L IS II USM too, like with the EF 100 f2.8L IS USM. It doesn't seem to be due to the lens itself as I suspected before with "electrical false contacts".

This tests @200mm seems special too: lots of steps (high precision) and different step-lengths for the two directions A focal length change has modified the step length between the two directions (nothing unknown):
- macro to infinity: 4 fine steps, then 3 fine steps,
- infinity to macro : only 3 fine steps,
though the step length graph is very clean (no outliers) !
Repeatability tests will maybe shed some light...


I had to modify my previous post as the step length change observed is due to a tiny rotation of the focal length barrel.
I will try to show the variation of the step length according to the focal length.
It also occurred during the following (2d repeatability) test : the barrel has to be at mechanical end.

It should be noted that the number of steps is very high (more than 8000) and that these are very tiny step length (3 fine steps) for step-size=1.


Found lens.focus_pos on 5D3 1.2.3, likely the same on 6D and other recent models. Also added it on EOS M, but not tested. Test builds on the Experiments page.

Couldn't reproduce the issues with 50/1.8 (mine is broken, and after trying to repair it the n'th time, the motor no longer gives signs of life). As I don't have any other use for this lens, other than checking the focus backend in ML, I hope to get away with tester feedback.

Therefore, I'm looking for a log to see what happens when you attempt drive this lens past its limit (with either follow focus or Lua commands). If weird things happen, please open the console and take a screenshot.

The focus backend in this build is also different from the others, so I'm looking for similar feedback with other lenses. In particular, the behavior of follow focus at the end points: it should stop driving the lens (it should not keep forcing the motor past its limit), and it should allow moving the lens in the opposite direction, even at small speeds.

Also please check whether this issue is still valid.


Quote from: a1ex on January 25, 2017, 02:31:09 AM
...Also added it on EOS M, but not tested. Test builds on the Experiments page.

EOSM lua Script API Tests results uploaded to Dropbox.

Ran tests using EF-S 17-55mm f2.8, EF-M 11-22mm f4-5.6 and EF-M 22mm f2 lenses using the build posted on the Experiments page. The camera was able to control the EF-S lens through the active adapter but the EF-M lenses didn't move. The 22mm lens is easy to tell because it makes a noise and the front element moves but the zoom lens is all internal. I thought it was working at first but it was only the autofocus tests that moved the lens. Note that it takes much longer for the tests to complete with the EF-M lenses--about 20 minutes compared to just a couple of minutes with the EF-S lens.

Quote from: a1ex on January 25, 2017, 02:31:09 AM
Also please check whether this issue is still valid.

I was trying to figure out how to test that when I realized that it isn't on the EOSM features list. Since the camera can control EF lenses is there any harm commenting out these undef statements?

/* Some Hope Yet */

Yeah, I know--try it and find out. That was the case with FEATURE_AUDIO_REMOTE_SHOT a while back. So I did and it looks like the EOSM can do Focus Stacking along with the other focus tricks.

I ran the tests for Issue #2452, Soft Focus Limit Incorrectly Reached When Using Focus Stack, though I don't quite understand this line in the instructions:

Quote3. Set Num Pics In front to 0 4 Set Focus steps / picture to 1

Perhaps the '4' is a typo or does it have some significance?

With the EOSM I got the 'Soft Focus Reached' in the first test at the end and on the third exposure with the second test.

Since I'm not familiar with these focus settings I also ran the test on the 700D. On that camera the focus steps are much larger than the EOSM. In fact on the EOSM the focus increments were so tiny that I had to set Focus steps / picture to 10 to see that it was indeed moving the lens. That same setting on the 700D would get the 'Soft Focus Reached' error because the of the larger steps.

So--it looks like the EOSM is moving EF lenses but at a much finer increment (the lua "Script API Tests" did move the lens through the entire range) but the native EF-M lenses are still unresponsive.

Finally--reproducing Soft Focus Limit Incorrectly Reached When Using Focus Stack as far as I understand it on the 700D did not bring up the 'Soft Focus Reached' on either the first or the second test so it looks like that issue was resolved.


Thanks for the tests.

Autofocus outside LiveView...

I wonder how this one worked on the M. Best guess: pressing the half-shutter enabled LiveView, and it autofocused there.

QuoteSo--it looks like the EOSM is moving EF lenses but at a much finer increment (the lua "Script API Tests" did move the lens through the entire range)

Focusing forward with step size 3, wait=true...
Focusing backward with step size 3, wait=true...
Focus range: 6 steps forward, 6 steps backward.
Motor steps: 2291 forward, 2291 backward, 0 lost.

Focusing forward with step size 2, wait=true...
Focusing backward with step size 2, wait=true...
Focus range: 35 steps forward, 31 steps backward.
Motor steps: 2291 forward, 2291 backward, 0 lost.

Focusing forward with step size 1, wait=true...
Focusing backward with step size 1, wait=true...

Focus range: 126 steps forward, 125 steps backward.
Motor steps: 2291 forward, 2291 backward, 0 lost.

These look fine, focus position counter works, so I guess changing step size actually makes a difference in speed. Adding some timestamps to the log should help answering this.

but the native EF-M lenses are still unresponsive.

Not sure what to do about that, but some dm-spy logs in LiveView during autofocus and during ML focus commands (e.g. follow focus) might give some clues.

Finally--reproducing Soft Focus Limit Incorrectly Reached When Using Focus Stack as far as I understand it on the 700D did not bring up the 'Soft Focus Reached' on either the first or the second test so it looks like that issue was resolved.

If you can reproduce the issue on the regular nightly or on the lua_fix branch, that's a good sign!


Not adding much here, other than another tester  ;)

Just tried my simple lens move test on the EOSM with a Canon adapter and 24-105 F4/L. Plus with latest experimental Lua fix build.

function test_lens()
    local lens_ok = false
    local start = lens.focus_distance -- position lens near macro end
          lens_ok = lens.focus(-1,3,true)
        until lens.focus_distance >= lens.hyperfocal
        -- take a picture
        -- now go back
         lens_ok = lens.focus(1,3,true)
        until lens.focus_distance <= start

function my_test(k)
    if k == KEY.PLAY then
        return false
        return true

event.keypress = my_test

Tried it with step 3 (above) and step 1. Both drive at the same slow speed. Neither make the return trip.