bluesky / ophyd

hardware abstraction in Python with an emphasis on EPICS
https://blueskyproject.io/ophyd
BSD 3-Clause "New" or "Revised" License
51 stars 79 forks source link

Improve FakeEpicsMotor enough to get `mv` working #1135

Open DominicOram opened 1 year ago

DominicOram commented 1 year ago

Currently if we do a bps.mv on a FakeEpicsMotor the plan will fail:

from unittest.mock import MagicMock

import bluesky.plan_stubs as bps
from bluesky import RunEngine
from ophyd import Component, Device, EpicsMotor
from ophyd.sim import make_fake_device
from ophyd.status import Status

class MyDevice(Device):
    x = Component(EpicsMotor, "")

FakeDevice = make_fake_device(MyDevice)
my_fake_device = FakeDevice(name="")

RE = RunEngine()

try:
    RE(bps.mv(my_fake_device.x.get(), 10))
except:
    print(f"Move failed: {my_fake_device.x}")

We can fix this doing something like:

my_fake_device.x.user_setpoint._use_limits = False

def mock_set_position(val: int):
    my_fake_device.x.user_readback.sim_put(val)
    return Status(done=True, success=True)

my_fake_device.x.set =  MagicMock(side_effect=mock_set_position)

RE(bps.mv(my_fake_device.x, 10))

print(f"Success {my_fake_device.x.get()}")

Which will remove trying to get the limits from the PV and make the motor appear to immediately move to the setpoint. I propose that we put something like this in as default behaviour in FakeEpicsMotor. Obviously generally simulating motion could be a pandoras box but this will at least allow plans with a basic mv in them to work