Using runnable to implement laser power ramp over z-stack

I’m trying to set up a runnable to ramp up the laser power over the course of a z-stack, the following executes and the contents of the runnable works if executed from the script panel outside of a runnable but the runnable itself doesn’t seem to work. Does anyone have any suggestions as to where I’m going wrong?

import org.micromanager.data.Coords;
import org.micromanager.data.Datastore;
import org.micromanager.display.DisplayWindow;

acq = mm.acquisitions();
acq.clearRunnables();

runnable = new Runnable() {
public void run() {
display = mm.getDisplayManager();
window = display.getCurrentWindow();
datastore = window.getDatastore();
coords = datastore.getMaxIndices();
Z = coords.getZSlice();
mmc.setProperty(“Lasers”,“Intensity-4-514/532nm”,10+Z);
}
};

acq.attachRunnable(-1,-1,-1,-1,runnable);

The first time this runs there will be no window (or at least not the one you want) so there will likely be a null pointer exception, and the thread on which this is executed will die.

Maybe a bit crazy, but can you create a runnable for each z-slice (in a loop), and attach each to the correct plane using the attachRunnable call?

Debugging Beanshell scripts is always hard. Putting in output to the script panel (using
mm.scripter().message("here we are");
can come in handy.

@pavak_shah if you can’t get this to work and you’re okay with switching from beanshell to python, you should be able to get this working relatively easily in with pycro-manager using acquisition hooks

Thanks @nicost, the per-slice runnables work but I was hoping for something easier to change on the fly.

@henrypinkard I would love to be able to migrate to pycromanager, but this is part of a franken-experiment where I’m tying together micro-manager for scope control, a MATLAB image analysis app, a Java GUI that displays the image analysis results and provides a UI for curating the results, and hooks to an external .NET app (ROE Syscon) for controlling an ablation laser. It’s a miracle that this works at all!

Hi @pavak_shah, you can generate the runnables programmatically (i.e. in a loop that includes the attachRunnable call), and then should give you the exact same control you have in your current code.

Henry’s acquisition engine is the future, and should give you more and easier control (disclaimer, I have never used it yet, but fully trust @henrypinkard ;). Hopefully someone can find the time to integrate it in MM so that we can start testing whether it fully replaces all use cases of the current engine.

Do you happen to have a simple example showing how to generate the runnables programmatically? I’m having a hard time imaging how that would work… wouldn’t I need to pass an external variable into each runnable to define the right laser power to set?

Try this (turned out to be a bit tricky, the “slice” variable needs to be read outside of the “run” method, or it will always be set to 10):

acq = mm.acquisitions();
acq.clearRunnables();

double zStart = -5.0;
double zStep = 1.0;

for (int slice = 0; slice < 10; slice++) {
  runnable = new Runnable() {
    final int s = slice;
    public void run() {
    	double currentZ = zStart + (s * zStep);
    	mm.scripter().message("Z is now: " + currentZ);
    }
  };
  acq.attachRunnable(-1,-1,-1,slice,runnable);
}

mm.scripter().message("Attached...");

Yikes! I don’t envy that. Good luck!