3636# so far very basic support for stages
3737# no support for filter, shutters, or slide loader as I dont have hardware
3838
39- # Issues to fix
40- # very slow in mosaic
41- # No limit support
42- # what is scaling?
43-
44-
45- # commands
46- # Where X - A: 12000
47- # Where X Y - :A -2000 1000
48- # Where X Y - :A -2000 N-2 # Y axis no installed N-2 is error -2
49-
39+ # Note:
5040# commands end in a '\r' but replies return ending in '\n'!
5141
5242# errors
6555# end limit, etc….)
6656# -17 Initialization erro
6757
68- # MOVE X=2000 - A: positive reply? need to check movement is finished.
69- # VMOVE X=1 y=2 -
70- # MOVREL
71- # REMRES - reset controller.
72-
73- #suggested startup routine for stage which will explore the extremes
74- #and then move stage to center and set that as 0,0
75- #"CENTER X=100000 Y=100000"
76- #"HERE X=0 Y=0"
77- #
58+ #On startup the stage move to extremes to find limits and then sets
59+ # the -ve limit on each axis to 0.
7860
7961LUDL_ERRORS = { - 1 : 'Unknown command' ,
80- - 2 : 'Illegal point type or axis, or module not installed' ,
81- - 3 : 'Not enough parameters (e.g. move r=)' ,
82- - 4 : 'Parameter out of range' ,
83- - 21 : 'Process aborted by HALT command' ,
84- }
62+ - 2 : 'Illegal point type or axis, or module not installed' ,
63+ - 3 : 'Not enough parameters (e.g. move r=)' ,
64+ - 4 : 'Parameter out of range' ,
65+ - 21 : 'Process aborted by HALT command' ,
66+ # Slide Loader:
67+ #-4:, (parameter out of range) used for cassette or slot range errors
68+ - 10 : 'No slides selected' ,
69+ - 11 : 'End of list reached' ,
70+ - 12 : 'Slide error' ,
71+ - 16 : 'Motor move error (move not completed successfully due to stall, end limit, etc.' ,
72+ - 17 : 'Initialization error' ,
73+ }
8574
8675AXIS_MAPPER = { 1 : 'X' ,
8776 2 : 'Y' ,
@@ -118,6 +107,7 @@ def __init__(self, port: str, baudrate: int, timeout: float) -> None:
118107 dsrdtr = False ,
119108 )
120109 self ._lock = threading .RLock ()
110+ self .homed = False
121111
122112 with self ._lock :
123113 # We do not use the general get_description() here because
@@ -138,42 +128,17 @@ def __init__(self, port: str, baudrate: int, timeout: float) -> None:
138128 # dev address,label,id,description, type
139129 self ._devlist [devinfo [0 ]]= devinfo [1 :]
140130
131+ # print(answer)
141132
142- # ['EMOT', 'X', 'X axis stage', 'MCMSE']
143- # >>> devinfo[0]
144- # '1'
145- # >>> answer[3]
146- # b''
147- # >>> answer[4]
148- # b'1 EMOT X X axis stage MCMSE'
149- # >>> answer[5]
150- # b'2 EMOT Y Y axis stage MCMSE'
151- # >>> answer[6]
152- # b'3 EMOT B B aux motor MCMSE'
153- # >>> answer[7]
154- # b'7 HSMOT T T rotation robot MCMSE **** Should be T rot'
155-
156- # for dev in self._devlist:
157-
158-
159- print (answer )
160- # if answer != b"PROSCAN INFORMATION\r":
161- # self.read_until_timeout()
162- # raise RuntimeError(
163- # "Not a ProScanIII device: '?' returned '%s'"
164- # % answer.decode()
165- # )
166- # # A description ends with END on its own line.
167- # line = self._serial.read_until(b"\rEND\r")
168- # if not line.endswith(b"\rEND\r"):
169- # raise RuntimeError("Failed to clear description")
170133
171134 def is_busy (self ):
172135 pass
173136
137+ def been_homed (self ):
138+ return self .homed
139+
174140 def get_number_axes (self ):
175141 return 2
176-
177142
178143 def command (self , command : bytes ) -> None :
179144 """Send command to device."""
@@ -193,8 +158,12 @@ def read_multiline(self):
193158 output .append (line .strip ())
194159 if line == b'N' or line [0 :2 ] == b':A' :
195160 #thins means an end of command strings doesn require an
196- #addition timeout before it returns
161+ #additional timeout before it returns
197162 return (output )
163+ elif line [0 ] == b'N' :
164+ #this is an error string
165+ error = line [2 :].strip ()
166+ raise ('Ludl controller error: %s,%s' % (error ,LUDL_ERRORS [error ]))
198167 return (output )
199168
200169 def read_until_timeout (self ) -> None :
@@ -310,8 +279,9 @@ def __init__(self, dev_conn: _LudlController, axis: str) -> None:
310279 # not a good solution as min/max are used to build the stage map in
311280 # mosaic etc... Maybe we just need to know it!
312281 self .min_limit = 0.0
313- self .max_limit = 0 .0
282+ self .max_limit = 100000 .0
314283 self .set_speed (100000 )
284+ self .home ()
315285
316286 def move_by (self , delta : float ) -> None :
317287 self ._dev_conn .move_by_relative_position (self ._axis , int (delta ))
@@ -330,11 +300,16 @@ def position(self) -> float:
330300 def limits (self ) -> microscope .AxisLimits :
331301 return microscope .AxisLimits (lower = self .min_limit , upper = self .max_limit )
332302
303+ # def speed(self) -> int:
304+ # return self.speed
305+
306+
333307 def home (self ) -> None :
334308 self .find_limits ()
335309 self .move_to (self .max_limit / 2 )
336310
337311 def set_speed (self , speed : int ) -> None :
312+ self .speed = speed
338313 self ._dev_conn .set_speed (self ._axis , speed )
339314
340315 def find_limits (self ,speed = 100000 ):
@@ -347,6 +322,7 @@ def find_limits(self,speed = 100000):
347322 print (self .position )
348323 self ._dev_conn .reset_position (self ._axis )
349324 self .min_limit = 0.0
325+ self ._dev_conn .homed = True
350326 # move to positive limit
351327 self ._dev_conn .move_to_limit (self ._axis ,speed )
352328 self ._dev_conn .wait_for_motor_stop (self ._axis )
@@ -373,8 +349,8 @@ def _do_enable(self) -> bool:
373349 # Before a device can moved, it first needs to establish a
374350 # reference to the home position. We won't be able to move
375351 # unless we home it first.
376- # if not self._dev_conn.been_homed():
377- # self._dev_conn .home()
352+ if not self ._dev_conn .been_homed ():
353+ self .home ()
378354 return True
379355
380356 @property
@@ -398,8 +374,11 @@ def move_to(self, position: typing.Mapping[str, float]) -> None:
398374 )
399375 self ._dev_conn .wait_until_idle ()
400376
401-
402-
377+ def home (self ,axes = None ):
378+ if axes == None :
379+ axes = self .axes
380+ for axis in axes :
381+ self .axes [axis ].home ()
403382
404383# def assert_filterwheel_number(self, number: int) -> None:
405384# assert number > 0 and number < 4
0 commit comments