ANC350 Attocube Controller

This is the controller level of the position ANC350 from Attocube (in the Montana)

This code is strongly based and using PyANC350, which was written by Rob Heath; rob@robheath.me.uk; 24-Feb-2015; It was taken from github in August 2019 by Irina Komen and made to work with Hyperion

Copyright (c) 2018 Rob Heath

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Description from Rob Heath: PyANC350 is a control scheme suitable for the Python coding style for the attocube ANC350 closed-loop position system.

It implements ANC350lib, which in turn depends on anc350v2.dll which is provided by attocube in the ANC350_DLL folders on the driver disc. This in turn requires nhconnect.dll and libusb0.dll. Place all of these in the same folder as this module (and that of ANC350lib).

Unlike ANC350lib which is effectively a re-imagining of the C++ header, PyANC350 is intended to behave as one might expect Python to. This means: returning values; behaving as an object.

At present this only addresses the first ANC350 connected to the machine.

Usage:
  1. instantiate Positioner() class to begin, eg. pos = Positioner().
  2. methods from the ANC350v2 documentation are implemented such that function PositionerGetPosition(handle, axis, &pos) becomes position = pos.getPosition(axis), PositionerCapMeasure(handle,axis,&cap) becomes cap = pos.capMeasure(axis), and so on. Return code handling is within ANC350lib.
  3. bitmask() and debitmask() functions have been added for convenience when using certain functions (e.g. getStatus,moveAbsoluteSync)
  4. for tidiness remember to Positioner.close() when finished!

Important NOTE:

This code assumes that the following files are stored in this folder (hyperion/controller/attocube/)

  • anc350v2.dll
  • anc350v2.lib
  • libusb0.dll

And the (actor) calibration files:

  • ANPx101-A3-1079.aps
  • ANPx101-A3-1087.aps
  • ANPz102-F8-393.aps

You should get these files from the manufacturer (except for libusb0.dll).

class hyperion.controller.attocube.anc350.Anc350(settings)

Class for the ANC350 controller

Parameters:settings (dict) – this includes all the settings needed to connect to the device in question, in this case just dummy.
acInEnable(axis, state)
UNUSED
Activates/deactivates AC input of addressed axis; only applicable for dither axes.
amplitude(axis, amp)
Set the amplitude setpoint of the Stepper in mV.
You need to set the amplitude, max 60V.
At room temperature you need 30V for x and y and 40V for z.
At low temperature that is higher, 40V or even 50V.
Higher amplitude influences step size though.
Parameters:
  • axis (integer) – axis number from 0 to 2 for steppers
  • amp (integer) – amplitude to be set to the Stepper in mV, between 0 and 60V; needs to be an integer!
amplitudeControl(axis, mode)
Selects the type of amplitude control in the Stepper.
The amplitude is controlled by the positioner to hold the value constant determined by the selected type of amplitude control.
I thought for closed loop it needs to be set in Step Width mode, nr. 2.
However, that gives issues, since sometimes the amplitude is not high enough to make the thing move at all.
So Amplitude control mode, nr. 1, seems better.
Parameters:
  • axis (integer) – axis number from 0 to 2 for steppers
  • mode (integer) – Mode takes values 0: speed, 1: amplitude, 2: step size
bandwidthLimitEnable(axis, state)
UNUSED
activates/deactivates the bandwidth limiter of the addressed axis. only applicable for scanner axes.
capMeasure(axis)
Determines the capacitance of the piezo addressed by axis.
Pay attention: the 0 that you give to the ANC350lib.Int32 is the first Attocube device; not the first of the 6 positioners.
Parameters:axis (integer) – axis number from 0 to 2 for steppers and 3 to 5 for scanners
Returns:capacitance value in mF
check()

Determines number of connected attocube controller devices and their respective hardware IDs.

clearStopDetection(axis)
UNUSED
when .setStopDetectionSticky() is enabled, this clears the stop detection status.
connect()
Establishes connection to the first attocube device found.
Pay attention: the 0 that you give to the ANC350lib.Int32 is the first attocube device; not the first of the 6 positioners.
dcInEnable(axis, state)
UNUSED
Activates/deactivates DC input of addressed axis; only applicable for scanner/dither axes.
dcLevel(axis, dclev)

Sets the dc level of selected scanner (or maybe stepper, if you want).

Parameters:
  • axis (integer) – axis number from 0 to 2 for steppers and 3 to 5 for scanners
  • dclev (integer) – DC level in mV; needs to be an integer!
dutyCycleEnable(state)

UNUSED controls duty cycle mode.

dutyCycleOffTime(value)

UNUSED sets duty cycle off time.

dutyCyclePeriod(value)

UNUSED sets duty cycle period.

externalStepBkwInput(axis, input_trigger)
UNUSED
configures external step trigger input for selected axis. a trigger on this input results in a backwards single step.
input_trigger: 0 disabled, 1-6 input trigger.
externalStepFwdInput(axis, input_trigger)
UNUSED
configures external step trigger input for selected axis.
a trigger on this input results in a forward single step.
input_trigger: 0 disabled, 1-6 input trigger.
externalStepInputEdge(axis, edge)
UNUSED
configures edge sensitivity of external step trigger input for selected axis.
edge: 0 rising, 1 falling.
finalize()

Closes connection to ANC350 device.

frequency(axis, freq)
Sets the frequency of selected stepper axis.
Higher means more noise and faster (= less precise?).
Parameters:
  • axis (integer) – axis number from 0 to 2 for steppers
  • freq (integer) – frequency in Hz, from 1Hz to 2kHz; needs to be an integer!
getAcInEnable(axis)
UNUSED
determines status of ac input of addressed axis. only applicable for dither axes.
getAmplitude(axis)
Determines the actual amplitude.
In case of standstill of the actor this is the amplitude setpoint.
In case of movement the amplitude set by amplitude control is determined.
Parameters:axis (integer) – axis number from 0 to 2 for steppers
Returns:measured amplitude in mV
getBandwidthLimitEnable(axis)
UNUSED
determines status of bandwidth limiter of addressed axis. only applicable for scanner axes.
getDcInEnable(axis)
UNUSED
determines status of dc input of addressed axis. only applicable for scanner/dither axes.
getDcLevel(axis)
Determines the status actual DC level on the scanner (or stepper).
Again: the 0 is for the number of controller units, not the 6 positioners.
Parameters:axis (integer) – axis number from 3 to 5 for scanners
Returns:measured DC level in mV
getFrequency(axis)

Determines the frequency on the stepper.

Parameters:axis (integer) – axis number from 0 to 2 for steppers
Returns:measured frequency in Hz
getIntEnable(axis)

Determines status of internal signal generation of addressed axis. only applicable for scanner/dither axes.

Parameters:axis (integer) – axis number from 3 to 5 for scanners
Returns:True if the INT mode is selected, False if not
getPosition(axis)
Determines actual position of addressed stepper axis.
Pay attention: the sensor resolution is specified for 200nm.
Parameters:axis (integer) – axis number from 0 to 2 for steppers
Returns:position in nm
getReference(axis)

UNUSED determines distance of reference mark to origin.

getReferenceRotCount(axis)

UNUSED determines actual position of addressed axis.

getRotCount(axis)

UNUSED determines actual number of rotations in case of rotary actuator.

getSpeed(axis)
Determines the actual speed.
In case of standstill of this actor this is the calculated speed resultingfrom amplitude setpoint, frequency, and motor parameters.
In case of movement this is measured speed.
Parameters:axis (integer) – axis number from 0 to 2 for steppers
Returns:speed in nm/s
getStatus(axis)
Determines the status of the selected axis.
It is not clear whether it also works for the scanner, or only for the stepper.
result: bit0 (moving) (+1), bit1 (stop detected) (+2), bit2 (sensor error) (+4), bit3 (sensor disconnected) (+8).
Parameters:axis (integer) – axis number from 0 to 2 for steppers and 3 to 5 for scanners
Returns:1: moving, 2: stop detected, 4: sensor error, 8: sensor disconnected
getStepwidth(axis)
Determines the step width.
In case of standstill of the motor this is the calculated step width resulting from amplitude setpoint, frequency, and motor parameters.
In case of movement this is measured step width.
Parameters:axis (integer) – axis number from 0 to 2 for steppers
Returns:stepwidth in nm
initialize()
Initializes the controller.
Checks for attocube controller units and connects to it.
Pay attention: there are 6 positioners, but only 1 controller; we connect to the 1.
intEnable(axis, state)

Activates/deactivates internal signal generation of addressed axis; only applicable for scanner/dither axes.

Parameters:
  • axis (integer) – axis number from 3 to 5 for scanners
  • state (bool) – True is enabled, False is disabled
load(axis)
Loads a parameter file for actor configuration.
note: this requires a pointer to a char datatype.
the actor files are in this controller folder, their names are hard coded in the init.
note: Attocube called the up-down actor file ANPz, I called that axis YPiezo.
Parameters:axis (integer) – axis number from 0 to 2 for steppers and 3 to 5 for scanners
moveAbsolute(axis, position, rotcount=0)
Starts approach to absolute target position.
Previous movement will be stopped.
Rotcount optional argument, not in our case since we dont have rotation options.
Parameters:
  • axis (integer) – axis number from 0 to 2 for steppers
  • position (integer) – absolute target position in nm; needs to be an integer!
  • rotcount – optional argument position units are in ‘unit of actor multiplied by 1000’ (generally nanometres)
moveAbsoluteSync(bitmask_of_axes)
UNUSED
Starts the synchronous approach to absolute target position for selected axis.
Previous movement will be stopped.
Target position for each axis defined by .setTargetPos() takes a bitmask of axes!
Not clear what’s the difference with moveAbsolute.
Parameters:bitmask_of_axes
moveContinuous(axis, direction)

Starts continuously positioning with set parameters for ampl and speed and amp control respectively.

Parameters:
  • axis (integer) – axis number from 0 to 2 for steppers
  • direction (integer) – can be 0 (forward) or 1 (backward)
moveReference(axis)
UNUSED
Starts approach to reference position.
Previous movement will be stopped.
No idea whats the difference with moveRelative
Parameters:axis (integer) – axis number from 0 to 2 for steppers
moveRelative(axis, position, rotcount=0)
Starts approach to relative target position.
Previous movement will be stopped.
Rotcount optional argument, not in our case since we dont have rotation options.
Parameters:
  • axis (integer) – axis number from 0 to 2 for steppers
  • position (integer) – relative target position in nm, can be both positive and negative; needs to be an integer!
  • rotcount – optional argument position units are in ‘unit of actor multiplied by 1000’ (generally nanometres)
moveSingleStep(axis, direction)
Starts a one-step positioning, where the stepwidht is determined by the amplitude and frequency.
Previous movement will be stopped.
Parameters:
  • axis (integer) – axis number from 0 to 2 for steppers
  • direction – can be 0 (forward) or 1 (backward)
quadratureAxis(quadratureno, axis)
UNUSED
selects the axis for use with this trigger in/out pair.
quadratureno: number of addressed quadrature unit (0-2).
quadratureInputPeriod(quadratureno, period)
UNUSED
selects the stepsize the controller executes when detecting a step on its input AB-signal.
quadratureno: number of addressed quadrature unit (0-2). period: stepsize in unit of actor * 1000.
quadratureOutputPeriod(quadratureno, period)
UNUSED
selects the position difference which causes a step on the output AB-signal.
quadratureno: number of addressed quadrature unit (0-2). period: period in unit of actor * 1000.
resetPosition(axis)
UNUSED
sets the origin to the actual position.
Parameters:axis (integer) – axis number from 0 to 2 for steppers
sensorPowerGroupA(state)
UNUSED
switches power of sensor group A.
Sensor group A contains either the sensors of axis 1-3 or 1-2 dependent on hardware of controller.
sensorPowerGroupB(state)
UNUSED
switches power of sensor group B.
Sensor group B contains either the sensors of axis 4-6 or 3 dependent on hardware of controller.
setHardwareId(hwid)

UNUSED sets the hardware ID for the device (used to differentiate multiple devices).

setOutput(axis, state)
UNUSED
activates/deactivates the addressed axis.
no idea what that means, but sounds interesting.
Parameters:
  • axis
  • state
setStopDetectionSticky(axis, state)
UNUSED
when enabled, an active stop detection status remains active until cleared manually by .clearStopDetection().
Is this what in Daisy is called hump detection? Than it might be useful.
Parameters:
  • axis (integer) – axis number from 0 to 2 for steppers
  • state
setTargetGround(axis, state)

UNUSED when enabled, actor voltage set to zero after closed-loop positioning finished.

setTargetPos(axis, pos, rotcount=0)

UNUSED sets target position for use with .moveAbsoluteSync().

singleCircleMode(axis, state)
UNUSED
switches single circle mode.
In case of activated single circle mode the number of rotations are ignored and the shortest way to target position is used. Only relevant for rotary actors.
staticAmplitude(amp)

UNUSED sets output voltage for resistive sensors.

stepCount(axis, stps)

UNUSED configures number of successive step scaused by external trigger or manual step request. steps = 1 to 65535.

stopApproach(axis)
Stops approaching target/relative/reference position.
DC level of affected axis after stopping depends on setting by .setTargetGround().
Dont know for sure whats the difference with stopMoving.
Parameters:axis (integer) – axis number from 0 to 2 for steppers
stopDetection(axis, state)
UNUSED
switches stop detection on/off.
Is this what in Daisy is called hump detection? Than it might be useful.
Parameters:
  • axis (integer) – axis number from 0 to 2 for steppers
  • state
stopMoving(axis)
UNUSED
stops any positioning, DC level of affected axis is set to zero after stopping.
Parameters:axis
trigger(triggerno, lowlevel, highlevel)
UNUSED
sets the trigger thresholds for the external trigger.
triggerno is 0-5, lowlevel/highlevel in units of actor * 1000.
triggerAxis(triggerno, axis)

UNUSED selects the corresponding axis for the addressed trigger. triggerno is 0-5.

triggerEpsilon(triggerno, epsilon)

UNUSED sets the hysteresis of the external trigger. epsilon in units of actor * 1000.

triggerModeIn(mode)
UNUSED
selects the mode of the input trigger signals.
state: 0 disabled - inputs trigger nothing,
1 quadrature - three pairs of trigger in signals are used to accept AB-signals for relative positioning,
2 coarse - trigger in signals are used to generate coarse steps.
triggerModeOut(mode)
UNUSED
selects the mode of the output trigger signals.
state: 0 disabled - inputs trigger nothing,
1 position - the trigger outputs reacts to the defined position ranges with the selected polarity,
2 quadrature - three pairs of trigger out signals are used to signal relative movement as AB-signals, 3 IcHaus - the trigger out signals are used to output the internal position signal of num-sensors.
triggerPolarity(triggerno, polarity)

UNUSED

sets the polarity of the external trigger, triggerno: 0-5, polarity: 0 low active, 1 high active.

updateAbsolute(axis, position)
UNUSED
update s target position for a running approach.
function has lower performance impact on running approach compared to .moveAbsolute().
position units are in ‘unit of actor multiplied by 1000’ (generally nanometres).
Parameters:
  • axis
  • position
class hyperion.controller.attocube.anc350.Anc350Dummy(settings)
hyperion.controller.attocube.anc350.bitmask(input_array)
takes an array or string and converts to integer bitmask.
reads from left to right e.g. 0100 = 2 not 4.
hyperion.controller.attocube.anc350.debitmask(input_int, num_bits=False)
takes a bitmask and returns a list of which bits are switched.
reads from left to right e.g. 2 = [0, 1] not [1, 0].