diff --git a/cfg/phytron.cfg b/cfg/phytron.cfg index ee75c8a..26e6e15 100644 --- a/cfg/phytron.cfg +++ b/cfg/phytron.cfg @@ -8,7 +8,7 @@ uri = tcp://5000 [drv_io] description = class = secop_psi.phytron.PhytronIO -uri = ma10-ts.psi.ch:3004 +uri = ma7-ts.psi.ch:3007 # uri = serial:///dev/tty.usbserial?baudrate=57600 # uri = serial:///dev/ttyUSB0?baudrate=9600 @@ -16,4 +16,5 @@ uri = ma10-ts.psi.ch:3004 description = a phytron motor class = secop_psi.phytron.Motor io = drv_io +abslimits = -180,360 encoder_mode = CHECK diff --git a/cfg/ppmssim.cfg b/cfg/ppmssim.cfg index 1bc9f6b..82cc65e 100644 --- a/cfg/ppmssim.cfg +++ b/cfg/ppmssim.cfg @@ -14,111 +14,111 @@ io = ppms class = secop_psi.ppms.Field target.min = -9 target.max = 9 -.description = magnetic field -.io = ppms +description = magnetic field +io = ppms [pos] class = secop_psi.ppms.Position -.description = sample rotator -.io = ppms +description = sample rotator +io = ppms [lev] class = secop_psi.ppms.Level -.description = helium level -.io = ppms +description = helium level +io = ppms [chamber] class = secop_psi.ppms.Chamber -.description = chamber state -.io = ppms +description = chamber state +io = ppms [r1] class = secop_psi.ppms.BridgeChannel -.description = resistivity channel 1 -.no = 1 +description = resistivity channel 1 +no = 1 value.unit = Ohm -.io = ppms +io = ppms [r2] class = secop_psi.ppms.BridgeChannel -.description = resistivity channel 2 -.no = 2 +description = resistivity channel 2 +no = 2 value.unit = Ohm -.io = ppms +io = ppms [r3] class = secop_psi.ppms.BridgeChannel -.description = resistivity channel 3 -.no = 3 +description = resistivity channel 3 +no = 3 value.unit = Ohm -.io = ppms +io = ppms [r4] class = secop_psi.ppms.BridgeChannel -.description = resistivity channel 4 -.no = 4 +description = resistivity channel 4 +no = 4 value.unit = Ohm -.io = ppms +io = ppms [i1] class = secop_psi.ppms.Channel -.description = current channel 1 -.no = 1 +description = current channel 1 +no = 1 value.unit = uA -.io = ppms +io = ppms [i2] class = secop_psi.ppms.Channel -.description = current channel 2 -.no = 2 +description = current channel 2 +no = 2 value.unit = uA -.io = ppms +io = ppms [i3] class = secop_psi.ppms.Channel -.description = current channel 3 -.no = 3 +description = current channel 3 +no = 3 value.unit = uA -.io = ppms +io = ppms [i4] class = secop_psi.ppms.Channel -.description = current channel 4 -.no = 4 +description = current channel 4 +no = 4 value.unit = uA -.io = ppms +io = ppms [v1] class = secop_psi.ppms.DriverChannel -.description = voltage channel 1 -.no = 1 +description = voltage channel 1 +no = 1 value.unit = V -.io = ppms +io = ppms [v2] class = secop_psi.ppms.DriverChannel -.description = voltage channel 2 -.no = 2 +description = voltage channel 2 +no = 2 value.unit = V -.io = ppms +io = ppms [tv] class = secop_psi.ppms.UserChannel -.description = VTI temperature +description = VTI temperature enabled = 1 value.unit = K -.io = ppms +io = ppms [ts] class = secop_psi.ppms.UserChannel -.description = sample temperature +description = sample temperature enabled = 1 value.unit = K -.io = ppms +io = ppms [ppms] class = secop_psi.ppms.Main -.description = the main and poller module -.class_id = QD.MULTIVU.PPMS.1 -.visibility = 3 +description = the main and poller module +class_id = QD.MULTIVU.PPMS.1 +visibility = 3 pollinterval = 2 diff --git a/secop_psi/phytron.py b/secop_psi/phytron.py index 805c940..cc0e585 100644 --- a/secop_psi/phytron.py +++ b/secop_psi/phytron.py @@ -20,11 +20,13 @@ # # ***************************************************************************** -"""driver for pythron motors""" +"""driver for phytron motors""" from secop.core import Done, Command, EnumType, FloatRange, IntRange, \ - HasIO, Parameter, Property, Drivable, PersistentMixin, PersistentParam, StringIO, StringType -from secop.errors import CommunicationFailedError, HardwareError + HasIO, Parameter, Property, Drivable, PersistentMixin, PersistentParam, \ + StringIO, StringType, TupleOf +from secop.errors import CommunicationFailedError, HardwareError, BadValueError +from secop.lib import clamp class PhytronIO(StringIO): @@ -65,14 +67,24 @@ class Motor(PersistentMixin, HasIO, Drivable): encoder = Parameter('encoder reading', FloatRange(unit='deg')) sameside_offset = Parameter('offset when always approaching from the same side', FloatRange(unit='deg'), readonly=False, default=0) + abslimits = Parameter('abs limits (raw values)', default=(0, 0), + datatype=TupleOf(FloatRange(unit='deg'), FloatRange(unit='deg'))) + userlimits = PersistentParam('user limits', readonly=False, default=(0, 0), initwrite=True, + datatype=TupleOf(FloatRange(unit='deg'), FloatRange(unit='deg'))) ioClass = PhytronIO fast_poll = 0.1 _sameside_pending = False _mismatch_count = 0 + _rawlimits = None def earlyInit(self): super().earlyInit() + if self.abslimits == (0, 0): + self.abslimits = -9e99, 9e99 + if self.userlimits == (0, 0): + self._rawlimits = self.abslimits + self.read_userlimits() self.loadParameters() def get(self, cmd): @@ -151,10 +163,20 @@ class Motor(PersistentMixin, HasIO, Drivable): raise HardwareError('speed factor does not match') return float(self.set_get('P15S', int(value * self.speed_factor), 'P15R')) / self.speed_factor + def _check_limits(self, *values): + for name, (mn, mx) in ('user', self._rawlimits), ('abs', self.abslimits): + mn -= self.offset + mx -= self.offset + for v in values: + if not (mn <= v <= mx): + raise BadValueError('%s limits violation: %g <= %g <= %g' % (name, mn, v, mx)) + v += self.offset + def write_target(self, value): if self.status[0] == self.Status.ERROR: raise HardwareError('need reset') self.status = self.Status.BUSY, 'changed target' + self._check_limits(value, value + self.sameside_offset) if self.sameside_offset: # drive first to target + sameside_offset # we do not optimize when already driving from the right side @@ -165,8 +187,18 @@ class Motor(PersistentMixin, HasIO, Drivable): self.setFastPoll(True, self.fast_poll) return value + def read_userlimits(self): + return self._rawlimits[0] - self.offset, self._rawlimits[1] - self.offset + + def write_userlimits(self, value): + self._rawlimits = [clamp(self.abslimits[0], v + self.offset, self.abslimits[1]) for v in value] + value = self.read_userlimits() + self.saveParameters() + return value + def write_offset(self, value): self.offset = value + self.read_userlimits() self.saveParameters() return Done @@ -182,6 +214,7 @@ class Motor(PersistentMixin, HasIO, Drivable): pos = self.value + self.offset if abs(enc - pos) > self.encoder_tolerance: if enc < 0: + # assume we have a rotation (not a linear motor) while enc < 0: self.offset += 360 enc += 360