rt_flomni: add ConstEmitter client access to RtFlomniController
Expose the flOMNI ConstEmitter runtime constants (served over the control-loop TCP server, command letter 'e') to BEC users. These were previously baked into Orchestra module parameter files; they can now be read and set live. New RtFlomniController methods (all added to USER_ACCESS): emitter_get() -> dict of the four values emitter_show_all() -> PrettyTable printout emitter_set_tracking_target_y(val) -> "ey<val>" emitter_set_tracking_target_z(val) -> "ez<val>" emitter_set_intensity_threshold_laser(val) -> "et<val>" emitter_set_psd_intensity_threshold_tracking_low(val) -> "el<val>" emitter_get issues "es" and parses the CSV reply (targetpos_tracking_y, targetpos_tracking_z, intensity_threshold_laser, PSD_intensity_threshold_tracking_low), same pattern as the Ts/sr readouts. Setters use socket_put with a fixed %.4f value, same pattern as the pa setpoint command; they are fire-and-forget (the server does not ack sets). The rotation-loop laser threshold (intensity_threshold_rot_laser) is a startup constant on the server side and is intentionally neither read back nor settable here. Named methods were chosen over a single opaque command to match the existing laser_tracker_* / feedback_* convention and to self-document each value. Requires the corresponding flOMNI control-loop change (ConstEmitter module + 'e' command in CommunicationServer). Additive change; no existing behaviour modified.
This commit was merged in pull request #250.
This commit is contained in:
@@ -45,6 +45,12 @@ class RtFlomniController(Controller):
|
||||
"laser_tracker_check_signalstrength",
|
||||
"laser_tracker_check_enabled",
|
||||
"is_axis_moving",
|
||||
"emitter_show_all",
|
||||
"emitter_get",
|
||||
"emitter_set_tracking_target_y",
|
||||
"emitter_set_tracking_target_z",
|
||||
"emitter_set_intensity_threshold_laser",
|
||||
"emitter_set_psd_intensity_threshold_tracking_low",
|
||||
]
|
||||
|
||||
def __init__(
|
||||
@@ -391,6 +397,63 @@ class RtFlomniController(Controller):
|
||||
return True
|
||||
return False
|
||||
|
||||
def emitter_get(self) -> dict:
|
||||
"""Read the runtime constants served by the ConstEmitter Orchestra module.
|
||||
|
||||
These are values that used to live in individual module parameter files
|
||||
(tracking targets and intensity thresholds) and are now emitted centrally
|
||||
so they can be tweaked live. The rotation-loop laser threshold
|
||||
(intensity_threshold_rot_laser) is a pure startup constant and is
|
||||
intentionally not reported here.
|
||||
|
||||
Returns:
|
||||
dict: current emitter values.
|
||||
"""
|
||||
ret = self.socket_put_and_receive("es")
|
||||
# remove trailing \n
|
||||
ret = ret.split("\n")[0]
|
||||
values = [float(val) for val in ret.split(",")]
|
||||
if len(values) != 4:
|
||||
raise RtCommunicationError(
|
||||
f"Expected to receive 4 emitter values. Instead received {values}"
|
||||
)
|
||||
return {
|
||||
"targetpos_tracking_y": values[0],
|
||||
"targetpos_tracking_z": values[1],
|
||||
"intensity_threshold_laser": values[2],
|
||||
"PSD_intensity_threshold_tracking_low": values[3],
|
||||
}
|
||||
|
||||
def emitter_show_all(self):
|
||||
"""Print all ConstEmitter runtime constants as a table."""
|
||||
t = PrettyTable()
|
||||
t.title = "ConstEmitter Runtime Constants"
|
||||
t.field_names = ["Name", "Value"]
|
||||
for key, val in self.emitter_get().items():
|
||||
t.add_row([key, val])
|
||||
print(t)
|
||||
|
||||
def emitter_set_tracking_target_y(self, val: float) -> None:
|
||||
"""Set the y tracking target position (PID_tracking_y)."""
|
||||
self.socket_put(f"ey{val:.4f}")
|
||||
|
||||
def emitter_set_tracking_target_z(self, val: float) -> None:
|
||||
"""Set the z tracking target position (PID_tracking_z)."""
|
||||
self.socket_put(f"ez{val:.4f}")
|
||||
|
||||
def emitter_set_intensity_threshold_laser(self, val: float) -> None:
|
||||
"""Set the shared laser intensity threshold.
|
||||
|
||||
Wired into the slew-rate limiters (x/y/z) and the PID loops
|
||||
(x/y/z and the fast FZP x/y loops). Does not affect the
|
||||
rotation loops, which use a separate fixed threshold.
|
||||
"""
|
||||
self.socket_put(f"et{val:.4f}")
|
||||
|
||||
def emitter_set_psd_intensity_threshold_tracking_low(self, val: float) -> None:
|
||||
"""Set the low PSD intensity threshold used by the tracking PIDs (y and z)."""
|
||||
self.socket_put(f"el{val:.4f}")
|
||||
|
||||
def pid_y(self) -> float:
|
||||
ret = float(self.socket_put_and_receive("G").strip())
|
||||
return ret
|
||||
@@ -929,4 +992,4 @@ if __name__ == "__main__":
|
||||
socket_cls=SocketIO, socket_host="mpc2844.psi.ch", socket_port=2222, device_manager=None
|
||||
)
|
||||
rtcontroller.on()
|
||||
rtcontroller.laser_tracker_on()
|
||||
rtcontroller.laser_tracker_on()
|
||||
Reference in New Issue
Block a user