def test_move_update(self): child = simulated.Stage("stage", "test", axes=["z"]) # Slow speed to give some chance of the move update to work child.speed.value = {"z": 100e-6} stage = AntiBacklashActuator("absact", "abs", {"orig": child}, backlash={"z": 100e-6}) self.called = 0 orig_pos = stage.position.value stage.position.subscribe(self._on_position) for i in range(10): if i % 2: d = 1 else: d = -1 dist = d * (i + 1) * 10e-6 f = stage.moveRel({"z": dist}, update=True) time.sleep(0.05) # 50 ms for 'user update' f = stage.moveAbs(orig_pos, update=True) f.result() # If there is an antibacklash for each move against backlash, we should # see ~ 16 moves. If only an antibacklash at the last move # (or integrated in last move), we should see 11 or 12 moves. self.assertLessEqual(self.called, 12) test.assert_pos_almost_equal(child.position.value, orig_pos) stage.terminate()
def test_move_rel(self): # Test relative moves self.dev.moveAbs({ 'x': 0, 'y': 0, 'z': 0, 'rx': 0, 'ry': 0, 'rz': 0 }).result() old_pos = self.dev.position.value shift = {'x': 0.01, 'y': -0.001, 'ry': -0.0003, 'rz': 0} self.dev.moveRel(shift).result() new_pos = self.dev.position.value test.assert_pos_almost_equal(smaract.add_coord(old_pos, shift), new_pos, **COMP_ARGS) # Test several relative moves and ensure they are queued up. old_pos = self.dev.position.value shift = { 'z': -0.000001, 'rx': 0.00001, 'ry': -0.000001, 'rz': -0.00001 } self.dev.moveRel(shift) self.dev.moveRel(shift) self.dev.moveRel(shift).result() new_pos = smaract.add_coord( smaract.add_coord(smaract.add_coord(old_pos, shift), shift), shift) test.assert_pos_almost_equal(self.dev.position.value, new_pos, **COMP_ARGS)
def test_auto_update_function(self): self.dev.moveAbs({"x": 0.0, "y": 0.0, "z": 0.0}).result() pos_before_move = self.dev.position.value rel_move = {"z": 5e-6} expected_pos = pos_before_move.copy() expected_pos["z"] += rel_move["z"] self.dev.moveRel(rel_move).result() # the position updater function is called every 1 sec, wait a bit more. time.sleep(2) pos_after_move = self.dev.position.value test.assert_pos_almost_equal(expected_pos, pos_after_move, **COMP_ARGS)
def test_position_abs(self): """ Test moving to an absolute position. """ exp_pos = self.dev.position.value.copy() for pos in (0, 0.1, 0.15, -0.1, 0): new_pos = {'x': pos} f = self.dev.moveAbs(new_pos) f.result() exp_pos["x"] = pos test.assert_pos_almost_equal(self.dev.position.value, exp_pos, **COMP_ARGS)
def test_reference_and_deactivate_move(self): # Set a deactive position and check to be sure that the controller moves to this location # after a reference move de_pos = {'x': 0, 'y': -1.2e-4, 'z': 0} self.dev.updateMetadata({model.MD_FAV_POS_DEACTIVE: de_pos}) f = self.dev.reference(set(self.dev.axes.keys())) f.result() test.assert_pos_almost_equal(self.dev.position.value, de_pos, **COMP_ARGS)
def test_pivot_set(self): # Test setting the pivot to some value through metadata old_pos = self.dev.position.value new_pivot = {'x': 0.05, 'y': 0.05, 'z': 0.01} self.dev.updateMetadata({model.MD_PIVOT_POS: new_pivot}) test.assert_pos_almost_equal(old_pos, self.dev.position.value, **COMP_ARGS) old_pos = self.dev.position.value new_pivot = {'x': 0.01, 'y':-0.05, 'z': 0.01} self.dev.updateMetadata({model.MD_PIVOT_POS: new_pivot}) test.assert_pos_almost_equal(old_pos, self.dev.position.value, **COMP_ARGS)
def test_moveAbs(self): # It's optional if not hasattr(self.dev, "moveAbs"): self.skipTest("Actuator doesn't support absolute move") move = {} # move to the centre for axis in self.dev.axes: rng = self.dev.axes[axis].range move[axis] = (rng[0] + rng[1]) / 2 f = self.dev.moveAbs(move) f.result() # wait test.assert_pos_almost_equal(move, self.dev.position.value, atol=1e-7)
def test_offset(self): # Start near the origin self.dev.moveAbs({'x': 0.01}).result() logging.info("POSITION = %s", self.dev.position.value) # Bad offset with self.assertRaises(ValueError): self.dev.updateMetadata({model.MD_POS_COR: 5}) # Test offset #1 old_pos = self.dev.position.value offset_1 = {'x': 0.05} self.dev.updateMetadata({model.MD_POS_COR: offset_1}) test.assert_pos_almost_equal(subtract_coord(old_pos, offset_1), self.dev.position.value, **COMP_ARGS) # Test offset #2 old_pos = self._getRealPosition() offset_2 = {'x':-0.05} self.dev.updateMetadata({model.MD_POS_COR: offset_2}) exp_pos = subtract_coord(old_pos, offset_2) test.assert_pos_almost_equal(exp_pos, self.dev.position.value, **COMP_ARGS) # now move to the origin new_pos = {'x': 0} f = self.dev.moveAbs(new_pos) f.result() exp_pos = self.dev.position.value.copy() exp_pos["x"] = 0 test.assert_pos_almost_equal(exp_pos, self.dev.position.value, **COMP_ARGS) exp_real = self.dev.position.value.copy() exp_real.update(offset_2) test.assert_pos_almost_equal(exp_real, self._getRealPosition(), **COMP_ARGS) # Remove the offset self.dev.updateMetadata({model.MD_POS_COR: {'x': 0}})
def test_smaract_stage_fallback_movement(self): """ Test behaviour of smaract 5dof stage when the linear axes are near the maximum range """ # 1. Move to imaging position cryoSwitchSamplePosition(IMAGING).result() # 2. Move the stage linear axes to their max range + move rx from 0 cryoSwitchAlignPosition(LOADING).result() self.stage.moveAbs({'x': self.stage.axes['x'].range[1], 'y': self.stage.axes['y'].range[1], 'z': self.stage.axes['z'].range[1], 'rx': 0.15}).result() # 3. Move to loading where the ordered submoves would start from rx/rx, resulting in an invalid move # exception if it's not handled cryoSwitchSamplePosition(LOADING).result() test.assert_pos_almost_equal(self.stage.position.value, self.stage_deactive, atol=ATOL_LINEAR_POS)
def test_position_rel(self): """ Test moving to a relative position. """ # Start at the origin to prevent hitting the ends self.dev.moveAbs({'x': 0.3}).result() # Test another relative move for shift in (0, 0.12, -0.12): new_shift = {'x': shift} old_pos = self.dev.position.value f = self.dev.moveRel(new_shift) f.result() test.assert_pos_almost_equal(add_coord(old_pos, new_shift), self.dev.position.value, **COMP_ARGS)
def test_moveRel(self): prev_pos = self.dev.position.value move = {} # move by 1% for axis in self.dev.axes: move[axis] = self.dev.axes[axis].range[1] * 0.01 expected_pos = {} for axis in self.dev.axes: expected_pos[axis] = prev_pos[axis] + move[axis] f = self.dev.moveRel(move) f.result() # wait test.assert_pos_almost_equal(expected_pos, self.dev.position.value, atol=1e-7)
def test_reference_and_deactivate_move(self): # Set a deactive position and check to be sure that the controller moves to this location # after a reference move de_pos = {'x': 3.5801e-4, 'y': 0, 'z': 1e-3, 'rx': -1.2e-6, 'rz': 0.0} self.dev.updateMetadata({model.MD_FAV_POS_DEACTIVE: de_pos}) f = self.dev.reference() f.result() for a, i in self.dev.referenced.value.items(): self.assertTrue(i) test.assert_pos_almost_equal(self.dev.position.value, de_pos, **COMP_ARGS)
def test_pivot_set(self): # Check that the pivot position is available from the beginning old_pivot = self.dev.getMetadata()[model.MD_PIVOT_POS] try: # Test setting the pivot to some value through metadata old_pos = self.dev.position.value new_pivot = {'x': 0.05, 'y': 0.05, 'z': 0.01} self.dev.updateMetadata({model.MD_PIVOT_POS: new_pivot}) test.assert_pos_almost_equal(old_pos, self.dev.position.value, **COMP_ARGS) self.dev.moveRelSync({"x": 0}) # WARNING: this can cause a move! test.assert_pos_almost_equal(old_pos, self.dev.position.value, **COMP_ARGS) old_pos = self.dev.position.value new_pivot = {'x': 0.01, 'y': -0.05, 'z': 0.01} self.dev.updateMetadata({model.MD_PIVOT_POS: new_pivot}) test.assert_pos_almost_equal(old_pos, self.dev.position.value, **COMP_ARGS) self.dev.moveRelSync({"x": 0}) # WARNING: this can cause a move! test.assert_pos_almost_equal(old_pos, self.dev.position.value, **COMP_ARGS) finally: self.dev.updateMetadata({model.MD_PIVOT_POS: old_pivot}) self.dev.moveRelSync({"x": 0})
def test_move_abs(self): pos1 = {'x': 0, 'y': 0, 'z': 0, 'rx': 0.001, 'rz': 0.001} pos2 = {'x': 0, 'y': 0, 'z': 0, 'rx': 0, 'rz': 0} pos3 = { 'x': 3.5218e-4, 'y': 1.785e-5, 'z': 1e-3, 'rx': -1e-6, 'rz': -1.253e-6 } # test where not all axes are defined pos4 = {'x': 1e-3, 'rx': 1e-5, 'rz': 0} self.dev.moveAbs(pos1).result() test.assert_pos_almost_equal(self.dev.position.value, pos1, **COMP_ARGS) self.dev.moveAbs(pos2).result() test.assert_pos_almost_equal(self.dev.position.value, pos2, **COMP_ARGS) self.dev.moveAbs(pos3).result() test.assert_pos_almost_equal(self.dev.position.value, pos3, **COMP_ARGS) self.dev.moveAbs(pos4).result() # add missing axes to do the comparison pos4['y'] = pos3['y'] pos4['z'] = pos3['z'] test.assert_pos_almost_equal(self.dev.position.value, pos4, **COMP_ARGS)
def test_move_abs(self): pos1 = {'x': 0, 'y': 0, 'z': 0, 'rx': 0, 'ry': 0, 'rz': 0.0005} pos2 = { 'x': -0.0102, 'y': 0, 'z': 0.0, 'rx': 0.0001, 'ry': 0.0001, 'rz': 0 } pos3 = {'x': 0.0102, 'y': -0.00002, 'z': 0, 'rx': 0, 'ry': 0, 'rz': 0} # test where not all axes are defined pos4 = {'x': 1e-3, 'rx': 1e-5, 'ry': 0, 'rz': 0} self.dev.moveAbs(pos1).result() test.assert_pos_almost_equal(self.dev.position.value, pos1, **COMP_ARGS) self.dev.moveAbs(pos2).result() test.assert_pos_almost_equal(self.dev.position.value, pos2, **COMP_ARGS) self.dev.moveAbs(pos3).result() test.assert_pos_almost_equal(self.dev.position.value, pos3, **COMP_ARGS) self.dev.moveAbs(pos4).result() # add missing axes to do the comparison pos4['y'] = pos3['y'] pos4['z'] = pos3['z'] test.assert_pos_almost_equal(self.dev.position.value, pos4, **COMP_ARGS) logging.debug(self.dev.position.value)
def test_move(self): """ Check it's possible to move the stage """ pos = self.stage.position.value f = self.stage.moveRel({"x":-100e-6, "y":-100e-6}) # 1 mm f.result() # FIXME: this should fail self.assertNotEqual(self.stage.position.value, pos) time.sleep(1) f = self.stage.moveRel({"x":100e-6, "y":100e-6}) # 1 mm f.result() test.assert_pos_almost_equal(self.stage.position.value, pos)
def test_navcam_focus(self): """ Check it's possible to change the overview focus """ pos = self.navcam_focus.position.value f = self.navcam_focus.moveRel({"z": 0.1e-3}) # 1 mm f.result() self.assertNotEqual(self.navcam_focus.position.value, pos) time.sleep(1) # restore original position f = self.navcam_focus.moveAbs(pos) f.result() test.assert_pos_almost_equal(self.navcam_focus.position.value, pos)
def test_position_rel(self): """ Test moving to a relative position. """ # Start at the origin to prevent hitting the ends self.dev.moveAbs({'x': 0}).result() # Test another relative move for shift in (0, 0.12, -0.12): new_shift = {'x': shift} old_pos = self.dev.position.value f = self.dev.moveRel(new_shift) f.result() test.assert_pos_almost_equal(add_coord(old_pos, new_shift), self.dev.position.value, **COMP_ARGS)
def test_move(self): """ Check it's possible to move the stage """ pos = self.stage.position.value f = self.stage.moveRel({"x": -100e-6, "y": -100e-6}) # 1 mm f.result() # FIXME: this should fail self.assertNotEqual(self.stage.position.value, pos) time.sleep(1) f = self.stage.moveRel({"x": 100e-6, "y": 100e-6}) # 1 mm f.result() test.assert_pos_almost_equal(self.stage.position.value, pos)
def test_multimove(self): """ Test running multimoves """ # start at origin self.dev.moveAbs({'x': 0}).result() orig_pos = self.dev.position.value f1 = self.dev.moveRel({'x': 0.15}) time.sleep(0.02) f2 = self.dev.moveRel({'x':-0.15}) f2.result() test.assert_pos_almost_equal(orig_pos, self.dev.position.value, **COMP_ARGS)
def test_navcam_focus(self): """ Check it's possible to change the overview focus """ f = self.pressure.moveAbs({"pressure":1e04}) # move to NavCam f.result() pos = self.navcam_focus.position.value f = self.navcam_focus.moveRel({"z":0.1e-3}) # 1 mm f.result() self.assertNotEqual(self.navcam_focus.position.value, pos) time.sleep(1) # restore original position f = self.navcam_focus.moveAbs(pos) f.result() test.assert_pos_almost_equal(self.navcam_focus.position.value, pos)
def test_stop(self): """ Check it's possible to move the stage """ pos = self.stage.position.value.copy() logging.info("Initial pos = %s", pos) f = self.stage.moveRel({"y": 50e-3}) exppos = pos.copy() exppos["y"] += 50e-3 time.sleep(0.5) # abort after 0.5 s f.cancel() time.sleep(6) # wait for position to update self.assertNotEqual(self.stage.position.value, pos) self.assertNotEqual(self.stage.position.value, exppos) f = self.stage.moveAbs(pos) # Back to orig pos f.result() time.sleep(6) # wait for position to update test.assert_pos_almost_equal(self.stage.position.value, pos, atol=0.1e-6) # Same thing, but using stop() method pos = self.stage.position.value.copy() f = self.stage.moveRel({"y": 10e-3}) time.sleep(0.5) self.stage.stop() with self.assertRaises(CancelledError): f.result() exppos = pos.copy() exppos["y"] += 10e-3 self.assertNotEqual(self.stage.position.value, pos) self.assertNotEqual(self.stage.position.value, exppos) f = self.stage.moveAbs(pos) # Back to orig pos f.result() time.sleep(6) test.assert_pos_almost_equal(self.stage.position.value, pos, atol=0.1e-6)
def test_move_rel(self): # Test relative moves self.dev.moveAbs({'x': 0, 'y': 0, 'z': 0, 'rx': 0, 'ry': 0, 'rz': 0}).result() old_pos = self.dev.position.value shift = {'x': 0.01, 'y':-0.001, 'ry':-0.0003, 'rz': 0} self.dev.moveRel(shift).result() new_pos = self.dev.position.value test.assert_pos_almost_equal(smarpod.add_coord(old_pos, shift), new_pos, **COMP_ARGS) # Test several relative moves and ensure they are queued up. old_pos = self.dev.position.value shift = {'z':-0.000001, 'rx': 0.00001, 'ry':-0.000001, 'rz':-0.00001} self.dev.moveRel(shift) self.dev.moveRel(shift) self.dev.moveRel(shift).result() new_pos = smarpod.add_coord(smarpod.add_coord(smarpod.add_coord(old_pos, shift), shift), shift) test.assert_pos_almost_equal(self.dev.position.value, new_pos, **COMP_ARGS)
def test_move_to_tiles(self): """ Test moving the stage to a tile based on its index """ area = (-0.001, -0.001, 0.001, 0.001) overlap = 0.2 tiled_acq_task = TiledAcquisitionTask( self.fm_streams, self.stage, area=area, overlap=overlap, future=model.InstantaneousFuture()) fov = compute_camera_fov(self.ccd) exp_shift = fov[0] * (1 - overlap), fov[1] * (1 - overlap) # move to starting position (left, top) starting_pos = tiled_acq_task._starting_pos self.stage.moveAbs(starting_pos).result() logging.debug("Starting position: %s", starting_pos) # no change in movement tiled_acq_task._moveToTile((0, 0), (0, 0), fov) assert_pos_almost_equal(self.stage.position.value, starting_pos, atol=100e-9, match_all=False) # Note that we cannot predict precisely, as the algorithm may choose to spread # more or less the tiles to fit within the area. tiled_acq_task._moveToTile((1, 0), (0, 0), fov) # move right on x exp_pos = {'x': starting_pos["x"] + exp_shift[0] / 2} assert_pos_almost_equal(self.stage.position.value, exp_pos, atol=10e-6, match_all=False) tiled_acq_task._moveToTile((1, 1), (1, 0), fov) # move down on y exp_pos = { 'x': starting_pos["x"] + exp_shift[0] / 2, 'y': starting_pos["y"] - exp_shift[1] / 2 } assert_pos_almost_equal(self.stage.position.value, exp_pos, atol=10e-6, match_all=False) tiled_acq_task._moveToTile((0, 1), (1, 1), fov) # move back on x exp_pos = { 'x': starting_pos["x"], 'y': starting_pos["y"] - exp_shift[1] / 2 } assert_pos_almost_equal(self.stage.position.value, exp_pos, atol=10e-6, match_all=False)
def test_tilting_procedures(self): """ Test moving the sample stage from imaging position to tilting position and back to imaging """ stage = self.stage align = self.aligner # Test tilting from imaging # Get the stage to imaging position cryoSwitchSamplePosition(LOADING).result() cryoSwitchSamplePosition(IMAGING).result() # Tilt the stage on rx only f = cryoTiltSample(rx=self.rx_angle) f.result() test.assert_pos_almost_equal(stage.position.value, {'rx': self.rx_angle}, match_all=False, atol=ATOL_ROTATION_POS) # Tilt the stage on rx and rz f = cryoTiltSample(rx=self.rx_angle, rz=self.rz_angle) f.result() test.assert_pos_almost_equal(stage.position.value, { 'rx': self.rx_angle, 'rz': self.rz_angle }, match_all=False, atol=ATOL_ROTATION_POS) # align should be in deactive position test.assert_pos_almost_equal(align.position.value, self.align_deactive, atol=ATOL_LINEAR_POS)
def test_tilting_procedures(self): """ Test moving the sample stage from imaging position to tilting position and back to imaging """ stage = self.stage # Test tilting from imaging # Get the stage to imaging position f = cryoLoadSample(LOADING) f.result() f = cryoLoadSample(IMAGING) f.result() # Tilt the stage on rx only f = cryoTiltSample(rx=self.rx_angle) f.result() test.assert_pos_almost_equal(stage.position.value, {'rx': self.rx_angle, 'rz': 0}, match_all=False, atol=ATOL_ROTATION_POS) # Tilt the stage on rx and rz f = cryoTiltSample(rx=self.rx_angle, rz=self.rz_angle) f.result() test.assert_pos_almost_equal(stage.position.value, {'rx': self.rx_angle, 'rz': self.rz_angle}, match_all=False, atol=ATOL_ROTATION_POS) # Test imaging from tilting f = cryoTiltSample(rx=0, rz=0) f.result() test.assert_pos_almost_equal(stage.position.value, self.stage_active, atol=ATOL_LINEAR_POS)
def test_align_switch_procedures(self): """ Test moving the sample stage from loading position to both imaging, alignment and coating, then back to loading """ align = self.aligner # Get the stage to loading position f = cryoSwitchAlignPosition(LOADING) f.result() test.assert_pos_almost_equal(align.position.value, self.align_deactive, atol=ATOL_LINEAR_POS) # Get the stage to imaging position f = cryoSwitchAlignPosition(IMAGING) f.result() test.assert_pos_almost_equal(align.position.value, self.align_active, atol=ATOL_LINEAR_POS) # Get the stage to imaging position f = cryoSwitchAlignPosition(ALIGNMENT) f.result() test.assert_pos_almost_equal(align.position.value, self.align_alignment, atol=ATOL_LINEAR_POS)
def test_ab_rotation(self): """ Test typical rotation stage for the SECOM v1 A/B alignment """ child = simulated.Stage("stage", "test", axes=["a", "b"]) stage = ConvertStage("inclined", "align", {"orig": child}, axes=["b", "a"], rotation=math.radians(-135)) f = stage.moveRel({"x": 1e-06, "y": 2e-06}) f.result() test.assert_pos_almost_equal(stage.position.value, {"x": 1e-06, "y": 2e-06}) test.assert_pos_almost_equal(child.position.value, {"a":-2.1213203435596424e-06, "b": 7.071067811865477e-07}) f = stage.moveRel({"x": -1e-06, "y": -2e-06}) f.result() test.assert_pos_almost_equal(stage.position.value, {"x": 0, "y": 0}) test.assert_pos_almost_equal(child.position.value, {"a": 0, "b": 0})
def test_move_abs(self): pos1 = {'x': 0, 'y': 0, 'z': 0, 'rx': 0, 'ry': 0, 'rz': 0.0005} pos2 = {'x':-0.0102, 'y': 0, 'z': 0.0, 'rx': 0.0001, 'ry': 0.0001, 'rz': 0} pos3 = {'x': 0.0102, 'y':-0.00002, 'z': 0, 'rx': 0, 'ry': 0, 'rz': 0} self.dev.moveAbs(pos1).result() test.assert_pos_almost_equal(self.dev.position.value, pos1, **COMP_ARGS) self.dev.moveAbs(pos2).result() test.assert_pos_almost_equal(self.dev.position.value, pos2, **COMP_ARGS) self.dev.moveAbs(pos3).result() test.assert_pos_almost_equal(self.dev.position.value, pos3, **COMP_ARGS) logging.debug(self.dev.position.value)
def test_move_to_tiles(self): """ Test moving the stage to a tile based on its index """ area = (-0.001, -0.001, 0.001, 0.001) overlap = 0.2 tiled_acq_task = TiledAcquisitionTask( self.fm_streams, self.stage, area=area, overlap=overlap, future=model.InstantaneousFuture()) fov = (10**-5, 10**-5) self.stage.moveAbs({'x': -0.001, 'y': -0.001}).result() tiled_acq_task._moveToTile((0, 0), (0, 0), fov) exp_pos = {'x': -0.001, 'y': -0.001} assert_pos_almost_equal(self.stage.position.value, exp_pos, atol=100e-9, match_all=False) tiled_acq_task._moveToTile((1, 0), (0, 0), fov) # move right on x exp_pos = {'x': -0.000992} assert_pos_almost_equal(self.stage.position.value, exp_pos, atol=100e-9, match_all=False) tiled_acq_task._moveToTile((1, 1), (1, 0), fov) # move down on y exp_pos = {'x': -0.000992, 'y': -0.001008} assert_pos_almost_equal(self.stage.position.value, exp_pos, atol=100e-9, match_all=False) tiled_acq_task._moveToTile((0, 1), (1, 1), fov) # move back on x exp_pos = {'x': -0.001, 'y': -0.001008} assert_pos_almost_equal(self.stage.position.value, exp_pos, atol=100e-9, match_all=False)
def test_move_abs(self): pos1 = {'x': 0, 'y': 0, 'z': 0} pos2 = {'x': 0, 'y': -1.2e-4, 'z': 0} pos3 = {'x': 0.643e-3, 'y': 0, 'z': 1e-3} self.dev.moveAbs(pos1).result() test.assert_pos_almost_equal(self.dev.position.value, pos1, **COMP_ARGS) self.dev.moveAbs(pos2).result() test.assert_pos_almost_equal(self.dev.position.value, pos2, **COMP_ARGS) self.dev.moveAbs(pos3).result() test.assert_pos_almost_equal(self.dev.position.value, pos3, **COMP_ARGS) logging.debug(self.dev.position.value)
def test_unreachable_position_error(self): edge_move = {'x': 1.6e-2, 'y': 1.5e-2, 'z': -0.002, 'rx': 0, 'rz': 0} rot_move = {'rx': 0.001, 'rz': 0.001} zero_move = {'x': 0, 'y': 0, 'z': 0} # move the stage to the maximum range self.dev.moveAbs(edge_move).result() test.assert_pos_almost_equal(self.dev.position.value, edge_move, match_all=False) # moving rx/rz would throw unreachable move exception with self.assertRaises(IndexError): self.dev.moveAbs(rot_move).result() # moving all linear axes from range then moving rx/rz would be fine self.dev.moveAbs(zero_move).result() test.assert_pos_almost_equal(self.dev.position.value, zero_move, match_all=False) self.dev.moveAbs(rot_move).result() test.assert_pos_almost_equal(self.dev.position.value, rot_move, match_all=False)
def test_simple(self): child = simulated.Stage("stage", "test", axes=["x", "y"]) stage = AntiBacklashActuator("absact", "align", {"orig": child}, backlash={"x": 100e-6, "y": -80e-6}) # moves should just go the same positions # abs test.assert_pos_almost_equal(stage.position.value, {"x": 0, "y": 0}) f = stage.moveAbs({"x": 1e-06, "y": 2e-06}) f.result() test.assert_pos_almost_equal(stage.position.value, {"x": 1e-06, "y": 2e-06}) test.assert_pos_almost_equal(child.position.value, {"x": 1e-06, "y": 2e-06}) f = stage.moveAbs({"x": 0, "y": 0}) f.result() test.assert_pos_almost_equal(stage.position.value, {"x": 0, "y": 0}) test.assert_pos_almost_equal(child.position.value, {"x": 0, "y": 0}) f = stage.moveAbs({"x": -23e-06, "y": -15e-06}) f.result() test.assert_pos_almost_equal(stage.position.value, {"x":-23e-06, "y":-15e-06}) test.assert_pos_almost_equal(child.position.value, {"x":-23e-06, "y":-15e-06}) # rel f = stage.moveAbs({"x": 0, "y": 0}) f = stage.moveRel({"x": 1e-06, "y": 2e-06}) f.result() test.assert_pos_almost_equal(stage.position.value, {"x": 1e-06, "y": 2e-06}) test.assert_pos_almost_equal(child.position.value, {"x": 1e-06, "y": 2e-06}) f = stage.moveRel({"x": 0, "y": 0}) f.result() test.assert_pos_almost_equal(stage.position.value, {"x": 1e-06, "y": 2e-06}) test.assert_pos_almost_equal(child.position.value, {"x": 1e-06, "y": 2e-06}) f = stage.moveRel({"x": -1e-06, "y": -2e-06}) f.result() test.assert_pos_almost_equal(stage.position.value, {"x": 0, "y": 0}) test.assert_pos_almost_equal(child.position.value, {"x": 0, "y": 0})
def test_move(self): """ Check it's possible to move the stage """ pos = self.stage.position.value.copy() f = self.stage.moveRel({"x":2e-6, "y":3e-6}) f.result() self.assertNotEqual(self.stage.position.value, pos) time.sleep(6) # wait until .position is updated self.assertNotEqual(self.stage.position.value, pos) f = self.stage.moveRel({"x":-2e-6, "y":-3e-6}) f.result() test.assert_pos_almost_equal(self.stage.position.value, pos, atol=0.1e-6) time.sleep(6) test.assert_pos_almost_equal(self.stage.position.value, pos, atol=0.1e-6) # Try a relative move outside of the range (less than min) axes = self.stage.axes toofar = {"x": axes["x"].range[0] - pos["x"] - 10e-6} f = self.stage.moveRel(toofar) with self.assertRaises(ValueError): f.result() test.assert_pos_almost_equal(self.stage.position.value, pos, atol=0.1e-6) time.sleep(6) test.assert_pos_almost_equal(self.stage.position.value, pos, atol=0.1e-6) # Try a relative move outside of the range (more than max) toofar = {"y": axes["y"].range[1] - pos["y"] + 10e-6} f = self.stage.moveRel(toofar) with self.assertRaises(ValueError): f.result() test.assert_pos_almost_equal(self.stage.position.value, pos, atol=0.1e-6) time.sleep(6) test.assert_pos_almost_equal(self.stage.position.value, pos, atol=0.1e-6) # f = self.stage.moveRel({"z": 4e-3}) # 100 µm # time.sleep(15) # wait for stage move # f.result() # self.assertNotEqual(self.stage.position.value, pos) # # f = self.stage.moveRel({"z":-4e-3}) # 100 µm # time.sleep(15) # wait for stage move # f.result() # test.assert_pos_almost_equal(self.stage.position.value, pos, atol=10e-6) with self.assertRaises(ValueError): f = self.stage.moveRel({"x":-200e-3}) p = self.stage.position.value.copy() subpos = self.stage.position.value.copy() subpos["x"] += 50e-6 f = self.stage.moveAbs(subpos) f.result() test.assert_pos_almost_equal(self.stage.position.value, subpos) time.sleep(6) test.assert_pos_almost_equal(self.stage.position.value, subpos) subpos = self.stage.position.value.copy() subpos.pop("y") subpos["x"] -= 50e-6 self.stage.moveAbsSync(subpos) test.assert_pos_almost_equal(self.stage.position.value, p) time.sleep(6) test.assert_pos_almost_equal(self.stage.position.value, p)
def assertXYAlmostEqual(self, actual, expected, *args, **kwargs): pos = {"x": actual["x"], "y": actual["y"]} test.assert_pos_almost_equal(pos, expected, *args, **kwargs)
def test_move_abs(self): child = simulated.Stage("stage", "test", axes=["x", "y"]) # no transformation stage = ConvertStage("conv", "align", {"orig": child}, axes=["x", "y"]) test.assert_pos_almost_equal(stage.position.value, {"x": 0, "y": 0}) f = stage.moveAbs({"x": 1e-06, "y": 2e-06}) f.result() test.assert_pos_almost_equal(stage.position.value, {"x": 1e-06, "y": 2e-06}) test.assert_pos_almost_equal(child.position.value, {"x": 1e-06, "y": 2e-06}) f = stage.moveAbs({"x": 0, "y": 0}) f.result() test.assert_pos_almost_equal(stage.position.value, {"x": 0, "y": 0}) test.assert_pos_almost_equal(child.position.value, {"x": 0, "y": 0}) # scaling stage = ConvertStage("conv", "align", {"orig": child}, axes=["x", "y"], scale=(10, 10)) test.assert_pos_almost_equal(stage.position.value, {"x": 0, "y": 0}) f = stage.moveAbs({"x": 1e-06, "y": 2e-06}) f.result() test.assert_pos_almost_equal(stage.position.value, {"x": 1e-06, "y": 2e-06}) test.assert_pos_almost_equal(child.position.value, {"x": 1e-05, "y": 2e-05}) f = stage.moveAbs({"x": 0, "y": 0}) f.result() test.assert_pos_almost_equal(stage.position.value, {"x": 0, "y": 0}) test.assert_pos_almost_equal(child.position.value, {"x": 0, "y": 0}) # rotation stage = ConvertStage("conv", "align", {"orig": child}, axes=["x", "y"], rotation=math.pi / 2) test.assert_pos_almost_equal(stage.position.value, {"x": 0, "y": 0}) f = stage.moveAbs({"x": 1e-06, "y": 2e-06}) f.result() test.assert_pos_almost_equal(stage.position.value, {"x": 1e-06, "y": 2e-06}) test.assert_pos_almost_equal(child.position.value, {"x":-2e-06, "y": 1e-06}) f = stage.moveAbs({"x": 0, "y": 0}) f.result() test.assert_pos_almost_equal(stage.position.value, {"x": 0, "y": 0}) test.assert_pos_almost_equal(child.position.value, {"x": 0, "y": 0}) # offset stage = ConvertStage("conv", "align", {"orig": child}, axes=["x", "y"], translation=(1e-06, 2e-06)) test.assert_pos_almost_equal(stage.position.value, {"x":-1e-06, "y":-2e-06}) f = stage.moveAbs({"x": 0, "y": 0}) f.result() test.assert_pos_almost_equal(stage.position.value, {"x": 0, "y": 0}) test.assert_pos_almost_equal(child.position.value, {"x": 1e-06, "y": 2e-06}) f = stage.moveAbs({"x": -1e-06, "y": -2e-06}) f.result() test.assert_pos_almost_equal(stage.position.value, {"x":-1e-06, "y":-2e-06}) test.assert_pos_almost_equal(child.position.value, {"x": 0, "y": 0}) # offset + scaling stage = ConvertStage("conv", "align", {"orig": child}, axes=["x", "y"], translation=(1e-06, 2e-06), scale=(10, 10)) test.assert_pos_almost_equal(stage.position.value, {"x":-1e-06, "y":-2e-06}) f = stage.moveAbs({"x": 0, "y": 0}) f.result() test.assert_pos_almost_equal(stage.position.value, {"x": 0, "y": 0}) test.assert_pos_almost_equal(child.position.value, {"x": 1e-05, "y": 2e-05})
def test_move_abs(self): stage = self.stage sem_stage = self.sem_stage align = self.align tmcm = self.tmcm # axes = set(["x", "y"]) # f = stage.reference(axes) # f.result() # no transformation stage.updateMetadata({model.MD_ROTATION_COR: 0, model.MD_POS_COR: (0, 0), model.MD_PIXEL_SIZE_COR: (1, 1)}) f = stage.moveAbs({"x": 1e-06, "y": 2e-06}) f.result() test.assert_pos_almost_equal(align.position.value, {"x": 1e-06, "y": 2e-06}, atol=1e-7) test.assert_pos_almost_equal(sem_stage.position.value, {"x": 1e-06, "y": 2e-06}, atol=1e-7) self.assertXYAlmostEqual(tmcm.position.value, {"x":-1e-06, "y":-2e-06}, atol=1e-7) # scaling stage.updateMetadata({model.MD_ROTATION_COR: 0}) stage.updateMetadata({model.MD_POS_COR: (0, 0)}) stage.updateMetadata({model.MD_PIXEL_SIZE_COR: (10, 10)}) f = stage.moveAbs({"x": 1e-06, "y": 2e-06}) f.result() test.assert_pos_almost_equal(align.position.value, {"x": 1e-06, "y": 2e-06}, atol=1e-7) test.assert_pos_almost_equal(sem_stage.position.value, {"x": 1e-05, "y": 2e-05}, atol=1e-7) self.assertXYAlmostEqual(tmcm.position.value, {"x":-1e-06, "y":-2e-06}, atol=1e-7) # rotation stage.updateMetadata({model.MD_ROTATION_COR: math.pi / 2}) stage.updateMetadata({model.MD_POS_COR: (0, 0)}) stage.updateMetadata({model.MD_PIXEL_SIZE_COR: (1, 1)}) f = stage.moveAbs({"x": 1e-06, "y": 2e-06}) f.result() test.assert_pos_almost_equal(align.position.value, {"x": 1e-06, "y": 2e-06}, atol=1e-7) test.assert_pos_almost_equal(sem_stage.position.value, {"x":-2e-06, "y": 1e-06}, atol=1e-7) self.assertXYAlmostEqual(tmcm.position.value, {"x":-1e-06, "y":-2e-06}, atol=1e-7) # offset stage.updateMetadata({model.MD_ROTATION_COR: 0}) stage.updateMetadata({model.MD_POS_COR: (-1e-06, -2e-06)}) stage.updateMetadata({model.MD_PIXEL_SIZE_COR: (1, 1)}) f = stage.moveAbs({"x": 1e-06, "y": 2e-06}) f.result() test.assert_pos_almost_equal(align.position.value, {"x": 1e-06, "y": 2e-06}, atol=1e-7) test.assert_pos_almost_equal(sem_stage.position.value, {"x": 0, "y": 0}, atol=1e-7) self.assertXYAlmostEqual(tmcm.position.value, {"x":-1e-06, "y":-2e-06}, atol=1e-7) # offset + scaling stage.updateMetadata({model.MD_ROTATION_COR: 0}) stage.updateMetadata({model.MD_POS_COR: (-1e-06, -2e-06)}) stage.updateMetadata({model.MD_PIXEL_SIZE_COR: (10, 10)}) f = stage.moveAbs({"x": 1e-06, "y": 2e-06}) f.result() test.assert_pos_almost_equal(align.position.value, {"x": 1e-06, "y": 2e-06}, atol=1e-7) test.assert_pos_almost_equal(sem_stage.position.value, {"x": 0, "y": 0}, atol=1e-7) self.assertXYAlmostEqual(tmcm.position.value, {"x":-1e-06, "y":-2e-06}, atol=1e-7) f = stage.moveAbs({"x": 0, "y": 0}) f.result()
def test_limited_backlash(self): """ Test when backlash doesn't involve all axes """ child = simulated.Stage("stage", "test", axes=["a", "b"]) stage = AntiBacklashActuator("absact", "align", {"orig": child}, backlash={"a": 100e-6}) # moves should just go the same positions # abs test.assert_pos_almost_equal(stage.position.value, {"a": 0, "b": 0}) f = stage.moveAbs({"a": 1e-06, "b": 2e-06}) f.result() test.assert_pos_almost_equal(stage.position.value, {"a": 1e-06, "b": 2e-06}) test.assert_pos_almost_equal(child.position.value, {"a": 1e-06, "b": 2e-06}) f = stage.moveAbs({"b": 0}) f.result() test.assert_pos_almost_equal(stage.position.value, {"a": 1e-06, "b": 0}) test.assert_pos_almost_equal(child.position.value, {"a": 1e-06, "b": 0}) f = stage.moveAbs({"a": -23e-06, "b": -15e-06}) f.result() test.assert_pos_almost_equal(stage.position.value, {"a":-23e-06, "b":-15e-06}) test.assert_pos_almost_equal(child.position.value, {"a":-23e-06, "b":-15e-06}) f = stage.moveAbs({"a": -20e-06}) # negative position but positive move f.result() test.assert_pos_almost_equal(stage.position.value, {"a":-20e-06, "b":-15e-06}) test.assert_pos_almost_equal(child.position.value, {"a":-20e-06, "b":-15e-06}) # rel f = stage.moveAbs({"a": 0}) f = stage.moveAbs({"b": 0}) f = stage.moveRel({"a": 1e-06, "b": 2e-06}) f.result() test.assert_pos_almost_equal(stage.position.value, {"a": 1e-06, "b": 2e-06}) test.assert_pos_almost_equal(child.position.value, {"a": 1e-06, "b": 2e-06}) f = stage.moveRel({"a": 0, "b": 0}) f.result() test.assert_pos_almost_equal(stage.position.value, {"a": 1e-06, "b": 2e-06}) test.assert_pos_almost_equal(child.position.value, {"a": 1e-06, "b": 2e-06}) f = stage.moveRel({"a": -1e-06, "b": -2e-06}) f.result() test.assert_pos_almost_equal(stage.position.value, {"a": 0, "b": 0}) test.assert_pos_almost_equal(child.position.value, {"a": 0, "b": 0})