def set(self, toutput, sp, **kwargs): """Setting a setpoint as quickly as possible """ if kwargs.has_key("ramp"): self.set_ramprate(toutput, kwargs["ramp"]) if kwargs.has_key("dwell"): self.set_dwell(toutput, kwargs["dwell"]) if kwargs.has_key("step"): self.set_step(toutput, kwargs["step"]) channel = toutput.config.get("channel",str) log.debug("mockup: set %s on channel %s" % (sp,channel)) #print kwargs start_temp = self.read_output(toutput) delta = sp-start_temp start_time = time.time() self.setpoints[channel].update({ "setpoint":sp, \ "t0":start_time, \ "sign":math.copysign(1, delta), \ "start_temp":start_temp , \ "target":sp}) #simulate we reached the setpoint self.setpoints[channel]["end_time"] = start_time self.setpoints[channel]["temp"] = sp
def start_all(self, *motion_list): """ Called once per controller with all the axis to move returns immediately, positions in motor units """ elog.debug("start_all() called")
def send(self, axis, cmd): """ - Adds the 'newline' terminator character : "\\\\r\\\\n" - Sends command <cmd> to the VSCANNER. - Channel is defined in <cmd>. - <axis> is passed for debugging purposes. - Returns answer from controller. Args: - <axis> : passed for debugging purposes. - <cmd> : command to send to controller (Channel is already mentionned in <cmd>). Returns: - 1-line answer received from the controller (without "\\\\n" terminator). Raises: ? """ elog.debug("cmd=%r" % cmd) _cmd = cmd + "\r\n" self.serial.write(_cmd) # _t0 = time.time() _ans = self.serial.readline().rstrip() elog.debug("ans=%s" % repr(_ans)) # _duration = time.time() - _t0 # print " Sending: %r Receiving: %r (duration : %g)" % (_cmd, _ans, _duration) return _ans
def set_velocity(self, axis, new_velocity): _new_vel = new_velocity / 1000.0 # "VEL <vel>" command sets velocity in V/ms self.send_no_ans(axis, "VEL %f 0" % _new_vel) elog.debug("velocity set : %g" % _new_vel)
def prepare_move(self, motion): _velocity = float(motion.axis.config.get("velocity")) if _velocity == 0: elog.debug("immediate move") else: elog.debug("scan move") if motion.axis.chan_letter == "X": scan_val1 = motion.delta scan_val2 = 0 elif motion.axis.chan_letter == "Y": scan_val1 = 0 scan_val2 = motion.delta else: print "ERRORR" number_of_pixel = 1 line_mode = "C" # mode continuous (S for stepping) _cmd = "LINE %g %g %d %s" % (scan_val1, scan_val2, number_of_pixel, line_mode) elog.debug("_cmd_LINE=%s" % _cmd) self.send_no_ans(motion.axis, _cmd) _cmd = "SCAN 0 0 1 U" elog.debug("_cmd_SCAN=%s" % _cmd) self.send_no_ans(motion.axis, _cmd) _cmd = "PSHAPE ALL" elog.debug("_cmd_PSHAPE=%s" % _cmd) self.send_no_ans(motion.axis, _cmd)
def start_one(self, motion): """ - Sends 'MOV' or 'SVA' depending on closed loop mode. Args: - <motion> : Bliss motion object. Returns: - None """ ### ### hummm a bit dangerous to mix voltage and microns for the same command isnt'it ? ### if motion.axis.closed_loop: # Command in position. self.command("MOV %s %g" % (motion.axis.channel, motion.target_pos)) elog.debug("Command to piezo MOV %s %g" % (motion.axis.channel, motion.target_pos)) else: # Command in voltage. self.command("SVA %s %g" % (motion.axis.channel, motion.target_pos)) elog.debug("Command to piezo SVA %s %g" % (motion.axis.channel, motion.target_pos))
def read_velocity(self, axis): """ Args: - <axis> : Bliss axis object. Returns: - <velocity> : float """ _ans = self.send(axis, "?VEL") # _ans should looks like '0.2 0.1' (yes with single quotes arround...) # First field is velocity (in V/ms) # Second field is "line waiting" (hummmm second field is not always present ???) _ans = _ans[1:][:-1] # (_vel, _line_waiting) = map(float, _ans.split()) _float_ans = map(float, _ans.split()) if len(_float_ans) == 1: _vel = _float_ans[0] elif len(_float_ans) == 2: (_vel, _line_waiting) = _float_ans else: elog.info("WHAT THE F.... ?VEL answer is there ???") # V/s = V/ms * 1000 _velocity = _vel * 1000 elog.debug("read_velocity : %g " % _velocity) return _velocity
def set_velocity(self, axis, velocity): log.debug("set_velocity() called") if velocity > MAX_VELOCITY or velocity < MIN_VELOCITY: log.error("PM600 Error: velocity out of range") reply = self.io_command("SV", axis.channel, velocity) if reply != "OK": log.error("PM600 Error: Unexpected response to set_velocity" + reply)
def set_firstvelocity(self, axis, creep_speed): log.debug("set_firstvelocity() called") if creep_speed > MAX_CREEP_SPEED or velocity < MIN_CREEP_SPEED: log.error("PM600 Error: creep_speed out of range") reply = self.io_command("SC", axis.channel, creep_speed) if reply != "OK": log.error("PM600 Error: Unexpected response to set_firstvelocity" + reply)
def raw_write_read(self, com): elog.debug("com=%s" % repr(com)) _com = com + "\n" self.serial.write(_com) _ans = self.serial.readline().rstrip() elog.debug("ans=%s" % repr(_ans)) return _ans
def send(self, axis, cmd): """ - Adds the 'newline' terminator character : "\\\\n" - Sends command <cmd> to the Serial line. - Axis_id must be defined in <cmd>. - <axis> is passed for debugging purposes. - Returns answer from controller. Args: - <axis> : passed for debugging purposes. - <cmd> : command to send to controller (Axis_id is already mentionned in <cmd>). Returns: - 1-line answer received from the controller (without "\\\\n" terminator). Raises: ? """ elog.debug("cmd=%s" % repr(cmd)) _cmd = cmd + "\n" self.serial.write(_cmd) _ans = self.serial.readline().rstrip() elog.debug("ans=%s" % repr(_ans)) return _ans
def stop_all(self, *motion_list): elog.debug("stop_all() called") error, reply = self.__xps.GroupMoveAbort(motion_list[0].axis.group) if error == -22: elog.info("NewportXPS: All positioners idle") elif error != 0: elog.error("NewportXPS Error: ", reply)
def state_input(self, tinput): """Get the status of a Input object """ log.debug("mockup: state Input") print "host is %s" %self.host return "READY"
def set_deceleration(self, axis, deceleration): log.debug("set_deceleration() called") if deceleration > MAX_DECELERATION or deceleration < MIN_DECELERATION: log.error("PM600 Error: deceleration out of range") reply = self.io_command("SD", axis.channel, deceleration) if reply != "OK": log.error("PM600 Error: Unexpected response to set_deceleration" + reply)
def setpoint_abort(self, toutput): """Aborting the setpoint on an Output object """ channel = toutput.config.get("channel",str) log.debug("mockup: abort: %s" % (channel)) self.setpoint_stop(toutput)
def _set_closed_loop(self, axis, onoff = True): """ Sets Closed loop status (Servo state) (SVO command) """ axis.closed_loop = onoff self.command("SVO %s %d" % (axis.channel, onoff)) elog.debug("Piezo Servo %r" % onoff) # Only when closing loop: waits to be ON-Target. if onoff: _t0 = time.time() cl_timeout = .5 _ont_state = self._get_on_target_status(axis) elog.info(u'axis {0:s} waiting to be ONTARGET'.format(axis.name)) while (not _ont_state) and (time.time() - _t0) < cl_timeout: time.sleep(0.01) print ".", _ont_state = self._get_on_target_status(axis) if not _ont_state: elog.error('axis {0:s} NOT on-target'.format(axis.name)) raise RuntimeError("Unable to close the loop : " "not ON-TARGET after %gs :( " % cl_timeout) else: elog.info('axis {0:s} ONT ok after {1:g} s'.format(axis.name, time.time() - _t0)) # Updates bliss setting (internal cached) position. axis._position() # "POS?"
def __init__(self, controller, config): """ Constructor """ log.debug("On Output") self.__controller = controller self.__name = config["name"] try: self.__limits = (config.get("low_limit"), config.get("high_limit")) except: self.__limits = (None, None) self.__setpoint_task = None self.__setpoint_event = gevent.event.Event() self.__setpoint_event_poll = 0.02 try: self.__deadband = float(config["deadband"]) except: self.__deadband = None self.__setpoint_event.set() self.__config = config self.__stopped = 0 self.__ramping = 0 self.__mode = 0 # if defined as self.deadband, attribute available from the instance # if defined as self.__deadband, not available. # in that case, use of decorator property offers it (read only) to world # useful attribute for a temperature controller writer self._attr_dict = {}
def set_velocity(self, axis, new_velocity): elog.debug("set_velocity new_velocity = %f" % new_velocity) _cmd = "VEL %s %f" % (axis.channel, new_velocity) self.send_no_ans(axis, _cmd) self.check_error(_cmd) return self.read_velocity(axis)
def update_cmd(self): """Read the controller and update all the parameter variables Args: None Returns: None """ # flush the buffer to clean old status packages self.serial.flush() # read the data data = self.serial.read(32, 10) # check if data if not data.__len__(): raise RuntimeError('Invalid answer from Cryostream') if data.__len__() != 32: data = "" data = self.serial.read(32, 10) # data = map(ord, data) data = [ord(nb) for nb in data] if data[0] == 32: self.statusPacket = StatusPacket(data) else: log.debug("Cryostream: Flushing serial line to start from skratch") self.serial.flush()
def set_gate(self, axis, state): """ CTO [<TrigOutID> <CTOPam> <Value>]+ - <TrigOutID> : {1, 2, 3} - <CTOPam> : - 3: trigger mode - <Value> : {0, 2, 3, 4} - 0 : position distance - 2 : OnTarget - 3 : MinMaxThreshold <---- - 4 : Wave Generator - 5: min threshold <--- must be greater than low limit - 6: max threshold <--- must be lower than high limit - 7: polarity : 0 / 1 ex : ID trigmod min/max ID min ID max ID pol + CTO 1 3 3 1 5 0 1 6 100 1 7 1 Args: - <state> : True / False Returns: - Raises: ? """ _ch = axis.channel if state: _cmd = "CTO %d 3 3 %d 5 %g %d 6 %g %d 7 1" % (_ch, _ch, self.low_limit, _ch, self.high_limit, _ch) else: _cmd = "CTO %d 3 3 %d 5 %g %d 6 %g %d 7 0" % (_ch, _ch, self.low_limit, _ch, self.high_limit, _ch) elog.debug("set_gate : _cmd = %s" % _cmd) self.send_no_ans(axis, _cmd)
def read_position(self, axis): elog.debug("read_position() called") reply = self.__xps.GroupPositionCurrentGet(axis.group, self.__nbAxes) if reply[0] != 0: elog.error("NewportXPS Error: Failed to read position", reply[1]) else: return reply[int(axis.channel)]
def _get_tns(self, axis): """Get Normalized Input Signal Value. Loop 10 times to straighten out noise""" accu = 0 for _ in range(10): time.sleep(0.01) _ans = self.command("TNS? %s" % axis.channel) #elog.debug("TNS? %d : %r" % (axis.channel, _ans)) if _ans != '0': accu += float(_ans) accu /= 2 elog.debug("TNS? %r" % accu) # during tests with the piezojack, problems with a blocked socket # towards the controller were encountered. Usually, that was # manifesting with 0 TNS readings. If The accumulated value of # TNS is 0, we're pretty sure the connection is broken. # Use self.finalize() to close the socket, it should be reopened # by the next communication attempt. if accu == 0: elog.info("%s##########################################################%s" % (bcolors.GREEN+bcolors.BOLD, bcolors.ENDC)) elog.info("%sPIEZO READ TNS, accu is zero, resetting socket connection!%s" % (bcolors.GREEN+bcolors.BOLD, bcolors.ENDC)) elog.info("%s##########################################################%s" % (bcolors.GREEN+bcolors.BOLD, bcolors.ENDC)) self.finalize() return accu
def read_acceleration(self, axis): """ returns acceleration read from flexdc controller in steps/s2 """ _acc_spss = float(self._flexdc_query("%sAC" % axis.channel)) elog.debug("read Acceleration : _acc_spss=%g " % _acc_spss) return _acc_spss
def start_one(self, motion): """ - Sends 'MOV' or 'SVA' depending on closed loop mode. Args: - <motion> : Bliss motion object. Returns: - None """ ### ### hummm a bit dangerous to mix voltage and microns for the same command isnt'it ? ### if motion.axis.closed_loop: # Command in position. self.command("MOV %s %g" % (motion.axis.channel, motion.target_pos)) elog.debug("Command to piezo MOV %s %g"% (motion.axis.channel, motion.target_pos)) else: # Command in voltage. self.command("SVA %s %g" % (motion.axis.channel, motion.target_pos)) elog.debug("Command to piezo SVA %s %g"% (motion.axis.channel, motion.target_pos))
def read_position(self, axis, last_read={ "t": time.time(), "pos": [None, None, None] }): """ Returns position's setpoint. Setpoint position is MOV? of VOL? or SVA? depending on closed-loop mode is ON or OFF. Args: - <axis> : bliss axis. Returns: - <position> : float : piezo position in Micro-meters or in Volts. """ cache = last_read if time.time() - cache["t"] < 0.005: # print "en cache not meas %f" % time.time() _pos = cache["pos"] else: # print "PAS encache not meas %f" % time.time() _pos = self._get_target_pos(axis) cache["pos"] = _pos cache["t"] = time.time() elog.debug("position setpoint read : %r" % _pos) return _pos[axis.channel - 1]
def __init__(self, controller, config): """ Constructor """ log.debug("On Output") self.__controller = controller self.__name = config["name"] try: self.__limits = (config.get("low_limit"), config.get("high_limit")) except: self.__limits = (None,None) self.__setpoint_task = None self.__setpoint_event = gevent.event.Event() self.__setpoint_event_poll = 0.02 try: self.__deadband = float(config["deadband"]) except: self.__deadband = None self.__setpoint_event.set() self.__config = config self.__stopped = 0 self.__ramping = 0 self.__mode = 0 # if defined as self.deadband, attribute available from the instance # if defined as self.__deadband, not available. # in that case, use of decorator property offers it (read only) to world # useful attribute for a temperature controller writer self._attr_dict = {}
def _setpoint_state(self, deadband): """ Return a string representing the setpoint state of an Output class type object. If a setpoint is set (by ramp or by direct setting) on an ouput, the status will be RUNNING until it is in the deadband. This RUNNING state is used by the ramping event loop in the case a user wants to block on the Output ramp method (wait=True) If deadband is None, returns immediately READY Args: toutput: Output class type object deadband: deadband attribute of toutput. Returns: object state string: READY/RUNNING from [READY/RUNNING/ALARM/FAULT] """ log.debug("On output:_setpoint_state: %s" % (deadband)) if (deadband == None): return "READY" mysp = self.controller.get_setpoint(self) if (mysp == None) : return "READY" if math.fabs(self.controller.read_output(self) - mysp) <= deadband: return "READY" else: return "RUNNING"
def _get_tns(self, axis): """Get Normalized Input Signal Value. Loop 10 times to straighten out noise""" accu = 0 for _ in range(10): time.sleep(0.01) _ans = self.command("TNS? %s" % axis.channel) #elog.debug("TNS? %d : %r" % (axis.channel, _ans)) if _ans != '0': accu += float(_ans) accu /= 2 elog.debug("TNS? %r" % accu) # during tests with the piezojack, problems with a blocked socket # towards the controller were encountered. Usually, that was # manifesting with 0 TNS readings. If The accumulated value of # TNS is 0, we're pretty sure the connection is broken. # Use self.finalize() to close the socket, it should be reopened # by the next communication attempt. if accu == 0: elog.info( "%s##########################################################%s" % (bcolors.GREEN + bcolors.BOLD, bcolors.ENDC)) elog.info( "%sPIEZO READ TNS, accu is zero, resetting socket connection!%s" % (bcolors.GREEN + bcolors.BOLD, bcolors.ENDC)) elog.info( "%s##########################################################%s" % (bcolors.GREEN + bcolors.BOLD, bcolors.ENDC)) self.finalize() return accu
def __init__(self, *args, **kwargs): Controller.__init__(self, *args, **kwargs) self._axis_moves = {} self.__encoders = {} # Custom attributes. self.__voltages = {} self.__cust_attr_float = {} self.__error_mode = False self._hw_state = AxisState("READY") self.__hw_limit = (None, None) self._hw_state.create_state("PARKED", "mot au parking") # Access to the config. try: self.host = self.config.get("host") except: elog.debug("no 'host' defined in config for %s" % self.name) # Adds Mockup-specific settings. self.axis_settings.add('init_count', int) self.axis_settings.add('hw_position', float)
def initialize_axis(self, axis): axis.channel = axis.config.get("channel", int) # Stores one axis to talk to the controller. if axis.channel == 1: self.ctrl_axis = axis elog.debug("AX CH =%r" % axis.channel)
def state_input(self, tinput): """Get the status of a Input object """ log.debug("mockup: state Input") print "host is %s" % self.host return "READY"
def setpoint_abort(self, toutput): """Aborting the setpoint on an Output object """ channel = toutput.config.get("channel", str) log.debug("mockup: abort: %s" % (channel)) self.setpoint_stop(toutput)
def set(self, toutput, sp, **kwargs): """Setting a setpoint as quickly as possible """ if kwargs.has_key("ramp"): self.set_ramprate(toutput, kwargs["ramp"]) if kwargs.has_key("dwell"): self.set_dwell(toutput, kwargs["dwell"]) if kwargs.has_key("step"): self.set_step(toutput, kwargs["step"]) channel = toutput.config.get("channel", str) log.debug("mockup: set %s on channel %s" % (sp, channel)) #print kwargs start_temp = self.read_output(toutput) delta = sp - start_temp start_time = time.time() self.setpoints[channel].update({ "setpoint":sp, \ "t0":start_time, \ "sign":math.copysign(1, delta), \ "start_temp":start_temp , \ "target":sp}) #simulate we reached the setpoint self.setpoints[channel]["end_time"] = start_time self.setpoints[channel]["temp"] = sp
def _set_closed_loop(self, axis, onoff=True): """ Sets Closed loop status (Servo state) (SVO command) """ axis.closed_loop = onoff self.command("SVO %s %d" % (axis.channel, onoff)) elog.debug("Piezo Servo %r" % onoff) # Only when closing loop: waits to be ON-Target. if onoff: _t0 = time.time() cl_timeout = .5 _ont_state = self._get_on_target_status(axis) elog.info(u'axis {0:s} waiting to be ONTARGET'.format(axis.name)) while (not _ont_state) and (time.time() - _t0) < cl_timeout: time.sleep(0.01) print ".", _ont_state = self._get_on_target_status(axis) if not _ont_state: elog.error('axis {0:s} NOT on-target'.format(axis.name)) raise RuntimeError("Unable to close the loop : " "not ON-TARGET after %gs :( " % cl_timeout) else: elog.info('axis {0:s} ONT ok after {1:g} s'.format( axis.name, time.time() - _t0)) # Updates bliss setting (internal cached) position. axis._position() # "POS?"
def _setpoint_state(self, deadband): """ Return a string representing the setpoint state of an Output class type object. If a setpoint is set (by ramp or by direct setting) on an ouput, the status will be RUNNING until it is in the deadband. This RUNNING state is used by the ramping event loop in the case a user wants to block on the Output ramp method (wait=True) If deadband is None, returns immediately READY Args: toutput: Output class type object deadband: deadband attribute of toutput. Returns: object state string: READY/RUNNING from [READY/RUNNING/ALARM/FAULT] """ log.debug("On output:_setpoint_state: %s" % (deadband)) if (deadband == None): return "READY" mysp = self.controller.get_setpoint(self) if (mysp == None): return "READY" if math.fabs(self.controller.read_output(self) - mysp) <= deadband: return "READY" else: return "RUNNING"
def stop(self, motion): elog.debug("stop() called") error, reply = self.__xps.GroupMoveAbort(motion.axis.group + '.' + motion.axis.name) if error == -22: elog.info("NewportXPS: All positioners idle") elif error != 0 and error != -22: elog.error("NewportXPS Error: ", reply)
def move(self, user_target_pos, wait=True, relative=False, polling_time=DEFAULT_POLLING_TIME): """ Move axis to the given absolute/relative position Args: user_target_pos: destination (user units) Keyword Args: wait (bool): wait or not for end of motion relative (bool): False if *user_target_pos* is given in absolute \ position or True if it is given in relative position polling_time (float): motion loop polling time (seconds) """ elog.debug("user_target_pos=%g wait=%r relative=%r" % (user_target_pos, wait, relative)) motion = self.prepare_move(user_target_pos, relative) if motion is None: return with error_cleanup(self._cleanup_stop): self.__controller.start_one(motion) motion_task = self._start_move_task(self._do_handle_move, motion, polling_time, being_waited=wait) motion_task._motions = [motion] if wait: self.wait_move()
def _handle_move(self, motion, polling_time): state = self._move_loop(polling_time) if state in ['LIMPOS', 'LIMNEG']: raise RuntimeError(str(state)) # gevent-atomic stopped, self.__stopped = self.__stopped, False if stopped or motion.backlash: dial_pos = self._read_dial_and_update() user_pos = self.dial2user(dial_pos) if motion.backlash: # broadcast reached position before backlash correction backlash_start = motion.target_pos if stopped: self._set_position(user_pos + self.backlash) backlash_start = dial_pos * self.steps_per_unit # axis has moved to target pos - backlash (or shorter, if stopped); # now do the final motion (backlash) relative to current/theo. pos elog.debug("doing backlash (%g)" % motion.backlash) return self._backlash_move(backlash_start, motion.backlash, polling_time) elif stopped: self._set_position(user_pos) elif self.config.get("check_encoder", bool, False) and self.encoder: self._do_encoder_reading() else: return state
def read_velocity(self, axis): """ Args: - <axis> : Bliss axis object. Returns: - <velocity> : float """ _ans = self.send(axis, "?VEL") # _ans should looks like '0.2 0.1' (yes with single quotes arround...) # First field is velocity (in V/ms) # Second field is "line waiting" (hummmm second field is not always present ???) _ans = _ans[1:][:-1] # (_vel, _line_waiting) = map(float, _ans.split()) _float_ans = map(float, _ans.split()) if len(_float_ans) == 1: _vel = _float_ans[0] elif len(_float_ans) == 2: (_vel, _line_waiting) = _float_ans else: print "WHAT THE F.... ?VEL answer is there ???" # V/s = V/ms * 1000 _velocity = _vel * 1000 elog.debug("read_velocity : %g " % _velocity) return _velocity
def wait(self): """ Waits on a setpoint task """ log.debug("On Output:wait") try: self.__setpoint_event.wait() except KeyboardInterrupt: self.stop()
def start_all(self, *motion_list): elog.debug("start_all() called") target_positions = [0, 0] for motion in motion_list: target_positions[int(motion.axis.channel)-1] = motion.target_pos error, reply = self.__xps.GroupMoveAbsolute(motion.axis.group, target_positions) if error != 0: elog.error("NewportXPS Error: ", reply)
def event_list(self, axis): error, reply = self.__xps.EventExtendedAllGet() if error == -83: elog.debug("NewportXPS: No events in list") elif error != 0: elog.error("NewportXPS Error: ", reply) else: elog.debug("Event id list: ", reply)
def stop(self, axis): """ * HLT -> stop smoothly * STP -> stop asap * 24 -> stop asap """ elog.debug("Stopping Piezo by opening loop") self._set_closed_loop(self, axis, False)