Understanding BLACS

152 views
Skip to first unread message

Apoorva Hegde

unread,
Nov 20, 2019, 10:39:00 AM11/20/19
to The labscript suite
Hi all,

I have the following basic questions concerning BLACS:
  • I have a dummy intermediate device in BLACS which isn't clocked by any pseudoclock. I  just want to use the script of this dummy device to establish serial communication with an Arduino, because I require the serial port to be opened and closed in every run so that I can write certain information onto the Arduino. My question is, where exactly can I write these serial communication instructions, so that it gets executed by BLACS in every run? i.e., Which part of BLACS is responsible for the hardware biding in every run? Since what I need to write is a device specific code, I have already tried doing it in the section of generate_code() function in the device script. This works very well in the case of single shots but not for repeated shots or scans. The reason for this as it seems to me, is that BLACS compiles/runs my code for all the shots in the beginning and only starts to control the hardware afterwards.  I need this code to be run when the BLACS actually starts executing the hardware control.
  • Is there a way to enter the number of repetitions we want in BLACS, other than pressing the repeat button in BLACS?
Thank you!

Regards,
Apoorva

Chris Billington

unread,
Nov 20, 2019, 2:52:40 PM11/20/19
to labscri...@googlegroups.com
Hi Apoorva,

To clear up when which code runs:
  • Shots are "compiled" by runmanager, and then "run" by BLACS. 
  • generate_code runs when your shot is compiled by runmanager. No communication with hardware should occur here. Of course, if you write code here that communicates with hardware, it will run, but that is not the intended role of this function. generate_code() should process any instructions the user has added in their labscript code, converting them to the low-level instructions that need to be programmed into the device, and then save those instructions to the shot file.
  • The code that actually communicates with hardware should be put in the BLACS worker class for the device. There are three relevant methods. init(), which runs when BLACS starts up or when the BLACS tab in question is restarted, transition_to_buffered(), which runs at the start of each shot, and transition_to_manual(), which runs at the end of each shot. The job of transition_to_buffered() is to read the shot file (which is given to it as a function argument), and obtain the instructions which were saved by generate_code(). It then should communicate with the hardware and use those instructions to set up the device so that it is ready for the shot to begin. transition_to_manual() should do any communication with the hardware that is needed at the end of the shot, such as reading acquired data, and writing it to the shot file as well.
If the same shot file is repeated many times, then it is only compiled once, but these two functions in BLACS will run multiple times as copies of the shot file are made and transition_to_buffered() and transition_to_manual() are called multiple times.

If you haven't already, reading our paper might help you get a better idea of how things fit together. A lot has changed since then, but the basic layout (as depicted in the flowcharts) of how the data flows between programs is the same now as it was then.

When you say you have an IntermediateDevice, do you mean that you made a subclass of IntermediateDevice, and overrode its generate_code() method? Firstly, since your device sounds like it does not have a parent device giving it clocking signals, or child devices with different outputs, I would subclass Device. Secondly, you will need to make several classes: a "labscript device" class, a "BLACS tab" class, and a "BLACS worker" class. The labscript device class is for interacting with your labscript code and saving instructions to the shot file (in generate_code()). The BLACS tab is about creating a graphical interface in BLACS for the device, and for you this will be mostly empty. The BLACS worker is for actually communicating with the device each shot.

I'll create an example of the files and classes you would need to do this, which will hopefully be instructive and might serve as a reference to others as well. Other examples exist, but are less minimal.

As for repeating a fixed number of times, there is currently no way to configure this in BLACS, but the way I would do it is to create a global in runmanager called "repeat_number" or similar, and set it to range(N) where N is the number of desired repeats. Runmanager will then treat this as a parameter to be iterated over, and will create N shots when you click the "engage" button.

I hope that clears up some things!

-Chris

 

--
You received this message because you are subscribed to the Google Groups "The labscript suite" group.
To unsubscribe from this group and stop receiving emails from it, send an email to labscriptsuit...@googlegroups.com.
To view this discussion on the web, visit https://groups.google.com/d/msgid/labscriptsuite/51c20465-19a5-4b8d-842c-ff209c80379f%40googlegroups.com.

Apoorva Hegde

unread,
Nov 20, 2019, 3:14:28 PM11/20/19
to labscri...@googlegroups.com
Hello Chris, 

Thanks a lot for your reply. Right now I have used the script for dummy intermediate device that's already there as an example in labscript_devices folder. I don't have the pseudoclock for it, but still it shows up in device tab in BLACS because all the classes that you have mentioned are being written in the device script. I can refresh it and so on without any error. As per using the BLACS worker class or the transition to buffered () to run the hardware related code, I already tried these and it didn't work. The shots were run without error but I didn't see the intended action on the Arduino. It's possible that I didn't place the code in the right place. I will follow your suggestions while I recheck the codes.

Thanks a lot for your help! 


Regards, 
Apoorva

Chris Billington

unread,
Nov 20, 2019, 4:23:42 PM11/20/19
to labscri...@googlegroups.com
Hi Apoorva,

Attached is an example minimal labscript device. There are four files for the actual device support:

blacs_tabs.py
blacs_workers.py
labscript_devices.py
register_classes.py

The first three of which contain the three classes I mentioned earlier. The register_classes.py file is to "register" the BLACS tab so that BLACS knows where to find the class for the tab, based on the name of the labscript device class that it finds in the connection table. You should put the folder CustomArduinoDevice in <labscript_suite>/userlib/user_devices, which is an alternate location that device code can be put (labscript_devices should be for code that has been included in the labscript suite itself - though if you write device support for commercially available devices, please do contribute it back and we will put it there!). 

Then there are two other files, one a connection table and one an example shot file. In this example device, commands can be added in a labscript script and are run by the BLACS worker at the start and end of the shot. If you comment out the two self.connection.write() lines in the BLACS worker, as well as the initial self.connection = serial.serial(...), then the code will just print instead of actually sending any serial data, so you can see what it does without an actual serial device connected by having the tab display its output box (the toolbutton with the terminal icon in the top-right of the tab).

Of course, you probably want to send some other kind of data, maybe you want to store a table of numbers instead of a table of strings, or similar, and if there is some serial communication sent every shot regardless, you may want to move that to be hard-coded in transition_to_buffered() and transition_to_static regardless of the contents of the actual shot file. But hopefully this example is instructive! The idea is that generate_code() can write anything to the HDF5 group for that device - datasets of any datatype, attributes, anything supported by HDF5, that says what the device should do that shot. Then transition_to_buffered() reads that group and does whatever is appropriate to send the data to the device in the right format and over the right protocol.

Let me know if I can clarify anything else or if you hit any other issues.

-Chris

CustomArduinoDeviceExample.zip

Apoorva Hegde

unread,
Nov 21, 2019, 10:44:32 AM11/21/19
to The labscript suite
Hello Chris,

Thanks a lot for these files. I think now I understood much better how it works. The method you suggested works perfectly for our setup. We are able to initiate a serial connection with the Arduino in the init() and we are able to send commands to it  in transition_to_buffered(). It gets executed in every shot without erros, which we can easily monitor in the output box of the device tab. I  think this is exactly we wanted to implement!

Once again, thanks very much your support!


Regards,
Apoorva 

On Wednesday, November 20, 2019 at 1:23:42 PM UTC-8, Chris Billington wrote:
Hi Apoorva,

Attached is an example minimal labscript device. There are four files for the actual device support:

blacs_tabs.py
blacs_workers.py
labscript_devices.py
register_classes.py

The first three of which contain the three classes I mentioned earlier. The register_classes.py file is to "register" the BLACS tab so that BLACS knows where to find the class for the tab, based on the name of the labscript device class that it finds in the connection table. You should put the folder CustomArduinoDevice in <labscript_suite>/userlib/user_devices, which is an alternate location that device code can be put (labscript_devices should be for code that has been included in the labscript suite itself - though if you write device support for commercially available devices, please do contribute it back and we will put it there!). 

Then there are two other files, one a connection table and one an example shot file. In this example device, commands can be added in a labscript script and are run by the BLACS worker at the start and end of the shot. If you comment out the two self.connection.write() lines in the BLACS worker, as well as the initial self.connection = serial.serial(...), then the code will just print instead of actually sending any serial data, so you can see what it does without an actual serial device connected by having the tab display its output box (the toolbutton with the terminal icon in the top-right of the tab).

Of course, you probably want to send some other kind of data, maybe you want to store a table of numbers instead of a table of strings, or similar, and if there is some serial communication sent every shot regardless, you may want to move that to be hard-coded in transition_to_buffered() and transition_to_static regardless of the contents of the actual shot file. But hopefully this example is instructive! The idea is that generate_code() can write anything to the HDF5 group for that device - datasets of any datatype, attributes, anything supported by HDF5, that says what the device should do that shot. Then transition_to_buffered() reads that group and does whatever is appropriate to send the data to the device in the right format and over the right protocol.

Let me know if I can clarify anything else or if you hit any other issues.

-Chris

To unsubscribe from this group and stop receiving emails from it, send an email to labscri...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "The labscript suite" group.
To unsubscribe from this group and stop receiving emails from it, send an email to labscri...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "The labscript suite" group.
To unsubscribe from this group and stop receiving emails from it, send an email to labscri...@googlegroups.com.

Chris Billington

unread,
Nov 21, 2019, 11:35:30 AM11/21/19
to labscri...@googlegroups.com
Fantastic! Glad it is making sense and that things are working for you.

Cheers,

Chris

To unsubscribe from this group and stop receiving emails from it, send an email to labscriptsuit...@googlegroups.com.
To view this discussion on the web, visit https://groups.google.com/d/msgid/labscriptsuite/d3dd94dd-e2e0-4c76-8949-302b6ba14159%40googlegroups.com.

Lufter Reis

unread,
Apr 6, 2024, 3:11:29 PMApr 6
to the labscript suite
Hi all,
Just a follow up question on this thread. Is there a way in transition_to_buffered for me to send a command to Arduino at a specific clock time? 
For example, if I've already implemented in generate_code(), storing which command I want to send at a specific clock tick:

command_data = [time0_send_command0, time1_send_command_1, ...]

Then in transition_to_buffered(), I can read in this "command_data" from the decoding the compiles hd5 file. And I can iterate through this "command_data" to send command to the Arduino. But what I don't understand is, doesn't transition_to_buffered() just send commands to the Arduino without caring the clock ticks? Since there seems no clock information being passed to transition_to_buffered(), how does transition_to_buffered()  know when to send command to Arduino? This question has been crowed me for a while and I now seek a chance to understand it. Thank you!
Best,
Lufter


chrisjbi...@gmail.com 在 2019年11月21日 星期四上午11:35:30 [UTC-5] 的信中寫道:
Reply all
Reply to author
Forward
0 new messages