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