diff --git a/pyproject.toml b/pyproject.toml index 8a08d4f..933a086 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "nipiezojenapy" -version = "1.0.2.dev0" +version = "1.0.3.dev0" description = "A package for controlling Jena PiezoSystem NV40 3CLE amplifier vi NIDAQMX." readme = "README.md" diff --git a/src/applications/tkcontrollerapp.py b/src/applications/tkcontrollerapp.py index d84f567..72c1e6b 100644 --- a/src/applications/tkcontrollerapp.py +++ b/src/applications/tkcontrollerapp.py @@ -18,7 +18,8 @@ parser.add_argument('--piezo-read-channels', metavar = '', default = 'ai0,ai1,ai2', type=str, help='List of analog input channels used to read the piezo position') parser.add_argument('-s', '--settle-time', metavar = 'settle_time', default = 0.01, type=float, - help='Amount of time, in seconds, that are paused after moving to a new position. This allows for the device to "settle" into position.') + help='''Amount of time, in seconds, that are paused after moving to a new position. +This allows for the device to "settle" into position.''') parser.add_argument('-q', '--quiet', action = 'store_true', help='When true,logger level will be set to warning. Otherwise, set to "info".') parser.add_argument('-t', '--test', action = 'store_true', @@ -27,8 +28,11 @@ help='sets min allowed position on piezo controller.') parser.add_argument('-pmax', '--piezo-max-position', metavar = 'microns', default = 80, type=float, help='sets min allowed position on piezo controller.') -parser.add_argument('-pscale', '--piezo-scale-microns-per-volt', default = 8, type=float, - help='sets micron to volt scale for piezo controller.') +parser.add_argument('-pscale', '--piezo-scale-microns-per-volt', nargs = "*", default = [8], type=float, + help='sets micron to volt scale for piezo controller for all channels or each channel individually.') +parser.add_argument('-poffset', '--piezo-scale-volts-offset', nargs = "*", default = [0], type=float, + help='''sets volt offset value for piezo controller for all channels or each channel individually. +This is the applied voltage that defines the position x, y, z = 0, 0, 0.''') args = parser.parse_args() @@ -208,13 +212,24 @@ def build_controller(): if args.test: controller = nipiezojenapy.BaseControl() else: + if len(args.piezo_scale_microns_per_volt) == 1: + piezo_scale_microns_per_volt = args.piezo_scale_microns_per_volt * 3 + else: + piezo_scale_microns_per_volt = args.piezo_scale_microns_per_volt + + if len(args.piezo_scale_volts_offset) == 1: + piezo_scale_volts_offset = args.piezo_scale_volts_offset * 3 + else: + piezo_scale_volts_offset = args.piezo_scale_volts_offset + controller = nipiezojenapy.PiezoControl(device_name = args.daq_name, write_channels = args.piezo_write_channels.split(','), read_channels = args.piezo_read_channels.split(','), move_settle_time = args.settle_time, min_position = args.piezo_min_position, max_position = args.piezo_max_position, - scale_microns_per_volt = args.piezo_scale_microns_per_volt) + scale_microns_per_volt = piezo_scale_microns_per_volt, + zero_microns_volt_offset = piezo_scale_volts_offset) return controller def main(): diff --git a/src/nipiezojenapy/controller.py b/src/nipiezojenapy/controller.py index 2b86856..129afbc 100644 --- a/src/nipiezojenapy/controller.py +++ b/src/nipiezojenapy/controller.py @@ -1,7 +1,7 @@ import nidaqmx import logging import time -from typing import List +from typing import List, Union, Tuple logger = logging.getLogger(__name__) @@ -77,7 +77,8 @@ class PiezoControl(BaseControl): def __init__(self, device_name: str, write_channels: List[str] = ['ao0','ao1','ao2'], read_channels: List[str] = None, - scale_microns_per_volt: float = 8, + scale_microns_per_volt: Union[float, Tuple[float, float, float]] = 8, + zero_microns_volt_offset: Union[float, Tuple[float, float, float]] = 0, move_settle_time: float = 0.001, min_position: float = 0.0, max_position: float = 80.0) -> None: @@ -86,17 +87,32 @@ def __init__(self, device_name: str, self.device_name = device_name self.write_channels = write_channels self.read_channels = read_channels - self.scale_microns_per_volt = scale_microns_per_volt + if isinstance(scale_microns_per_volt, float): + self.scale_microns_per_volt = tuple([scale_microns_per_volt] * 3) + else: + self.scale_microns_per_volt = tuple(scale_microns_per_volt) + + if len(self.scale_microns_per_volt) != 3: + raise ValueError('scale_microns_per_volt must be a float or a list of three floats.') + + if isinstance(zero_microns_volt_offset, float): + self.zero_microns_volt_offset = tuple([zero_microns_volt_offset] * 3) + else: + self.zero_microns_volt_offset = tuple(zero_microns_volt_offset) + + if len(self.zero_microns_volt_offset) != 3: + raise ValueError('zero_microns_volt_offset must be a float or a list of three floats.') + self.minimum_allowed_position = min_position self.maximum_allowed_position = max_position self.settling_time_in_seconds = move_settle_time #10 millisecond settle time self.last_write_values = [None, None, None] - def _microns_to_volts(self, microns: float) -> float: - return microns / self.scale_microns_per_volt + def _microns_to_volts(self, microns: float, axis: int) -> float: + return microns / self.scale_microns_per_volt[axis] + self.zero_microns_volt_offset[axis] - def _volts_to_microns(self, volts: float) -> float: - return self.scale_microns_per_volt * volts + def _volts_to_microns(self, volts: float, axis: int) -> float: + return self.scale_microns_per_volt[axis] * (volts - self.zero_microns_volt_offset[axis]) def go_to_position(self, x: float = None, @@ -115,7 +131,7 @@ def goto(val, idx): self._validate_value(val) with nidaqmx.Task() as task: task.ao_channels.add_ao_voltage_chan(self.device_name + '/' + self.write_channels[idx]) - task.write(self._microns_to_volts(val)) + task.write(self._microns_to_volts(val, idx)) self.last_write_values[idx] = val debug_string = [] @@ -167,4 +183,4 @@ def get_current_position(self) -> List[float]: return self.last_write_values else: - return [self._volts_to_microns(v) for v in self.get_current_voltage()] + return [self._volts_to_microns(v, i) for i, v in enumerate(self.get_current_voltage())]