added ruff test
This commit is contained in:
@@ -13,7 +13,12 @@ from typing import Any
|
||||
from orisys_app_shared import prefs as _prefs
|
||||
from orisys_app_shared.paths import preference_path
|
||||
|
||||
from .motion.service import DEFAULT_BAS_TASK, PLATFORM_AXES, clamp_bas_task
|
||||
from .motion.service import (
|
||||
DEFAULT_AXIS_ROLES,
|
||||
DEFAULT_BAS_TASK,
|
||||
PLATFORM_AXES,
|
||||
clamp_bas_task,
|
||||
)
|
||||
from .motion.units import DEFAULT_ACCEL, DEFAULT_SPEED, DEFAULT_UNITS
|
||||
|
||||
#: Connection modes, in the order the combo offers them.
|
||||
@@ -81,6 +86,10 @@ def _default_safety_limits() -> dict[str, float]:
|
||||
|
||||
``0`` means "not set" for the ones where a real value is required, and the
|
||||
app reports that at the P0 gate rather than treating it as unlimited.
|
||||
|
||||
Lengths are millimetres and angles degrees, because the roles they bound are:
|
||||
one number cannot bound both, and a degree target checked against a millimetre
|
||||
limit is not a check.
|
||||
"""
|
||||
return {
|
||||
"max_travel_mm": 100.0,
|
||||
@@ -90,6 +99,11 @@ def _default_safety_limits() -> dict[str, float]:
|
||||
#: How far the axis may descend looking for contact before the run is
|
||||
#: aborted (workflow P7, no-contact abort).
|
||||
"contact_search_mm": 3.0,
|
||||
#: Stage envelope, from the confirmed bench values: the yaw stage turns a
|
||||
#: half-turn either way, the pitch stage a full turn. These are the limits a
|
||||
#: pose move is checked against before any axis is commanded.
|
||||
"max_yaw_deg": 180.0,
|
||||
"max_pitch_deg": 360.0,
|
||||
}
|
||||
|
||||
|
||||
@@ -104,9 +118,10 @@ def _default_sensor_setup() -> dict[str, Any]:
|
||||
"sensor_type": "box",
|
||||
"config_ref": "",
|
||||
"geometry_id": "",
|
||||
#: Which axis presses, and the probe tip offset from the platform's
|
||||
#: reference point. Empty offset means "not set", which blocks P5.
|
||||
"press_axis": 2,
|
||||
#: The probe tip's offset from the platform's reference point. Empty offset
|
||||
#: means "not set", which blocks P5. Which axis presses is **not** here: it
|
||||
#: is ``axis_roles["z"]``, because one fact written twice is one fact that
|
||||
#: eventually disagrees.
|
||||
"probe_tip_offset_mm": [0.0, 0.0, 0.0],
|
||||
"probe_tip_set": False,
|
||||
#: 4x4 row-major sensor -> platform transform, plus how well it fitted.
|
||||
@@ -173,6 +188,19 @@ def default_preferences() -> dict[str, Any]:
|
||||
# --- workflow blocks (see apps/autocal/docs/workflow.md) --------------
|
||||
#: P0: limits enforced from P2 onward.
|
||||
"safety_limits": _default_safety_limits(),
|
||||
#: Which drive is which platform direction, from the bench wiring: drives
|
||||
#: 0-4 are x, y, pitch, yaw, z. There is no way to read this off the bus —
|
||||
#: five CiA-402 axes report numbers, not names — so it is configuration, and
|
||||
#: the pose-move path refuses to run until it is complete and free of
|
||||
#: duplicates. It is also the *only* place "which axis presses" is written:
|
||||
#: the sensor setup used to carry a second copy, which is how the two would
|
||||
#: have drifted apart.
|
||||
"axis_roles": dict(DEFAULT_AXIS_ROLES),
|
||||
#: Ask before a pose move. On by default — the first moves on a machine are
|
||||
#: the ones worth reading — and turnable off once the numbers are trusted,
|
||||
#: because a prompt that cannot be dismissed unread is one that gets clicked
|
||||
#: through without being read.
|
||||
"move_confirm": True,
|
||||
#: P3/P4: sensor under test, probe tip, sensor<->platform transform.
|
||||
"sensor_setup": _default_sensor_setup(),
|
||||
#: P5: grid generation and run parameters.
|
||||
@@ -206,9 +234,26 @@ def default_preferences() -> dict[str, Any]:
|
||||
}
|
||||
|
||||
|
||||
#: Preference blocks whose *keys* are added to over time. Stored preferences are
|
||||
#: merged one level deep, so a block saved by an older build replaces the whole
|
||||
#: default block and any key added since reads as absent. For a P0 limit that is not
|
||||
#: a cosmetic problem: the move is refused with "the limit is not set" while the file
|
||||
#: in front of the operator says nothing about it. Filling the block key by key keeps
|
||||
#: what was chosen and supplies only what was never there.
|
||||
_MERGED_BLOCKS = ("connection", "safety_limits", "sensor_setup", "sequence_profile")
|
||||
|
||||
|
||||
def load_preferences() -> dict[str, Any]:
|
||||
"""Stored preferences with AutoCal's defaults filling the gaps."""
|
||||
prefs = _prefs.load_preferences(default_preferences())
|
||||
defaults = default_preferences()
|
||||
prefs = _prefs.load_preferences(defaults)
|
||||
for name in _MERGED_BLOCKS:
|
||||
stored = prefs.get(name)
|
||||
if not isinstance(stored, dict):
|
||||
continue
|
||||
block = dict(defaults.get(name) or {})
|
||||
block.update(stored)
|
||||
prefs[name] = block
|
||||
# A stored document from an older build may miss a newly added axis block.
|
||||
axis_params = prefs.setdefault("axis_params", {})
|
||||
for axis, values in _default_axis_params().items():
|
||||
@@ -252,6 +297,39 @@ def load_preferences() -> dict[str, Any]:
|
||||
prefs["finger_tool_xy_mm"] = tool
|
||||
# A hand-edited task number must not reach the controller as typed.
|
||||
prefs["bas_task"] = clamp_bas_task(prefs.get("bas_task"))
|
||||
prefs = _migrate_axis_roles(prefs)
|
||||
return prefs
|
||||
|
||||
|
||||
def _migrate_axis_roles(prefs: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Complete the axis mapping, and take the old duplicate press axis out.
|
||||
|
||||
``sensor_setup.press_axis`` named the pressing drive on its own. That is
|
||||
``axis_roles["z"]`` now — the same fact — and a stored value is moved there when
|
||||
the mapping has not been set, so a bench that had it configured keeps working.
|
||||
The old key is removed either way: leaving it would keep a second answer to
|
||||
"which axis presses" in the file.
|
||||
"""
|
||||
roles = prefs.get("axis_roles")
|
||||
roles = dict(roles) if isinstance(roles, dict) else {}
|
||||
sensor = prefs.get("sensor_setup")
|
||||
if isinstance(sensor, dict):
|
||||
legacy = sensor.pop("press_axis", None)
|
||||
if legacy is not None and "z" not in roles:
|
||||
try:
|
||||
roles["z"] = int(legacy)
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
merged = dict(DEFAULT_AXIS_ROLES)
|
||||
# A stored mapping wins where it is usable; the default fills what it does not
|
||||
# cover, so an old document that only named the press axis still comes up with a
|
||||
# complete mapping rather than a refusal.
|
||||
for role, value in roles.items():
|
||||
try:
|
||||
merged[role] = int(value)
|
||||
except (TypeError, ValueError):
|
||||
continue
|
||||
prefs["axis_roles"] = merged
|
||||
return prefs
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user