完善释放控制:稳定/迅速行为预设、力曲线夹稳门控与会话记录。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
cheng
2026-09-22 12:05:22 +08:00
parent daa0ec8aec
commit 858e020c77
20 changed files with 3753 additions and 281 deletions
+196
View File
@@ -0,0 +1,196 @@
"""Grip behavior presets: extreme rapid open/close vs stable hold."""
from __future__ import annotations
import copy
# rapid = 迅速开合:优先跟手释放 / 再武装
# stable = 夹持稳定:优先防误开、夹得住
GRIP_BEHAVIOR_MODES = ("rapid", "stable")
GRIP_BEHAVIOR_LABELS = {
"rapid": "迅速开合",
"stable": "夹持稳定",
}
# Keys owned by a behavior profile. Selecting a mode rewrites these fields.
GRIP_BEHAVIOR_KEYS = (
"filter_alpha",
"shear_filter_alpha",
"open_wait_stable_samples",
"open_wait_stable_range_n",
"open_wait_stable_trend_n",
"grip_settle_seconds",
"force_ramp_step",
"force_ramp_interval",
"adaptive_grip_enabled",
"adaptive_force_interval",
"release_open_speed",
"release_open_accel",
"release_open_decel",
"release_arm_delay_seconds",
"release_min_hold_seconds",
"release_settle_seconds",
"release_min_change",
"release_touch_window_seconds",
"release_side_touch_change",
"release_confirm_window_seconds",
"release_sample_timeout_seconds",
"release_confirm_samples",
"release_slow_confirm_samples",
"release_normal_rate",
"release_shear_rate",
"release_slow_rate",
"release_normal_change",
"release_shear_change",
"release_curve_history",
"release_slope_window_seconds",
"release_slope_settle_rate",
"release_slope_min_points",
"release_require_slope_settle",
"release_slope_hold_seconds",
"release_settle_normal_only",
"release_side_shear_enabled",
"release_side_normal_enabled",
"release_shear_onset_enabled",
"release_normal_onset_enabled",
"rearm_seconds",
"recover_stable_seconds",
)
GRIP_BEHAVIOR_PROFILES = {
"rapid": {
"filter_alpha": 0.72,
"shear_filter_alpha": 0.78,
"open_wait_stable_samples": 3,
"open_wait_stable_range_n": 0.04,
"open_wait_stable_trend_n": 0.03,
"grip_settle_seconds": 0.05,
"force_ramp_step": 3,
"force_ramp_interval": 0.04,
"adaptive_grip_enabled": False,
"adaptive_force_interval": 0.05,
"release_open_speed": 85,
"release_open_accel": 90,
"release_open_decel": 90,
# Almost no normal-contact lock; rely on curve/side-touch rejection.
"release_arm_delay_seconds": 0.04,
"release_min_hold_seconds": 0.0,
"release_settle_seconds": 0.03,
"release_min_change": 0.03,
"release_touch_window_seconds": 0.28,
"release_side_touch_change": 0.04,
"release_confirm_window_seconds": 0.28,
"release_sample_timeout_seconds": 0.25,
"release_confirm_samples": 2,
"release_slow_confirm_samples": 3,
"release_normal_rate": 1.0,
"release_shear_rate": 1.0,
"release_slow_rate": 0.55,
"release_normal_change": 0.14,
"release_shear_change": 0.14,
"release_curve_history": 6,
"release_slope_window_seconds": 0.35,
"release_slope_settle_rate": 0.8,
"release_slope_min_points": 4,
"release_require_slope_settle": False,
"release_slope_hold_seconds": 0.0,
"release_settle_normal_only": False,
"release_side_shear_enabled": True,
"release_side_normal_enabled": True,
"release_shear_onset_enabled": True,
"release_normal_onset_enabled": True,
"rearm_seconds": 0.12,
"recover_stable_seconds": 0.12,
},
"stable": {
"filter_alpha": 0.42,
"shear_filter_alpha": 0.52,
"open_wait_stable_samples": 8,
"open_wait_stable_range_n": 0.025,
"open_wait_stable_trend_n": 0.015,
"grip_settle_seconds": 0.2,
"force_ramp_step": 1,
"force_ramp_interval": 0.1,
"adaptive_grip_enabled": True,
"adaptive_force_interval": 0.08,
"release_open_speed": 55,
"release_open_accel": 70,
"release_open_decel": 70,
"release_arm_delay_seconds": 0.28,
"release_min_hold_seconds": 0.65,
"release_settle_seconds": 0.12,
"release_min_change": 0.08,
"release_touch_window_seconds": 0.14,
"release_side_touch_change": 0.12,
"release_confirm_window_seconds": 0.14,
"release_sample_timeout_seconds": 0.2,
"release_confirm_samples": 4,
"release_slow_confirm_samples": 8,
"release_normal_rate": 2.6,
"release_shear_rate": 2.4,
"release_slow_rate": 0.22,
"release_normal_change": 0.42,
"release_shear_change": 0.35,
# Clean split: settle on normal plateau; open only via shear.
"release_curve_history": 30,
"release_slope_window_seconds": 0.8,
"release_slope_settle_rate": 0.22,
"release_slope_min_points": 10,
"release_require_slope_settle": True,
"release_slope_hold_seconds": 0.45,
"release_settle_normal_only": True,
"release_side_shear_enabled": True,
"release_side_normal_enabled": False,
"release_shear_onset_enabled": True,
"release_normal_onset_enabled": False,
"rearm_seconds": 0.55,
"recover_stable_seconds": 0.55,
},
}
def normalize_grip_behavior_mode(mode) -> str:
text = str(mode or "").strip().lower()
aliases = {
"fast": "rapid",
"quick": "rapid",
"snap": "rapid",
"迅速": "rapid",
"迅速开合": "rapid",
"hold": "stable",
"firm": "stable",
"secure": "stable",
"稳定": "stable",
"夹持稳定": "stable",
}
text = aliases.get(text, text)
if text not in GRIP_BEHAVIOR_PROFILES:
raise ValueError(
f"unsupported grip_behavior_mode: {mode!r}; "
f"expected one of {list(GRIP_BEHAVIOR_PROFILES)}"
)
return text
def grip_behavior_profile(mode: str) -> dict:
mode = normalize_grip_behavior_mode(mode)
return copy.deepcopy(GRIP_BEHAVIOR_PROFILES[mode])
def apply_grip_behavior_profile(target, mode: str) -> str:
"""Write profile fields onto a config object or dict. Returns normalized mode."""
mode = normalize_grip_behavior_mode(mode)
profile = GRIP_BEHAVIOR_PROFILES[mode]
if isinstance(target, dict):
target["grip_behavior_mode"] = mode
for key, value in profile.items():
target[key] = copy.deepcopy(value)
return mode
setattr(target, "grip_behavior_mode", mode)
for key, value in profile.items():
if hasattr(target, key):
setattr(target, key, copy.deepcopy(value))
return mode
+80 -3
View File
@@ -13,6 +13,10 @@ from .rotation import (
DEFAULT_ROTATION2,
normalize_rotation_config,
)
from .behavior_profiles import (
apply_grip_behavior_profile,
normalize_grip_behavior_mode,
)
DEFAULT_CONTROL_CONFIG = str(
@@ -78,6 +82,7 @@ class Demo02Config:
force_ramp_step: int = 1
force_ramp_interval: float = 0.1
grip_settle_seconds: float = 0.1
grip_behavior_mode: str = "stable"
adaptive_grip_enabled: bool = True
adaptive_shear_start_force: float = 0.10
adaptive_shear_full_force: float = 0.60
@@ -85,9 +90,32 @@ class Demo02Config:
adaptive_force_max: int = 45
adaptive_force_step: int = 1
adaptive_force_interval: float = 0.15
release_arm_delay_seconds: float = 0.8
release_normal_change: float = 0.03
release_shear_change: float = 0.03
release_arm_delay_seconds: float = 0.12
release_min_hold_seconds: float = 0.28
release_settle_seconds: float = 0.06
release_min_change: float = 0.04
release_touch_window_seconds: float = 0.2
release_side_touch_change: float = 0.06
release_confirm_window_seconds: float = 0.2
release_sample_timeout_seconds: float = 0.2
release_confirm_samples: int = 2
release_slow_confirm_samples: int = 5
release_normal_rate: float = 1.6
release_shear_rate: float = 1.6
release_slow_rate: float = 0.4
release_normal_change: float = 0.28
release_shear_change: float = 0.28
release_curve_history: int = 6
release_slope_window_seconds: float = 0.8
release_slope_settle_rate: float = 0.2
release_slope_min_points: int = 8
release_require_slope_settle: bool = False
release_slope_hold_seconds: float = 0.0
release_settle_normal_only: bool = True
release_side_shear_enabled: bool = True
release_side_normal_enabled: bool = True
release_shear_onset_enabled: bool = True
release_normal_onset_enabled: bool = True
rearm_seconds: float = 0.5
recover_normal_force: float = 0.02
recover_shear_force: float = 0.02
@@ -171,6 +199,14 @@ class Demo02Config:
add("--force-ramp-step", type=int, default=get("force_ramp_step", cls.force_ramp_step))
add("--force-ramp-interval", type=float, default=get("force_ramp_interval", cls.force_ramp_interval))
add("--grip-settle-seconds", type=float, default=get("grip_settle_seconds", cls.grip_settle_seconds))
add(
"--grip-behavior-mode",
type=str,
choices=["rapid", "stable"],
default=normalize_grip_behavior_mode(
get("grip_behavior_mode", cls.grip_behavior_mode)
),
)
add("--enable-adaptive-grip", dest="adaptive_grip_enabled", action="store_true", default=get("adaptive_grip_enabled", cls.adaptive_grip_enabled))
add("--disable-adaptive-grip", dest="adaptive_grip_enabled", action="store_false")
add("--adaptive-shear-start-force", type=float, default=get("adaptive_shear_start_force", cls.adaptive_shear_start_force))
@@ -180,8 +216,43 @@ class Demo02Config:
add("--adaptive-force-step", type=int, default=get("adaptive_force_step", cls.adaptive_force_step))
add("--adaptive-force-interval", type=float, default=get("adaptive_force_interval", cls.adaptive_force_interval))
add("--release-arm-delay-seconds", type=float, default=get("release_arm_delay_seconds", cls.release_arm_delay_seconds))
add("--release-min-hold-seconds", type=float, default=get("release_min_hold_seconds", cls.release_min_hold_seconds))
add("--release-settle-seconds", type=float, default=get("release_settle_seconds", cls.release_settle_seconds))
add("--release-min-change", type=float, default=get("release_min_change", cls.release_min_change))
add("--release-touch-window-seconds", type=float, default=get("release_touch_window_seconds", cls.release_touch_window_seconds))
add("--release-side-touch-change", type=float, default=get("release_side_touch_change", cls.release_side_touch_change))
add("--release-confirm-window-seconds", type=float, default=get("release_confirm_window_seconds", cls.release_confirm_window_seconds))
add("--release-sample-timeout-seconds", type=float, default=get("release_sample_timeout_seconds", cls.release_sample_timeout_seconds))
add("--release-confirm-samples", type=int, default=get("release_confirm_samples", cls.release_confirm_samples))
add("--release-slow-confirm-samples", type=int, default=get("release_slow_confirm_samples", cls.release_slow_confirm_samples))
add("--release-normal-rate", type=float, default=get("release_normal_rate", cls.release_normal_rate))
add("--release-shear-rate", type=float, default=get("release_shear_rate", cls.release_shear_rate))
add("--release-slow-rate", type=float, default=get("release_slow_rate", cls.release_slow_rate))
add("--release-normal-change", type=float, default=get("release_normal_change", cls.release_normal_change))
add("--release-shear-change", type=float, default=get("release_shear_change", cls.release_shear_change))
add("--release-curve-history", type=int, default=get("release_curve_history", cls.release_curve_history))
add("--release-slope-window-seconds", type=float, default=get("release_slope_window_seconds", cls.release_slope_window_seconds))
add("--release-slope-settle-rate", type=float, default=get("release_slope_settle_rate", cls.release_slope_settle_rate))
add("--release-slope-min-points", type=int, default=get("release_slope_min_points", cls.release_slope_min_points))
add("--release-require-slope-settle", dest="release_require_slope_settle", action="store_true",
default=get("release_require_slope_settle", cls.release_require_slope_settle))
add("--no-release-require-slope-settle", dest="release_require_slope_settle", action="store_false")
add("--release-slope-hold-seconds", type=float, default=get("release_slope_hold_seconds", cls.release_slope_hold_seconds))
add("--release-settle-normal-only", dest="release_settle_normal_only", action="store_true",
default=get("release_settle_normal_only", cls.release_settle_normal_only))
add("--release-settle-all-channels", dest="release_settle_normal_only", action="store_false")
add("--release-side-shear-enabled", dest="release_side_shear_enabled", action="store_true",
default=get("release_side_shear_enabled", cls.release_side_shear_enabled))
add("--no-release-side-shear", dest="release_side_shear_enabled", action="store_false")
add("--release-side-normal-enabled", dest="release_side_normal_enabled", action="store_true",
default=get("release_side_normal_enabled", cls.release_side_normal_enabled))
add("--no-release-side-normal", dest="release_side_normal_enabled", action="store_false")
add("--release-shear-onset-enabled", dest="release_shear_onset_enabled", action="store_true",
default=get("release_shear_onset_enabled", cls.release_shear_onset_enabled))
add("--no-release-shear-onset", dest="release_shear_onset_enabled", action="store_false")
add("--release-normal-onset-enabled", dest="release_normal_onset_enabled", action="store_true",
default=get("release_normal_onset_enabled", cls.release_normal_onset_enabled))
add("--no-release-normal-onset", dest="release_normal_onset_enabled", action="store_false")
add("--rearm-seconds", type=float, default=get("rearm_seconds", cls.rearm_seconds))
add("--recover-normal-force", type=float, default=get("recover_normal_force", cls.recover_normal_force))
add("--recover-shear-force", type=float, default=get("recover_shear_force", cls.recover_shear_force))
@@ -208,4 +279,10 @@ class Demo02Config:
values["shear_force_calibration"] = copy.deepcopy(
config_data.get("shear_force_calibration", DEFAULT_SHEAR_FORCE_CALIBRATION)
)
values["grip_behavior_mode"] = normalize_grip_behavior_mode(
values.get("grip_behavior_mode", cls.grip_behavior_mode)
)
return cls(**values)
def apply_grip_behavior_mode(self, mode: str) -> str:
return apply_grip_behavior_profile(self, mode)