def _check_start_status(self): if hasattr(self, '_HW_readStatusWord'): self.log.debug('_check_start_status') stat = self._HW_readStatusWord() if stat & (1 << 10): raise MoveError('Limit switch hit by HW') if stat & (1 << 11): raise MoveError('stop issued') if stat & (1 << 12): raise MoveError('Target ignored by HW')
def doStart(self, target): self.log.debug('SingleMotorOfADoubleMotorNOK for %s to %s', self.name, target) if self._seq_is_running(): raise MoveError(self, 'Cannot start device, it is still moving!') incmin, incmax = self._attached_both.inclinationlimits both = self._attached_both port = self._attached_both._attached_device if self.index == 1: code = 0x204 inclination = both.read(0)[0] else: code = 0x104 inclination = both.read(0)[1] self.log.debug('code 0x%03X d%d', code, code) inclination = target - inclination if incmin > inclination: brother = target - incmin / 2 elif incmax < inclination: brother = target - incmax / 2 else: self.log.debug('legal driving range') port._startSequence( port._generateSequence([target + both.masks[both.mode]], [self.index], code)) return self.log.debug('brother move %.2f', brother) if self.index == 1: both.move([brother, target]) else: both.move([target, brother])
def _checkDragerror(self): """Check if a "drag error" occurred. The values of motor and coder deviate too much. This indicates that the movement is blocked. This method sets the error state and returns False if a drag error occurs, and returns True otherwise. """ if self._maxdiff <= 0: return True diff = abs(self._attached_motor.read() - self._attached_coder.read()) self.log.debug('motor/coder diff: %s', diff) if diff > self._maxdiff: self._errorstate = MoveError( self, 'drag error (primary coder): ' 'difference %.4g, maximum %.4g' % (diff, self._maxdiff)) return False for obs in self._attached_obs: diff = abs(self._attached_motor.read() - obs.read()) if diff > self._maxdiff: self._errorstate = PositionError( self, 'drag error (%s): difference %.4g, maximum %.4g' % (obs.name, diff, self._maxdiff)) return False return True
def _startRaw(self, pos): if self._seq_is_running(): if self._mode == SIMULATION: self._seq_thread.join() self._seq_thread = None else: raise MoveError( self, 'Cannot start device, sequence is still ' 'running (at %s)!' % self._seq_status[1]) # switch det_img alias synchronously, the chopper sets its mode param! det_img_alias = session.getDevice('det_img') if pos[3]: det_img_alias.alias = 'det_img_jum' else: det_img_alias.alias = 'det_img_ge' seq = [] seq.append(SeqDev(self._attached_attenuator, pos[4])) if pos[3]: seq.append( SeqDev(self._attached_det_z, self.detbackpos, stoppable=True)) seq.append(SeqDev(self._attached_psd_y, pos[1], stoppable=True)) seq.append(SeqDev(self._attached_psd_x, pos[0], stoppable=True)) else: seq.append(SeqDev(self._attached_psd_x, 0, stoppable=True)) seq.append( SeqDev(self._attached_psd_y, self.psdtoppos, stoppable=True)) seq.append(SeqDev(self._attached_bs_y, pos[1], stoppable=True)) seq.append(SeqDev(self._attached_bs_x, pos[0], stoppable=True)) seq.append(SeqDev(self._attached_det_z, pos[2], stoppable=True)) # maybe reposition beamstop Y axis to counter jitter. seq.append(SeqCall(self._check_bsy, pos[1])) self._startSequence(seq)
def _checkMoveToTarget(self, target, pos): """Check that the axis actually moves towards the target position. This method sets the error state and returns False if a drag error occurs, and returns True otherwise. """ delta_last = self._lastdiff delta_curr = abs(pos - target) self.log.debug('position delta: %s, was %s', delta_curr, delta_last) # at the end of the move, the motor can slightly overshoot during # movement we also allow for small jitter, since airpads usually wiggle # a little resulting in non monotonic movement! ok = (delta_last >= (delta_curr - self.jitter)) or \ delta_curr < self.precision # since we allow to move away a little, we want to remember the # smallest distance so far so that we can detect a slow crawl away from # the target which we would otherwise miss self._lastdiff = min(delta_last, delta_curr) if not ok: self._errorstate = MoveError( self, 'not moving to target: ' 'last delta %.4g, current delta %.4g' % (delta_last, delta_curr)) return False return True
def _startRaw(self, pos): if self._seq_is_running(): if self._mode == SIMULATION: self._seq_thread.join() self._seq_thread = None else: raise MoveError( self, 'Cannot start device, sequence is still ' 'running (at %s)!' % self._seq_status[1]) det_z = self._attached_det_z seq = [] seq.append(SeqDev(self._attached_bs_y, pos[1], stoppable=True)) seq.append(SeqDev(self._attached_bs_x, pos[0], stoppable=True)) seq.append(SeqDev(det_z, pos[2], stoppable=True)) # if z has to move, reposition beamstop y afterwards by going to # some other value (damping vibrations) and back if self.beamstopsettlepos is not None and \ abs(det_z.read(0) - pos[2]) > det_z.precision: seq.append( SeqDev(self._attached_bs_y, self.beamstopsettlepos, stoppable=True)) seq.append(SeqSleep(30)) seq.append(SeqDev(self._attached_bs_y, pos[1], stoppable=True)) self._startSequence(seq)
def _checkTargetPosition(self, target, pos, error=True): """Check if the axis is at the target position. This method returns False if not arrived at target, or True otherwise. """ diff = abs(pos - target) prec = self.precision if (0 < prec <= diff) or (prec == 0 and diff): msg = 'precision error: difference %.4g, precision %.4g' % \ (diff, self.precision) if error: self._errorstate = MoveError(msg) else: self.log.debug(msg) return False maxdiff = self.dragerror for obs in self._attached_obs: diff = abs(target - (obs.read() - self.offset)) if 0 < maxdiff < diff: msg = 'precision error (%s): difference %.4g, maximum %.4g' % \ (obs, diff, maxdiff) if error: self._errorstate = PositionError(msg) else: self.log.debug(msg) return False return True
def doStart(self, target): if target == 'open' and not self._attached_data_in.read(0) & 0b100: raise MoveError(self, 'cannot open shutter: set to local mode') # bit 0: data valid, bit 1: open, bit 2: close (inverted) self._attached_data_out.start(0) time.sleep(0.1) self._attached_data_out.start(0b111 if target == 'open' else 0b001)
def doFinish(self): pos = self.read(0) if not self.isAtTarget(pos): raise MoveError( self, 'did not arrive at requested volume, ' 'check end switches!') return False # don't check again
def doReference(self): if self._seq_is_running(): raise MoveError(self, 'Cannot reference a moving device!') seq = self._gen_ref_sequence() if self.autopower == 'on': # disable if requested. seq.append(SeqMethod(self, '_HW_disable')) self._startSequence(seq)
def doStart(self, target): if self._seq_is_running(): if self._mode == SIMULATION: self._seq_thread.join() self._seq_thread = None else: raise MoveError(self, 'Cannot start device, sequence is still ' 'running (at %s)!' % self._seq_status[1]) self._startSequence(self._generateSequence(target))
def doReference(self): """Reference the NOK in a sophisticated way. First we try to reach the lowest point ever needed for referencing, then we reference the lower refpoint first, and the higher later. After referencing is done, we go to (0, 0). """ # XXX: EXTRA BIG TODO !!! if self._seq_is_running(): raise MoveError(self, 'Cannot reference device, it is still ' 'moving!') devices = self._devices refpos = [d.refpos for d in devices] # referencing is easier if device[0].refpos is always lower than # device[1].refpos if refpos[1] < refpos[0]: # wrong order: flip oder of entries devices.reverse() refpos.reverse() # go below lowest interesting point minpos = min(self.read() + refpos + [t + self.backlash for t in refpos]) # build a referencing sequence sequence = [] # go to lowest position first sequence.append([SeqDevMin(d, minpos) for d in devices]) # if one of the motors should have triggered the low-level-switch # move them up a little and wait until the movement has finished sequence.append([ SeqMoveOffLimitSwitch(d, backoffby=self.backlash / 4.) for d in devices ]) # ref lowest position, should finish at refpos[0] # The move should be first, as the referencing may block! sequence.append([ SeqDev(devices[1], refpos[0]), SeqMethod(devices[0], 'reference') ]) # ref highest position, should finish at refpos[1] sequence.append([ SeqDev(devices[0], refpos[1]), SeqMethod(devices[1], 'reference') ]) # fun: move both to 0 sequence.append([SeqDev(d, 0) for d in devices]) # GO self._startSequence(sequence)
def doStart(self, pos): if pos == 'out': self._attached_moveable.start(self.outpos) return respos = self._attached_resolution.target if respos != 'unknown': inpos = self._attached_resolution.presets[respos]['beamstop_x_in'] self._attached_moveable.start(inpos) else: raise MoveError('no position for beamstop, resolution is unknown')
def doStart(self, value, fromvarcheck=False): self._taco_guard(self._dev.write, value + self.offset) session.delay(0.5) # wait until server goes into "moving" status if self.variance > 0: newvalue = self.wait() maxdelta = value * (self.variance/100.) + 0.1 if abs(newvalue - value) > maxdelta: if not fromvarcheck: self.log.warning('value %s instead of %s exceeds variance', newvalue, value) self.doStart(value, fromvarcheck=True) else: raise MoveError(self, 'power supply failed to set correct value')
def doStart(self, pos): # do not start moving if already there, since the stability check in # the SPS always waits if pos == self.target and abs(self.read(0) - pos) < self.precision: return stbits = self._attached_status.read(0) if not stbits & 1: raise MoveError(self, 'selector is in local mode') # valid bit needs a rising edge self._attached_valid.move(0) self._attached_speed.maw(pos) time.sleep(0.2) self._attached_valid.move(1) time.sleep(0.2)
def doStart(self, pos): if self.curstatus[0] == status.DISABLED: raise MoveError(self, 'cannot move, motor is disabled') pos = float(pos) + self.offset if self._thread: self._setROParam('curstatus', (status.BUSY, 'waiting for stop')) self._stop = True self._thread.join() if self.speed != 0: self._setROParam('curstatus', (status.BUSY, 'virtual moving')) self._thread = createThread('virtual motor %s' % self, self.__moving, (pos, )) else: self.log.debug('moving to %s', pos) self._setROParam('curvalue', pos) self._setROParam('curstatus', (status.OK, 'idle'))
def doReference(self): """Reference the NOK. Just set the do_reference bit and wait for completion """ if self._seq_is_running(): raise MoveError(self, 'Cannot reference device, it is still ' 'moving!') # according to docu it is sufficient to set the ref bit of one of the # coupled motors for dev in self._devices: dev._HW_reference() for dev in self._devices: dev.wait()
def doStatus(self, maxage=0): st = TimerChannel.doStatus(self, maxage) # Normal mode: Gate is active if st[0] == status.BUSY: if self.extmode and self.extwait and self._mode == MASTER: self.log.info('external signal arrived, counting...') self.extwait = 0 return st elif self.extmode and self.extwait > 0: # External mode: there is no status indication of "waiting", # so use the time as an indication of wait/done if self._dev.value > 0: return (status.OK, '') elif currenttime() > self.extwait + self.exttimeout: raise MoveError(self, 'timeout waiting for external start') return (status.BUSY, 'waiting for external start') else: return (status.OK, '')
def _doStartPositions(self, positions): if self._seq_is_running(): if self._mode == SIMULATION: self._seq_thread.join() self._seq_thread = None else: raise MoveError( self, 'Cannot start device, sequence is still ' 'running (at %s)!' % self._seq_status[1]) f = self.coordinates == 'opposite' and -1 or +1 tl, tr, tb, tt = positions # determine which axes to move first, so that the blades can # not touch when one moves first cl, cr, cb, ct = [d.read(0) for d in self._axes] cl *= f cb *= f al, ar, ab, at = self._axes seq = [] if tr < cr and tl < cl: # both move to smaller values, need to start right blade first seq.append(SeqDev(al, tl * f)) seq.append(SeqDev(ar, tr)) elif tr > cr and tl > cl: # both move to larger values, need to start left blade first seq.append(SeqDev(ar, tr)) seq.append(SeqDev(al, tl * f)) else: # don't care seq.append(SeqDev(ar, tr)) seq.append(SeqDev(al, tl * f)) if tb < cb and tt < ct: seq.append(SeqDev(ab, tb * f)) seq.append(SeqDev(at, tt)) elif tb > cb and tt > ct: seq.append(SeqDev(at, tt)) seq.append(SeqDev(ab, tb * f)) else: seq.append(SeqDev(at, tt)) seq.append(SeqDev(ab, tb * f)) self._startSequence(seq)
def doStart(self, targets): """Generate and start a sequence if none is running. The sequence is optimised for negative backlash. It will first move both motors to the lowest value of (target + backlash, current_position) and then to the final target. So, inbetween, the NOK should be parallel to the beam. MP 12.12.2017 09:16:05 """ if self._seq_is_running(): raise MoveError(self, 'Cannot start device, it is still moving!') # check precision, only move if needed! traveldists = [ target - dev.read(0) - ofs for target, dev, ofs in zip(targets, self._devices, self.offsets) ] if max(abs(v) for v in traveldists) <= self.precision: return devices = self._devices # XXX: backlash correction and repositioning later # build a moving sequence sequence = [] # now go to target sequence.append([ SeqDev(d, t + ofs, stoppable=True) for d, t, ofs in zip(devices, targets, self.offsets) ]) # now go to target again sequence.append([ SeqDev(d, t + ofs, stoppable=True) for d, t, ofs in zip(devices, targets, self.offsets) ]) self.log.debug('Seq: %r', sequence) self._startSequence(sequence)
def doStart(self, target): if self._seq_is_running(): raise MoveError(self, 'Cannot start device, it is still moving!') self._startSequence(self._gen_move_sequence(target))
def _check_speed(self): if self._attached_selector.read(0) > self.maxtiltspeed + 50: raise MoveError(self, 'selector not in safe speed range')
def doStart(self, pos): if self._attached_is_enabled.read(): return MappedMoveable.doStart(self, pos) raise MoveError(self, 'Device is disabled')
def doStart(self, target): self.log.debug('DoubleMotorBeckhoff move to %s', target) if self._seq_is_running(): raise MoveError(self, 'Cannot start device, it is still moving!') self._startSequence(self._generateSequence(target, [0, 1], 0x304))
def doStart(self, value): if self._get_pv('drivepv') != 1: raise MoveError('Chopper drive must be active to change phase') self._put_pv('writepv', value)
def doStart(self, pos): """go to a absolute postition""" if self.doStatus(0)[0] != status.OK: raise MoveError('Can not start, please check status!') pos = int(pos * self.slope * self.microstep) self.comm('XE%d' % pos)