Future plans

I haven't done much in the last year, but now I am contemplating making a significant hardware/software upgrade:

  • Moving from Arduino Uno to Mega, for more pins and memory.
  • The tough part: re-writing the low level stepper motor controlling parts of the code, trying to implement a dynamic microstepping control. The current version uses a single fixed value for microstepping; if you set it to a large number (16), you gain accuracy, but loose on maximum speed (only 2.5 mm/s); with a smaller number, you gain on speed, but the accuracy goes down (and vibrations go up - bad for continuous mode). With Arduino Mega I'll have the extra 3 pins I need to control microstepping of the motor driver (between 1 and 1/16). In the new code initial (low speed) motion is done at the smallest microstep (1/16). If the speed grows above some threshold value, the stepper driver will be switched to 2x larger steps - on the fly, without loosing any steps, and so on. The opposite picture happens at deceleration. With this approach maximum speed can potentially be as high as 40 mm/s (if going all the way to full steps). With the acceleration limit corresponding to the breaking distance of 1mm at 5mm/s (12.5 mm/s^2), the full travel time across the 50mm rail will decrease from the current ~20s to only 4s.
  • Then I will design a new enclosure for the controller, and print it using my new 3D printer (Anet A8).

Software s1.17

Released on 15.09.2016. Requires new hardware version (h1.3)

New features and fixes:

  • The one major change is that now the same controller with the same cable (using the same Arduino code) can control either my macro rail or (new) motorized Telescope Focuser. The controller detects automatically which device it is connected to (at boot time), and changes its interface accordingly. I upgraded the stepper motor on my rail to a more powerful one, and used an identical motor for the telescope focuser. I also upgraded EasyDriver to BigEasyDriver in my controller. This allowed me to use twice smaller steps (1.25um on my macro rail and 7.5um on the telescope focuser) and resulted in a significantly better torque (can move easily 1kg camera vertically up on both devices). The only drawback is that the maximum speed of the macro rail is twice smaller (2.5 mm/s).
  • Check Telescope Focuser to see all its features.
  • Only small changes / improvements in the macro rail part of the code:
    • Significant code re-arrangements to save program space and RAM, to be able to fit all the new telescope functionality.
    • To save space, the new macro parameter SHORT_ERRORS is defined by default, resulting in very brief error messages.
    • Factory reset function (#*) now has a safety feature: now it displays a message "Factory reset?", and only if "1" key is pressed the reset takes place; any other key cancels the reset. Factory reset done in macro rail mode will only reset the macro rail part of the code; the same is true for the telescope mode.
    • I solved the old hardware bug with intermediate backlighting levels causing LCD instability, by soldering a 10uF capacitor between the cable going to the LCD backlight and the ground. (This effectively turned PWM into a proper DAC.) This allowed me to add two intermediate backlighting levels (great for working in the dark).
    • Some pins were swapped around in h1.3, only for the telescope mode benefit, not really needed for the macro mode.

Using the latest stable software version (s1.16) with the latest hardware (h1.3)

If you don't need the telescope control feature, and want to use my latest hardware (h1.3) with the latest stable software (s1.16), download the s1.16 software and do the following changes in your stacker.h file:

  • Replace
const short PIN_STEP = 0;
const short PIN_DIR = 1;
const short PIN_ENABLE = 2;


#define PIN_STEP A5
#define PIN_DIR A4
#define PIN_ENABLE A3
  • Replace
const short PIN_AF = 6;


#define PIN_AF A2
  • Replace
byte colPins[cols] = {A2, A3, A4, A5};


byte colPins[cols] = {6, 2, 1, 0};

September 2016 update

I have changed my software to allow my controller unit operate two different devices (one at a time), each with its own stepper motor and other optional hardware. Specifically, my controller can now operate either my macro rail, or the telescope focuser I just built (see The focuser currently doesn't have any limiting switches or relays. The controller automatically detects which device it is connected to, and then changes its behaviour accordingly. One can use all the controller functionality with both devices. With the telescope, it can store up to 24 different focus positions to EEPROM (with a two-click access to any of the points), do forward/rewind, or move in specified steps. It also has a thermistor-based telescope temperature reader, allowing one to correct for temperature-induced changes in the focusing positions caused by changes in the air temperature, in a fully automated fashion.

A related hardware change is that I just upgraded my Easy Driver to Big Easy Driver - I need this primarily to achieve the required small steps with the telescope focuser (as it has 16 microsteps per step - twice more than the old driver), 7.5um. As a bonus I will be able to make twice smaller steps on my macro rail - from 2.5um down to 1.25um. Finally, the Big driver is much more powerful (can easily drive up to 1.4A per motor coil without any heat sinks, compared to the old driver's 0.7A limit). To make full use of this, and also to add substantially more torque to the macro rail, I ordered two identical stepper motors, for the rail and telescope, NEMA 17, 2.1 Ohm, 1.33A per coil, 22 Nm torque ( ; 9$ with free shipping). It is quite a bit (80g) heavier than my original motor, but it should provide much more torque - hopefully enough to make the rail usable at large angles, perhaps even at 90 degrees angle.

The newest version of the software (to be used only with h1.3 hardware; can be used with both macro rail and telescope focuser) can be downloaded from here:

It is still an early beta, hence the odd version number. For the same reason I haven't uploaded it to GitHub yet.

Tested at 10:1 magnification

I got a quality Nikon microscope objective (M Plan 10x/0.25), so I was able to test my rail's performance at a much higher magnification than before (10:1 versus 4:1). I am happy to report here that my rail is totally usable with magnifications at least as high as 10:1, with steps as small as 5 um. See one of the tests shots here: .

Software s1.16

Just one change: fixed the annoying bug in the EXTENDED_REWIND section: multiple frequent presses of the key "1" often resulted in the rail refusing to stop (it keeps moving towards the foreground until you hit any key). In this new version s1.16 the bug is fixed. (02.04.2016)

Now the git repository for this project is hosted on

All the public releases there:

Software s1.14 (03.03.2016)

It requires hardware h1.2. As usual, you have to do the factory reset (keys #*) after upgrading the software.

Full Resolution Silent Picture

There is one important new feature introduced in this release (and two important bug fixes - see below). The new feature will only matter for Canon camera owners. Specifically, I added support for "Full Resolution Silent Picture" (FRSP, or electronic shutter) feature of the alternative firmware Magic Lantern, which is available for most Canon DSLRs and mirrorless camera models starting from ~2008 year models (Canon 500D/T1i, 50D and 5D2). It works great on my Canon 50D. Read this long thread if you want to understand it better: . The FRSP feature allows you to take any number of shots in a sequence without using the camera shutter, and without moving back and forth the camera's mirror. So there are two important advantages of FRSP for macro photography: it prolongs the camera's life (because each extreme macro stacked photo requires taking hundreds of shots), and also it reduces the camera vibrations as neither shutter nor the mirror move during stacking. The only source of vibrations left is the rail movement.

One important contribution I made to the long FRSP thread was the demonstration that FRSP is totally usable with an external flash (and that is critical for extreme macro: flash helps to reduce the impact of camera vibrations on image sharpness - due to environment etc.). The problems with a flash + FRSP are that (1) Canon doesn't let you use flash while in Live View (and FRSP needs Live View), and (2) shots taken in Live View take a variable (and unpredictable) time to happen, from the moment you initiate the shot. You could address the point #1 by using an external flash trigger, but the point #2 is trickier.

Fortunately, I converged to a fully usable solution - which requires my Arduino rail with the newest software s1.14, plus a bit of soldering. The hardware mod consists of soldering together a 3.5mm stereo phono jack, a 3.5mm phono socket, and a socket to trigger an external flash (could be a hot shoe socket, or a PC flash socket - if you have a PC cable). The idea is to let the Arduino's AF relay to do the usual job (triggering the camera's AF circuit), but redirect the output of the rail's shutter relay to trigger an external flash, instead of triggering the camera's shutter. (FRSP takes pictures by half-pressing the shutter button - in other words, by triggering the AF circuit; the shutter circuit should not be used during FRSP taking.) Once you made the adapter, you plug the 3.5mm stereo jack into the rail, the usual camera-rail cable is plugged into the camera and the 3.5mm stereo socket in your adapter, and the flash is connected to the adapter's hot shoe (or PC socket).

The slight modification to the software was the introduction of a new mirror lock mode = '2'. (Before I had only two mirror lock modes - '0' means no mirror lock, and '1' means use mirror lock - only for non-continuous stacking.) As before, the appropriate mirror_lock mode can be selected by using the *C keys, and as usual the current mode is always saved in EEPROM, and can be saved in any of the 5 custom registers. On a technical level, the mirror_lock=2 mode changes the values of the two delay parameters, SHUTTER_ON_DELAY and SHUTTER_OFF_DELAY (they became SHUTTER_ON_DELAY2 and SHUTTER_OFF_DELAY2). Because of the soldering hack, the meaning of the two delays is now different - the first one is the delay from the moment a silent picture is initiated (by engaging the AF switch) until the external flash is triggered. The second one now is the delay from the flash triggering until the AF switch is disengaged (which tells the camera to save the silent picture it just took).

The tricky part was to find such camera exposure, and the corresponding value of SHUTTER_ON_DELAY2, which would ensure that the flash is always triggered while the camera's electronic shutter is "open" - despite the variance in the times from initiating a FRSP until it actually takes place. For my Canon 50D, the best values appear to be SHUTTER_ON_DELAY2=1.1s, and the camera's exposure = 1/4s.

One inconvenience of FRSP is that the exposure has to be fairly long, meaning that your studio should be fairly dark (but with typical effective apertures used for extreme macro around f/20 it doesn't actually have to be very dark). Another inconvenience is that the time between two consecutive silent pictures cannot be very short; with my Canon 50D, I can reliably take hundreds of silent pics if that time is at least 5.5s.

But the advantages of FRSP outweigh the above inconveniences: you dramatically extend the life span of your camera (and now can go crazy with huge stacks, like 1000 shots long), and you reduce the camera vibrations (though in my tests it doesn't matter, at least up to 10:1 macro; perhaps it will matter for larger magnifications). Some people even reported they could take FRSP photos with a camera with a broken shutter!

Here are the steps required to use the FRSP feature (that assumes that you already figured out the proper timings for your camera - the values for SHUTTER_ON_DELAY2, camera's exposure, and minimum interval between FRSP shots):

  • Upgrade the rail's software to s1.14 or newer version. Set SHUTTER_ON_DELAY2 for your camera. (Use DELAY_DEBUG mode to figure out the correct value.)
  • Darken your studio
  • Use the adapter to connect the rail to the camera and the flash
  • On the rail, set non-continuous delays to 4 and 1.5s (for Canon 50D), set mirror_lock=2, and set the required frame step (um/frame)
  • Put the card with a recent (nightly) release of Magic Lantern in your camera.
  • Enable two optional Magic Lantern modules - mlv_record, and silent. Turn the camera off/on to load the modules.
  • Set the camera to fully manual mode ("M"), set the required camera exposure (1/4s for Canon 50D), and disable AF on your lens.
  • In Magic Lantern menu, go to so Silent picture settings, choose Full Resolution option, and MLV as the output file format
  • Your camera should be set to have a picture review on (after each shot), and long exposure noise reduction should be set to Auto or Off.
  • Turn on the Live View
  • Using the rail controller, set the foreground and background points for 2-point stacking
  • Briefly half-press the camera's shutter to go from Live View mode to FRSP mode (the camera's screen turns black)
  • To test FRSP, take a manual shot from the rail controller (#4 key). The flash will go off after some delay. If your timings are correct, the camera will briefly show a well exposed photo. If the timings are wrong, you will see a totally dark frame, or a frame with a black top.
  • Now you can initiate non-continuous stacking as usual - by pressing #0 key.
  • You can pause stacking at any point, by pressing any key, but unfortunately in FRSP mode you cannot easily see the recently taken shots. Resume by pressing "0" key.
  • All the stack photos are saved to one or a few huge MLV files. To finalize the file, you either disable the Silent picture in Magic Lantern menu, or turn off the camera. If you want to take a few stacks in a row, always disable/enable Silent picture mode between stacks, otherwise all stacks will be merged into one huge MLV file.

Individual FRSP shots are larger than CR2 shots by ~50%, so make sure you have enough of space on your card. It is likely beneficial to have a fast card (mine is Lexar 1000x 32GB).

To unpack MLV files into sequences of standard DNG files, you can use program MLV Mystic. The DNG files can be processed with many RAW image converters (like Adobe Camera Raw). The DNG files will have a different colors than CR2 files, so you have to calibrate DNG colors separately (using a grey target).

Other improvements

  • Two new debugging modes were added - BL_DEBUG (allows to change BACKLASH value on the fly by pressing "2"/"3" keys; displays the current BACKLASH value in microsteps on the fifth line) - can be used to figure out the backlash of your rail without multiple recompiles of the code. The other one is DELAY_DEBUG (allows to change SHUTTER_ON_DELAY2 value on the fly by pressing "2"/"3" keys) - to be used to figure out the proper timings for FRSP (mirror_lock=2) mode (see above).
  • A bug was fixed which made non-continuous stacking without mirror locking (mirror_lock=0) unusable. Now it is totally usable.
  • The keypad.ino module was re-written, now properly using the multi-key feature of the Keypad library. As a result the keypad became much more responsive, for two-key commands (#X and *X).
  • Parameter BACKLASH_2_MM value was slightly increased, to = 0.3333 (after testing at higher magnification - 10:1).

Software s1.12 (07.02.2016)

It requires hardware h1.2. As usual, you have to do the factory reset (keys #*) after upgrading the software.

The only serious change is that now you can change the type of all coordinates inside the code from the default one ("short") to "long", and visa versa, by simply changing the value of the new macro parameter COORD_TYPE in stacker.h. After each change you have to recompile and re-upload the code, and then do factory reset ("#*").

You only need this new feature if the rail you are building uses a different hardware (the rail itself, motor, and/or motor driver) than mine. More specifically, you need to set COORD_TYPE to long if the total number of microsteps required to move all the way from one end of your rail to the other end is larger than 32,000. You can compute this number as MOTOR_STEPS*N_MICROSTEPS/MM_PER_ROTATION*rail_length_mm, where rail_length_mm is the length of your rail in mm. Using long type will result in a larger memory consumption (from 90% to 95% of the flash memory). My timing tests show that the rail performance doesn't suffer from switching to long type coordinates. If your rail needs 32,000 microsteps or less, stick to the default type - short - as it leaves more space for future software improvements.

There is one more (small) fix - now when you disable and then enable again backlash compensation, by using the "*B" function, or by means of reading one of the five custom memory registers, the rail will automatically go through a full backlash loop (~0.5s), which is the correct behavior.

Software s1.10 (22.01.2016)

It requires hardware h1.2. As usual, you have to do the factory reset (keys #*) after upgrading the software.

This is likely the most significant single update I ever made to my rail's software. The rail gained a large number of functions (14 new key bindings), including new features like timelapse focus stacking. In a summary, the new version will make my rail much more usable for extreme macro photographers (magnifications 5:1 and up; should be usable up to 20:1), and for those who regularly use a wide range of macro lenses (from standard 1:1 macro to 20:1 extreme macro). The update also significantly improves the user interface, and dramatically reduces the need to recompile the code.

Here is a more detailed description:

  • New functions
    • By scrapping my old and not very useful function "*" (single-point stacking in a negative - not backlash compensated - direction), I was able to designate the key "*" to be an equivalent of "Alt" key in PCs (the way the other key - "#" - is already a kind of "Ctrl" key) - a basis of up to 15 new two-key bindings, all starting with "*".
    • They key * acquired a new meaning: if you press it by itself, it will bring up a new screen, displaying all the parameters which can be modified via new *X functions. Also, it displays the current software version in the bottom right corner. This allowed me to scrap the initial screen message (when the device is powered up), which in turn reduces the power-up initialization time: now it takes less than a second from the moment it is powered up to the moment when the rail is fully operational. (And even shorter if backlash compensation is disabled; see below.)
    • To compensate for the loss of the stacking ability in the reverse (background to foreground) direction, I introduced a new function - rail reverse (*1). Pressing "*1" will switch the rail in the reverse regime: background direction becomes foreground one and visa versa; also backlash compensation works in the opposite direction. This should be particularly useful when you have to face your camera in the opposite direction, because one of your macro lenses is much shorter or much longer than your other lenses.
    • In addition to the two memory registers the rail already had (registers 1 and 2 operated with #2/5 and #3/6 keys), I added three more memory registers. Use keys *2/5/8 to save to the new registers 3, 4, 5; use keys *3/6/9 to read from those registers. There are now many more user-adjustable parameters which are saved in memory registers. (The full list of parameters which are saved in registers can be found in the declaration of the structure regist in stacker.h.)
    • New function *A: change the acceleration factor used for rail rewinding (keys "1" and "A"). This was formerly done by modifying the macro parameter ACCEL_FACTOR in stacker.h, which required recompiling the code after each change. Now this parameter can be changed dynamically at runtime: by using the "*A" keys combo the current value of the parameter cycles through a user provided table. Currently the table has three values: 1, 3, and 6. Use "1" for low magnifications (1:1), "3" for intermediate magnifications (3...8:1), and "6" for extreme macro (10:1 and up). The benefit of the larger value of accel_factor at higher magnifications is that the positional accuracy (when using rewind keys 1/A) becomes better; also the rail vibrations after each rewind operation become smaller.
    • New function *B: turn on/off backlash compensation. ("On" by default.) Normally backlash compensation should be on, but sometimes (for example, when you are measuring the backlash compensation for your rail) you would want to turn it off.
    • New function *C ("on" be default). Turn it on when using the mirror lock feature on your camera during non-continuous two-point stacking. (As a result, the rail will press the camera shutter twice per frame - first one to raise the mirror, the second time to take the shot.) Turn it off if you don't use mirror lock on your camera during non-continuous two-point stacking. (Normally you should use the mirror lock feature, to reduce the camera vibrations.)
    • New function *D (debug; off by default): to temporarily disable limiting switches. Use it for those rare occasions (likely to happen only when updating the rail software) when the rail "gets lost" and drives into the physical limit, and cannot be brought back into the safe area using 1/A keys. In such situations set *D to "on", and then carefully use the keys 1/A to bring the rail into the safe area. This is one of the very few parameters which is not saved when the rail is powered cycled, and also not saved to memory registers.
    • New functions *4 and *7 are used to modify the values of the two parameters (N_timelapse and dt_timelapse) for the new stacking mode - timelaspe stacking. The default value for N_timelapse is "1", meaning no timelapse stacking. Once you make its value larger than "1" (by using the "*4" function), next time you start two-point stacking (either continuous, "0", or non-continuous, "#0"), the whole stacking sequence will be repeated more than once - specifically, N_timelapse number of times. The time interval (in seconds) between starting points of individual stacks is determined by the value of the second parameter, dt_timelapse (function "*7"). The possible values for these parameters can be (as usually) modified by editing the corresponding tables in stacker.h. The current values for N_timelapse are 1, 3, 10, 30, ..., 999, and for dt_timelapse - 1, 3, 10, ..., 9999 (in seconds). Timelapse mode can be paused at any time by pressing any key. If a pause happened during an active stacking, as usually one can use 1/A and #1/#A keys to navigate between different frame positions, and use #7 to manually take a shot. As usually, pressing the key "0" while paused will resume the operation - in this case resume the whole timelapse sequence. Or press #B while paused to completely abort the timelapse shooting. If a single stacking cycle is longer than the dt_timelapse parameter, all the N_timelapse stacks will still take place, one after another without a pause.
    • New function *0: can be used to turn on/off the save energy feature (formerly SAVE_ENERGY macro constant in stacker.h). When "on" (default), the motor driver goes to sleep when the rail is not moving - meaning the motor will have no holding torque. This is great for energy saving (especially when powered from AA batteries), but might result in a lack of positional accuracy at the level of a single full step (20 um in my rail) - not sure about this, still needs to be tested - which if true could be a problem when doing extreme macro (10:1 and up). Also, this would not work if the rail you are using requires a holding torque from the motor to stay still when not moving. (My rail - Velbon Super Mag Slider - doesn't require holding torque.) Click *0 to set save_energy to "off". You will hear a low volume whining sound from the motor - the sign that the holding torque is at work. Now the positional accuracy should get as good as it possible can.
  • Improvements for extreme macro (from 10:1 and up)
    • I discovered that my old version didn't work particularly well with the smallest steps (less than 50 um, especially less than 10 um). This was due to the fact that my table of possible values for the um/frame parameter uses mm, not microsteps, as the unit. As a result, some shots would be skipped when using very small values of um/frame. I fixed this issue by rounding off the values in the table to the nearest whole number of microsteps, for the steps smaller than 20 microsteps. In addition, I extended the table to the lowest possible value - 1 microstep (2.5 um). So now one can reliably use small steps - 2.5, 5, 7.5, 10 etc. um. This is critical for extreme macro - magnifications 10:1 an up. With the smallest 2.5 um step, my rail should now be totally usable for magnifications up to 20:1.
    • As described above, one can enable the holding torque (disable the energy save feature) by pressing "*0", which will likely (to be tested) improve positional accuracy of the rail at the scales <20 um.
  • Improvements when using a wide range of macro lenses
    • If you regularly need to switch from regular macro (1:1) lens to super (5:1) to extreme macro (10:1 an up) lenses, the new updated software should work much better for you. Now all the important rail parameters can be modified at runtime, without a need to recompile the code, and saved to one of the five available memory registers. (In addition, the rail always remembers the last used combination of parameters).
    • In particular, use the "*A" keys to set the accel_factor to lower values when doing smaller magnification, and higher values for extreme macro.
    • One can set the energy save parameter to off when doing extreme macro (this will likely improve the positional accuracy, but decrease the battery life), and on otherwise.
    • Set the rail direction accordingly (will depend on which way the camera is facing, which in turn depends on the length of your macro lens + the working distance for the lens), using "*1".
    • One can turn the backlash compensation off when doing low magnification work (*B) - simply for convenience (you do lose accuracy with the compensation off).
  • Other improvements and bug fixes
    • Significant improvements to the display. For example, invalid (negative or too large) parameters are no longer displayed (which would often break the screen in the past); instead, a rows of *'s are shown. This happens for example if you swap the order of the foreground and background points. As a consequence, I am now enforcing the largest possible number of shots in a stack to 10 thousand (9999 more specifically).
    • The Pause functionality has been extended to the new timelapse mode. At any time during a timelapse shooting one can press any key to put the operation on pause. If it happened during the wait between different stacks, or during the time when the rail moves to the starting position for the next stack, one can only use the keys #4 (change backlight), #7 (take s hot), #B (abort timelapse), or "0" (resume timelapse). All other keys will be ignored. If the pause takes place during an active stacking, in addition one can also use the keys #1/#A (rewind/fast forward one frame) and 1/A (rewind/fast forward 10 frames) if needed.
    • Added new feature, enabled by uncommenting the line "#define BL_DEBUG" in stacker.h. When enabled, the keys 2/3 are re-assigned to a new function - changing the value of the parameter BACKLASH_2 (in stacker.h). The current value is displayed at the end of the fifth line on the screen, in micrometers. This only needs to be done once, and only if your rail is not Velbon Super Mag Slider. You find the best value of BACKLASH_2 for your rail by pointing your camera with the largest magnification lens you have to a target. Using the live view on the camera, press the rail reverse keys (*1) repeatedly, and fine-tune the BACKLASH_2 parameter to the point when after each rail reverse the camera position is the same (after the backlash compensation loop). This is only relevant if backlash compensation is on. Once you found the optimal parameter value, convert it to mm (from um), and update the "#define BACKLASH_2_MM" line in stacker.h with the new value. The default value of BACKLASH_2_MM (0.259 mm) seems to be doing a good job for my Velbon Super Mag Slider, but I will fine tune it once I get my new Nikon 10x microscope objective.
    • Factory reset feature (#*) was significantly improved - in the past one would often need to do it twice after a software upgrade, but now it should work in one shot.
    • I had to significantly (by 15%) decrease the size of the binary code and the memory footprint (RAM size), otherwise I wouldn't be able to fit in all those new features. At this point, my code uses 90% of the FLASH space on Arduino Uno, and 72% of its RAM. (So there is still a bit of space left for new features.)
    • Some small bug fixes. (E.g., in the past the rail would not memorize its current coordinate if one turns the rail off right after running a rail calibration cycle.)
    • I deleted a lot of "dead code", corresponding to macro parameters DEBUG and LCD, which are obsolete at this point.

Hardware h1.2 and software s1.00 (07.01.2016)

It requires hardware h1.2.

This is my ultimate hardware mod - h1.2, and a new software version (s1.00) which makes use of the new hardware capabilities of h1.2. The main improvement is the ability to independently control from Arduino both camera's shutter and autofocus. This should make my macro rail usable for a wide range of camera makes. The hardware changes involved the following (compared to h1.1):

  • LCD reset pin (RST) disconnected from Arduino (pin 6); instead it is now hardware controlled via RC delay circuit (R=47k, C=0.1uF, connected to VCC=+3.3V).
  • Arduino pin 6 is now used to control the second relay (+ diod + R=33 Ohm), for camera autofocus.
  • As there would not be enough of wires in the Cat5/6 cable to add the output of the second relay, significant rearrangements were made:
    • The old relay (+ diode + 33R resistor) were moved from the controller unit to the motor unit's breadboard.
    • The second relay (+ diode + 33R resistor) were added to the motor unit's breadboard.
    • The mono 2.5mm phono socket in the motor unit was upgraded to stereo 3.5mm screw type phono socket.
    • In the Yongnuo shutter cable connecting the motor unit to the camera the 2.5 mm stereo jack was replaced with a 3.5mm stereo jack.
    • The assignment of some of the 8 wires of the Cat5/5 cable has changed: now wire #1 (white-orange) is directly connected to Arduino pin 3 (camera shutter); wire #2 (orange) is the common ground; wire #3 (white-green) is directly connected to Arduino pin 6 (camera AF); wire #6 (green) is directly connected to Arduino pin 8 (limiters). The motors' four wires (4, 5, 7, 8) stayed unchanged.

This is quite a bit of soldering when upgrading from h1.1, but not really much more work if building h1.2 from scratch.

Now that the new hardware allows to control both camera's shutter and AF independently, software had to be modified to make use of this functionality. In particular, the module camera.ino had to be rewritten from scratch.

Here is the list of new features and improvements in the software s1.00 (requires hardware h1.2):

  1. The default behaviour now is to have AF permanently on during continuous focus stacking (either one or two point), and go on and off with each shot during non-continuous stacking. (This is especially important when MIRROR_LOCK is defined: I discovered that my Canon 50D will not take multiple shots when the mirror lock is enabled and AF is permanently on.) For my Canon 50D camera, having AF permanently on during continuous stacking is beneficial, as it allows me to speed up focus stacking. In my tests, my camera can now reliably do 4 fps focus stacking for at least 30 frames when used with my macro rail. (Writing RAW files to a fast CF card - Lexar 1000x 32GB.) This could be critical when trying to shoot live insects, using 1-point continuous stacking.
  2. If the above default behaviour doesn't work for your camera, you can change the value of the new parameter (in stacker.h), AF_SYNC, from 0 to 1. This will make AF go on and off with the shutter for all modes, even for continuous stacking. This will likely reduce the maximum fps your camera can achieve.
  3. Two new delay parameters (constants in stacker.h): SHUTTER_ON_DELAY and SHUTTER_OFF_DELAY. The former is the minimum delay between triggering camera's AF on followed by the camera's shutter on; the latter is the minimum delay between releasing the camera's shutter followed by releasing the camera's AF. The presence of these delays ensures that the shutter is pressed only when AF is on, the way it is done in the camera, despite the two relays having different time-to-trigger parameters (and no two relays will have identical time-to-trigger parameter). Also some camera makes might need certain delays for proper operation. The default values for the delays (5ms each) seem to be a sensible choice, but you can increase them if your camera requires it.
  4. The old delay parameter STACKING_DELAY became CONT_STACKING_DELAY (in stacker.h) to emphasize that this is the initial delay (between AF on followed by the first shutter on) applicable only to continuous stacking modes. Increase its value if your camera skips the first shot in fast continuous stacking.
  5. As always, all the delays implemented in my software are dynamic (interruptable; not using the Arduino's delay functions). This results in a much more responsive behaviour. (Keys, limiters etc. work even during one of those delays.)
  6. The Pause feature was modified to properly take care of the new hardware feature (AF control).
  7. Same for #7 function (single shot): it now uses both AF and shutter, enforcing the two delays (SHUTTER_ON_DELAY and SHUTTER_OFF_DELAY).
  8. I fixed a bug: when paused while traveling from one frame position to the next one, the rail instantly rewinds to the last taken frame position, which makes much more sense than the old behaviour (just stopping wherever the pause took place).
  9. I put a limiter on the maximum value for the FPS parameter which depends on the current values of delay parameters in stacker.h - SHUTTER_TIME_US + SHUTTER_ON_DELAY + SHUTTER_OFF_DELAY.
  10. Small bugs fixed, some code rearrangement. Parameters are now grouped properly in stacker.h.

Software s0.14 (25.12.2015)

A minor update compared to the previous version (s0.12). Two changes:

  1. A separate (lower) speed limit, SPEED_LIMIT2_MM_S in stacker.h, was introduced. When power up, the controller senses if it is powered by AC or batteries (by using a simple critical voltage criteria: < 11.5V is considered to be battery operated). If it is AC operated, it uses the standard (high) limit - 5 mm/s in my code. If it is battery operated, it uses the slower speed limit - 2.5 mm/s in my code. This will help to improve torque (and eliminate steps skipping by the motor) when battery operated, in the field. If you want to disable this new feature, set the critical voltage parameter (SPEED_VOLTAGE in stacker.h) to a negative number (say, -1).
  2. A bug fix: factory reset was sometimes misbehaving (would drive the rail against the foreground physical limit, and then get stuck there). This was fixed by increasing the value of the parameter DELTA_LIMITER from 400 to 1000, in stacker.h.

Software s0.12

It requires hardware h1.1 (same as for s0.10).

Improvements and changes (compared to s0.10):

  1. I introduced a new mode: non-continuous stacking (only available for 2-point stacking; 1-point stacking can only be done using the continuous stacking mode). Unlike my old continuous stacking mode, in the new (non-continuous) mode the camera doesn't move when taking a shot. There are two new parameters - First_delay and Second_delay - which can be cycled through by pressing "#8" and "#9", respectively. (I had to sacrifice my memory Register 3 to gain these two key bindings.) Non-continuous stacking is initiated by pressing "#0" (the continuous one - by pressing "0"; both modes always start shooting from the foreground point, which eliminates the backlash). The camera moves to the foreground point, then stops and right away the shutter is triggered (this locks the mirror in the camera; the camera should have had the mirror lock enabled). Then it waits for First_delay ("#8") seconds - this lets the vibrations caused by the camera movement and the mirror moving decay, and then the camera shutter is triggered again - this time to initiate the shot. Finally, after Second_delay ("#9") seconds - should be larger than the exposure time - the camera starts moving again, to the next frame position. This mode minimizes rail vibrations caused by the moving rail and the camera mirror, and can be used when the best possible sharpness is required (though my tests show no improvement in sharpness - when using flash at 1/16 power as the light source), or when using a continuous source of light (not a flash). The drawback: this mode is substantially slower, and eats up your camera/rail battery faster.
  2. Related change - now key "#" has a function of its own: as long as it is pressed the fifth line in the LCD will show three numbers related to the non-continuous stacking: First_delay (seconds), Second_delay (seconds), and the estimated non-continuous stacking time (seconds; properly takes into account limited acceleration/deceleration of the rail movements). While pressing "#" one can also press "0" (making it a "#0" key binding) to initiate non-continuous focus stacking with the displayed parameters.
  3. The meaning of "#0" key binding changed: instead of 2-point continuous stacking (always starting from the foreground point) it now triggers 2-point non-continuous stacking, always from the foreground point (which is backlash compensated = accurate).
  4. The meaning of "0" also changed - instead of 2-point stacking from the nearest of the two points, it now starts continuous 2-point stacking always from the foreground point (backlash compensated).
  5. Introduced new macro parameter in stacker.h - MIRROR_LOCK (defined by default). Comment this definition out if you don't want to use the mirror lock feature on your camera when doing non-continuous stacking. (Though it makes much more sense to always use the mirror lock in non-continuous stacking, as the whole point of non-continuous stacking is to minimize camera vibrations while shooting, and mirror contributes a substantial part to the vibrations.)
  6. The "Pause" function (pressing any key while doing 2-point stacking) has been extended to include the new non-continuous stacking mode. Now pressing any key while doing non-continuous 2-point stacking will put the rail in the paused mode, with the same behaviour as the original paused mode - "#1"/"#A" will move the camera back/forward one frame without taking a shot, "1"/"A" will travel 10 frames back/forward, "#7" will take a shot, "#B" will abort stacking, and "0" will resume stacking from the currently displayed frame number. When using MIRROR_LOCK parameter (which is default), putting the rail in the pause mode when the mirror is locked will instantly trigger the camera shutter to unlock the mirror.
  7. As mentioned above, the meaning of "#8" and "#9" key bindings changed - instead of doing save/restore of all rail parameters to custom Register 3, now it cycles through the table of different values for two new non-continuous parameters - First_delay and Second_delay, respectively (seconds). The current tables for these parameters have the following values: 0.2, 0.5, 1, 2, 5, 10 seconds. One can always modify / extend /reduce the tables in stacker.h, by modifying constants FIRST_DELAY, SECOND_DELAY, and the corresponding table length parameters - N_FIRST_DELAY and N_SECOND_DELAY.
  8. I fixed the behaviour of the frame number displayed when in the paused mode - now it displays the number for the last taken frame. As the pause happens somewhere between the last taken shot and the next one, pressing "#1" now (properly) rewinds the rail to the exact position of the last frame, without changing the frame number displayed. Pressing "#1" one more time will rewind one frame back, reducing the frame number displayed. The proper procedure to recover from a problem (e.g. flash battery died) while stacking is to press any key (putting the rail into Paused mode), check your camera for the number of the first failed frame, then rewind the rail with "#1" until the first failed frame number is displayed, and then press "0" to resume stacking from the first failed frame.
  9. I found the line where one can change the contrast of the LCD display - line 234 in pcd8544.cpp, command(PCD8544_VOP | 0x47);. The default value (0x3F) resulted in low contrast on my display. I changed the value to 0x47 which resulted in a much better contrast. Your LCD might need a different value - play with this parameter until you are happy with the result.

Hardware h1.1 and software s0.10

This is a fairly minor hardware revision (a bit of re-soldering needs to be done, and only inside the controller unit; one additional 10 k resistor is required). Here are the changes, compared to h1.0:

  • Second row keypad pin (6) moved from Arduino pin 10 to 7.
  • Pin 10 left free (for hardware SPI).
  • Display's pin SCE (CE / chip select) disconnected from pin 7.
  • Instead, display SCE pin is soldered to the ground via ~10k (pulldown) resistor.

The reason for the above changes: I finally figured out how to enable hardware SPI connection between the Arduino and the Nokia 5110 LCD display (so far my design have been using the much slower software emulation SPI). I discovered that for this to work the Arduino's pin 10 needs to be freed up, and some small software modifications applied. I managed to gain one extra Arduino pin by using a pulldown resistor on the Nokia's SCE pin.

I already did the mod, and it seems to be working as expected. The hardware SPI resulted in ~10 times faster communication between Arduino and LCD, and that in turn resulted in more accurate (in fact, perfectly accurate) rail motions during stacking (the only time when my software updates both the motor and the display states).

And here is the list of major improvements and changes in the s0.10 software (requires hardware h1.1 to work), compared to s0.08.

  1. I did a major work with the software profiling - now the Arduino loop became substantially faster, which is critical for accurate rail motions. In particular, I optimized my own code, and also both the LCD and keypad libraries I am using. Because one now needs the custom versions of these libraries, I am providing them along with my code (so no need to install any libraries from now on). In particular, I enabled hardware SPI for 10x faster Arduino-LCD communications in the LCD library, and reduced data dimensions and disabled pin Arduino sharing in the keypad library.
  2. As a part of my profiling I discovered that even with the optimized code my software skips microsteps occasionally (around 0-3 microsteps skipped per 10,000 microsteps travelled), because some Arduino loops are substantially longer than average. This is very minor, but my new software has a module to completely eliminate all step skipping, so from now on the program coordinates always match the physical (rail) coordinates. (This is controlled by the macro parameter PRECISE_STEPPING in stacker.h; it is enabled by default.) Also the next improvement is critical for this.
  3. I fully implemented backlash compensation in my software (constant BACKLASH_MM in stacker.h; set it to 0 to disable backlash compensation). From my measurements, the full backlash of my rail is 0.2mm, and from now on it is going to be fully compensated: every time rail comes to a stop, the required compensation will have been made. This applies to all rail motions - go_to operations, rewinding, stacking etc. This guarantees that the program coordinates always match the physical ones, at least for the situation when it is at rest or is moving in the "good" direction (which is from foreground to background in my software). The only problematic function in this regard is doing 2-point stacking in the "bad" (towards foreground) direction, where backlash is not compensated, so coordinates will not be accurate. Because of this I introduced a new keypad shortcut, "#0" (see below), which always starts 2-point stacking from the foreground point.
  4. As part of my backlash compensation package, I introduced a new module (macro parameter EXTENDED_REWIND in stacker.h; enabled by default). This module makes the rewind function (key "1") emulate the fast-forward key, "A", with full backlash compensation. Specifically, if you say press "A" key for 0.1s, the rail will travel (in the good direction) say 20 um. Now if you press the rewind key "1" for the same time 0.1s, the rail will do a full backlash compensation, and at the end will be 20 um behind. So the same amount of pressing on "1" results in the same amount of traveling as with "A"; the only difference is that after you release "1" it takes longer for the rail to come to a complete stop. This function is very useful when you want to have both high accuracy (full backlash compensation) and convenience when using 1/A keys.
  5. Now I have a fully-functioning "pause" feature. Before, if you pressed any key while stacking was in progress, it would abort the stacking, which wasn't ideal. Now (only for 2-point stacking) pressing any key will place the rail in the special "paused" mode, with most keys disabled, and some changing their meaning. In particular, "#1" and "#A" will now move the rail precisely to the next frame in the fore/background directions (without taking a shot), and "1" and "A" will do the same with larger steps of 10 frames. "#4" and "#7" will still work as usual. Pressing "0" at any time will resume stacking from the current frame, while pressing "#B" will abort the stacking. This should significantly improve handling problems during lengthy stacking, such as dead flash/camera battery or overheated flash. If something like this happens, you just have to press any key to place the rail into the "paused" mode, change the batteries or let the flash cool down, check the camera to see how many frames were wasted (black), then use "#1"/"#A" or "1"/"A" keys to go back to the position of the first failed shot, and then press "0" to resume stacking.
  6. New convenient function added, linked to the keys "#D". This will move the rail back to the starting point of your last stacking (not memorized in EEPROM). Should be convenient for 1-point stacking: you just need to press "#D" to go to the starting point, if you want to redo stacking. Also convenient for 2-point stacking, if you always want to start stacking from the same point (either fore or background). The default behavior (when pressing "0") is to start stacking from the nearest of the two points. Should be used for critical work when you need to precisely reproduce your stacking sequence.
  7. Another new function: "#0". Initiates 2-point stacking (the rail can be anywhere when you press it), but unlike function "0" it always starts from the foreground point, and moves towards the background point when stacking. This direction is "good" in terms of backlash compensation. Use this function to do 2-point stacking when the most accurate and reproducible results are required.
  8. I draw and programmed some nice bitmaps for the display - different levels of the battery charge, and the direction of motion. Before I used two chars of standard ASCII.
  9. Now the software has the ability to have a slower "ramp" (acceleration) when initiating rewind/fast forward (keys "1"/"A"); all other movements will still be done at the maximum acceleration/deceleration level, ACCEL_LIMIT. This should make it easier to fine tune the rail position when setting up the foreground and/or background points for stacking, but still retaining the ability to go to the maximum possible speed fairly quickly (with just a bit more of a delay). Modify the new constant ACCEL_FACTOR in stacker.h to change the ratio between the fast and slow acceleration values (the default ratio is 4).

Minor improvements and bug fixes:

  • Fixed a small dx bug in go_to()
  • Small code re-arrangements to reduce Arduino loop duration when a starting to move.
  • Change to the displayed frame counter: now it includes 0.
  • Another frame counter issue fixed: now when aborting stacking, it reverts to "0".
  • Some of my recent changes (most likely borrowing the two Arduino pins from LCD control) resulted in the intermediate brightness backlighting crashing the LCD. I fixed that by making my backlighting control to only use two levels - no backlighting, and full backlighting.
  • Fixed a small bug: backlighting level wasn't memorized when the device is turned off.
  • Some cosmetic code re-arrangement and cleanup.

Heads up

In the near future I will remove the old function "*" (single-point stacking in the bad - non backlash compensated - negative direction), and will be able to add up to 15 new two-key functions, starting with the key "*". (So "*" will be sort of "Alt" key in a computer, whereas "#" is sort of "Ctrl" key.) I am contemplating which new functions to add. The obvious thing to do is to make many fixed parameters in stacker.h adjustable at runtime. (Right now you have to recompile and reupload the software every time you change one of those parameters.) For example, parameters like MIRROR_LOCK, AF_SYNC, BACKLASH (on or off), SAVE_ENERGY, ACCEL_FACTOR, MOTOR_DEBUG. Also one can have the ability to switch between different cameras - convenient if you have more than one camera.