gardner-lab / printimage

1 stars 1 forks source link

Requirements

Installation

Calibration

Size Calibration is done through parameters in ScanImage's Machine_Data_File.m, not through PrintImage. This is because we figure you'll want your microscope calibrated properly whether or not you're printing anything today.

I will refer to the axis over which the resonant scanner scans as X. The galvo scans over Y. The "fast Z" stage, perpendicular to the focal plane, is (surprise!) Z.

Unsurprisingly, you will want to set zoom to 1, using either ScanImage's interface or hSI.hRoiManager.scanZoomFactor = 1

For X and Y, three parameters affect two degrees of freedom. I think there's a correct way to do this, but I'll describe the kludge.

X and Y (field of view)

Background

ScanImage mainains its idea of the lens's field of view in a variable called hSI.hRoiManager.imagingFovUm. This is a matrix giving the corner positions of the FOV. I've assumed that this is square and centered around 0, so if it's not, my code will be buggy! But here's one way to read ScanImage's idea of the FOV in X and Y:

    fov = hSI.hRoiManager.imagingFovUm
    [fov(3,1) - fov(1,1)      fov(3,2) - fov(1,2)]

Parameters in Machine_Data_File.m

Setting the values

You'll need a way to measure the actual FOV. This can be done by imaging something of known size, or by printing something and then measuring it on a calibrated device. For this purpose we have calibration rulers. FIXME Add links to our calibration rulers and the paper's instructions.

This accomplished, compute your error in X and Y, and just multiply some combination of those numbers to scale the image. It is likely that the numbers have nominal values (e.g. for our hardware, in theory galvoVoltsPerOpticalDegreeY = 1), so maybe try not to stray too far from those values, or keep one of them at the nominal value or something. We've found that one iteration of this procedure can get us to within 1% or so.

Scan phase

If the size of objects appears different on the left vs. right sides of the display (e.g. if you print or image a grid, and scrolling left-right changes the apparent grid size), you may need to adjust the scan phase. It's hSI.hScan2D.linePhase, available in the "Scan Phase" box in ScanImage's CONFIGURATION window. I haven't had much luck with "Auto Adjust".

Note that since this is not available in Machine_Data_File.m, I set it by hand in printimage.m. This will be moved to a printimage config file soon... For now, change the value until it looks right, and then modify hSI.hScan2D.linePhase in printimage.m.

Z scale (adjusting the FastZ actuator)

Background

ScanImage allows you to specify certain known models of FastZ stage. From Machine_Data_File.m:

    actuators(1).controllerType = 'thorlabs.pfm450';           % If supplied, one of {'pi.e665', 'pi.e816', 'npoint.lc40x', 'analog'}.

We have a ThorLabs pfm450, which ScanImage should know how to talk to. However, ours was not moving quite as far as ScanImage expected. In order to correct that, I modified some variables.

Also, note that it is essential to run at least our FastZ controller in closed-loop mode!

Measuring the error

The procedure is generally the same as for X and Y: either print something of ostensible size and measure it, or image something of known size. For this we provide a vertical pyramid ruler. FIXME Link to it!

Setting the values

If you need to adjust the scaling, you must not tell ScanImage what kind of FastZ controller you have, so it will actually use your adjusted values rather than its own. Just tell it you're using an analog controller:

    actuators(1).controllerType = 'analog';          % If supplied, one of {'thorlabs.pfm450', 'pi.e665', 'pi.e816', 'npoint.lc40x', 'analog'}.

Now, adjust the VoltsPerMicron values according to your measurements:

    actuators(1).commandVoltsPerMicron = (10/450)/1.1;    % Conversion factor for desired command position in um to output voltage

The maximum voltage is 10 (specified in the manual, transcribed to actuators(1).maxCommandVolts; likewise the 450 and other constants (see below).

The "/1.1" is the important part--it compensates for the 10% error that we measured.

    actuators(1).commandVoltsOffset = [];        % Offset in volts for desired command position in um to output voltage
    actuators(1).sensorVoltsPerMicron = (10/450)/1.1;     % Conversion factor from sensor signal voltage to actuator position in um. Leave empty for automatic calibration

Same thing here--the sensor was off by the same amount. That led us to double-check our measurements (looks like two independent (?) systems were in agreement), but the printed parts really were the wrong size, measured on an SEM and via our slow Z stage (Sutter MOM, which is notoriously inaccurate but which in this case agreed with the SEM, as well as with itself at different locations in its range). So that can happen, I guess. Photoresist shrinkage? Anyway, our parts are the right size now.

    actuators(1).sensorVoltsOffset = -0.12;        % Sensor signal voltage offset. Leave empty for automatic calibration
    actuators(1).maxCommandVolts = 10;          % Maximum allowable voltage command
    actuators(1).maxCommandPosn = 450;           % Maximum allowable position command in microns
    actuators(1).minCommandVolts = 0;          % Minimum allowable voltage command
    actuators(1).minCommandPosn = 0;           % Minimum allowable position command in microns

Leveling (with a hexapod)

Background:

Desiderata:

Now imagine that your printable medium is a piece of something (e.g. an electrode in need of a cuff) loosely taped onto a slide. It may not be parallel to, well, anything. First step is to tilt the medium into alignment with the optical plane. Second step is to align the movement coordinate system.

Tilting

Start a "focus", and add a bullseye. Focus on the substrate, and then bring the lens up just far enough to see a hint of fluorescence beginning to show. Use the hexapod's angle controls to put that hint of fluorescence in the middle of the FOV (using the bullseye). It will probably be necessary to tilt the object and then re-focus on the hint-of-fluorescence, tilt some more, re-focus again, etc.

Leveling

Again focus on the substrate and then bring the lens up just far enough to see a hint of fluorescence, as above. Run a "brightness test" and look at the results (FIXME falloff_slide.m right now, but that's not ready for primetime). The goal will be to set the leveling coordinate system so that the (possibly tilted, but optically aligned) substrate moves along the optical XY plane. This is controlled by STL.motors.hex.leveling = [ X Y Z U V W ]; Set it in printimage_config.m, and adjust as needed. For example, on our printer:

My favourite workflow: edit the values in printimage_config.m, copy and paste the definition into the MATLAB commandline, and run hexapod_set_leveling(), which will store the values in the hexapod. Run another brightness test and repeat until the brightness traces don't change too much over XY movement (I can usually get them down to about 10% variation, depending on how close I am to the substrate).

The sixth value of STL.motors.hex.leveling controls the alignment of stitched parts. Print something stitched and adjust W in order to align the hexapod's XY motion with the resonant-galvo axis.

Saving the tilt

One more parameter should be saved in printimage_config.m: STL.motors.hex.slide_level = [ 0 0 0 0.255 -0.09 0 ]; These numbers are the tilt offsets from the tilt calibration process, above, but they must be read after the leveling coordinate system is correctly defined and tuned.

Vignetting compensation

Background

This began as an effort to model the falloff due to optical vignetting. The theoretical model of cos(theta)^4 seemed to fit pretty well, but couldn't be justified for a near-field laser (i.e. working less than a few kilometres from the laser source). And then I reasoned that since all models are wrong, it might be better to do something free-form. Hence the adaptive power compensation.

THINGS I NEED TO FIX

How?

Zero: Set your desired print zoom level...? Still working on this.

First, focus within the IP-Dip (yielding a fluorescent image that appears approximately Gaussian). Use Calibrate / Save baseline image to save the default brightness at the camera.

Second, find the substrate: follow the instructions regarding "Finding 0" in "Printing" (below in this document), and use the Calibrate / Calibrate vignetting compensation menu item to begin. This will:

To start from scratch, use the Calibrate / Clear vignetting compensation menu item. You may then start again. Feel free to add your own calibration procedure! They're applied in printimage_modify_beam.m.

Printing

Preparing the sample

Interacting with the substrate

The working distance of the lens is important, as you do not want the lens to touch anything solid! Our lens has a 380-um working distance, which has the following implications:

Finding 0 (where the substrate meets the IP-Dip)

Printing in a specific location (e.g. on a nonuniform object attached to the substrate)

Power calibration

PrintImage's "Power Test" button will print a bunch of rectangular prisms at various power settings, which can be seen in ScanImage's "Power Box Settings" window, available through the "POWER CONTROLS" window.

Understage zeroing

Aligning a rotation stage with the microscope stage

Print something (e.g. a power test pattern). Use the rotation slider to rotate the stage, and see if it rotates about the centre of the screen (the "bullseye" can be used to facilitate this). Move the microscope stage toward what looks like the centre of rotation. Repeat until the image rotates about the centre of the field. This is the alignment point. You may add "STL.motors.mom.understage_centre = [12655 10857 16890];" to your printimage_config, reading those numbers off the microscope stage's location (microns).

Leveling a hexapod

Find the substrate, and then pull the lens just a little bit away from it so you can just see some light in the image centre. Scroll up and down on Y while adjusting the hexapod's X rotation control such that scrolling on Y doesn't affect the spot's brightness (closeness to substrate). Vice versa for X-Y.

For Z, print something that involves stitching, such as a linearity test. Scrolling back and forth with the microscope's stage should produce motion parallel with the line of dots that the stitching procedure produced.

The final numbers can be added to printimage_config; e.g., "STL.motors.hex.leveling = [0 0 0 0.9 -0.1 -1.1];"

Controlling print dimensions

Controlling print resolution

X and Y resolutions are functions of various things (position on the X axis, zoom level, hardware...), and you have limited control over them. Z is easiest.

Controlling print size

Because STL files are dimensionless, you have to choose the size of the object.

Stitching

If the object to be printed exceeds any of the dimensions allowed by your hardware, PrintImage will break it into parts and print them in sequence using your XYZ stage.

After printing

Inspecting the print

Resetting the Z position

Developing the print