稳定度配置条与自定义挡位、独立速度调节;状态文字中文简写与平滑;灵敏挡切向振荡判据收紧;新增重置底图按钮。
- 设置框新增 0~100 稳定度配置条(灵敏 0 / 较稳定 50 / 十分稳定 100 为内置挡位,中间按比例插值),支持滚轮/左键拖动,可另存/删除自定义挡位;速度改为独立滑块。 - 状态栏改为中文简写(悬停显示原文);夹持保护期文字按挡位区分;合并同义子状态并加最短停留,避免逐帧跳动。 - 灵敏挡切向振荡:0.5 s 内换向 4 次,并须持续至少 0.15 s 才张开(新参数 release_shear_oscillation_min_seconds)。 - 传感器控制区新增「重置底图」:左右传感器一起用当前画面更换光流参考底图(orisys Sensor.reset),不断开相机。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -8,6 +8,7 @@ import copy
|
||||
# sensitive = 灵敏:跟手释放,自适应夹持力
|
||||
# stable = 较稳定:接触即 70% 恒力夹持,2 s 保护期,Y 拟合偏移 0.6 N 张开
|
||||
# firm = 十分稳定:接触即 100% 恒力夹持,2.5 s 保护期,Y 拟合偏移 0.8 N 张开
|
||||
# 稳定度 0..100:三挡分别位于 0 / 50 / 100,中间值按比例插值(见 grip_behavior_level_profile)。
|
||||
GRIP_BEHAVIOR_MODES = ("sensitive", "stable", "firm")
|
||||
|
||||
GRIP_BEHAVIOR_LABELS = {
|
||||
@@ -74,6 +75,7 @@ GRIP_BEHAVIOR_KEYS = (
|
||||
"release_shear_oscillation_min_flips",
|
||||
"release_shear_oscillation_amplitude",
|
||||
"release_shear_oscillation_confirm_samples",
|
||||
"release_shear_oscillation_min_seconds",
|
||||
"release_side_shear_enabled",
|
||||
"release_side_normal_enabled",
|
||||
"release_shear_onset_enabled",
|
||||
@@ -157,10 +159,11 @@ _SENSITIVE_PROFILE = {
|
||||
"release_settle_normal_only": True,
|
||||
# Intentional rub/twist: oscillating shear opens even before plateau latch.
|
||||
"release_shear_oscillation_open": True,
|
||||
"release_shear_oscillation_window_seconds": 0.4,
|
||||
"release_shear_oscillation_min_flips": 3,
|
||||
"release_shear_oscillation_window_seconds": 0.5,
|
||||
"release_shear_oscillation_min_flips": 4,
|
||||
"release_shear_oscillation_amplitude": 0.15,
|
||||
"release_shear_oscillation_confirm_samples": 2,
|
||||
"release_shear_oscillation_min_seconds": 0.15,
|
||||
"release_side_shear_enabled": True,
|
||||
"release_side_normal_enabled": True,
|
||||
"release_shear_onset_enabled": True,
|
||||
@@ -288,6 +291,103 @@ def grip_behavior_profile(mode: str = "sensitive") -> dict:
|
||||
return _merged_profile(mode)
|
||||
|
||||
|
||||
# Stability level 0..100: the three built-in modes sit at fixed anchors.
|
||||
# Below the stable anchor the sensitive algorithm runs with its numeric params
|
||||
# scaled toward the stable values; from the stable anchor on, the held
|
||||
# algorithm runs, scaled from stable to firm.
|
||||
GRIP_BEHAVIOR_LEVEL_MIN = 0
|
||||
GRIP_BEHAVIOR_LEVEL_MAX = 100
|
||||
GRIP_BEHAVIOR_LEVELS = {"sensitive": 0, "stable": 50, "firm": 100}
|
||||
# Only read by the held (stable/firm) release; stays off on the sensitive side.
|
||||
_HELD_ONLY_KEYS = ("release_shear_displacement",)
|
||||
|
||||
|
||||
def clamp_grip_behavior_level(level) -> int:
|
||||
try:
|
||||
value = int(round(float(level)))
|
||||
except (TypeError, ValueError):
|
||||
value = GRIP_BEHAVIOR_LEVEL_MIN
|
||||
return max(GRIP_BEHAVIOR_LEVEL_MIN, min(GRIP_BEHAVIOR_LEVEL_MAX, value))
|
||||
|
||||
|
||||
def grip_behavior_mode_for_level(level) -> str:
|
||||
level = clamp_grip_behavior_level(level)
|
||||
if level >= GRIP_BEHAVIOR_LEVELS["firm"]:
|
||||
return "firm"
|
||||
if level >= GRIP_BEHAVIOR_LEVELS["stable"]:
|
||||
return "stable"
|
||||
return "sensitive"
|
||||
|
||||
|
||||
def default_grip_behavior_level(mode) -> int:
|
||||
return GRIP_BEHAVIOR_LEVELS[normalize_grip_behavior_mode(mode)]
|
||||
|
||||
|
||||
def builtin_grip_behavior_presets() -> list:
|
||||
return [
|
||||
{
|
||||
"name": GRIP_BEHAVIOR_LABELS[mode],
|
||||
"level": GRIP_BEHAVIOR_LEVELS[mode],
|
||||
"speed": GRIP_BEHAVIOR_PROFILES[mode]["speed"],
|
||||
"builtin": True,
|
||||
}
|
||||
for mode in GRIP_BEHAVIOR_MODES
|
||||
]
|
||||
|
||||
|
||||
def normalize_grip_behavior_presets(presets) -> list:
|
||||
"""User presets as [{name, level[, speed]}], without duplicates of built-in names."""
|
||||
reserved = {GRIP_BEHAVIOR_LABELS[mode] for mode in GRIP_BEHAVIOR_MODES}
|
||||
result = []
|
||||
seen = set()
|
||||
for item in presets if isinstance(presets, list) else []:
|
||||
if not isinstance(item, dict):
|
||||
continue
|
||||
name = str(item.get("name") or "").strip()
|
||||
if not name or name in reserved or name in seen:
|
||||
continue
|
||||
seen.add(name)
|
||||
preset = {"name": name, "level": clamp_grip_behavior_level(item.get("level"))}
|
||||
if item.get("speed") is not None:
|
||||
preset["speed"] = clamp_grip_behavior_level(item.get("speed"))
|
||||
result.append(preset)
|
||||
return result
|
||||
|
||||
|
||||
def _lerp_value(a, b, t):
|
||||
if isinstance(a, bool) or isinstance(b, bool):
|
||||
return copy.deepcopy(a)
|
||||
if not isinstance(a, (int, float)) or not isinstance(b, (int, float)):
|
||||
return copy.deepcopy(a)
|
||||
value = a + (b - a) * t
|
||||
if isinstance(a, int) and isinstance(b, int):
|
||||
return int(round(value))
|
||||
return round(float(value), 4)
|
||||
|
||||
|
||||
def grip_behavior_level_profile(level) -> dict:
|
||||
"""Merged params for stability *level*; anchors equal the built-in modes."""
|
||||
level = clamp_grip_behavior_level(level)
|
||||
for mode, anchor in GRIP_BEHAVIOR_LEVELS.items():
|
||||
if level == anchor:
|
||||
return _merged_profile(mode)
|
||||
stable_at = GRIP_BEHAVIOR_LEVELS["stable"]
|
||||
if level < stable_at:
|
||||
low, high = _merged_profile("sensitive"), _merged_profile("stable")
|
||||
t = (level - GRIP_BEHAVIOR_LEVELS["sensitive"]) / float(stable_at - GRIP_BEHAVIOR_LEVELS["sensitive"])
|
||||
else:
|
||||
low, high = _merged_profile("stable"), _merged_profile("firm")
|
||||
t = (level - stable_at) / float(GRIP_BEHAVIOR_LEVELS["firm"] - stable_at)
|
||||
fixed = GRIP_TRIGGER_KEYS + (_HELD_ONLY_KEYS if level < stable_at else ())
|
||||
profile = {}
|
||||
for key, value in low.items():
|
||||
if key in fixed:
|
||||
profile[key] = copy.deepcopy(value)
|
||||
else:
|
||||
profile[key] = _lerp_value(value, high.get(key, value), t)
|
||||
return profile
|
||||
|
||||
|
||||
def apply_grip_behavior_profile(target, mode: str = "sensitive") -> str:
|
||||
mode = normalize_grip_behavior_mode(mode)
|
||||
profile = _merged_profile(mode)
|
||||
|
||||
@@ -122,6 +122,8 @@ class Demo02Config:
|
||||
release_shear_oscillation_min_flips: int = 3
|
||||
release_shear_oscillation_amplitude: float = 0.15
|
||||
release_shear_oscillation_confirm_samples: int = 2
|
||||
# Oscillation must persist this long (in addition to confirm samples) before opening.
|
||||
release_shear_oscillation_min_seconds: float = 0.0
|
||||
# Block oscillation/side-touch release during contact hold and servo motion.
|
||||
release_guard_fast_paths: bool = False
|
||||
# Shear axes for release only: "" follows shear_control_axes; "y" | "x" | "xy".
|
||||
@@ -281,6 +283,8 @@ class Demo02Config:
|
||||
default=get("release_shear_oscillation_amplitude", cls.release_shear_oscillation_amplitude))
|
||||
add("--release-shear-oscillation-confirm-samples", type=int,
|
||||
default=get("release_shear_oscillation_confirm_samples", cls.release_shear_oscillation_confirm_samples))
|
||||
add("--release-shear-oscillation-min-seconds", type=float,
|
||||
default=get("release_shear_oscillation_min_seconds", cls.release_shear_oscillation_min_seconds))
|
||||
add("--release-guard-fast-paths", dest="release_guard_fast_paths", action="store_true",
|
||||
default=get("release_guard_fast_paths", cls.release_guard_fast_paths))
|
||||
add("--no-release-guard-fast-paths", dest="release_guard_fast_paths", action="store_false")
|
||||
|
||||
Reference in New Issue
Block a user