Focus stacking with IMX477 motorized focus on Raspberry Pi without reloading libcamera each shot

Hi everyone, I’m trying to do focus stacking with an IMX477 Motorized Focus camera connected to a Raspberry Pi. The goal is simple: move the lens to a focus position, take a picture, move to the next focus position, take another picture, and repeat. Has anyone managed to get this working smoothly?

Could you share how you’re currently driving the lens? Are you using libcamera-still with the --lens-position flag for each shot?

Yes, right now I’m using libcamera-still with --lens-position for every frame. The issue is it’s really slow. Each time the process runs, the lens drives all the way back to its home position and libcamera reloads all its programs. So every capture takes way too long.

That’s expected behavior with repeated libcamera-still invocations. Each process starts fresh, so the camera gets reinitialized and the lens parks at home before moving to your requested position. That round trip is what you’re seeing.

I’d really like to keep the lens moving forward and just snap pictures without returning home or reloading libcamera each time. I know there are keyboard controls in libcamera: ‘a’ increases the lens position and ‘d’ decreases it, with a minimum step of 1. I tried to find the code that handles those a/d key presses so I could change the step to 0.5 and add a capture once the position is reached, then keep moving 0.5, take another, and repeat. But I can’t find that code anywhere.

That a/d step is hardcoded in the source, so to change the increment from 1 to 0.5 you’d need to modify the source code. Specifically, it’s defined in rpicam_still.cpp in the ArduCAM fork of libcamera-apps, around lines 215 (L215C3-L215C20): libcamera-apps/apps/rpicam_still.cpp at arducam · ArduCAM/libcamera-apps · GitHub

Thanks, but I can’t find rpicam_still.cpp on the Pi at all. Is that file actually stored somewhere on the device, or does it just get compiled into the binary? I searched the whole filesystem and came up empty.

It’s not on the Pi by default. The installed libcamera-still binary is pre-compiled, so the .cpp source isn’t shipped alongside it. You’ll need to download the libcamera-apps source project (the ArduCAM fork), make your changes, and compile it yourself.

Got it, I’ll look into building from source. While I’m at it, there’s another problem: I want to take a series of pictures at different focal lengths. My current method is move the camera to a position with --lens-position, capture, then run the command again. After every picture the lens slams back to home and then forward again, which makes a big clunking noise. Is there any way to tell the VCM motor to hold its position and not go back home between photos?

Unfortunately not. The VCM (voice coil motor) can’t hold its position across power cycles. Every time the camera loses power, the focusing motor resets to the home position. So there’s no way to instruct it to stay parked at a specific position between separate captures.

That’s a shame. Do you know how many grams of lens the VCM can actually move? Is there a datasheet available for the VCM?

There’s no datasheet available for the VCM, so I can’t give you the exact load or travel specs.

Update: I gave up on libcamera for this workflow — it just isn’t practical for focus stacking. I got exactly what I wanted using the Picamera2 Python library instead. I run a loop that directs the lens to a position, reads the lens metadata to know when the lens has actually reached that position, captures the image file, then moves on to the next position and repeats. I can grab over 20 images at different focus positions in under a few seconds.

That sounds like a solid approach — reading the lens metadata to confirm the position before capture is the key part. Could you share a bit more detail on the setup for anyone else trying this?

Sure. You need the correct config file, and Picamera2 needs to point to a tuning file for the IMX477 — the support team sent me that tuning file link via private message. I also control the AD5398 directly from Python using i2cset, and I use the standard IMX477 driver so the I2C address 0x0c is freed up.

That’s a really useful breakdown, thanks. To recap for anyone landing here: libcamera-still isn’t great for focus stacking because each run reinitializes and returns the lens home, and the VCM can’t hold position across power cycles. The working route is Picamera2 with a capture loop that checks lens metadata before each shot, plus the correct config and tuning file, and optionally driving the AD5398 directly via i2cset while the standard IMX477 driver frees up 0x0c.