Experiment Scripts
Users can write experimental scripts and these scripts can interact with the Motif using the Motif API in several ways:
- Scripts can operation in a one-time fashion, for example by setting up an experimental protocol consisting of scheduled outputs and recordings. For more experimental scripts which use the scheduler, see here.
- Scripts can also run continuously, manipulating the motif API in realtime.
- Advanced scripts can even perform realtime image processing to implement closed loop behavioural paradigms depending on the animal behaviour.
Running Scripts
Scripts can be run on the Motif PC directly from the WebUI, or they can be run on another computer where they can control Motif remotely.
Directly From the WebUI
Scripts placed in the appropriate directory are then shown in the user
interface, where they can be launched. By default, scripts should be placed
in the directory, /etc/motif/experiments
on Linux or
C:\ProgramData\Motif\Experiments
on Windows.
Tip
If the /etc/motif/experiments
or C:\ProgramData\Motif\Experiments
directory
does not exist, it can be created. You can also change the directory which Motif looks in
for these scripts be adjusting the ExperimentScriptsDirectory
configuration variable
in the config file.
Once you have added your script to the appropriate directory it should appear in the "I/O & Scheduled" tab
Info
The screenshot above shows the result of the example script here.
Clicking "Start" A
will execute the script. If the script runs for a long time, it will indicate
'Running' at B
. If the script crashes you can consult the
adminstration page, clicking on the appropriate 'experiment:'
section, and see any error messages.
Tip
While the Motif user interface provides an easy way to launch scripts, they may
also be launched manually from either on the system, or another computer. This
may provide more debugging information, however take care to provide the IP_ADDRESS
and API_KEY
of the Motif system if required
On Another Computer
The python-motifapi library is pure Python and scripts can therefor be easily run on most PCs in your preferred python environment (such as conda or virtualenv, Windows, Mac or Linux).
When running a script on a PC separate to the Motif PC two things need to be certain
- The Motif PC must be accessible over the network from your PC (please contact support or IT for configuration changes or to confirm network connectivity)
- The
MotifApi()
object must be manually constructed with theIP_ADDRESS
andAPI_KEY
correct for the Motif system.
from motifapi import MotifApi api = MotifApi('192.168.1.1', '0a1e123463d341298205d5433ed64123')
Tip
To find the API_KEY
of a Motif recording system, you can ask support, or connect to it remotely
over ssh and executed the $ recnode-apikey
command.
Writing Scripts
The following examples demonstrate how to use experiment scripts to control Motif itself and IO (flash LEDs). For examples more focused on scheduling actions, see the examples here.
By default, scripts are written in Python and use the python-motifapi library.
- this library wraps the REST+JSON API and handles sending and parsing the responses
- this library is compatible with all motif versions, although real-time image streaming and some IO operations are only supported in motif 5 and above
When an experiment script using this library is launched by Motif, then the
constructed MotifApi()
object is pre-configured for the executing motif
system and you do not need to explicitly specify IP_ADDRESS
and API_KEY
. If not
explicitly included in the example snippets below, a Motif experiment script must
begin with
from motifapi import MotifApi # already configured with correct IP address and API Key api = MotifApi()
Example: Recording Control
Start Recording on All Cameras
api.call('recording/start', duration=5, filename='test', metadata={'genotype': 'wildtype', 'user': 'sarah'})
Stop Recording on All Cameras
api.call('recording/stop')
Start Recording on One Camera
# start recording on camera with serial number 12345 api.call('camera/12345/recording/start', codec='h264-hq')
Example: Copy and Export
# if true, delete files after successful copy api.call('recordings/copy_all', delete_after=True))
Example: Flash One LED
The following two scripts perform the same task 'flash a LED while recording', but use two different methods.
Note
These examples assume your Motif system has an appropriately configured and connected IO Device with one LED. It may not work on your system without modification.
from motifapi import MotifApi # already configured with correct IP address and API Key api = MotifApi() # schedule a stimulus and start recording api.call('schedule/io/led/set', task_name='toggle_led_2s', cron_expression='%2 * * ? * * *', camera_relative=True, value=float('+inf')) api.call('recording/start')
or
api.call('recording/start') while True: api.call('io/led/set', value=random.random()) time.sleep(2.0)
Example: Flash Two LEDs
The following example is slightly more complicated than the above and
alternately flashes a red and blue LED when a specific camera
with serial number 22075785
is connected.
Note
These examples assume your Motif system has an appropriately configured and connected IO Device with two LEDs and a camera with the configured serial number. It may not work on your system without modification.
from motifapi import MotifApi api = MotifApi() camera_serial = '22075785' api.call('io/led_red/set', value=0) api.call('io/led_green/set', value=1) api.call('schedule/camera/%s/io/led_red/set' % camera_serial, task_name='toggle_red', cron_expression='%2 * * ? * * *', camera_relative=True, value=float('+inf')) api.call('schedule/camera/%s/io/led_green/set' % camera_serial, task_name='toggle_green', cron_expression='%2 * * ? * * *', camera_relative=True, value=float('-inf'))
Multiple Camera Support
When experiment scripts are executed, they are passed the associated camera serial number, if executed from a 'camera specific context'. A camera specific context is one of the following situations
- executing a script in a single camera setup
- executing a script from the camera-specific user interface of a connected camera, in a multi-camera setup
Scripts can then adapt their behaviour accordingly. For example, the following script calls different Motif API depending on whether is is launched in a multi- or single-camera context
api = MotifApi() try: sn = os.environ['MOTIF_CAMERA_SERIAL'] api.call('camera/%s/configure' % sn, AcquisitionFrameRate=10.0) except KeyError: api.call('cameras/configure', AcquisitionFrameRate=10.0)
Realtime Streaming
Motif can, with very low latency (<1ms), stream realtime images from the camera, without interfering with the recording, compression, or any other motif functions. This allows developing out of process realtime image processing algorithms for closed loop experiments. Such experiments could for example then provide stimulus to the animal using either Motif connected and configured outputs, or other user provided methods.
Per default streaming is limited to localhost (so such scripts must run on the same PC as Motif), however Motif can be configured to stream also to other network locations if you are aware of the latency implications and have sufficient network infrastructure.
Streaming Images
A realtime image stream can be established as follows (after constructing the api
object with the
correct IP address and API_KEY as indicated above
# small example using opencv to show the image in realtime, outside of motif stream = api.get_stream(stream_type=MotifApi.STREAM_TYPE_IMAGE) if stream is not None: while True: I, md = stream.get_next_image() cv2.imshow('live', I) cv2.waitKey(1)
Info
Motif sends ('pushes' - the image stream is push-pull) a new image every time one is received from the camera, which means that if the application processing the images can not operate at faster than the framerate, images will be buffered by ZMQ and the latency will increase. If this is the case your application should decide how it wants to discard unprocessed frames. Often what you want is to just process the 'most recent frame' - discarding ones that arrived while busy. An example of how to use a separate thread to do this is provided here here.
Streaming State
If you have other more custom data acquisition needs not supported by Motif IO / DAQ support, and want to subsequently
integrate or synchronize this custom data with the motif imagestore frame_number
s and frame_time
s then you can use the realtime state streaming. Motif publishes to this stream, at low latency (<<1ms), the current frame_number
, frame_time
, and other information. A realtime state stream is established as follows
stream = api.get_stream(stream_type=MotifApi.STREAM_TYPE_STATE) if stream is not None: while True: print stream.get_next_state()