Basic, Part B: Motor and Move#

From APS Python Training for Bluesky Data Acquisition.

Objective

Work with an EPICS positioning motor (for precise positioning) in Bluesky and related tools.

First, we’ll connect with an EPICS motor (using ophyd), and then use the Bluesky software to scan the motor (with the scaler from basic_scaler).

Load ophyd device support for the EpicsMotor and connect with one EPICS motor channel. We have a synApps XXX-style IOC with the prefix gp:. It has a scaler, 16 soft channel motors, and some other support we’ll ignore in this lesson.

note: This tutorial expects to find an EPICS IOC on the local network configured as a synApps xxx IOC with prefix gp:.

A docker container is available to provide this IOC. See this URL for instructions: prjemian/epics-docker

[1]:
from ophyd import EpicsMotor
m1 = EpicsMotor("gp:m1", name="m1")
m1.wait_for_connection()

Show the current value of the motor (that’s the .RBV field, in case you were interested).

[2]:
print(f"{m1.position = }")
m1.position = 1.0

Connect the scaler (as was done in the basic_scaler lesson). Define some of the channel names and clear out others.

[3]:
from ophyd.scaler import ScalerCH
scaler = ScalerCH("gp:scaler1", name="scaler")
scaler.wait_for_connection()

# Since there are no detectors actually connected to this scaler,
# we can change names at our choice.  A real scaler will have
# detectors connected to specific channels and we should not modify
# these names without regard to how signals are physically connected.
scaler.channels.chan01.chname.put("clock")
scaler.channels.chan02.chname.put("I0")
scaler.channels.chan03.chname.put("scint")
scaler.channels.chan04.chname.put("")
scaler.channels.chan05.chname.put("")
scaler.channels.chan06.chname.put("")
scaler.channels.chan07.chname.put("")
scaler.channels.chan08.chname.put("")
scaler.channels.chan09.chname.put("")

Use only the channels with EPICS names, those are the interesting channels.

[4]:
scaler.select_channels(None)
scaler.read()
[4]:
OrderedDict([('clock', {'value': 16000000.0, 'timestamp': 1684257260.223683}),
             ('I0', {'value': 7.0, 'timestamp': 1684257260.223683}),
             ('scint', {'value': 8.0, 'timestamp': 1684257260.223683}),
             ('scaler_time', {'value': 1.6, 'timestamp': 1684257260.223683})])

Create a RunEngine but do not connect it with a data collection strategy. That will come in the next lessons.

[5]:
from bluesky import RunEngine
import bluesky.plans as bp
RE = RunEngine({})

Run a step scan using the motor and the scaler.

[6]:
RE(bp.scan([scaler], m1, -1, 1, 5))
[6]:
('588b3330-2fc0-48db-8943-0383db1d22f0',)

Ah, yes. Nothing to see here since we did not setup anything to receive the documents from the RunEngine. Here’s the basic callback from the basic_scaler lesson.

[7]:
import pprint
def myCallback(key, doc):
    print()
    print(key, len(doc))
    pprint.pprint(doc)

Repeat the same scan but handle the document stream with myCallback().

[8]:
RE(bp.scan([scaler], m1, -1, 1, 5), myCallback)

start 15
{'detectors': ['scaler'],
 'hints': {'dimensions': [(['m1'], 'primary')]},
 'motors': ('m1',),
 'num_intervals': 4,
 'num_points': 5,
 'plan_args': {'args': ["EpicsMotor(prefix='gp:m1', name='m1', "
                        'settle_time=0.0, timeout=None, '
                        "read_attrs=['user_readback', 'user_setpoint'], "
                        "configuration_attrs=['user_offset', "
                        "'user_offset_dir', 'velocity', 'acceleration', "
                        "'motor_egu'])",
                        -1,
                        1],
               'detectors': ["ScalerCH(prefix='gp:scaler1', name='scaler', "
                             "read_attrs=['channels', 'channels.chan01', "
                             "'channels.chan01.s', 'channels.chan02', "
                             "'channels.chan02.s', 'channels.chan03', "
                             "'channels.chan03.s', 'time'], "
                             "configuration_attrs=['channels', "
                             "'channels.chan01', 'channels.chan01.chname', "
                             "'channels.chan01.preset', "
                             "'channels.chan01.gate', 'channels.chan02', "
                             "'channels.chan02.chname', "
                             "'channels.chan02.preset', "
                             "'channels.chan02.gate', 'channels.chan03', "
                             "'channels.chan03.chname', "
                             "'channels.chan03.preset', "
                             "'channels.chan03.gate', 'count_mode', 'delay', "
                             "'auto_count_delay', 'freq', 'preset_time', "
                             "'auto_count_time', 'egu'])"],
               'num': 5,
               'per_step': 'None'},
 'plan_name': 'scan',
 'plan_pattern': 'inner_product',
 'plan_pattern_args': {'args': ["EpicsMotor(prefix='gp:m1', name='m1', "
                                'settle_time=0.0, timeout=None, '
                                "read_attrs=['user_readback', "
                                "'user_setpoint'], "
                                "configuration_attrs=['user_offset', "
                                "'user_offset_dir', 'velocity', "
                                "'acceleration', 'motor_egu'])",
                                -1,
                                1],
                       'num': 5},
 'plan_pattern_module': 'bluesky.plan_patterns',
 'plan_type': 'generator',
 'scan_id': 2,
 'time': 1684257283.2970834,
 'uid': '27c27453-9632-4f8c-b0a7-602c5db0a2e1',
 'versions': {'bluesky': '1.10.0', 'ophyd': '1.7.0'}}

descriptor 8
{'configuration': {'m1': {'data': {'m1_acceleration': 0.2,
                                   'm1_motor_egu': 'degrees',
                                   'm1_user_offset': 0.0,
                                   'm1_user_offset_dir': 0,
                                   'm1_velocity': 1.0},
                          'data_keys': OrderedDict([('m1_user_offset',
                                                     {'dtype': 'number',
                                                      'lower_ctrl_limit': -1e+300,
                                                      'precision': 4,
                                                      'shape': [],
                                                      'source': 'PV:gp:m1.OFF',
                                                      'units': 'degrees',
                                                      'upper_ctrl_limit': 1e+300}),
                                                    ('m1_user_offset_dir',
                                                     {'dtype': 'integer',
                                                      'enum_strs': ('Pos',
                                                                    'Neg'),
                                                      'lower_ctrl_limit': None,
                                                      'shape': [],
                                                      'source': 'PV:gp:m1.DIR',
                                                      'units': None,
                                                      'upper_ctrl_limit': None}),
                                                    ('m1_velocity',
                                                     {'dtype': 'number',
                                                      'lower_ctrl_limit': 0.1,
                                                      'precision': 4,
                                                      'shape': [],
                                                      'source': 'PV:gp:m1.VELO',
                                                      'units': 'degrees',
                                                      'upper_ctrl_limit': 0.0}),
                                                    ('m1_acceleration',
                                                     {'dtype': 'number',
                                                      'lower_ctrl_limit': -1e+300,
                                                      'precision': 4,
                                                      'shape': [],
                                                      'source': 'PV:gp:m1.ACCL',
                                                      'units': 'sec',
                                                      'upper_ctrl_limit': 1e+300}),
                                                    ('m1_motor_egu',
                                                     {'dtype': 'string',
                                                      'lower_ctrl_limit': None,
                                                      'shape': [],
                                                      'source': 'PV:gp:m1.EGU',
                                                      'units': None,
                                                      'upper_ctrl_limit': None})]),
                          'timestamps': {'m1_acceleration': 1684257260.388981,
                                         'm1_motor_egu': 1684257260.388981,
                                         'm1_user_offset': 1684257260.388981,
                                         'm1_user_offset_dir': 1684257260.388981,
                                         'm1_velocity': 1684257260.388981}},
                   'scaler': {'data': {'scaler_auto_count_delay': 0.0,
                                       'scaler_auto_count_time': 1.0,
                                       'scaler_channels_chan01_chname': 'clock',
                                       'scaler_channels_chan01_gate': 'Y',
                                       'scaler_channels_chan01_preset': 15000000.0,
                                       'scaler_channels_chan02_chname': 'I0',
                                       'scaler_channels_chan02_gate': 'N',
                                       'scaler_channels_chan02_preset': 0.0,
                                       'scaler_channels_chan03_chname': 'scint',
                                       'scaler_channels_chan03_gate': 'N',
                                       'scaler_channels_chan03_preset': 0.0,
                                       'scaler_count_mode': 'OneShot',
                                       'scaler_delay': 0.0,
                                       'scaler_egu': '',
                                       'scaler_freq': 10000000.0,
                                       'scaler_preset_time': 1.5},
                              'data_keys': OrderedDict([('scaler_channels_chan01_chname',
                                                         {'dtype': 'string',
                                                          'lower_ctrl_limit': None,
                                                          'shape': [],
                                                          'source': 'PV:gp:scaler1.NM1',
                                                          'units': None,
                                                          'upper_ctrl_limit': None}),
                                                        ('scaler_channels_chan01_preset',
                                                         {'dtype': 'number',
                                                          'lower_ctrl_limit': 0.0,
                                                          'precision': 0,
                                                          'shape': [],
                                                          'source': 'PV:gp:scaler1.PR1',
                                                          'units': '',
                                                          'upper_ctrl_limit': 0.0}),
                                                        ('scaler_channels_chan01_gate',
                                                         {'dtype': 'string',
                                                          'enum_strs': ('N',
                                                                        'Y'),
                                                          'lower_ctrl_limit': None,
                                                          'shape': [],
                                                          'source': 'PV:gp:scaler1.G1',
                                                          'units': None,
                                                          'upper_ctrl_limit': None}),
                                                        ('scaler_channels_chan02_chname',
                                                         {'dtype': 'string',
                                                          'lower_ctrl_limit': None,
                                                          'shape': [],
                                                          'source': 'PV:gp:scaler1.NM2',
                                                          'units': None,
                                                          'upper_ctrl_limit': None}),
                                                        ('scaler_channels_chan02_preset',
                                                         {'dtype': 'number',
                                                          'lower_ctrl_limit': 0.0,
                                                          'precision': 0,
                                                          'shape': [],
                                                          'source': 'PV:gp:scaler1.PR2',
                                                          'units': '',
                                                          'upper_ctrl_limit': 0.0}),
                                                        ('scaler_channels_chan02_gate',
                                                         {'dtype': 'string',
                                                          'enum_strs': ('N',
                                                                        'Y'),
                                                          'lower_ctrl_limit': None,
                                                          'shape': [],
                                                          'source': 'PV:gp:scaler1.G2',
                                                          'units': None,
                                                          'upper_ctrl_limit': None}),
                                                        ('scaler_channels_chan03_chname',
                                                         {'dtype': 'string',
                                                          'lower_ctrl_limit': None,
                                                          'shape': [],
                                                          'source': 'PV:gp:scaler1.NM3',
                                                          'units': None,
                                                          'upper_ctrl_limit': None}),
                                                        ('scaler_channels_chan03_preset',
                                                         {'dtype': 'number',
                                                          'lower_ctrl_limit': 0.0,
                                                          'precision': 0,
                                                          'shape': [],
                                                          'source': 'PV:gp:scaler1.PR3',
                                                          'units': '',
                                                          'upper_ctrl_limit': 0.0}),
                                                        ('scaler_channels_chan03_gate',
                                                         {'dtype': 'string',
                                                          'enum_strs': ('N',
                                                                        'Y'),
                                                          'lower_ctrl_limit': None,
                                                          'shape': [],
                                                          'source': 'PV:gp:scaler1.G3',
                                                          'units': None,
                                                          'upper_ctrl_limit': None}),
                                                        ('scaler_count_mode',
                                                         {'dtype': 'string',
                                                          'enum_strs': ('OneShot',
                                                                        'AutoCount'),
                                                          'lower_ctrl_limit': None,
                                                          'shape': [],
                                                          'source': 'PV:gp:scaler1.CONT',
                                                          'units': None,
                                                          'upper_ctrl_limit': None}),
                                                        ('scaler_delay',
                                                         {'dtype': 'number',
                                                          'lower_ctrl_limit': 0.0,
                                                          'precision': 3,
                                                          'shape': [],
                                                          'source': 'PV:gp:scaler1.DLY',
                                                          'units': '',
                                                          'upper_ctrl_limit': 0.0}),
                                                        ('scaler_auto_count_delay',
                                                         {'dtype': 'number',
                                                          'lower_ctrl_limit': 0.0,
                                                          'precision': 3,
                                                          'shape': [],
                                                          'source': 'PV:gp:scaler1.DLY1',
                                                          'units': '',
                                                          'upper_ctrl_limit': 0.0}),
                                                        ('scaler_freq',
                                                         {'dtype': 'number',
                                                          'lower_ctrl_limit': 0.0,
                                                          'precision': 3,
                                                          'shape': [],
                                                          'source': 'PV:gp:scaler1.FREQ',
                                                          'units': '',
                                                          'upper_ctrl_limit': 0.0}),
                                                        ('scaler_preset_time',
                                                         {'dtype': 'number',
                                                          'lower_ctrl_limit': 0.0,
                                                          'precision': 3,
                                                          'shape': [],
                                                          'source': 'PV:gp:scaler1.TP',
                                                          'units': '',
                                                          'upper_ctrl_limit': 0.0}),
                                                        ('scaler_auto_count_time',
                                                         {'dtype': 'number',
                                                          'lower_ctrl_limit': 0.0,
                                                          'precision': 3,
                                                          'shape': [],
                                                          'source': 'PV:gp:scaler1.TP1',
                                                          'units': '',
                                                          'upper_ctrl_limit': 0.0}),
                                                        ('scaler_egu',
                                                         {'dtype': 'string',
                                                          'lower_ctrl_limit': None,
                                                          'shape': [],
                                                          'source': 'PV:gp:scaler1.EGU',
                                                          'units': None,
                                                          'upper_ctrl_limit': None})]),
                              'timestamps': {'scaler_auto_count_delay': 1684257287.283159,
                                             'scaler_auto_count_time': 1684257287.283159,
                                             'scaler_channels_chan01_chname': 1684257287.283159,
                                             'scaler_channels_chan01_gate': 1684257287.283159,
                                             'scaler_channels_chan01_preset': 1684257287.283159,
                                             'scaler_channels_chan02_chname': 1684257287.283159,
                                             'scaler_channels_chan02_gate': 1684257287.283159,
                                             'scaler_channels_chan02_preset': 1684257287.283159,
                                             'scaler_channels_chan03_chname': 1684257287.283159,
                                             'scaler_channels_chan03_gate': 1684257287.283159,
                                             'scaler_channels_chan03_preset': 1684257287.283159,
                                             'scaler_count_mode': 1684257287.283159,
                                             'scaler_delay': 1684257287.283159,
                                             'scaler_egu': 1684257287.283159,
                                             'scaler_freq': 1684257287.283159,
                                             'scaler_preset_time': 1684257287.283159}}},
 'data_keys': {'I0': {'dtype': 'number',
                      'lower_ctrl_limit': 0.0,
                      'object_name': 'scaler',
                      'precision': 0,
                      'shape': [],
                      'source': 'PV:gp:scaler1.S2',
                      'units': '',
                      'upper_ctrl_limit': 0.0},
               'clock': {'dtype': 'number',
                         'lower_ctrl_limit': 0.0,
                         'object_name': 'scaler',
                         'precision': 0,
                         'shape': [],
                         'source': 'PV:gp:scaler1.S1',
                         'units': '',
                         'upper_ctrl_limit': 0.0},
               'm1': {'dtype': 'number',
                      'lower_ctrl_limit': -1000.0,
                      'object_name': 'm1',
                      'precision': 4,
                      'shape': [],
                      'source': 'PV:gp:m1.RBV',
                      'units': 'degrees',
                      'upper_ctrl_limit': 1000.0},
               'm1_user_setpoint': {'dtype': 'number',
                                    'lower_ctrl_limit': -1000.0,
                                    'object_name': 'm1',
                                    'precision': 4,
                                    'shape': [],
                                    'source': 'PV:gp:m1.VAL',
                                    'units': 'degrees',
                                    'upper_ctrl_limit': 1000.0},
               'scaler_time': {'dtype': 'number',
                               'lower_ctrl_limit': 0.0,
                               'object_name': 'scaler',
                               'precision': 3,
                               'shape': [],
                               'source': 'PV:gp:scaler1.T',
                               'units': '',
                               'upper_ctrl_limit': 0.0},
               'scint': {'dtype': 'number',
                         'lower_ctrl_limit': 0.0,
                         'object_name': 'scaler',
                         'precision': 0,
                         'shape': [],
                         'source': 'PV:gp:scaler1.S3',
                         'units': '',
                         'upper_ctrl_limit': 0.0}},
 'hints': {'m1': {'fields': ['m1']},
           'scaler': {'fields': ['clock', 'I0', 'scint']}},
 'name': 'primary',
 'object_keys': {'m1': ['m1', 'm1_user_setpoint'],
                 'scaler': ['clock', 'I0', 'scint', 'scaler_time']},
 'run_start': '27c27453-9632-4f8c-b0a7-602c5db0a2e1',
 'time': 1684257287.3060765,
 'uid': 'facadfef-8068-4c5b-b641-c9ebb91e1220'}

event 7
{'data': {'I0': 8.0,
          'clock': 16000000.0,
          'm1': -1.0,
          'm1_user_setpoint': -1.0,
          'scaler_time': 1.6,
          'scint': 8.0},
 'descriptor': 'facadfef-8068-4c5b-b641-c9ebb91e1220',
 'filled': {},
 'seq_num': 1,
 'time': 1684257288.5562477,
 'timestamps': {'I0': 1684257287.283159,
                'clock': 1684257287.283159,
                'm1': 1684257285.657212,
                'm1_user_setpoint': 1684257283.400607,
                'scaler_time': 1684257287.283159,
                'scint': 1684257287.283159},
 'uid': 'e3cadd5d-36aa-4d65-a86c-e5e3b40f38db'}

event 7
{'data': {'I0': 9.0,
          'clock': 16000000.0,
          'm1': -0.5,
          'm1_user_setpoint': -0.5,
          'scaler_time': 1.6,
          'scint': 7.0},
 'descriptor': 'facadfef-8068-4c5b-b641-c9ebb91e1220',
 'filled': {},
 'seq_num': 2,
 'time': 1684257290.9914892,
 'timestamps': {'I0': 1684257290.988253,
                'clock': 1684257290.988253,
                'm1': 1684257289.36312,
                'm1_user_setpoint': 1684257288.603839,
                'scaler_time': 1684257290.988253,
                'scint': 1684257290.988253},
 'uid': '3b448615-cfbf-4fa6-949b-bfc5f38669db'}

event 7
{'data': {'I0': 7.0,
          'clock': 16000000.0,
          'm1': 0.0,
          'm1_user_setpoint': 0.0,
          'scaler_time': 1.6,
          'scint': 5.0},
 'descriptor': 'facadfef-8068-4c5b-b641-c9ebb91e1220',
 'filled': {},
 'seq_num': 3,
 'time': 1684257293.3976073,
 'timestamps': {'I0': 1684257293.391206,
                'clock': 1684257293.391206,
                'm1': 1684257291.768174,
                'm1_user_setpoint': 1684257291.056937,
                'scaler_time': 1684257293.391206,
                'scint': 1684257293.391206},
 'uid': 'd170727a-038b-432a-9fa4-a14d9857e41d'}

event 7
{'data': {'I0': 7.0,
          'clock': 16000000.0,
          'm1': 0.5,
          'm1_user_setpoint': 0.5,
          'scaler_time': 1.6,
          'scint': 8.0},
 'descriptor': 'facadfef-8068-4c5b-b641-c9ebb91e1220',
 'filled': {},
 'seq_num': 4,
 'time': 1684257295.9012296,
 'timestamps': {'I0': 1684257295.898317,
                'clock': 1684257295.898317,
                'm1': 1684257294.272727,
                'm1_user_setpoint': 1684257293.50185,
                'scaler_time': 1684257295.898317,
                'scint': 1684257295.898317},
 'uid': '47180649-a9b0-4a10-b380-95541a096c24'}

event 7
{'data': {'I0': 9.0,
          'clock': 16000000.0,
          'm1': 1.0,
          'm1_user_setpoint': 1.0,
          'scaler_time': 1.6,
          'scint': 7.0},
 'descriptor': 'facadfef-8068-4c5b-b641-c9ebb91e1220',
 'filled': {},
 'seq_num': 5,
 'time': 1684257298.4070554,
 'timestamps': {'I0': 1684257298.403889,
                'clock': 1684257298.403889,
                'm1': 1684257296.778319,
                'm1_user_setpoint': 1684257295.981387,
                'scaler_time': 1684257298.403889,
                'scint': 1684257298.403889},
 'uid': '303a8aa8-8fdb-44c6-8366-1b1cc3000b08'}

stop 6
{'exit_status': 'success',
 'num_events': {'primary': 5},
 'reason': '',
 'run_start': '27c27453-9632-4f8c-b0a7-602c5db0a2e1',
 'time': 1684257298.5027833,
 'uid': 'ed996294-1aaf-4052-b82b-c1b7d5bc9a3a'}
[8]:
('27c27453-9632-4f8c-b0a7-602c5db0a2e1',)

Summary#

We’ll show this code as a python program:

#!/usr/bin/env python

"""Basic : motor"""

from ophyd import EpicsMotor
from ophyd.scaler import ScalerCH
from bluesky import RunEngine
import bluesky.plans as bp


def myCallback(key, doc):
    print()
    print(key, len(doc))
    pprint.pprint(doc)


m1 = EpicsMotor("gp:m1", name="m1")
m1.wait_for_connection()
print(m1.position)

scaler = ScalerCH("gp:scaler1", name="scaler")
scaler.wait_for_connection()


# Since there are no detectors actually connected to this scaler,
# we can change names at our choice.  A real scaler will have
# detectors connected to specific channels and we should not modify
# these names without regard to how signals are physically connected.
scaler.channels.chan01.chname.put("clock")
scaler.channels.chan02.chname.put("I0")
scaler.channels.chan03.chname.put("scint")
scaler.channels.chan04.chname.put("")
scaler.channels.chan05.chname.put("")
scaler.channels.chan06.chname.put("")
scaler.channels.chan07.chname.put("")
scaler.channels.chan08.chname.put("")
scaler.channels.chan09.chname.put("")


scaler.match_names()
scaler.select_channels()
print(scaler.read())

RE = RunEngine({})

RE(bp.scan([scaler], m1, -1, 1, 5))

RE(bp.scan([scaler], m1, -1, 1, 5), myCallback)