Per-unit instrument configuration

(this to me seems more related to Updating PLR API for machine interfaces discussion than the backend kwargs proposal)

there are two ways to get a specific instrument’s configuration:

  • from the user at init
  • from the machine at setup

so optional capabilities can’t be discovered from firmware at [construction] (setup?) time

in the original proposal, i was thinking we could actually create them at setup time, like

class STAR(Device, Resource):
  def __init__(self, ...):
    self.iswap: Optional[OrientableArm] = None

  def setup(self, ...):
    self._driver.setup()
    if self._driver.config.has_iswap:
      self.iswap = OrientableArm (backend=iSWAP(driver=self._driver))

in fact, you can even have capabilities that are even shorter lived. The core gripper example from that thread:

async with star.core_grippers(front_channel=6) as arm:
  read_plate_byonoy(arm=arm, ...)

(the core grippers are mounted on channels, so this capability does not even exist physically sometimes)

a separate class per configuration doesn’t scale (iSWAP × 96-head × tube gripper × channels = too many classes)

which is why i want to move the a composition architecture :slight_smile:

What if we had a config object, a “device card”, that tells init what this specific unit has? A model base (what every unit always has) plus instance overrides (what THIS unit has):

I think this could be useful as a description of a device at a time, if people have a need for it. As a prescription, it might be more difficult since some capabilities are loaded from hardware. We should ideally avoid asking users for stuff we can just load from the machine (in the base case).

How this all connects to backend_params: the card could validate that STARMoveParams(grip_force=80) is only sent to a STAR that actually has an iSWAP.

well rather than the card validating params, with the above proposal star.iswap would not even exist, it would be None!

1 Like