Source code for psj_lib.devices.nv_family.capabilities.nv_knob

"""NV-series encoder knob capabilities."""

from enum import Enum

from ...base.capabilities import PiezoCapability

[docs] class NVKnobMode(Enum): """NV encoder knob operating modes. Defines the operating behavior of the front-panel encoder knob for setpoint adjustment. Attributes: UNKNOWN: Unrecognized mode (fallback when parsing fails). ACCELERATION: Step size scales with rotation speed. INTERVAL: Fixed step interval mode. INTERVAL_ACCELERATION: Interval mode with acceleration behavior. Example: >>> from psj_lib import NVKnobMode >>> await device.knob.set(mode=NVKnobMode.INTERVAL) >>> mode = await device.knob.get_mode() >>> print(mode.name) """ UNKNOWN = -1 ACCELERATION = 0 INTERVAL = 1 INTERVAL_ACCELERATION = 2
[docs] class NVKnob(PiezoCapability): """Encoder knob configuration for open-loop and shared settings.""" CMD_MODE = "KNOB_MODE" CMD_SAMPLE_TIME = "KNOB_SAMPLE_TIME" CMD_ACCEL_EXPONENT = "KNOB_ACCEL_EXPONENT" CMD_STEP_LIMIT = "KNOB_STEP_LIMIT" CMD_STEP_OPEN_LOOP = "KNOB_STEP_OPEN_LOOP"
[docs] async def set( self, mode: NVKnobMode | None = None, sample_time: float | None = None, accel_exponent: int | None = None, step_limit: int | None = None, step_open_loop: float | None = None, ) -> None: """ Set encoder knob parameters. Only parameters that are not None will be updated. Args: mode: Encoder knob mode (acceleration, interval, or interval with acceleration) sample_time: Sample time in seconds (NV expects multiples of 20ms) accel_exponent: Exponent for acceleration mode (higher = more aggressive) step_limit: Maximum step size for interval mode step_open_loop: Step size for open loop control (V) Returns: None """ if mode is not None: await self._write(self.CMD_MODE, [mode.value]) if sample_time is not None: output = int(sample_time / 0.02) # NV expects sample time in units of 20ms await self._write(self.CMD_SAMPLE_TIME, [output]) if accel_exponent is not None: await self._write(self.CMD_ACCEL_EXPONENT, [accel_exponent]) if step_limit is not None: await self._write(self.CMD_STEP_LIMIT, [step_limit]) if step_open_loop is not None: await self._write(self.CMD_STEP_OPEN_LOOP, [step_open_loop])
[docs] async def get_mode(self) -> NVKnobMode: """Read the currently configured knob mode. Returns: Current :class:`NVKnobMode`. Returns ``NVKnobMode.UNKNOWN`` if parsing fails. """ result = await self._write(self.CMD_MODE) try: mode_value = int(result[0]) return NVKnobMode(mode_value) except Exception: return NVKnobMode.UNKNOWN
[docs] async def get_sample_time(self) -> float: """Read encoder sampling period. Returns: Sampling period in seconds. """ result = await self._write(self.CMD_SAMPLE_TIME) return int(result[0]) * 0.02 # Convert back to seconds
[docs] async def get_accel_exponent(self) -> int: """Read acceleration exponent. Returns: Configured acceleration exponent. """ result = await self._write(self.CMD_ACCEL_EXPONENT) return int(result[0])
[docs] async def get_step_limit(self) -> int: """Read configured knob step limit. Returns: Maximum step limit value. """ result = await self._write(self.CMD_STEP_LIMIT) return int(result[0])
[docs] async def get_step_open_loop(self) -> float: """Read open-loop knob step value. Returns: Open-loop step size (typically in volts). """ result = await self._write(self.CMD_STEP_OPEN_LOOP) return float(result[0])
[docs] class NVCLEKnob(NVKnob): """Encoder knob capability variant with closed-loop step settings.""" CMD_STEP_CLOSED_LOOP = "KNOB_STEP_CLOSED_LOOP"
[docs] async def set( self, mode: NVKnobMode | None = None, sample_time: float | None = None, accel_exponent: int | None = None, step_limit: int | None = None, step_open_loop: float | None = None, step_closed_loop: float | None = None, ) -> None: """ Set encoder knob parameters. Only parameters that are not None will be updated. Args: mode: Encoder knob mode (acceleration, interval, or interval with acceleration) sample_time: Sample time in seconds (NV expects multiples of 20ms) accel_exponent: Exponent for acceleration mode (higher = more aggressive) step_limit: Maximum step size for interval mode step_open_loop: Step size for open loop control (V) step_closed_loop: Step size for closed loop control (µm) Returns: None """ await super().set(mode, sample_time, accel_exponent, step_limit, step_open_loop) if step_closed_loop is not None: await self._write(self.CMD_STEP_CLOSED_LOOP, [step_closed_loop])
[docs] async def get_step_closed_loop(self) -> float: """Read closed-loop knob step value. Returns: Closed-loop step size (typically in µm). """ result = await self._write(self.CMD_STEP_CLOSED_LOOP) return float(result[0])