Plesty Documentation

The Rig

The three instruments of the demo, reached by name through one CompositeDevice — where their addresses come from, and the preflight that checks them before the first step.

An experiment never holds an instrument. It holds its rig: one CompositeDevice with a client for each instrument's server, under a short name. In __main__.py, the rig is one line — each name, and the operations the experiment will call on it:

RIG = {
    "hwp": ["home_stage", "move_absolute"],  # the half-wave plate's stage
    "spec": ["acquire", "get_recent_file", "set_data_path"],  # the spectrometer
    "pm": ["measure_power"],  # the power meter
}

The scaffold builds the CompositeDevice from it; nothing else in the module names an instrument. The scaffold's example rig is one instrument called device, and three places still name it — replace each:

  • in __main__.py, the --device-address option and the two lines of build_devices that use it: delete them;
  • the DEVICE_ADDRESS entry of MANIFEST: one EnvVar per instrument instead, HWP_ADDRESS, SPEC_ADDRESS and PM_ADDRESS;
  • setup.yaml, which says which bench runs each instrument: on one PC, all three on this one.
# setup.yaml, below benches:
devices:
  hwp:
    host_name: bench-local
  spec:
    host_name: bench-local
  pm:
    host_name: bench-local

Where each address comes from

Each name reads its server's address from <NAME>_ADDRESS — HWP_ADDRESS, SPEC_ADDRESS, PM_ADDRESS:

  • From PLESTY Bench — a run started there gets them from the bench, which started each instrument on its PC (see Run It from the Bench).
  • By hand — in .env, for servers you started yourself, like the three demo servers:
# .env
LOCAL_DATA=/Users/you/plesty-tutorial/data    # the shared data disk, as this PC sees it
HWP_ADDRESS=tcp://localhost:5552
SPEC_ADDRESS=tcp://localhost:5553
PM_ADDRESS=tcp://localhost:5551

LOCAL_DATA is the same folder the spectrometer writes into: the run's folder goes there, and every spectrum lands inside it. A ~ in it is this PC's home. Which folder a device may write in, and how a bench sets it, is in Benches, Fleets & the Share. The ports are the ones plesty-server printed. No address or path is ever in the code, so the same module runs in any lab.

The preflight

Before the first step, the rig connects to every server and checks that it answers and offers every operation RIG lists:

Setup: connecting devices
Preflight hwp @ tcp://localhost:5552: ok (SIM-APT (S/N: 55123456, firmware: 1.0.0))
Preflight spec @ tcp://localhost:5553: ok (Mock LightField Spectrometer (no hardware))
Preflight pm @ tcp://localhost:5551: ok (THORLABS,PM100D,MOCK0001,1.0.0)

A server that is not there stops the run by name before anything moves — Sub-device 'hwp' unreachable at tcp://localhost:5599 after 10.1 s — instead of at row 40. From a terminal it asks whether to try again (after you start the server) or stop. A device that the run can do without is declared with cli.optional("name"), and the operator may then skip it.

Calling an instrument

In the experiment, self.devices is the rig:

reached = self.devices.call("hwp", "move_absolute", angle)  # the angle it reached
self.devices.call("spec", "acquire")  # one spectrum, saved by the spectrometer
reading = self.devices.call("pm", "measure_power", averaging=10)  # {"power": <W>}

call(name, operation, …) is the same as calling the operation on that instrument's client, plus resilience: a server on another PC that does not answer in time is reconnected and the call tried again. Each call waits as long as the operation's declared budget — an exposure of the spectrometer waits longer than a move.

Next: Run Setup.