feat: 优化双臂采摘QP稳健性
This commit is contained in:
@@ -11,6 +11,7 @@ from xr_rm_teleop.single_arm_velocity_teleop import (
|
||||
SingleArmVelocityTeleop,
|
||||
_make_transform,
|
||||
_so3_exp,
|
||||
_so3_log,
|
||||
)
|
||||
|
||||
|
||||
@@ -610,7 +611,7 @@ def test_first_feedback_initializes_last_valid_target_without_solving() -> None:
|
||||
assert teleop._ik_solver.solve_calls == 0
|
||||
|
||||
|
||||
def test_qp_failure_returns_last_known_good_target() -> None:
|
||||
def test_qp_failure_returns_none_and_keeps_last_known_good_target() -> None:
|
||||
class FailingSolver:
|
||||
def solve(self, target):
|
||||
del target
|
||||
@@ -624,11 +625,11 @@ def test_qp_failure_returns_last_known_good_target() -> None:
|
||||
|
||||
target = teleop._solve_joint_target(np.eye(4))
|
||||
|
||||
assert target == pytest.approx([0.1] * 7)
|
||||
assert target is None
|
||||
assert teleop._last_valid_joint_target == pytest.approx([0.1] * 7)
|
||||
|
||||
|
||||
def test_qp_success_updates_last_known_good_target() -> None:
|
||||
def test_qp_success_waits_for_send_before_updating_last_known_good_target() -> None:
|
||||
class SuccessfulSolver:
|
||||
def solve(self, target):
|
||||
del target
|
||||
@@ -643,7 +644,54 @@ def test_qp_success_updates_last_known_good_target() -> None:
|
||||
target = teleop._solve_joint_target(np.eye(4))
|
||||
|
||||
assert target == pytest.approx([0.2] * 7)
|
||||
assert teleop._last_valid_joint_target == pytest.approx([0.2] * 7)
|
||||
assert teleop._last_valid_joint_target == pytest.approx([0.1] * 7)
|
||||
|
||||
|
||||
def test_target_filters_do_not_commit_candidate_state() -> None:
|
||||
teleop = object.__new__(SingleArmVelocityTeleop)
|
||||
teleop._filtered_target = [0.0, 0.0, 0.0]
|
||||
teleop._filtered_orientation_target = np.eye(3)
|
||||
teleop._target_filter_alpha = 0.5
|
||||
teleop._target_filter_alpha_fast = 0.5
|
||||
teleop._target_filter_fast_threshold_m = 1.0
|
||||
teleop._orientation_filter_alpha = 0.5
|
||||
|
||||
position = teleop._filter_target([0.2, 0.0, 0.0])
|
||||
orientation = teleop._filter_orientation_target(
|
||||
_so3_exp(np.asarray([0.0, 0.0, 0.2]))
|
||||
)
|
||||
|
||||
assert position == pytest.approx([0.1, 0.0, 0.0])
|
||||
assert teleop._filtered_target == pytest.approx([0.0, 0.0, 0.0])
|
||||
assert teleop._filtered_orientation_target == pytest.approx(np.eye(3))
|
||||
assert np.linalg.norm(_so3_log(orientation)) == pytest.approx(0.1)
|
||||
|
||||
|
||||
def test_failed_send_does_not_commit_cartesian_reference_state() -> None:
|
||||
teleop = object.__new__(SingleArmVelocityTeleop)
|
||||
teleop._last_valid_joint_target = [0.1] * 7
|
||||
teleop._filtered_target = [0.2, 0.0, 0.0]
|
||||
teleop._filtered_orientation_target = np.eye(3)
|
||||
teleop._last_sent_target = [0.2, 0.0, 0.0]
|
||||
teleop._last_sent_orientation = np.eye(3)
|
||||
teleop._last_command_time = FakeTime()
|
||||
teleop._send_joint_target = lambda joints: False
|
||||
|
||||
sent = teleop._send_and_commit_joint_target(
|
||||
[0.3] * 7,
|
||||
[0.3, 0.0, 0.0],
|
||||
_so3_exp(np.asarray([0.0, 0.0, 0.1])),
|
||||
[0.3, 0.0, 0.0],
|
||||
_so3_exp(np.asarray([0.0, 0.0, 0.1])),
|
||||
FakeTime(),
|
||||
)
|
||||
|
||||
assert not sent
|
||||
assert teleop._last_valid_joint_target == pytest.approx([0.1] * 7)
|
||||
assert teleop._filtered_target == pytest.approx([0.2, 0.0, 0.0])
|
||||
assert teleop._filtered_orientation_target == pytest.approx(np.eye(3))
|
||||
assert teleop._last_sent_target == pytest.approx([0.2, 0.0, 0.0])
|
||||
assert teleop._last_sent_orientation == pytest.approx(np.eye(3))
|
||||
|
||||
|
||||
def test_enter_active_control_initializes_se3_orientation_state() -> None:
|
||||
|
||||
Reference in New Issue
Block a user