feat: update hand gestures and direct locomotion

This commit is contained in:
2026-08-11 14:35:51 +08:00
parent 89a8c3418f
commit 4cceebfa5f
11 changed files with 469 additions and 71 deletions

View File

@@ -82,6 +82,7 @@ class RobotSessionGateTest(unittest.TestCase):
bridge.cfg = {"control": {"auto_home_on_stop": True}}
bridge.hands_enabled = False
bridge.right_point_gesture_enabled = False
bridge.right_a_pose_enabled = False
bridge.robot_arm_positions = [0.0] * 14
bridge.last_command = None
bridge.last_publish_at = 0.0
@@ -229,10 +230,9 @@ class RobotSessionGateTest(unittest.TestCase):
bridge._source_restart_reason(12.0, active),
)
def test_locomotion_reacts_immediately_after_repress(self) -> None:
def test_locomotion_reacts_directly_to_sticks_without_buttons(self) -> None:
bridge = LocalTeleopBridge.__new__(LocalTeleopBridge)
bridge.locomotion_cfg = {
"hold_seconds": 0.0,
"joystick_deadzone": 0.2,
"joystick_expo": 2.0,
"yaw_joystick_expo": 1.0,
@@ -243,10 +243,10 @@ class RobotSessionGateTest(unittest.TestCase):
"yaw_axis_sign": -1.0,
"zero_burst_frames": 10,
}
bridge.walk_combo_started_at = None
bridge.walk_active = False
bridge.walk_command = [0.0, 0.0]
bridge.walk_zero_frames_remaining = 0
bridge.walk_require_neutral = False
bridge.get_logger = MethodType(lambda _self: NullLogger(), bridge)
published: list[tuple[float, float]] = []
@@ -262,7 +262,7 @@ class RobotSessionGateTest(unittest.TestCase):
{
"button": {
"left": [False, False, False],
"right": [False, False, True],
"right": [False, False, False],
},
"joystick": {
"left": [1.0, 0.0],
@@ -278,7 +278,7 @@ class RobotSessionGateTest(unittest.TestCase):
"right": [False, False, False],
},
"joystick": {
"left": [1.0, 0.0],
"left": [0.0, 0.0],
"right": [0.0, 0.0],
},
},
@@ -294,7 +294,7 @@ class RobotSessionGateTest(unittest.TestCase):
turning = ArmSnapshot(
{
"button": {
"left": [False, False, True],
"left": [False, False, False],
"right": [False, False, False],
},
"joystick": {
@@ -323,6 +323,49 @@ class RobotSessionGateTest(unittest.TestCase):
bridge._tick_locomotion(1.4, old_wrong_binding)
self.assertEqual(published[-1], (0.0, 0.0))
def test_locomotion_requires_one_neutral_sample_after_arming(self) -> None:
bridge = LocalTeleopBridge.__new__(LocalTeleopBridge)
bridge.locomotion_cfg = {
"joystick_deadzone": 0.2,
"joystick_expo": 2.0,
"yaw_joystick_expo": 1.0,
"max_forward_m_s": 1.0,
"max_reverse_m_s": 0.8,
"max_angular_rad_s": 0.8,
"forward_axis_sign": 1.0,
"yaw_axis_sign": -1.0,
"zero_burst_frames": 10,
}
bridge.walk_active = False
bridge.walk_command = [0.0, 0.0]
bridge.walk_zero_frames_remaining = 0
bridge.walk_require_neutral = True
bridge.get_logger = MethodType(lambda _self: NullLogger(), bridge)
published: list[tuple[float, float]] = []
def publish(
self: object, linear_x: float, angular_z: float, _now: float
) -> None:
published.append((linear_x, angular_z))
self.walk_command = [linear_x, angular_z]
bridge._publish_walk = MethodType(publish, bridge)
deflected = ArmSnapshot(
{"joystick": {"left": [1.0, 0.0], "right": [0.0, 0.0]}},
received_at=2.0,
)
neutral = ArmSnapshot(
{"joystick": {"left": [0.0, 0.0], "right": [0.0, 0.0]}},
received_at=2.1,
)
bridge._tick_locomotion(2.0, deflected)
self.assertTrue(bridge.walk_require_neutral)
self.assertEqual(bridge.walk_command, [0.0, 0.0])
bridge._tick_locomotion(2.1, neutral)
self.assertFalse(bridge.walk_require_neutral)
bridge._tick_locomotion(2.2, deflected)
self.assertEqual(published[-1], (1.0, -0.0))
def test_l3_hold_reaches_nonblocking_capture_request(self) -> None:
bridge = LocalTeleopBridge.__new__(LocalTeleopBridge)
bridge.data_collection_enabled = True