From 4c5109e5a3aebaaaad38dd37727af0fff9696b3a Mon Sep 17 00:00:00 2001 From: Markus Zolliker Date: Fri, 18 Aug 2023 10:07:20 +0200 Subject: [PATCH] fix frappy_demo.lakeshore reading back the target does not work properly, because a) the readback value might be delayed b) there is no command to read back the target, SETP?1 is returning the working setpoint, which might be distinct in case of a ramp Change-Id: I0da2dbfc1a8ddbecbae6d0456ff64e008bc56336 Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31983 Tested-by: Jenkins Automated Tests Reviewed-by: Markus Zolliker --- doc/source/tutorial_t_control.rst | 22 ++++++++++++++-------- frappy_demo/lakeshore.py | 11 ++++------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/doc/source/tutorial_t_control.rst b/doc/source/tutorial_t_control.rst index 420d294..786e7a4 100644 --- a/doc/source/tutorial_t_control.rst +++ b/doc/source/tutorial_t_control.rst @@ -200,7 +200,10 @@ implemented the readable stuff. We need to define some properties of the ``targe parameter and add a property ``loop`` indicating, which control loop and heater output we use. -In addition, we have to implement the methods ``write_target`` and ``read_target``: +In addition, we have to implement the method ``write_target``. Remark: we do not +implement ``read_target`` here, because the lakeshore does not offer to read back the +real target. The SETP command is returning the working setpoint, which may be distinct +from target during a ramp. .. code:: python @@ -216,11 +219,9 @@ In addition, we have to implement the methods ``write_target`` and ``read_target def write_target(self, target): # we always use a request / reply scheme - reply = self.communicate(f'SETP {self.loop},{target};SETP?{self.loop}') - return float(reply) + self.communicate(f'SETP {self.loop},{target};*OPC?') + return target - def read_target(self): - return float(self.communicate(f'SETP?{self.loop}')) In order to test this, we will need to change the entry module ``T`` in the configuration file: @@ -272,13 +273,12 @@ There are two things still missing: def write_target(self, target): # reactivate heater in case it was switched off self.communicate(f'RANGE {self.loop},{self.heater_range};RANGE?{self.loop}') - reply = self.communicate(f'SETP {self.loop},{target};SETP? {self.loop}') + self.communicate(f'SETP {self.loop},{target};*OPC?') self._driving = True # Setting the status attribute triggers an update message for the SECoP status # parameter. This has to be done before returning from this method! self.status = BUSY, 'target changed' - return float(reply) - + return target ... def read_status(self): @@ -403,4 +403,10 @@ Appendix 2: Extract from the LakeShore Manual Command (340) RANGE? *term* Command (336/350) RANGE? *term* Reply *term* + **Operation Complete Query** + ---------------------------------------------- + Command *OPC? + Reply 1 + Description in Frappy, we append this command to request in order + to generate a reply ====================== ======================= diff --git a/frappy_demo/lakeshore.py b/frappy_demo/lakeshore.py index c0442bc..a363712 100644 --- a/frappy_demo/lakeshore.py +++ b/frappy_demo/lakeshore.py @@ -69,24 +69,21 @@ class TemperatureSensor(HasIO, Readable): class TemperatureLoop(TemperatureSensor, Drivable): # lakeshore loop number to be used for this module loop = Property('lakeshore loop', IntRange(1, 2), default=1) - target = Parameter(datatype=FloatRange(min=0, max=1500, unit='K')) + target = Parameter(datatype=FloatRange(unit='K', min=0, max=1500)) heater_range = Property('heater power range', IntRange(0, 5)) # max. 3 on LakeShore 336 - tolerance = Parameter('convergence criterion', FloatRange(0), default=0.1, readonly = False) + tolerance = Parameter('convergence criterion', FloatRange(0), default=0.1, readonly=False) _driving = False def write_target(self, target): # reactivate heater in case it was switched off # the command has to be changed in case of model 340 to f'RANGE {self.heater_range};RANGE?' self.communicate(f'RANGE {self.loop},{self.heater_range};RANGE?{self.loop}') - reply = self.communicate(f'SETP {self.loop},{target};SETP? {self.loop}') + self.communicate(f'SETP {self.loop},{target};*OPC?') self._driving = True # Setting the status attribute triggers an update message for the SECoP status # parameter. This has to be done before returning from this method! self.status = BUSY, 'target changed' - return float(reply) - - def read_target(self): - return float(self.communicate(f'SETP?{self.loop}')) + return target def read_status(self): code = int(self.communicate(f'RDGST?{self.channel}'))