fix(omny): report gripper force aborts from the v136 forceab flag
CI for csaxs_bec / test (push) Successful in 3m34s
CI for csaxs_bec / test (push) Successful in 3m34s
Firmware v136 sets forceab when the force check stops all programs, so a trip is reported even when the voltage has recovered by the time BEC looks. ForceAbort is also shown in the status line of describe(). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M8zoDz1DGZxhmZy9jzaUYf
This commit is contained in:
1 parent
5ad605c869
commit
c5a9272d1f
4 files changed
+26
-23
No files matched your search
@@ -174,10 +174,10 @@ class OMNYGalilController(GalilController):
|
||||
"""Clear the init-motion flags left behind by a #FES/#FRM that was killed.
|
||||
|
||||
#FES and #FRM set initmv and clear it only on their last lines. If they are
|
||||
killed partway (AB from the temperature, following error or gripper force
|
||||
checks, AB/HX from #CMDERR), initmv stays 1 and every later #NEWPAR, #FES
|
||||
and #FRM exits silently. Both routines run on thread 0, so initmv=1 with
|
||||
thread 0 idle can only be such a leftover.
|
||||
killed partway, initmv stays 1 and every later #NEWPAR, #FES and #FRM exits
|
||||
silently. Since firmware v136 the abort paths clear it themselves, this covers
|
||||
a routine stopped any other way, e.g. HX from a terminal. Both routines run on
|
||||
thread 0, so initmv=1 with thread 0 idle can only be such a leftover.
|
||||
"""
|
||||
if float(self.socket_put_and_receive("MG initmv")) != 1 or self.is_thread_active(0):
|
||||
return
|
||||
@@ -193,19 +193,17 @@ class OMNYGalilController(GalilController):
|
||||
return "Motor over temperature (tempab)."
|
||||
if float(self.socket_put_and_receive("MG folerr")) == 1:
|
||||
return "Following error (folerr)."
|
||||
if (
|
||||
float(self.socket_put_and_receive("MG contrID")) == 1
|
||||
and float(self.socket_put_and_receive("MG _IHH2")) == -2
|
||||
):
|
||||
if float(self.socket_put_and_receive("MG forceab")) == 1:
|
||||
# only controller 1 sets forceab, the flag stays until the next #GRFCAL
|
||||
voltage = float(self.socket_put_and_receive("MG @AN[8001]"))
|
||||
force0 = float(self.socket_put_and_receive("MG force0"))
|
||||
limit = float(self.socket_put_and_receive("MG forcablm"))
|
||||
if abs(voltage - force0) > limit:
|
||||
return (
|
||||
f"Gripper force check stopped all programs: sensor {voltage:.2f} V, "
|
||||
f"force0 {force0:.2f} V, limit {limit:.2f} V. Check that the gripper "
|
||||
"is free, then run omny_calibrate_gripper_force()."
|
||||
)
|
||||
return (
|
||||
"Gripper force check stopped all programs since the last calibration "
|
||||
f"(forceab): sensor now {voltage:.2f} V, force0 {force0:.2f} V, limit "
|
||||
f"{limit:.2f} V. Check that the gripper is free, then run "
|
||||
"omny_calibrate_gripper_force()."
|
||||
)
|
||||
if float(self.socket_put_and_receive("MG initmv")) == 1:
|
||||
return "The routine was killed before it finished, no reason found."
|
||||
return "The controller reports no abort."
|
||||
@@ -276,9 +274,10 @@ class OMNYGalilController(GalilController):
|
||||
allaxref = float(self.socket_put_and_receive("MGallaxref"))
|
||||
tempab = float(self.socket_put_and_receive("MGtempab"))
|
||||
timeab = float(self.socket_put_and_receive("MGtimeab"))
|
||||
forceab = float(self.socket_put_and_receive("MGforceab"))
|
||||
IgNoFol = float(self.socket_put_and_receive("MGIgNoFol"))
|
||||
print(
|
||||
f"OMNY galil firmware {swver:2.0f}, TempAbort: {tempab:1.0f}, Allaxref: {allaxref:1.0f}, TimeAbort: {timeab:1.0f}, Ignore Folerr: {IgNoFol:1.0f}\n"
|
||||
f"OMNY galil firmware {swver:2.0f}, TempAbort: {tempab:1.0f}, Allaxref: {allaxref:1.0f}, TimeAbort: {timeab:1.0f}, ForceAbort: {forceab:1.0f}, Ignore Folerr: {IgNoFol:1.0f}\n"
|
||||
)
|
||||
if self.sock.port == 8083:
|
||||
self._ogalil_switchsocket_status()
|
||||
|
||||
@@ -186,6 +186,8 @@ class SimGalilState:
|
||||
"initmv": 0.0,
|
||||
"folerr": 0.0,
|
||||
"force0": 0.0,
|
||||
"fcalok": 0.0,
|
||||
"forceab": 0.0,
|
||||
"forcablm": 2.0,
|
||||
"_IHH2": -2.0,
|
||||
# dialect status variables (LamNI / OMNY); overridable via sim_variables
|
||||
@@ -652,6 +654,8 @@ class SimGalilSocket(SimSocketBase):
|
||||
if routine == "#GRFCAL":
|
||||
with state.lock:
|
||||
state.variables["force0"] = state.analog_inputs[8001]
|
||||
state.variables["fcalok"] = 1.0
|
||||
state.variables["forceab"] = 0.0
|
||||
return ":"
|
||||
if routine == "#CRESET":
|
||||
with state.lock:
|
||||
|
||||
@@ -4,7 +4,7 @@ Simulated OMNY endstation devices.
|
||||
Galil (controller1.dmc and siblings): reuses the shared SimGalilState — same base move
|
||||
mechanics as flOMNI and the *identical* gripper transfer variable protocol
|
||||
(getaprch/mntaprch/mntprgs/mntmod/confirm/atconfir, with mntax=4 and signed mntprgs),
|
||||
plus OMNY status variables (swver=134, tempab/timeab, IgNoFol, grstat/relpos/toppin)
|
||||
plus OMNY status variables (swver=136, tempab/timeab, IgNoFol, grstat/relpos/toppin)
|
||||
and direct axis commands for the shuttle/dewar handling (AC/DC/SP/PR/BG/SH/MO/LD).
|
||||
Motor resolutions are hardcoded Python-side (51200; 89565.87 for the rotation axis on
|
||||
port 8083) and seeded accordingly.
|
||||
@@ -102,7 +102,7 @@ class SimOMNYGalilMotor(OMNYGalilMotor):
|
||||
stppermm = _OMNY_RESOLUTION
|
||||
if int(port) == _OMNY_ROTATION_PORT and self.axis_Id_numeric == _OMNY_ROTATION_AXIS:
|
||||
stppermm = _OMNY_ROTATION_RESOLUTION
|
||||
variables = {"swver": 134, "mntax": 4}
|
||||
variables = {"swver": 136, "mntax": 4}
|
||||
variables.update(sim_variables or {})
|
||||
state.configure_axis(
|
||||
self.axis_Id_numeric,
|
||||
|
||||
@@ -42,8 +42,7 @@ NO_ABORT = {
|
||||
"MG tempab": "0.0000",
|
||||
"MG timeab": "0.0000",
|
||||
"MG folerr": "0.0000",
|
||||
"MG contrID": "1.0000",
|
||||
"MG _IHH2": "-2.0000",
|
||||
"MG forceab": "0.0000",
|
||||
"MG @AN[8001]": "-2.1826",
|
||||
"MG force0": "-2.1826",
|
||||
"MG forcablm": "2.0000",
|
||||
@@ -55,14 +54,15 @@ NO_ABORT = {
|
||||
"changes, expected",
|
||||
[
|
||||
({}, "no abort"),
|
||||
({"MG force0": "2.5488"}, "Gripper force check"),
|
||||
({"MG forceab": "1.0000", "MG force0": "2.5488"}, "Gripper force check"),
|
||||
# a brief spike: the flag is set although the voltage is back within the limit
|
||||
({"MG forceab": "1.0000"}, "sensor now -2.18 V"),
|
||||
({"MG tempab": "1.0000"}, "over temperature"),
|
||||
({"MG tempab": "1.0000", "MG timeab": "1.0000"}, "timeab"),
|
||||
({"MG folerr": "1.0000"}, "Following error"),
|
||||
({"MG initmv": "1.0000"}, "killed"),
|
||||
# the force check only exists on controller 1 and only with the RIO connected
|
||||
({"MG contrID": "2.0000", "MG force0": "2.5488"}, "no abort"),
|
||||
({"MG _IHH2": "0.0000", "MG force0": "2.5488"}, "no abort"),
|
||||
# the flag decides, not the voltage difference
|
||||
({"MG force0": "2.5488"}, "no abort"),
|
||||
],
|
||||
)
|
||||
def test_abort_reason(changes, expected):
|
||||
|
||||
Reference in new issue
Block a user