Files
mujoco_linkerbot/tools/middle_step_cmd_pub.py
2026-07-23 17:55:52 +08:00

114 lines
3.4 KiB
Python
Executable File

#!/usr/bin/env python3
"""O6 中指 step 控制指令(真机 / 仿真共用,时序完全一致)。
时序(默认):
pre_wait=3s 保持张开
hold=3s 中指握紧 (middle u8=0)
hold=3s 中指张开 (middle u8=255)
用法(单独发令,配合录制脚本):
export ROS_DOMAIN_ID=31
python3 tools/middle_step_cmd_pub.py
"""
from __future__ import annotations
import argparse
import time
# 与 run_middle_step_experiment.py 共用,改这里两边一起变
DEFAULT_PRE_WAIT = 3.0
DEFAULT_HOLD = 3.0
DEFAULT_RATE_HZ = 10.0
FINGER_ROS_IDX = {"index": 2, "middle": 3, "ring": 4, "pinky": 5}
def hold_finger_pose(pub, hand: str, finger: str, u8: float, duration: float, rate_hz: float):
from sensor_msgs.msg import JointState
idx = FINGER_ROS_IDX[finger]
end = time.perf_counter() + duration
dt = 1.0 / max(1.0, rate_hz)
while time.perf_counter() < end:
msg = JointState()
msg.position = [255.0, 255.0, 255.0, 255.0, 255.0, 255.0]
msg.position[idx] = float(u8)
pub.publish(msg)
time.sleep(dt)
def run_step_sequence(
node,
*,
hand: str = "left",
finger: str = "middle",
pre_wait: float = DEFAULT_PRE_WAIT,
hold: float = DEFAULT_HOLD,
rate_hz: float = DEFAULT_RATE_HZ,
cmd_topic: str | None = None,
):
from sensor_msgs.msg import JointState
topic = cmd_topic or f"/cb_{hand}_hand_control_cmd"
pub = node.create_publisher(JointState, topic, 10)
time.sleep(0.3)
t0 = time.perf_counter()
node.get_logger().info(
f"step cmd | finger={finger} | pre={pre_wait}s hold={hold}s | topic={topic}"
)
# 阶段0:保持张开
node.get_logger().info(f"[t={time.perf_counter()-t0:.2f}s] baseline open (255)")
hold_finger_pose(pub, hand, finger, 255.0, pre_wait, rate_hz)
# 阶段1:握紧
node.get_logger().info(f"[t={time.perf_counter()-t0:.2f}s] CLOSE middle u8=0")
hold_finger_pose(pub, hand, finger, 0.0, hold, rate_hz)
# 阶段2:张开
node.get_logger().info(f"[t={time.perf_counter()-t0:.2f}s] OPEN middle u8=255")
hold_finger_pose(pub, hand, finger, 255.0, hold, rate_hz)
node.get_logger().info(f"[t={time.perf_counter()-t0:.2f}s] sequence done")
return t0
def total_duration(pre_wait: float, hold: float, record_after: float = 0.0) -> float:
return pre_wait + hold + hold + record_after + 1.0
def main():
parser = argparse.ArgumentParser(description="O6 middle finger step command publisher")
parser.add_argument("--hand", default="left", choices=["left", "right"])
parser.add_argument("--finger", default="middle", choices=list(FINGER_ROS_IDX))
parser.add_argument("--pre-wait", type=float, default=DEFAULT_PRE_WAIT)
parser.add_argument("--hold", type=float, default=DEFAULT_HOLD)
parser.add_argument("--rate", type=float, default=DEFAULT_RATE_HZ)
parser.add_argument("--cmd-topic", default="")
args = parser.parse_args()
import rclpy
from rclpy.node import Node
rclpy.init()
node = Node("middle_step_cmd_pub")
try:
run_step_sequence(
node,
hand=args.hand,
finger=args.finger,
pre_wait=args.pre_wait,
hold=args.hold,
rate_hz=args.rate,
cmd_topic=args.cmd_topic or None,
)
finally:
node.destroy_node()
if rclpy.ok():
rclpy.shutdown()
if __name__ == "__main__":
main()