Skip to content

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 the IP_ADDRESS and API_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_numbers and frame_times 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()