APS-4ID-POLAR / polar_instrument

Bluesky setup for the POLAR beamline
0 stars 0 forks source link

Rough flyscan #15

Open gfabbris opened 5 months ago

gfabbris commented 5 months ago

We did some testing on running a "rough" flyscan that is completely managed by Bluesky, meaning that there is no external synchronization. First, the IOC motor setup needs to be modified to increase the readout speed:

From @jwkim-anl :

in vme.cmd file, find 'oms58Setup(7, 0x1000, 190, 5, 10)' and change '10' to '60' and reboot. It may do the 60 Hz update which means 16.7 ms update.

So we can have a plan that sends the motor to the final position and then reads the data as fast as it can. Based on our preliminary tests, a bluesky.plan_stubs.trigger_and_read can process 1 scaler + 1 motor in around 40 msec, with scaler counting for 10 msec. See plan and data below.

Some of what remains to be done:

from bluesky.plan_stubs import trigger_and_read
from bluesky.plans import count
from bluesky.preprocessors import stage_decorator, run_decorator
from bluesky.utils import Msg
from instrument.collection import abs_set, mv

def flyscan(detectors, motor, start, end, speed, delay=0):

    yield from mv(motor, start)

    # change this to staging
    speed_stash = yield from rd(motor.velocity)
    yield from mv(motor.velocity, speed)

    if per_shot is None:
        per_shot = trigger_and_read

    devices = list(detectors) + [motor]

    @stage_decorator(devices)
    @run_decorator(md={})
    def inner_count():
        yield from abs_set(motor.user_setpoint, end)
        # yield from sleep(0.1)
        _motor_moving_stash = False
        while True:
            if (_motor_moving_stash is True) and (motor.moving is False):
                break
            _motor_moving_stash = motor.moving
            yield Msg('checkpoint')
            yield from trigger_and_read(devices)
            yield from sleep(delay)  # TODO: tweak to account for how long this took?

        yield from mv(motor, end)

    return (yield from inner_count())
    yield from mov(motor.velocity, speed_stash)

image

image

gfabbris commented 5 months ago

A couple of extra ideas:

gfabbris commented 5 months ago

Some extra tweaks

def flyscan(detectors, motor, start, end, speed, delay=0, per_shot=None):

    yield from mv(motor, start)

    # change this to staging
    speed_stash = yield from rd(motor.velocity)
    print(speed_stash)
    yield from mv(motor.velocity, speed)

    if per_shot is None:
        per_shot = trigger_and_read

    devices = list(detectors) + [motor]

    @stage_decorator(devices)
    @monitor_during_decorator([motor])
    @run_decorator(md={})
    def inner_count():
        yield from abs_set(motor.user_setpoint, end)
        _motor_moving_stash = False
        while True:
            t0 = time()
            if (_motor_moving_stash is True) and (motor.moving is False):
                break
            if (_motor_moving_stash is False) and (motor.moving is True):
                _motor_moving_stash = True
            yield Msg('checkpoint')
            yield from trigger_and_read(devices)
            d = delay - (time() - t0)
            if d > 0:
                yield from sleep(d)

        yield from mv(motor, end)
        yield from mv(motor.velocity, speed_stash)

    return (yield from inner_count())
gfabbris commented 5 months ago

To get the .read() timestamps: cat[-1].primary.timestamps.read()

gfabbris commented 4 months ago

We will need to tweak the detector trigger

gfabbris commented 2 months ago

Using the ACS controller, the fastest EPICS updated the position was ~200 Hz. This was done by only changing the MOVING_POLL to 0.001 (smaller numbers didn't make it faster), this can be added as an option here: https://github.com/epics-motor/motorAcsMotion/blob/f99eda1de1cdb43fae1f9c8b9f9d763f5aceca4b/iocs/acsMotionIOC/iocBoot/iocAcsMotion/AcsMotion.cmd#L4