Skip to content

Commit 7986977

Browse files
Merge pull request #16 from Daniel-Buckelew/asi_daq
Bringing all of the pieces into develop for packaging purposes
2 parents a4bf414 + 0e49218 commit 7986977

File tree

8 files changed

+986
-84
lines changed

8 files changed

+986
-84
lines changed

src/navigate/config/configuration_database.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@
109109
daq_device_types = {
110110
"National Instruments": "NI",
111111
"Virtual Device": "Synthetic",
112+
"Applied Scientific Instrumentation": "ASI"
112113
}
113114

114115
daq_hardware_widgets = {

src/navigate/model/device_startup_functions.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,7 @@ def start_device(
492492
device_not_found(microscope_name, device_category, device_type, device_id)
493493

494494

495-
def start_daq(configuration: Dict[str, Any], device_type: str = "NI") -> DAQBase:
495+
def start_daq(configuration: Dict[str, Any], device_type: str = "NI", name: str = "name") -> DAQBase:
496496
"""Initializes the data acquisition (DAQ) class on a dedicated thread.
497497
498498
Load daq information from the configuration file. Proper daq types include NI and
@@ -515,6 +515,12 @@ def start_daq(configuration: Dict[str, Any], device_type: str = "NI") -> DAQBase
515515
from navigate.model.devices.daq.ni import NIDAQ
516516

517517
return NIDAQ(configuration)
518+
519+
elif device_type == "asi.ASI":
520+
# from navigate.model.devices.daq.asi import ASIDaq
521+
# name = "Microscope-0"
522+
return start_device(name, configuration, "daq")
523+
518524

519525
elif device_type.lower().startswith("synthetic"):
520526
from navigate.model.devices.daq.synthetic import SyntheticDAQ
@@ -594,6 +600,10 @@ def load_devices(
594600
]["hardware"]["type"]
595601

596602
if device_type not in devices_dict["daq"]:
597-
devices_dict["daq"][device_type] = start_daq(configuration, device_type)
603+
print(device_type)
604+
if (device_type == "asi.ASI"):
605+
devices_dict["daq"][device_type] = start_daq(configuration, device_type, microscope_name)
606+
else:
607+
devices_dict["daq"][device_type] = start_daq(configuration, device_type)
598608

599609
return devices_dict

src/navigate/model/devices/APIs/asi/asi_tiger_controller.py

Lines changed: 259 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -998,7 +998,7 @@ def logic_card_on(self, axis : str):
998998
self.read_response()
999999
self.send_command(f'6 CCA Z=64\r')
10001000
self.read_response()
1001-
1001+
10021002
def logic_card_off(self, axis : str):
10031003
"""Turn off the logic card
10041004
@@ -1013,28 +1013,49 @@ def logic_card_off(self, axis : str):
10131013
self.send_command(f'6 CCA Z=0\r')
10141014
self.read_response()
10151015

1016-
def SA_waveform(self, axis:str, waveform=0, amplitude=1000, offset=500):
1016+
def logic_cell_on(self, axis : str):
1017+
self.send_command(f'M E = {axis}\r')
1018+
self.read_response()
1019+
self.send_command(f'CCA Z=1\r')
1020+
self.read_response()
1021+
1022+
def logic_cell_off(self, axis :str):
1023+
self.send_command(f'M E = {axis}\r')
1024+
self.read_response()
1025+
self.send_command(f'CCA Z=0\r')
1026+
self.read_response()
1027+
1028+
def SA_waveform(self, axis:str, waveform=0, amplitude=1000, offset=500, frequency=1000):
10171029
"""Programs the analog waveforms using SAA, SAO, and SAP
10181030
Default waveform is a sawtooth waveform with an amplitude of 1V with an offset of 0.5V
10191031
10201032
Parameters
10211033
----------
10221034
axis: str
1023-
Laser axis
1035+
Tiger Controller axis
10241036
waveform:
10251037
Type of waveform pattern according to https://asiimaging.com/docs/commands/sap
10261038
amplitude:
1027-
amplitude of the waveform
1039+
amplitude of the waveform in mV
10281040
offset:
1029-
sets the center position of the waveform
1041+
sets the center position of the waveform in mV
1042+
frequency:
1043+
sets the period of the waveform in milliseconds
10301044
"""
10311045

10321046
"Verify if this is for synchronous or asynchronous"
1033-
self.send_command(f"SAP {axis}={waveform}")
1047+
print(f"Period (ms): {frequency}")
1048+
if (waveform % 128 == 3):
1049+
offset = .5*(offset+amplitude)
1050+
amplitude = amplitude*2
1051+
1052+
self.send_command(f"3 SAP {axis}={waveform}")
1053+
self.read_response()
1054+
self.send_command(f"3 SAA {axis}={amplitude}")
10341055
self.read_response()
1035-
self.send_command(f"SAA {axis}={amplitude}")
1056+
self.send_command(f"3 SAO {axis}={offset}")
10361057
self.read_response()
1037-
self.send_command(f"SAO {axis}={offset}")
1058+
self.send_command(f"3 SAF {axis}={frequency}")
10381059
self.read_response()
10391060

10401061
def SAM(self, axis: str, mode: int):
@@ -1054,6 +1075,234 @@ def SAM(self, axis: str, mode: int):
10541075
Integer code
10551076
"""
10561077

1057-
self.send_command(f"SAM {axis}={mode}")
1078+
self.send_command(f"3 SAM {axis}={mode}")
10581079
self.read_response()
1059-
1080+
1081+
def setup_control_loop(self,delays,camera_delay,rfvc_delay,sweep_time : float, analog_outputs : dict): # delay (ms), sweep_time (ms)
1082+
# def setup_control_loop(self, analog_outputs: dict):
1083+
"""
1084+
Sets up the control loop
1085+
1086+
Arguments: self, waveform type dict (axis, waveform)
1087+
1088+
If/Else statements: send the right loop
1089+
1090+
"""
1091+
# channels = analog_outputs.keys()
1092+
TTLs = {'A': 42, 'B': 44, 'C': 46}
1093+
# if channels:
1094+
start_delay = int(delays[0]*4) #- int(round(period))
1095+
if len(delays) > 1:
1096+
galvo2_delay = int((delays[0] - delays[1])*4)
1097+
galvo1_axis = analog_outputs["galvo 0"]
1098+
galvo2_axis = analog_outputs["galvo 1"]
1099+
elif len(delays) == 1:
1100+
galvo1_axis = analog_outputs["galvo 0"]
1101+
galvo2_delay = 0
1102+
else:
1103+
galvo2_delay = 0
1104+
rfvc_axis = analog_outputs["remote_focus"]
1105+
1106+
1107+
1108+
sweep_time = int(sweep_time*4) - 2
1109+
1110+
if rfvc_delay > camera_delay + 2:
1111+
camera_output = 6
1112+
rfvc_output = 12
1113+
start_delay += int((camera_delay + 2) * 4)
1114+
difference_delay = int((rfvc_delay - (camera_delay + 2)) * 4)
1115+
elif rfvc_delay < camera_delay + 2:
1116+
camera_output = 12
1117+
rfvc_output = 6
1118+
start_delay += int((rfvc_delay) * 4)
1119+
difference_delay = int(((camera_delay + 2) - rfvc_delay) * 4)
1120+
elif rfvc_delay == camera_delay + 2:
1121+
camera_output = 6
1122+
rfvc_output = 6
1123+
start_delay += int((camera_delay + 2) * 4)
1124+
difference_delay = int((rfvc_delay - (camera_delay + 2)) * 4)
1125+
1126+
1127+
print(f"Delays: {delays}, RFVC Delay: {rfvc_delay}, Camera Delay: {camera_delay}")
1128+
1129+
print(f"Camera: {camera_output}, RFVC: {rfvc_output}")
1130+
1131+
print(f'Sweep Time Cycles: {sweep_time}')
1132+
print(f"Start Delay: {start_delay}, Difference Delay: {difference_delay}")
1133+
print(f"Galvo2_delay: {galvo2_delay}")
1134+
1135+
commands = [
1136+
'6 CCA X=0',
1137+
1138+
# Set cell 2 to one shot to trigger TTL for galvo, For I am the LORD
1139+
'6 m e = 2',
1140+
'6 cca y = 8',
1141+
'6 cca z = 10',
1142+
'6 ccb x = 1',
1143+
'6 ccb y = 192',
1144+
# Set cell 3 to delay cell to give time to send serial commands, For I am the LORD
1145+
'6 m e = 3',
1146+
'6 cca y = 9',
1147+
f'6 cca z = {start_delay}',
1148+
'6 ccb x = 1',
1149+
'6 ccb y = 192',
1150+
# Set cell 4 to JK-Flop, to trigger & cell, For I am the LORD
1151+
'6 m e = 4',
1152+
'6 cca y = 13',
1153+
'6 ccb x = 3',
1154+
'6 ccb y = 8',
1155+
'6 ccb z = 192',
1156+
# Set cell 5 to & cell for loop, For I am the LORD
1157+
'6 m e = 5',
1158+
'6 cca y = 5',
1159+
'6 ccb x = 4',
1160+
'6 ccb y = 71',
1161+
# Set cell 6 to one-shot to trigger TTL for RFVC repeatedly and to trigger CT, For I am the LORD
1162+
'6 m e = 6',
1163+
'6 cca y = 8',
1164+
'6 cca z = 10',
1165+
'6 ccb x = 5',
1166+
'6 ccb y = 192',
1167+
# Set cell 7 to delay cell for loop, For I am the LORD
1168+
'6 m e = 7',
1169+
'6 cca y = 9',
1170+
f'6 cca z= {sweep_time}',
1171+
'6 ccb x = 6',
1172+
'6 ccb y = 192',
1173+
#Sets cell 9 to a delay cell to account for the second galvo
1174+
'6 m e = 9',
1175+
'6 cca y = 9',
1176+
f'6 cca z = {galvo2_delay}',
1177+
'6 ccb x = 2',
1178+
'6 ccb y = 192',
1179+
#Sets cell 10 to a one shot to trigger Galvo 2
1180+
'm e = 10',
1181+
'cca y = 8',
1182+
'cca z = 10',
1183+
'ccb x = 9',
1184+
'ccb y = 192',
1185+
#Sets cell 11 to a delay reading the output of cell 6
1186+
'6 m e = 11',
1187+
'6 cca y = 9',
1188+
f'6 cca z = {difference_delay}',
1189+
'6 ccb x = 6',
1190+
'6 ccb y = 192',
1191+
#Sets cell 12 to one shot to trigger camera
1192+
'm e = 12',
1193+
'cca y = 8',
1194+
'cca z = 10',
1195+
'ccb x = 11',
1196+
'ccb y = 192',
1197+
#Sets TTL2 to output from the RFVC cell in this case , For I am the LORD
1198+
f'6 m e = {TTLs[rfvc_axis]+1}',
1199+
'6 cca y = 1',
1200+
f'6 cca z = {rfvc_output}',
1201+
#Sets TTL1 to output the same thing as TTL0, For I am the LORD
1202+
f'6 m e = {TTLs[rfvc_axis]}',
1203+
'6 cca y = 1',
1204+
f'6 cca z = {TTLs[rfvc_axis]+1}',
1205+
#Sets PLC output 3 to cell 6
1206+
'6 m e = 33',
1207+
f'6 cca z = {camera_output}',
1208+
]
1209+
# if galvos exist
1210+
galvo_commands = []
1211+
if len(delays) > 0:
1212+
galvo_commands = [
1213+
#Sets TTL4 to output for the first Galvo, For I am the LORD
1214+
f'6 m e = {TTLs[galvo1_axis]+1}',
1215+
'6 cca y = 1',
1216+
'6 cca z = 2',
1217+
#Sets TTL3 to output the same thing as TTL2
1218+
f'6 m e = {TTLs[galvo1_axis]}',
1219+
'cca y = 1',
1220+
f'cca z = {TTLs[galvo1_axis]+1}',
1221+
]
1222+
1223+
if len(delays) > 1:
1224+
galvo_commands = [
1225+
#Sets TTL4 to output for the first Galvo, For I am the LORD
1226+
f'6 m e = {TTLs[galvo1_axis]+1}',
1227+
'6 cca y = 1',
1228+
'6 cca z = 2',
1229+
#Sets TTL3 to output the same thing as TTL2
1230+
f'6 m e = {TTLs[galvo1_axis]}',
1231+
'cca y = 1',
1232+
f'cca z = {TTLs[galvo1_axis]+1}',
1233+
#Sets TTL4 to output for the first Galvo, For I am the LORD
1234+
f'6 m e = {TTLs[galvo2_axis]+1}',
1235+
'6 cca y = 1',
1236+
'6 cca z = 10',
1237+
#Sets TTL3 to output the same thing as TTL2
1238+
f'6 m e = {TTLs[galvo2_axis]}',
1239+
'cca y = 1',
1240+
f'cca z = {TTLs[galvo2_axis]+1}',
1241+
]
1242+
print(galvo_commands)
1243+
1244+
print(analog_outputs)
1245+
print(f"{TTLs[galvo1_axis]+ 1}")
1246+
for command in commands:
1247+
# Send data
1248+
self.send_command(f'{command}\r')
1249+
self.read_response()
1250+
for command in galvo_commands:
1251+
self.send_command(f'{command}\r')
1252+
self.read_response()
1253+
1254+
def tweak_control_loop(self, delays, sweep_time):
1255+
1256+
start_delay = int(delays[0]*4) #- int(round(period))
1257+
if len(delays) > 1:
1258+
galvo2_delay = int((delays[0] - delays[1])*4)
1259+
else:
1260+
galvo2_delay = 0
1261+
1262+
sweep_time = int(sweep_time*4) - 2
1263+
1264+
print(f'Sweep Time Cycles: {sweep_time}')
1265+
1266+
commands = [
1267+
# Set cell 3 to delay cell to give time to send serial commands, For I am the LORD
1268+
'6 m e = 3',
1269+
'6 cca y = 9'
1270+
f'6 cca z = {start_delay}',
1271+
'6 ccb x = 1',
1272+
'6 ccb y = 192',
1273+
# Set cell 7 to delay cell for loop, For I am the LORD
1274+
'6 m e = 7',
1275+
'6 cca y = 9'
1276+
f'6 cca z= {sweep_time}',
1277+
'6 ccb x = 6',
1278+
'6 ccb y = 192',
1279+
#Sets cell 9 to a delay cell to account for the second galvo
1280+
'6 m e = 9',
1281+
'6 cca y = 9'
1282+
f'6 cca z = {galvo2_delay}',
1283+
'6 ccb x = 2',
1284+
'6 ccb y = 192',
1285+
]
1286+
for command in commands:
1287+
# Send data
1288+
self.send_command(f'{command}\r')
1289+
self.read_response()
1290+
1291+
def send_ttl_pulse(self, channel: int, pulse_width_ms: int, delay_ms: int) -> str:
1292+
1293+
command = f"TTL X={channel} P={pulse_width_ms} D={delay_ms}"
1294+
self.send_command(command)
1295+
response = self.read_response()
1296+
return response
1297+
1298+
# def trigger_acquisition(self):
1299+
# commands = [
1300+
# #Changes the TTL input from cell 2 to cell 6, For I am the LORD
1301+
# '6 m e = 43',
1302+
# '6 cca z = 6',
1303+
# ]
1304+
# for command in commands:
1305+
# # Send data
1306+
# self.send_command(f'{command}\r')
1307+
# self.read_response()
1308+

0 commit comments

Comments
 (0)