phytron next version
with adaption of HasStates Change-Id: I167ac8031bc5f7120c30031e7cfcb7587b42b61d
This commit is contained in:
parent
df4a37085a
commit
050a2dc8dc
@ -183,12 +183,13 @@ class HasStates:
|
||||
override for code to be executed after stopping
|
||||
"""
|
||||
|
||||
def start_machine(self, statefunc, fast_poll=True, **kwds):
|
||||
def start_machine(self, statefunc, fast_poll=True, restart_text='restarting', **kwds):
|
||||
"""start or restart the state machine
|
||||
|
||||
:param statefunc: the initial state to be called
|
||||
:param fast_poll: flag to indicate that polling has to switched to fast
|
||||
:param cleanup: a cleanup function
|
||||
:param restart_text: status text when machine was already running
|
||||
:param kwds: attributes to be added to the state machine on start
|
||||
|
||||
If the state machine is already running, the following happens:
|
||||
@ -202,9 +203,10 @@ class HasStates:
|
||||
4) the state machine continues at the given statefunc
|
||||
"""
|
||||
sm = self._state_machine
|
||||
sm.status = self.get_status(statefunc, BUSY)
|
||||
if sm.statefunc:
|
||||
sm.status = sm.status[0], 'restarting'
|
||||
sm.status = sm.status[0], restart_text
|
||||
else:
|
||||
sm.status = self.get_status(statefunc, BUSY)
|
||||
sm.start(statefunc, cleanup=kwds.pop('cleanup', self.on_cleanup), **kwds)
|
||||
self.read_status()
|
||||
if fast_poll:
|
||||
@ -212,24 +214,23 @@ class HasStates:
|
||||
self.setFastPoll(True)
|
||||
self.pollInfo.trigger(True) # trigger poller
|
||||
|
||||
def stop_machine(self, stopped_status=(IDLE, 'stopped')):
|
||||
def stopping(self, sm):
|
||||
return self.final_status(IDLE, 'stopped')
|
||||
|
||||
def stop_machine(self):
|
||||
"""stop the currently running machine
|
||||
|
||||
:param stopped_status: status to be set after stopping
|
||||
|
||||
If the state machine is not running, nothing happens.
|
||||
Else the state machine is stoppen, the predefined cleanup
|
||||
Else the state machine is stopped, the predefined cleanup
|
||||
sequence is executed and then the status is set to the value
|
||||
given in the sopped_status argument.
|
||||
given in the stopped_status argument.
|
||||
An already running cleanup sequence is not executed again.
|
||||
"""
|
||||
sm = self._state_machine
|
||||
if sm.is_active:
|
||||
sm.idle_status = stopped_status
|
||||
sm.stop()
|
||||
sm.status = self.get_status(sm.statefunc, sm.status[0])[0], 'stopping'
|
||||
self.read_status()
|
||||
self.pollInfo.trigger(True) # trigger poller
|
||||
self.start_machine(self.stopping, restart_text='stopping')
|
||||
|
||||
@Command
|
||||
def stop(self):
|
||||
|
@ -77,11 +77,11 @@ class Motor(HasOffset, HasStates, PersistentMixin, HasIO, Drivable):
|
||||
target_max = Limit()
|
||||
alive_time = PersistentParam('alive time for detecting restarts',
|
||||
FloatRange(), default=0, export=False)
|
||||
sim_error = Parameter('run time error simulation', StringType(), readonly=False, default='')
|
||||
|
||||
ioClass = PhytronIO
|
||||
_step_size = None # degree / step
|
||||
_reset_needed = False
|
||||
_blocking_error = None # None or a string indicating the reason of an error needing reset
|
||||
_running = False # status indicates motor is running
|
||||
|
||||
STATUS_MAP = {
|
||||
'08': (IDLE, ''),
|
||||
@ -119,7 +119,7 @@ class Motor(HasOffset, HasStates, PersistentMixin, HasIO, Drivable):
|
||||
self.set('P37S', axisbit | active_axes) # activate axis
|
||||
if now < self.alive_time + 7 * 24 * 3600: # the device was running within last week
|
||||
# inform the user about the loss of position by the need of doing reset_error
|
||||
self._reset_needed = True
|
||||
self._blocking_error = 'lost position'
|
||||
else: # do reset silently
|
||||
self.reset_error()
|
||||
self.alive_time = now
|
||||
@ -167,9 +167,8 @@ class Motor(HasOffset, HasStates, PersistentMixin, HasIO, Drivable):
|
||||
|
||||
def write_target(self, value):
|
||||
self.read_alive_time()
|
||||
if self._reset_needed:
|
||||
if not self.status[1].startswith('reset needed'):
|
||||
self.status = ERROR, 'reset needed after ' + self.status[1]
|
||||
if self._blocking_error:
|
||||
self.status = ERROR, 'reset needed after ' + self._blocking_error
|
||||
raise HardwareError(self.status[1])
|
||||
self.saveParameters()
|
||||
if self.backlash:
|
||||
@ -180,17 +179,16 @@ class Motor(HasOffset, HasStates, PersistentMixin, HasIO, Drivable):
|
||||
else:
|
||||
self.set('A', self.sign * value)
|
||||
self.start_machine(self.driving)
|
||||
self._running = True
|
||||
return value
|
||||
|
||||
def read_status(self):
|
||||
if self.sim_error:
|
||||
sysstatus = self.sim_error
|
||||
else:
|
||||
sysstatus = self.communicate(f'{self.address:x}SE')
|
||||
sysstatus = sysstatus[2:4] if self.axis == 'X' else sysstatus[6:8]
|
||||
status = self.STATUS_MAP.get(sysstatus) or (ERROR, f'unknown error {sysstatus}')
|
||||
sysstatus = self.communicate(f'{self.address:x}SE')
|
||||
sysstatus = sysstatus[1:4] if self.axis == 'X' else sysstatus[5:8]
|
||||
self._running = sysstatus[0] != '1'
|
||||
status = self.STATUS_MAP.get(sysstatus[1:]) or (ERROR, f'unknown error {sysstatus[1:]}')
|
||||
if status[0] == ERROR:
|
||||
self._reset_needed = True
|
||||
self._blocking_error = status[1]
|
||||
return status
|
||||
return super().read_status() # status from state machine
|
||||
|
||||
@ -200,8 +198,7 @@ class Motor(HasOffset, HasStates, PersistentMixin, HasIO, Drivable):
|
||||
enc = self.read_encoder()
|
||||
else:
|
||||
enc = self.value
|
||||
status = self.get('=H')
|
||||
if status != 'N': # at target
|
||||
if not self._running: # at target
|
||||
return False
|
||||
if self.encoder_mode != 'CHECK':
|
||||
return True
|
||||
@ -212,8 +209,8 @@ class Motor(HasOffset, HasStates, PersistentMixin, HasIO, Drivable):
|
||||
self.value, e1, e2)
|
||||
self.get('S') # stop
|
||||
self.saveParameters()
|
||||
self._reset_needed = True
|
||||
raise HardwareError('encoder lag error')
|
||||
self._blocking_error = 'encoder lag error'
|
||||
raise HardwareError(self._blocking_error)
|
||||
|
||||
@status_code(BUSY)
|
||||
def driving(self, sm):
|
||||
@ -243,21 +240,29 @@ class Motor(HasOffset, HasStates, PersistentMixin, HasIO, Drivable):
|
||||
if sm.mismatch_count > 2:
|
||||
self.log.error('encoder mismatch: abs(%g - %g) < %g',
|
||||
enc, pos, self.encoder_tolerance)
|
||||
self._reset_needed = True
|
||||
raise HardwareError('encoder does not match pos')
|
||||
self._blocking_error = 'encoder does not match pos'
|
||||
raise HardwareError(self._blocking_error)
|
||||
sm.mismatch_count += 1
|
||||
return Retry
|
||||
self.saveParameters()
|
||||
return self.final_status(IDLE, '')
|
||||
|
||||
@status_code(BUSY)
|
||||
def stopping(self, sm):
|
||||
if self._running:
|
||||
return Retry
|
||||
return self.final_status(IDLE, 'stopped')
|
||||
|
||||
@Command
|
||||
def stop(self):
|
||||
self.get('S')
|
||||
self.start_machine(self.stopping, status=(BUSY, 'stopping0'))
|
||||
|
||||
@Command
|
||||
def reset_error(self):
|
||||
"""Reset error, set position to encoder"""
|
||||
self.read_value()
|
||||
if self._reset_needed:
|
||||
if self._blocking_error:
|
||||
newenc = enc = self.read_encoder()
|
||||
pos = self.value
|
||||
if abs(enc - pos) > self.encoder_tolerance or self.encoder_mode == 'NO':
|
||||
@ -278,7 +283,7 @@ class Motor(HasOffset, HasStates, PersistentMixin, HasIO, Drivable):
|
||||
self.set('P20S', newenc * self.sign) # set pos to encoder
|
||||
self.read_value()
|
||||
self.status = 'IDLE', 'after error reset'
|
||||
self._reset_needed = False
|
||||
self._blocking_error = None
|
||||
|
||||
# TODO:
|
||||
# '=E' electronics status
|
||||
|
Loading…
x
Reference in New Issue
Block a user