StepScan PowerScript Code
PowerScript
This code run StepScan in SmartScan
main
0 files
StepScan PowerScript Code..js
StepScan PowerScript Code..js
14461 bytes
var $ = {
"flag" : {
"useCantileverFromStepScanParam" : false,
"isNeedNCMSweep" : true
},
"msg" : {
"moveXY" : __tr("stepScan_run", "Prepare / Moving XY stage to (%1, %2)"),
"repeat" : __tr("stepScan_run", "[ Repeat #%1 (of total %2) ]"),
"ncmStart" : __tr("stepScan_run", "Prepare / ncm sweep started"),
"ncmError" : __tr("stepScan_run", "Prepare / ncm sweep result is not good, change cantilever"),
"parkingError" : __tr("stepScan_run", "Prepare / parking cantilever was unsuccessful"),
"ncmDone" : __tr("stepScan_run", "Prepare / ncm sweep done, peak = %1 kHz"),
"done" :__tr("stepScan_run", "Done"),
"error" : __tr("stepScan_run", "Error occured : %1")
},
"init" : function() {
// parameter validation
if (!__methods || !__recipe)
throw "variable was not set";
app.setErrorStatusVisible(false);
app.msg.category = "__autoScan__";
app.msg.sendCmd("reset+show");
},
"finalize" : function() {
app.msg.sendProgress(this.msg.done, 100, 10 * 1000);
app.msg.sendCmd("hide.later");
},
"startApproach" : function(postWait) {
var type = "q+s";
var args = {
"isFastApproachEnabled" : false
};
app.msg.sendProgress('Approach / start');
spm.approach.start(type, args);
spm.sleep(postWait);
app.msg.sendProgress('Approach / done'); // + setpoint and Z Scanner Pos.
},
"tryNcmSweep" : function(params) {
if (!spm.head.isNonContactType)
return;
this.flag.isNeedNCMSweep = false;
var amplitudeFromParam = params.basicParams.params.zservo.setpoint.amplitude;
var amplitudeRatio = params.basicParams.params.zservo.setpoint.amplitudeRatio;
var useSetpointPreset = params.basicParams.params.zservo.setpoint.useSetpointPreset;
var useAmplitudeRatio = params.basicParams.params.zservo.setpoint.useAmplitudeRatio;
var drive = 10.0;
var startHz = spm.cantilever.resonanceRange.start * 1000;
var endHz = spm.cantilever.resonanceRange.end * 1000;
var amplitude = amplitudeFromParam;
app.msg.sendProgress(this.msg.ncmStart, 30, 30 * 1000);
spm.ncm.sweepAuto(amplitude, startHz, endHz, drive);
var peakHz = spm.ncm.sweepResult.peakFreq;
var peakKHz = (peakHz / 1000.0).toFixed(1);
if (peakHz < startHz || peakHz >= endHz)
throw this.msg.ncmError;
// if (useSetpointPreset)
// spm.zservo.setpoint.normValue = params.basicParams.params.zservo.setpoint.normValue;
if (useAmplitudeRatio) {
var tryNumber = 0;
var tryMaximumNumber = 30;
while (spm.ncm.isRunning && (tryNumber < tryMaximumNumber)) {
tryNumber = tryNumber + 1;
spm.sleep(1000);
}
app.msg.sendProgress("Prepare / applied amplitude ratio to setpoint");
spm.sleep(500);
spm.zservo.setpoint.value = amplitudeFromParam * amplitudeRatio / 100;
}
app.msg.sendProgress(__arg(this.msg.ncmDone, peakKHz));
app.msg.sendProgress(__arg("Prepare / Setpoint: %1 nm", spm.zservo.setpoint.value));
},
"getQRInfoOnProbehand" : function() {
var qrType = spm.fx.probeExchanger.fetchDefaultProbeTypeOnProbehand();
var isEdited = spm.fx.probeExchanger.isEditedProbeTypeOnProbehand();
var isNullQR = qrType === "Non_QR" || qrType === "Not_Classified";
return [isNullQR, isEdited];
},
"tryExchangeProbe" : function(method) {
if (!spm.capability.supportsProbeExchanger){
this.flag.useCantileverFromStepScanParam = true;
return false;
}
var params = method.params;
if (!params.basicParams.params.probe.use) {
this.flag.useCantileverFromStepScanParam= true;
return false;
}
if (spm.fx.probeExchanger.probehandIndex === params.basicParams.params.probe.index) {
var result = this.getQRInfoOnProbehand();
var isNullQR = result[0]; isEdited = result[1]
if (!isNullQR){
var qrName = spm.fx.probeExchanger.fetchDefaultProbeTypeOnProbehand();
spm.cantilever.changeTo(qrName)
} else {
if (isEdited) {
var EditedName = spm.fx.probeExchanger.fetchEditedProbeTypeOnProbehand();
spm.cantilever.changeTo(EditedName)
} else {
this.flag.useCantileverFromStepScanParam = true;
}
}
return false;
}
if (!spm.fx.probeExchanger.isProbehandEmpty) {
app.msg.sendProgress("Prepare / Parking into cantilever")
var isParking = spm.fx.probeExchanger.putback(); // Validation: Always return value is false
// TODO: Need Revision SmartScan
// if (!isParking) {
// throw this.msg.parkingError
// }
}
app.msg.sendProgress("Prepare / Picking up cantilever")
spm.fx.probeExchanger.pickupAt(params.basicParams.params.probe.index, false);
result = this.getQRInfoOnProbehand();
isNullQR = result[0]; isEdited = result[1];
if (isNullQR && !isEdited) {
this.flag.useCantileverFromStepScanParam = true;
}
spm.fx.analyzer.autoAlign();
return true;
},
"tryChangeHeadMode" : function(next) {
var current = __kernel__.findHeadModeId(spm.head.modeName)
if (current !== next) {
try {
spm.head.setMode(next);
// wait time is not precise
spm.sleep(200);
app.msg.sendProgress('Prepare / Changing head mode: '+ next);
} catch (e) {
// intended catch
}
}
},
"applyParametersAfterApproach" : function(method, env) {
var params = method.params;
var headMode = method.headMode;
if (spm.head.isEfm) {
spm.kpfm.config = params.basicParams.params.biasPage.kpfm;
app.msg.sendProgress("applied EFM parameter after approach");
spm.sleep(1000);
}
},
"applyParameters" : function(method, env) {
var params = method.params;
var headMode = method.headMode;
if (typeof method !== "object" || typeof params !== "object")
throw "internal error, method is invalid";
// change headmode
this.tryChangeHeadMode(headMode);
if (this.flag.useCantileverFromStepScanParam && (spm.cantilever.name !== params.basicParams.params.cantileverName)){
spm.cantilever.changeTo(params.basicParams.params.cantileverName);
app.msg.sendProgress("Cantilever changed to " + params.basicParams.params.cantileverName);
this.flag.useCantileverFromStepScanParam = false
}
if (method.scanType === "adaptive") {
if (!spm.head.isNonContactType) {
app.alert("Cannot enable adaptive scan other than NCM mode");
throw "error";
}
}
if (!spm.head.isNonContactType && params.basicParams.params.zservo.setpoint.useSetpointPreset) {
spm.zservo.setpoint.normValue = params.basicParams.params.zservo.setpoint.normValue;
spm.zservo.setpoint.useSetpointPreset = params.basicParams.params.zservo.setpoint.useSetpointPreset;
}
if (spm.head.isNonContactType) {
if (this.flag.isNeedNCMSweep) {
this.tryNcmSweep(params);
} else {
app.msg.sendProgress("Prepare / skipping ncm sweep", 50, 10 * 1000);
}
if (params.basicParams.params.zservo.setpoint.useAmplitudeRatio) {
spm.zservo.setpoint.value = spm.ncm.sweepResult["peakAmp"] * params.basicParams.params.zservo.setpoint.amplitudeRatio / 100;
}
if (!params.basicParams.params.zservo.setpoint.useAmplitudeRatio) {
spm.zservo.setpoint.value = spm.ncm.sweepResult["peakAmp"] * 0.74;
}
}
spm.zservo.gain = params.basicParams.params.zservo.gain;
// spm.bias.tip = params.basicParams.params.biasPage.tipBias;
// spm.bias.sample = params.basicParams.params.biasPage.sampleBias;
spm.bias.setBiasConfig(params.basicParams.params.biasPage);
spm.scan.rate = params.basicParams.params.rate;
spm.scan.quickStep = params.scanTypeParams.quickStep;
spm.scan.adaptiveLinewise = params.scanTypeParams.adaptive;
spm.scan.type = method.scanType;
spm.scan.options = params.optionParams.scanParamOptions;
spm.scan.channels.all = params.basicParams.params.channels;
spm.scan.setScanGeometry(params.basicParams.params.geometry);
spm.scan.liftMode = params.basicParams.params.liftMode;
if (spm.head.isEfm) {
var kpfmConfig = spm.kpfm.config;
if (kpfmConfig.isServoOn)
kpfmConfig.isServoOn = false;
spm.kpfm.config = kpfmConfig;
app.msg.sendProgress("Prepare / tip bias servo off before approach");
spm.sleep(1000);
spm.lockin2.detector.config = params.basicParams.params.lockinAmp.detector2;
spm.sleep(200);
spm.lockin2.modulator.config = params.basicParams.params.lockinAmp.modulator2;
spm.sleep(200);
spm.lockin3.detector.config = params.basicParams.params.lockinAmp.detector3;
spm.sleep(200);
spm.lockin3.modulator.config = params.basicParams.params.lockinAmp.modulator3;
spm.sleep(200);
}
if (spm.head.isCurrentAmpRelated) {
spm.currentamp.config = params.basicParams.params.currentAmp;
spm.sleep(200);
}
},
"preparePoint" : function(lift) {
try {
spm.scan.stop();
app.msg.sendProgress(__arg("Prepare / Lifting Z stage %1 um",lift));
spm.zstage.move(lift, 1.0);
} catch (e) {
}
},
"run" : function() {
var env = __recipe.env;
var items = __recipe.items;
var itemCount = items.length;
var repeatCount = env.repeatCount;
var totalIteration = repeatCount * itemCount;
if (env.ncmSweep === "none") {
this.flag.isNeedNCMSweep = true // specified for safety reasons.
}
for (var repeat = 0; repeat < repeatCount; repeat += 1)
{
if (repeatCount > 1) {
app.msg.textPrefix = "";
app.msg.sendProgress(__arg(this.msg.repeat, (repeat + 1), repeatCount));
}
app.msg.textPrefix = __arg("%1-- : ", repeat + 1);
if (env.ncmSweep === "perRepeat" && !__isTestRun) {
var firstMethodName = items[0].method;
var firstMethod = __methods[firstMethodName];
var params = firstMethod.params;
if (typeof firstMethod !== "object" || typeof params !== "object")
throw "internal error, method is invalid";
this.flag.isNeedNCMSweep = true;
}
for (var i = 0; i < itemCount; i += 1)
{
var pos = items[i].pos;
var methodName = items[i].method;
var method = __methods[methodName];
if (typeof pos == "undefined" ||
typeof methodName == "undefined" ||
typeof method == "undefined")
continue;
app.msg.sendCmd("reset+show");
var exchanged = this.tryExchangeProbe(method);
// preparing
app.msg.textPrefix = __arg("[ Repeat(%1/%2) Recipe(%3/%4: %5) ]: ",repeat+1, repeatCount, i + 1, itemCount, methodName);
this.preparePoint(env.liftHeight);
// xy positioning
app.msg.sendProgress(__arg(this.msg.moveXY, pos.x, pos.y), 50, 10 * 1000);
spm.xystage.moveTo(pos.x, pos.y, 0.8, 0.8);
if ((env.ncmSweep === "perPoint" && !__isTestRun) || exchanged)
this.flag.isNeedNCMSweep = true;
// set parameters and approach with ncm sweep when needed
this.applyParameters(method, env);
var context = {
"reason" : "batch.stepScan",
"params" : {
"x" : pos.x,
"y" : pos.y,
"method" : methodName,
"note" : items[i].note,
"repeatIndex" : repeat,
"repeatCount" : repeatCount
}
};
if (__isTestRun) {
app.msg.sendProgress("(test run / skipping approach)");
app.msg.sendProgress("(test run / waiting a little instead of imaging)");
spm.sleep(5000);
} else {
this.startApproach(env.postApproachWait);
this.applyParametersAfterApproach(method, env);
spm.scan.context = context;
app.msg.sendProgress("Scan / start");
spm.scan.startImageScan();
app.msg.sendProgress("Scan / done"); // + time information
}
app.msg.textPrefix = "";
var ProgressPercent = 100 * (repeat * itemCount + i + 1) / totalIteration
app.msg.sendProgress(__arg("[Progress %1% (#%2 of total %3)]",ProgressPercent.toFixed(0) ,repeat * itemCount + i + 1, totalIteration));
}
}
}
}
// main flow
try {
$.init();
$.run();
$.finalize();
}
catch (e) {
app.msg.sendProgress(__arg($.msg.error, e), 0);
throw e;
}
Comments (0)
No comments yet. Be the first to comment!
Snippet Information
Author:
admin_alex
Language: PowerScript
Created:
Oct 22, 2025
Updated:
0 minutes ago
Views: 54
Stars: 1