Blocks
Blocks are one of IBEX’s central abstractions, which present a uniform interface to any scientifically interesting PV.
The ibex_bluesky_core.devices.block module provides support for four types of blocks:
Read-only (
BlockR)Read/write (
BlockRw)Read/write with setpoint readback (
BlockRwRbv)Motors (
BlockMot)
Note
All signals in bluesky have a strong type. This must match the underlying EPICS type of the PV, which helps to catch problems up-front rather than the middle of a plan.
The following is an example error that will occur at the start of a plan, if trying to connect a str block to a float PV:
ophyd_async.core._utils.NotConnected:
mot: NotConnected:
setpoint_readback: TypeError: TE:NDW2922:CS:SB:mot:SP:RBV has type float not str
setpoint: TypeError: TE:NDW2922:CS:SB:mot:SP has type float not str
readback: TypeError: TE:NDW2922:CS:SB:mot has type float not str
Block types
Read-only (BlockR)
This is a read-only block. It supports bluesky’s Readable protocol, as well as
basic metadata protocols such as HasName.
This type of block is usable by:
Plans like
bluesky.plans.countorbluesky.plans.scanas a detector object.Plan stubs like
bluesky.plan_stubs.rd, which plans may use to get the current value of a block for use within a plan.
A BlockR object does not implement any logic on read - it simply returns the most recent
value of the block.
A simple constructor, block_r, is available, which assumes the current instrument’s PV
prefix:
from ibex_bluesky_core.devices.block import block_r
readable_block = block_r(float, "my_block_name")
Read-write (BlockRw)
This is a read-write block. It supports the same protocols as a BlockR, plus the Movable protocol.
The addition of the Movable protocol means that this type of block can be moved by plan
stubs such as bluesky.plan_stubs.mv or bluesky.plan_stubs.abs_set.
It can also be used as the movable in full plans like bluesky.plans.scan.
Note
In bluesky terminology, any object with a set() method is ‘Movable’. Therefore, a
temperature controller is “moved” from one temperature to another, and a run title
is also “moved” from one title to another.
This is simply a matter of terminology - bluesky fully supports moving things which are not motors, even if the documentation tends to use motors as the examples.
A simple constructor, block_rw, is available, which assumes the current instrument’s PV
prefix:
from ibex_bluesky_core.devices.block import block_rw, BlockWriteConfig
writable_block = block_rw(
float,
"my_block_name",
# Example: configure to always wait 5 seconds after being set.
# For further options, see docstring of BlockWriteConfig.
write_config=BlockWriteConfig(settle_time_s=5.0)
)
Read/write/setpoint-readback (BlockRwRbv)
This is a block with full support for reading and writing as per BlockRw, but with
the addition of bluesky’s Locatable protocol, which allows you to read back the
current setpoint. Where possible, the setpoint will be read back from hardware.
This object is suitable for use in plan stubs such as bluesky.plan_stubs.locate.
This object is also more suitable for use in plans which use relative moves - the relative move will be calculated with respect to the setpoint readback from hardware (if available).
A simple constructor (block_rw_rbv) is available:
from ibex_bluesky_core.devices.block import block_rw_rbv, BlockWriteConfig
rw_rbv_block = block_rw_rbv(
float,
"my_block_name",
# Example: configure to always wait 5 seconds after being set.
# For further options, see docstring of BlockWriteConfig.
write_config=BlockWriteConfig(settle_time_s=5.0)
)
Motors (BlockMot)
This represents a block pointing at a motor record. This has support for:
Reading (
Readable)Writing (
Movable)Limit-checking (
Checkable)Stopping (e.g. on scan abort) (
Stoppable)And advanced use-cases like fly-scanning
This type is recommended to be used if the underlying block is a motor record. It always has
type float, and as such does not take a type argument (unlike the other block types).
Checkable means that moves which would eventually violate limits can be detected by
bluesky simulators, before the plan ever runs. This can help to catch errors before
the plan is executed against hardware. There is also limit-checking at runtime;
a MotorLimitsException will be raised
at runtime if a requested position is outside the motor’s limits.
Stoppable means that the motor can be asked to stop by bluesky. Plans may choose to execute
a stop() on failure, or explicitly during a plan.
Similar to other block types, a utility constructor (block_mot) is available; however, it does not
require an explicit type as motors are always of float data type:
from ibex_bluesky_core.devices.block import block_mot
mot_block = block_mot("motor_block")
A motor block does not need an explicit write config: it always waits for the requested motion
to complete. See BlockMot for a detailed mapping of
the usual write-configuration options and how these are instead achieved by a motor block.
Configuring block write behaviour
BlockRw and BlockRwRbv both take a write_config argument, which can be used to configure
the behaviour on writing to a block, for example tolerances and settle times.
See BlockWriteConfig for a detailed
description of the available options.
Run Control
Run-control information is available via the block.run_control sub-device.
Both configuring and reading the current status of run control are permitted.
The signals available on the run-control subdevice are:
block.run_control.in_range: Whether run-control is currently in-range (bool, read-only)block.run_control.low_limit: Low run-control limit (float, read-write)block.run_control.high_limit: High run-control limit (float, read-write)block.run_control.suspend_if_invalid: Whether to suspend data collection on invalid data (bool, read-write)block.run_control.enabled: Whether run-control is enabled (bool, read-write)block.run_control.out_time: Time, in seconds, for which run-control has been out-of-range (float, read-only)block.run_control.in_time: Time, in seconds, for which run-control has been in-range (float, read-only)
Note
Run control limits are always float, regardless of the datatype of the block.