Skip to content

Commit 4c31945

Browse files
authored
Topas4 Api calls (#258)
* Use yaqc topas4 api calls * Remove absolute path for Led indicator * Consolidate on using motor names * Remove unused imports * Use underscores in motor names for TOPAS-C * Handle leveling and units better in tuning modules
1 parent b66fd51 commit 4c31945

File tree

9 files changed

+59
-748
lines changed

9 files changed

+59
-748
lines changed

hardware/opas/TOPAS/TOPAS-800.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
class Driver(BaseDriver):
1616

1717
def __init__(self, *args, **kwargs):
18-
#self.motor_names = ['Crystal', 'Amplifier', 'Grating', 'NDFG_Crystal', 'NDFG_Mirror', 'NDFG_Delay']
19-
self.motor_names = ['0', '1', '2', '3', '4', '5']
18+
self.motor_names = ['Crystal', 'Amplifier', 'Grating', 'NDFG_Crystal', 'NDFG_Mirror', 'NDFG_Delay']
19+
#self.motor_names = ['0', '1', '2', '3', '4', '5']
2020
self.curve_indices = {'Base': 1, 'Mixer 3': 4}
2121
self.kind = "TOPAS-800"
2222
BaseDriver.__init__(self, *args, **kwargs)

hardware/opas/TOPAS/TOPAS-C.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,9 @@ class Driver(BaseDriver):
1313
def __init__(self, *args, **kwargs):
1414
self.motor_names = ['Crystal_1', 'Delay_1', 'Crystal_2', 'Delay_2',
1515
'Mixer_1', 'Mixer_2','Mixer_3']
16-
self.curve_indices = {'Base': 1, 'Mixer 1': 2, 'Mixer 2': 3, 'Mixer 3': 4}
16+
self.curve_indices = {'Base': 1, 'Mixer_1': 2, 'Mixer_2': 3, 'Mixer_3': 4}
1717
self.kind = 'TOPAS-C'
1818
BaseDriver.__init__(self, *args, **kwargs)
19-
self.homeable = [True]
2019

2120

2221
# --- gui -----------------------------------------------------------------------------------------

hardware/opas/TOPAS/TOPAS.py

Lines changed: 33 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,17 @@
33

44
import os
55
import time
6-
import copy
76
import collections
87

9-
import numpy as np
10-
11-
from ctypes import *
12-
138
import attune
9+
import yaqc
1410

1511
import project
1612
import project.classes as pc
1713
import project.project_globals as g
1814
from project.ini_handler import Ini
1915
from hardware.opas.opas import Driver as BaseDriver
2016
from hardware.opas.opas import GUI as BaseGUI
21-
from hardware.opas.TOPAS.TOPAS_API import TOPAS_API
2217

2318
# --- define --------------------------------------------------------------------------------------
2419

@@ -36,13 +31,29 @@ def __init__(self, *args, **kwargs):
3631
self.curve_paths = collections.OrderedDict()
3732
self.ini = project.ini_handler.Ini(os.path.join(main_dir, 'hardware', 'opas', 'TOPAS', 'TOPAS.ini'))
3833
self.has_shutter = kwargs['has_shutter']
34+
self.yaq_port = kwargs['yaq_port']
3935
if self.has_shutter:
4036
self.shutter_position = pc.Bool(name='Shutter', display=True, set_method='set_shutter')
4137
BaseDriver.__init__(self, *args, **kwargs)
38+
self.serial_number = self.ini.read('OPA' + str(self.index), 'serial number')
39+
# load api
40+
self.api = yaqc.Client(self.yaq_port)
41+
if self.has_shutter:
42+
self.api.set_shutter(False)
43+
44+
# motor positions
45+
for motor_name in self.motor_names:
46+
min_position, max_position = self.api.get_motor_range(motor_name)
47+
limits = pc.NumberLimits(min_position, max_position)
48+
number = pc.Number(initial_value=0, limits=limits, display=True, decimals=6)
49+
self.motor_positions[motor_name] = number
50+
self.recorded['w%d_'%self.index + motor_name] = [number, None, 1., motor_name]
51+
# finish
52+
4253
if self.has_shutter:
4354
self.exposed += [self.shutter_position]
4455
# tuning curves
45-
self.serial_number = self.ini.read('OPA' + str(self.index), 'serial number')
56+
self.serial_number = self.ini.read(f"OPA{self.index}", 'serial number')
4657
self.TOPAS_ini_filepath = os.path.join(g.main_dir.read(), 'hardware', 'opas', 'TOPAS', 'configuration', str(self.serial_number) + '.ini')
4758
self.TOPAS_ini = Ini(self.TOPAS_ini_filepath)
4859
self.TOPAS_ini.return_raw = True
@@ -66,6 +77,7 @@ def __init__(self, *args, **kwargs):
6677
self.interaction_string_combo.updated.connect(self.load_curve)
6778
g.queue_control.disable_when_true(self.interaction_string_combo)
6879
self.load_curve(update = False)
80+
self.homeable = {m: True for m in self.motor_names}
6981

7082
def _get_motor_index(self, name):
7183
c = self.curve
@@ -76,98 +88,9 @@ def _get_motor_index(self, name):
7688
raise KeyError(name)
7789

7890
def _home_motors(self, motor_names):
79-
motor_indexes = []
80-
c = self.curve
81-
while len(motor_names):
82-
for m in motor_names:
83-
if m in c.dependents:
84-
motor_indexes.append(c[m].index)
85-
motor_names.pop(name)
86-
c = c.subcurve
87-
88-
section = 'OPA' + str(self.index)
89-
# close shutter
90-
if self.has_shutter:
91-
original_shutter = self.shutter_position.read()
92-
self.set_shutter([False])
93-
# record current positions
94-
original_positions = []
95-
for motor_index in motor_indexes:
96-
error, position = self.api.get_motor_position(motor_index)
97-
original_positions.append(position)
98-
# send motors to left reference switch ----------------------------------------------------
99-
# set all max, current positions to spoof values
100-
overflow = 8388607
101-
for motor_index in motor_indexes:
102-
self.api.set_motor_positions_range(motor_index, 0, overflow)
103-
self.api.set_motor_position(motor_index, overflow)
104-
# send motors towards zero
105-
for motor_index in motor_indexes:
106-
self.api.start_motor_motion(motor_index, 0)
107-
# wait for motors to hit left reference switch
108-
motor_indexes_not_homed = copy.copy(motor_indexes)
109-
while len(motor_indexes_not_homed) > 0:
110-
for motor_index in motor_indexes_not_homed:
111-
time.sleep(0.1)
112-
error, left, right = self.api.get_reference_switch_status(motor_index)
113-
if left:
114-
motor_indexes_not_homed.remove(motor_index)
115-
# set counter to zero
116-
self.api.set_motor_position(motor_index, 0)
117-
# send motors to 400 steps ----------------------------------------------------------------
118-
for motor_index in motor_indexes:
119-
self.api.start_motor_motion(motor_index, 400)
91+
for m in motor_names:
92+
self.api.home_motor(m)
12093
self.wait_until_still()
121-
# send motors left reference switch slowly ------------------------------------------------
122-
# set motor speed
123-
for motor_index in motor_indexes:
124-
min_velocity = self.ini.read(section, 'motor {} min velocity (us/s)'.format(motor_index))
125-
max_velocity = self.ini.read(section, 'motor {} max velocity (us/s)'.format(motor_index))
126-
acceleration = self.ini.read(section, 'motor {} acceleration (us/s^2)'.format(motor_index))
127-
error = self.api.set_speed_parameters(motor_index, min_velocity, int(max_velocity/2), acceleration)
128-
# set all max, current positions to spoof values
129-
for motor_index in motor_indexes:
130-
self.api.set_motor_positions_range(motor_index, 0, overflow)
131-
self.api.set_motor_position(motor_index, overflow)
132-
# send motors towards zero
133-
for motor_index in motor_indexes:
134-
self.api.start_motor_motion(motor_index, 0)
135-
# wait for motors to hit left reference switch
136-
motor_indexes_not_homed = copy.copy(motor_indexes)
137-
while len(motor_indexes_not_homed) > 0:
138-
for motor_index in motor_indexes_not_homed:
139-
time.sleep(0.1)
140-
error, left, right = self.api.get_reference_switch_status(motor_index)
141-
if left:
142-
motor_indexes_not_homed.remove(motor_index)
143-
# set counter to zero
144-
self.api.set_motor_position(motor_index, 0)
145-
# send motors to 400 steps (which is now true zero) ---------------------------------------
146-
for motor_index in motor_indexes:
147-
self.api.start_motor_motion(motor_index, 400)
148-
self.wait_until_still()
149-
for motor_index in motor_indexes:
150-
self.api.set_motor_position(motor_index, 0)
151-
# finish ----------------------------------------------------------------------------------
152-
# set speed back to real values
153-
for motor_index in motor_indexes:
154-
min_velocity = self.ini.read(section, 'motor {} min velocity (us/s)'.format(motor_index))
155-
max_velocity = self.ini.read(section, 'motor {} max velocity (us/s)'.format(motor_index))
156-
acceleration = self.ini.read(section, 'motor {} acceleration (us/s^2)'.format(motor_index))
157-
error = self.api.set_speed_parameters(motor_index, min_velocity, max_velocity, acceleration)
158-
# set range back to real values
159-
for motor_index in motor_indexes:
160-
min_position = self.ini.read(section, 'motor {} min position (us)'.format(motor_index))
161-
max_position = self.ini.read(section, 'motor {} max position (us)'.format(motor_index))
162-
error = self.api.set_motor_positions_range(motor_index, min_position, max_position)
163-
# launch return motion
164-
for motor_index, position in zip(motor_indexes, original_positions):
165-
self.api.start_motor_motion(motor_index, position)
166-
# wait for motors to finish moving
167-
self.wait_until_still()
168-
# return shutter
169-
if self.has_shutter:
170-
self.set_shutter([original_shutter])
17194

17295
def _load_curve(self, interaction):
17396
interaction = self.interaction_string_combo.read()
@@ -176,27 +99,31 @@ def _load_curve(self, interaction):
17699
del curve_paths_copy['Poynting']
177100
crv_paths = [m.read() for m in curve_paths_copy.values()]
178101
all_curves = attune.TopasCurve.read_all(crv_paths)
102+
for curve in all_curves.values():
103+
for dependent in curve.dependent_names:
104+
if dependent not in self.motor_names:
105+
try:
106+
curve.rename_dependent(dependent, self.motor_names[int(dependent)])
107+
except:
108+
pass
179109
self.interaction_string_combo.set_allowed_values(list(all_curves.keys()))
180110
self.curve = all_curves[interaction]
181111
return self.curve
182112

183113
def _set_motors(self, motor_destinations):
184114
for motor_name, destination in motor_destinations.items():
185-
motor_index = self._get_motor_index(motor_name)
186-
error, destination_steps = self.api.convert_position_to_steps(motor_index, destination)
187-
self.api.start_motor_motion(motor_index, destination_steps)
115+
destination = float(destination)
116+
self.api.set_motor_position(motor_name, destination)
188117

189118
def _update_api(self, interaction):
190119
# write to TOPAS ini
191-
self.api.close()
192120
for curve_type, curve_path_mutex in self.curve_paths.items():
193121
if curve_type == 'Poynting':
194122
continue
195123
curve_path = curve_path_mutex.read()
196124
section = 'Optical Device'
197125
option = 'Curve ' + str(self.curve_indices[curve_type])
198126
self.TOPAS_ini.write(section, option, curve_path)
199-
self.api = TOPAS_API(self.TOPAS_ini_filepath)
200127
# save current interaction string
201128
self.ini.write('OPA%i'%self.index, 'current interaction string', interaction)
202129

@@ -210,59 +137,21 @@ def close(self):
210137
self.api.close()
211138

212139
def get_motor_positions(self):
213-
for i in range(6):
214-
motor_mutex = list(self.motor_positions.values())[i]
215-
error, position_steps = self.api.get_motor_position(i)
216-
error, position = self.api.convert_position_to_units(i, position_steps)
140+
for m, motor_mutex in self.motor_positions.items():
141+
position = self.api.get_motor_position(m)
217142
motor_mutex.write(position)
218143
if self.poynting_correction:
219144
self.poynting_correction.get_motor_positions()
220145

221-
def get_speed_parameters(self, inputs):
222-
motor_index = inputs[0]
223-
error, min_speed, max_speed, acceleration = self.api._get_speed_parameters(motor_index)
224-
return [error, min_speed, max_speed, acceleration]
225-
226-
def initialize(self):
227-
self.serial_number = self.ini.read('OPA' + str(self.index), 'serial number')
228-
# load api
229-
self.api = TOPAS_API(self.TOPAS_ini_filepath)
230-
if self.has_shutter:
231-
self.api.set_shutter(False)
232-
233-
# motor positions
234-
for motor_index, motor_name in enumerate(self.motor_names):
235-
error, min_position_steps, max_position_steps = self.api.get_motor_positions_range(motor_index)
236-
valid_position_steps = np.arange(min_position_steps, max_position_steps+1)
237-
valid_positions_units = [self.api.convert_position_to_units(motor_index, s)[1] for s in valid_position_steps]
238-
min_position = min(valid_positions_units)
239-
max_position = max(valid_positions_units)
240-
limits = pc.NumberLimits(min_position, max_position)
241-
number = pc.Number(initial_value=0, limits=limits, display=True, decimals=6)
242-
self.motor_positions[motor_name] = number
243-
self.recorded['w%d_'%self.index + motor_name] = [number, None, 1., motor_name]
244-
# finish
245-
BaseDriver.initialize(self)
246-
247146
def is_busy(self):
248-
if self.api.open:
249-
error, still = self.api.are_all_motors_still()
250-
print('TOPAS is busy', error, still)
251-
return not still
252-
else:
253-
return False # for shutdown
147+
return any(self.api.is_motor_busy(m) for m in self.motor_names)
254148

255149
def set_shutter(self, inputs):
256150
shutter_state = inputs[0]
257151
error = self.api.set_shutter(shutter_state)
258152
self.shutter_position.write(shutter_state)
259153
return error
260154

261-
def set_speed_parameters(self, inputs):
262-
motor_index, min_speed, max_speed, accelleration = inputs
263-
error = self.api._set_speed_parameters(motor_index, min_speed, max_speed, acceleration)
264-
return error
265-
266155

267156
# --- gui -----------------------------------------------------------------------------------------
268157

0 commit comments

Comments
 (0)