by

Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
    Thomas A Caswell
    @tacaswell
    how does a motor tell you it got where it was going?
    Blaise Thompson
    @untzag
    so you call set_position
    and then you sit in a loop calling busy until it returns false
    and then (most of the time) you don't communicate with the motor at all until you need to move it again
    if you have a graphical interface you can call get_position while it's moving
    and have that streaming feedback experience
    Kyle Sunden
    @ksunden_gitlab
    Part of this is from the fact that JSON-RPC is an inheriently mono-directional protocol
    Blaise Thompson
    @untzag
    it's not optimized for tight timing---I guess that's just not something I've found necessary in my work
    Thomas A Caswell
    @tacaswell
    can I make the test motor have an appreciable move time?
    Blaise Thompson
    @untzag
    um...
    edit source? that's all I got. @ksunden_gitlab ?
    Kyle Sunden
    @ksunden_gitlab
    I can make one pretty quick (and just put the python in here)
    Thomas A Caswell
    @tacaswell
    if you don't have one handy don't worry about it
    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