by

Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
    Kyle Sunden
    @ksunden_gitlab
    
    import asyncio
    from yaqd_core import Hardware
    
    class SlowHardware(Hardware):
        _kind = "slow-hardware"
    
        def _set_position(self, position):
            self._loop.create_task(self.wait_and_set(position))
    
        async def wait_and_set(self, position):
            self._busy = True
            await asyncio.sleep(2)
            self._position = position
            self._busy = False
    
    if __name__ == "__main__":
        SlowHardware.main()
    Then just python slow_motor_test.py --config config.toml
    Or whatever you call the python file, rather
    (I will note that I did not put any protections in there for calling set_position multiple times while it is 'moving', more properly I would. Most real hardware you set the busy state via other means, so it can handle it fine, some you do have to prempt motion as its occurring.)
    Till Stensitzki
    @Tillsten
    isn't json rpc little bit slow for sensor readout?
    Thomas A Caswell
    @tacaswell
    from ophyd import Device, Component as Cpt, Signal, DeviceStatus
    
    
    class YaqMotor(Device):
        setpoint = Cpt(Signal, kind="hinted")
        readback = Cpt(Signal)
        busy = Cpt(Signal, kind="omitted")
    
        def __init__(self, port, *, name):
            self._client = yaqc.Client(port)
            super().__init__(name=name)
            # force initial reading
            self.read()
    
        def set(self, value):
            self._client.send("set_position", value)
            st = DeviceStatus(self)
            # TODO set up thread to poll busy, for now insta-done
            st._finished()
            # update the signals
            self.read()
            return st
    
        def read(self):
            v = self._client.send("get_state")
            self.setpoint.put(v["destination"])
            self.readback.put(v["position"])
            return super().read()
    Blaise Thompson
    @untzag
    @Tillsten yes it can be slow if you need to transfer a relatively large amount of data
    Thomas A Caswell
    @tacaswell
    there are lots of things wrong with that class, but that is enough to make bluesky happy to use the device...
    Blaise Thompson
    @untzag
    our approach is to do data processing on the daemon side, and transfer the smaller processed arrays
    Kyle Sunden
    @ksunden_gitlab

    For a lot of what we have been doing, our sensors are scalar values... That said, we are looking towards array detecteion/cameras.

    I have some ideas, including something I think I saw in Ophyd, which is writing directly to a file on the daemon side for such large detectors (thereby only needing to transmit what is actually displayed in a client application over the RPC)

    Blaise Thompson
    @untzag
    I'll also note that you can use yaq daemons for a subset of your hardware, and use a more direct approach for any really high density information like array detectors
    @tacaswell wow that's super helpful
    Thomas A Caswell
    @tacaswell
    
    In [49]: RE(bp.scan([], ym, -5, 5, 25))                                                                                                                              
    
    
    Transient Scan ID: 8     Time: 2020-04-08 19:22:56
    Persistent Unique Scan ID: '667c5f23-c416-4ee7-9004-86c722454a00'
    New stream: 'primary'
    +-----------+------------+-------------+
    |   seq_num |       time | ym_setpoint |
    +-----------+------------+-------------+
    |         1 | 19:22:56.6 |      -5.000 |
    |         2 | 19:22:56.6 |      -4.583 |
    |         3 | 19:22:56.6 |      -4.167 |
    |         4 | 19:22:56.6 |      -3.750 |
    |         5 | 19:22:56.6 |      -3.333 |
    |         6 | 19:22:56.6 |      -2.917 |
    |         7 | 19:22:56.6 |      -2.500 |
    |         8 | 19:22:56.6 |      -2.083 |
    |         9 | 19:22:56.6 |      -1.667 |
    |        10 | 19:22:56.6 |      -1.250 |
    |        11 | 19:22:56.6 |      -0.833 |
    |        12 | 19:22:56.6 |      -0.417 |
    |        13 | 19:22:56.6 |       0.000 |
    |        14 | 19:22:56.6 |       0.417 |
    |        15 | 19:22:56.6 |       0.833 |
    |        16 | 19:22:56.6 |       1.250 |
    |        17 | 19:22:56.6 |       1.667 |
    |        18 | 19:22:56.6 |       2.083 |
    |        19 | 19:22:56.6 |       2.500 |
    |        20 | 19:22:56.6 |       2.917 |
    |        21 | 19:22:56.6 |       3.333 |
    |        22 | 19:22:56.6 |       3.750 |
    |        23 | 19:22:56.6 |       4.167 |
    |        24 | 19:22:56.6 |       4.583 |
    |        25 | 19:22:56.6 |       5.000 |
    +-----------+------------+-------------+
    generator scan ['667c5f23'] (scan num: 8)
    
    
    
    Out[49]: ('667c5f23-c416-4ee7-9004-86c722454a00',)
    that is a very fast motor :-p
    Till Stensitzki
    @Tillsten
    Some real motors are not much slower :)
    Assuming 500 mm/s, it would have been 20 mu s
    Thomas A Caswell
    @tacaswell
    from ophyd import Device, Component as Cpt, Signal, DeviceStatus
    import yaqc
    import threading
    import time
    
    class YaqMotor(Device):
        setpoint = Cpt(Signal, kind="hinted")
        readback = Cpt(Signal)
        busy = Cpt(Signal, kind="omitted")
    
        def __init__(self, port, *, name):
            self._client = yaqc.Client(port)
            assert 'has-position' in self._client.send('get_traits')
            self._busy_lock = threading.Lock()
            super().__init__(name=name)
            # force initial reading
            self._read_yaq()
    
        def set(self, value):
            with self._busy_lock:
                self.busy.put(1)
            self._client.send("set_position", value)
            st = DeviceStatus(self)
    
            def poll_busy():
                busy = self._client.send('busy')
                while busy:
                    time.sleep(.1)
                    busy = self._client.send('busy')
                with self._busy_lock:
                    self.busy.put(int(busy))
                st._finished()
    
            threading.Thread(target=poll_busy).start()
            # update the signals
            self._read_yaq()        
            return st
    
        def _read_yaq(self):
            v = self._client.send("get_state")
            self.setpoint.put(v["destination"])
            self.readback.put(v["position"])
            b = self._client.send('busy')
            with self._busy_lock:
                self.busy.put(int(b))
    
        def read(self):
            self._read_yaq()
            return super().read()
    
    
    ym = YaqMotor(38001, name='ym')
    the version that waits for the slow motor...
    Blaise Thompson
    @untzag
    @tacaswell thanks so much you've really gone above and beyond in return to my humble publication request
    Thomas A Caswell
    @tacaswell
    this is much more fun than writing papers ;)
    Blaise Thompson
    @untzag
    believe me I don't want to reinvent wheels... seems like there is a lot that I could just have if I can get a foot in the door with bluesky
    at the very least it's neat to imagine that we could just use your implementation for directives and client interfaces
    @Tillsten if you ever want to chat more directly about ultrafast spectroscopy hit me up :smile:
    @ksunden_gitlab and I have specific packages for OPAs, tuning spectrometers, multidimensional spectroscopy data processing and simulation packages... and we would love to have more force behind those of course
    Thomas A Caswell
    @tacaswell
    there is also https://github.com/python-data-acquisition which is coming out of optical micoscopy
    Kyle Sunden
    @ksunden_gitlab
    I follow along there (learned about it the same place you did over on pyqtgraph slack)... But hesitated posting yet because we don't have the best soluton for large array detectors yet
    Blaise Thompson
    @untzag
    wow... so many parallel projects
    blows my mind honestly
    Till Stensitzki
    @Tillsten
    @untzag We mostly doing pump-probe, my data pipeline for that is at https://github.com/Tillsten/skultrafast
    In the instrumentation space there is also https://github.com/Exopy/exopy
    Uses enaml which also quite cool, but again needs a buy in. Also the seperation between experiment and monitoring is a little bit to strict for my usecases.
    Due the amount on manual alignement we are doing, having direct responsive views for monitoring is abolutly essential.
    Till Stensitzki
    @Tillsten
    Alignment is much easier with 60 hz than with 10
    I would like to team up, but currently I have to write up some grants, since my funding ends this year.
    Blaise Thompson
    @untzag
    awesome thanks for the links @Tillsten
    Blaise Thompson
    @untzag
    are there examples or opinions regarding using bluesky as a "backend" for an entirely graphical user interface
    for example, write a custom pyside2 app that allows users to interactively set hardware, and then configure and launch plans
    not necessarily thinking of a gui which encompasses the full flexibility of bluesky, but just a simple ui for repetitive experiments on more "static" instruments
    any thoughts would be appreciated :smile:
    Thomas A Caswell
    @tacaswell
    You should look at pydm (https://github.com/slaclab/pydm)
    Thomas A Caswell
    @tacaswell
    which is more about working directly with the control layer to see the prompt monitoring / poking the hardware (the tight human-in-the-loop process Till was talking about above)
    there has been a scattering of work on putting bluesky behind a GUI (use the UI to collect user input, call the RE on pushing a button). It works, but we have not fully settled on "the" solution or a standard set of widgets etc
    https://github.com/bluesky/bluesky-ui <- that needs some love
    we also have some very very beamline specific tools that have grown
    Blaise Thompson
    @untzag
    thanks---this is helpful
    Thomas A Caswell
    @tacaswell
    I tend to think if this is nested control loops. There is a very tight loop that should be below the control system (things like PID loops etc), tight human-in the loop tweaking (due with an engineering screen interacting directly with the control layer), scientific orchestration (done via bluesky plans), CLI driven data acquisition (using RE + plans), user acquisition screens (which in turn defers to bluesky)
    yangdl-github
    @yangdl-github

    Dear all, I'm new to bluesky and trying to create a ophyd object.
    I have a very basic problem, but I don't know how to fix it.
    When I typed these command lines, lots of errors occurred.

    In [1]: from ophyd import EpicsMotor
    In [2]: motor = EpicsMotor('Newport:m1', name='motor')

    'Newport:m1' is the motor's PV name in EPICS ioc and the IOC works well.
    Can you give me any advice?

    Thomas A Caswell
    @tacaswell
    The issues is that we did not find either pyepics or caproto installed and have fallen back to a "dummy" backend which has enough of the API to let ophyd import and built purely synthetic Signals, but can not actually talk to EPICS
    what do you get if you do import epics?
    yangdl-github
    @yangdl-github
    Very helpful. Thanks, Tom.
    After I installed pyepics by using python -m pip install --upgrade pyepics, this issue was resolved.
    In fact, I had already installed pyepics under the epics directory. But why did it go wrong? Is it because I didn't add the directory into PATH?