Hardware Guide

There are two API’s available for hardware control: high level functions that are device independent are described in this document and lower level functions that are more device specific.

If you need lower level functions that are device specific, refer to Nion Swift Instrumentation.

Instrument Control

You can access and control instruments, devices, and hardware sources via the instrument control API.

Getting an Instrument Object

To do instrument control, you will need to get a versioned instrument object from the api object using an instrument_id (see Hardware Configuration).

autostem = api.get_instrument_by_id("autostem", version="1.0")

Instrument Properties

Once you have an instrument object, you can set and get properties on the instrument.

if autostem.get_property_as_bool("ShowTuningImages"):
    show_data()

Properties are typed and the following types are supported:

  • float

  • int

  • str

  • bool

  • float_point

You can also set properties on an instrument.

superscan.set_property_as_float_point("probe_position", (0.5, 0.5))

For more information about these methods, see nion.swift.Facade.Instrument.

Instrument Controls

A set of methods to access a special subset of properties called controls is also available.

Controls are special properties that are always represented as float values and may represent combinations of other controls. Their methods have special features which allow more precise setting within the network of controls.

Autostem controls are characterized as having a internal “local” value added to weighted sum of values from zero or more input controls. Changing the value of an input control can change the output value of other controls.

Setting Output Values

You can set values on controls in such a way as to allow changes to propogate to dependent controls or not.

To set the output value of a control, use the set_control method with no options.

autostem.set_control_output("d3x", d3x_value)

Confirmation

When setting the absolute output value of a control, you can confirm the value gets set by passing an options dict with a value_type key of confirm.

autostem.set_control_output("d3x", 0.0, options={'confirm': True})

You can also add options for tolerance factor when confirming. The tolerance factor default is 1.0 and should be thought of as the nominal tolerance for that control. Passing a higher tolerance factor (for example 1.5) will increase the permitted error margin and passing lower tolerance factor (for example 0.5) will decrease the permitted error margin and consequently make a timeout more likely. The tolerance factor value 0.0 is a special value which removes all checking and only waits for any change at all and then returns.

To set d3x to within 2% of its nominal target value

autostem.set_control_output("d3x", 0.0, options={'confirm': True, 'confirm_tolerance_factor': 1.02})

You can also add timeout options when confirming. The default timeout is 16 seconds.

autostem.set_control_output("d3x", 0.0, options={'confirm': True, 'confirm_timeout': 16.0})

If the timeout occurs before the value is confirmed, a TimeoutException will be raised.

Local Values

You can set the local value of a control by passing an options dict with a value_type key of local.

autostem.set_control_output("d3x", 0.0, options={'value_type': 'local'})

Delta Values

You can change a control by a delta value by passing an options dict with a value_type key of delta.

autostem.set_control_output("d3x", d3x_delta, options={'value_type': 'delta'})

Inform, or Keeping Dependent Outputs Constant

Finally, you can adjust a control in such a way that the output values of dependent controls stay constant. This is useful during setup when you want to change the displayed value without actually changing the dependent outputs. You do this by passing an options dict with a inform key of True. This parameter is named inform for historical reasons but can also be thought of as keep dependent outputs constant.

autostem.set_control_output("d3x", d3x_value, options={'inform': True})

Control State

Finally, you can query the state of a control to see if it exists or to see its current state. The only defined return values at the moment are None and ‘undefined’ state.

if autostem.get_control_state("dqt") is not None:
    run_dqt_adjustment()

For more information about these methods, see nion.swift.Facade.Instrument.

Data Acquisition

In addition to instrument control, you can also control data acquisition on hardware sources.

Introduction

Acquisition can be started in View or Record mode. View mode is an ongoing acquisition whereas Record mode is a single acquisition.

Acquisition is started with frame parameters that specify the readout configuration to be used. You can configure specific frame parameters or use one of the user defined profiles available in the user interface.

In View mode, you can specify the initial frame parameters, but other scripts may be able to change the frame parameters during acquisition. The acquisition API doesn’t attempt to prevent this.

In Record mode, since you are acquiring a single frame, your frame parameters are guaranteed to be used. Record mode can be used while View mode is already in progress. When the Record is finished, the View will continue.

Acquisition code in extensions should be run on threads to prevent locking the user interface. Acquisition code in scripts will always run on threads due to the nature of scripts.

Getting a Hardware Source Object

To do acquisition, you will need to get a versioned hardware_source from the api object using a hardware_source_id (see Hardware Configuration).

camera = api.get_hardware_source_by_id("ronchigram", version="1.0")

Frame Parameters Overview

You will first configure the frame_parameters for the hardware source. There are several ways to do this.

Frame parameters are specific to the hardware source. The easiest way to get valid frame parameters is to ask the camera for the default frame parameters.

frame_parameters = camera.get_default_frame_parameters()

Next you can modify the frame_parameters (this is hardware source specific).

frame_parameters["binning"] = 4
frame_parameters["exposure_ms"] = 200

You can also get the frame parameters for one of the acquisition profiles configured by the user.

frame_parameters = camera.get_frame_parameters_for_profile_by_index(1)

You can get and set the currently selected acquisition profile in the user interface using the profile_index property. Setting the selected acquisition profile is discouraged since it can be confusing to the user if their selected profile suddenly changes.

old_profile_index = camera.profile_index
camera.profile_index = new_profile_index

You can also update the frame parameters associated with a profile. Again, use this ability with caution since it can be confusing to the user to lose their settings.

camera.set_frame_parameters_for_profile_by_index(1, frame_parameters)

Querying Acquisition State

Hardware sources can be in one of several state: idle, viewing/playing, or recording.

is_playing = camera.is_playing
is_recording = camera.is_recording

Note

Recording can occur during viewing, in which case the camera can be viewing/playing and recording simultaneously.

Acquisition Frame Parameters

Hardware sources have frame parameters associated with both view/play and record modes. You can query and set those frame parameters using several methods. Setting the frame parameters will apply the frame parameters to soonest possible frame.

To query and set the frame parameters for view/play mode:

frame_parameters = camera.get_frame_parameters()
camera.set_frame_parameters(frame_parameters)

To query and set the frame parameters for record mode:

frame_parameters = camera.get_record_frame_parameters()
camera.set_record_frame_parameters(frame_parameters)

Controlling Acquisition State

You can control the acquisition view/play state using these methods:

camera.start_playing(frame_parameters, channels_enabled)
camera.stop_playing()
camera.abort_playing()

Passing frame_parameters and channels_enabled are optional. Passing None will use the existing frame parameters and enabled channels. Not all hardware sources support channels.

Stopping will finish the current frame. Aborting will immediately stop acquisition, potentially mid-frame.

You can control acquisition record state using these methods:

camera.start_recording(frame_parameters, channels_enabled)
camera.abort_recording()

Again, frame_parameters and channels_enabled are optional.

Recording occurs on a frame by frame basis, so there is no need to stop recording as it will always finish at the end of a frame. Calling abort_recording will immediately stop recording, if desired.

Recording in this way will generate a new data item.

Note

Recording can occur during view/play. How the view is stopped (stop or abort) to begin recording is specific to the camera implementation. After recording, the view will resume with current frame parameters.

Acquiring Data

You can acquire data during a view. Acquired data is returned as a list of DataAndMetadata objects.

There are a few techniques to grab data:

  • grab_next_to_finish is used to grab data from view/play mode when frame parameters and other state related to the hardware source is already known.

  • grab_next_to_start is used to grab data from view/play mode when you need to ensure that the next frame represents data with new frame parameters or other state related to the hardware source.

  • record is used to grab data in record mode.

You can pass frame parameters and enabled channels to grab_next_to_start and record methods. There is no need to pass them to grab_next_to_finish since that method will be grabbing data from acquisition that is already in progress.

Only a single record can occur at once but there is no defined coordination technique to avoid multiple records from occuring simultaneously. If two records are requested simultaneously, the latest one will override.

All three methods will start either view/play mode or record mode if not already started.

Some example code to demonstate calling these methods.

data_and_metadata_list = camera.grab_next_to_finish(timeout)
data_and_metadata = data_and_metadata_list[0]

data_and_metadata_list = camera.grab_next_to_start(frame_parameters, channels_enabled, timeout)
data_and_metadata = data_and_metadata_list[0]

data_and_metadata_list = hardware_source_api.record(frame_parameters, channels_enabled, timeout)
data_and_metadata = data_and_metadata_list[0]

The frame_parameters, channels_enabled, and timeout parameters are all optional.

For more information about these methods, see nion.swift.Facade.HardwareSource.

Record Tasks

For a Record data acquisition, you can also use an acquisition task.

with contextlib.closing(hardware_source_api.create_record_task(frame_parameters)) as record_task:
    do_concurrent_task()
    data_and_metadata_list = record_task.grab()

The acquisition is started as soon as the Record task is created. The grab method will wait until the recording is done and then return.

Record tasks are useful to do concurrent work while the recording is taking place.

For more information about these methods, see nion.swift.Facade.HardwareSource.

Hardware Configuration

With a hardware_source object, you can set and get properties on the instrument.

if camera.get_property_as_bool("use_gain"):
    do_gain_image_processing()

Properties are typed and the following types are supported:

  • float

  • int

  • str

  • bool

  • float_point

You can also set properties on a hardware source.

superscan.set_property_as_float_point("probe_position", (0.5, 0.5))

For more information about these methods, see nion.swift.Facade.Instrument.

Hardware Source Identifiers

Instruments and hardware sources are identified by id’s. Id’s are divided into direct id’s and aliases. Aliases are configurable in .ini files. For instance, the direct hardware might have a hardware_source_id of nionccd1010 but there might be an alias ronchigram which points to the nionccd1010. It is recommended to make an alias for each application that you write, making it easy for users to configure what camera to use for your application.