gazebo_world_manager/scene/grasp-box/scripts/grasp_box_example.py
2025-08-10 11:58:37 +08:00

240 lines
9.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
import time
from kuavo_humanoid_sdk import (KuavoRobot, KuavoRobotState, KuavoRobotTools,
KuavoRobotVision, KuavoSDK)
from kuavo_humanoid_sdk.common.logger import SDKLogger
from kuavo_humanoid_sdk.interfaces.data_types import (AprilTagData,
PoseQuaternion)
from kuavo_humanoid_sdk.kuavo_strategy.grasp_box.grasp_box_strategy import (
BoxInfo, KuavoGraspBox)
"""
安全须知:
请注意
实物机器人当中因为搬箱子需要用到末端力控制, 请把 arm_transport_target_up 当中的sim_mode设置为False
仿真机器人当中因为物理性质差异,所以不需要用到末端力控制 请把 arm_transport_target_up 当中的sim_mode设置为True
长春一汽绿色箱子质量为1.5kg, 请根据实际情况修改箱子质量
"""
def main(real: bool = True):
start_time = time.time() # 记录开始时间
# Initialize SDK
if not KuavoSDK().Init():
print("Init KuavoSDK failed, exit!")
exit(1)
SDKLogger.info("初始化机器人...")
# 初始化机器人及相关组件
robot = KuavoRobot()
robot_state = KuavoRobotState()
robot_tools = KuavoRobotTools()
robot_vision = KuavoRobotVision()
# 初始化箱子抓取策略
grasp_strategy = KuavoGraspBox(robot, robot_state, robot_tools, robot_vision)
# 粘贴在箱子上的 AprilTag 信息: 需要 ID尺寸和基于odom坐标系下的大致位姿
box_tag = AprilTagData(
id=[1], # AprilTag ID
size=[0.1], # AprilTag 标签尺寸
pose=[PoseQuaternion(
# TODO: 需要根据实际情况调整
position=(0.0, -1.5, 0.8), # 基于odom坐标系下的大致位置, 查找时会对齐到这个方向
orientation=(0.0, 0.0, 0.0, 1.0) # 四元数方向
)]
)
# 粘贴在放置位置的 AprilTag 信息: 需要 ID尺寸和基于odom坐标系下的大致位姿
placement_tag = AprilTagData(
id=[0], # AprilTag ID
size=[0.1], # AprilTag 标签尺寸
pose=[PoseQuaternion(
# TODO: 需要根据实际情况调整
position=(0.0, 1.5, 1.5), # 基于odom坐标系下的大致位置, 查找时会对齐到这个方向
orientation=(0.0, 0.0, 1.0, 0.0) # 四元数方向 - 旋转180度
)]
)
# 创建箱子信息对象
box_size = (0.3, 0.4, 0.22) # xyz( 宽, 长, 高)
box_mass = 1.5
time.sleep(1)
# 执行完整抓取策略
try:
SDKLogger.info("========== 开始执行箱子抓取策略 ==========")
# !!! Important: 关闭 basePitch 限制, 否则无法进行大幅度的前后倾动作 会导致摔倒
SDKLogger.info("⚠️ 重要提示: basePitch 限制需要关闭!!!")
SDKLogger.info("⚠️ 重要提示: basePitch 限制需要关闭!!!")
SDKLogger.info("⚠️ 重要提示: basePitch 限制需要关闭!!!")
grasp_strategy.robot.enable_base_pitch_limit(False) # 关闭 basePitch 限制
# Retry up to 3 times to check pitch limit status
for i in range(3):
if not robot_state.pitch_limit_enabled():
SDKLogger.info("✅ 已关闭 basePitch 限制")
break
else:
if i < 2: # Don't log on last attempt
SDKLogger.info(f"⚠️ 第{i+1}次检查 basePitch 限制状态...")
time.sleep(0.5) # Brief pause between retries
else: # Loop completed without break
SDKLogger.info("❌ 关闭 basePitch 限制失败")
return
# -----------------------------------------------------------
# 步骤1使用头部寻找目标
SDKLogger.info("1. 寻找目标箱子...")
grasp_strategy.robot.disable_head_tracking()
SDKLogger.info("✅ 已关闭头部追踪")
find_success = grasp_strategy.head_find_target(
box_tag,
max_search_time=15.0,
search_pattern="rotate_body" # rotate_head
)
if not find_success:
SDKLogger.info("❌ 寻找目标失败,无法继续执行")
return
SDKLogger.info("✅ 已找到目标箱子")
time.sleep(1) # 短暂暂停
box_tag_data = robot_vision.get_data_by_id_from_odom(box_tag.id[0]) # 拿到箱子tag数据 odom系
if not box_tag_data:
SDKLogger.info(f"❌ 未识别到 AprilTag ID 为{box_tag.id[0]} 的目标箱子")
return
SDKLogger.info(f"box_tag_data: {box_tag_data}")
box_info = BoxInfo.from_apriltag(
box_tag_data,
xyz_offset=(box_size[0]/2, 0.0, -0.00), # tag 粘贴在箱子正面,为了得到箱子中心点,因此偏移量为箱子宽度的一半
size=box_size, # 箱子尺寸,单位:米
mass=box_mass # 箱子重量,单位:千克
)
SDKLogger.info(f"box_info: {box_info}")
# 步骤2走路接近目标
# for i in range(1):
SDKLogger.info("2. 走路接近目标...")
approach_success = grasp_strategy.walk_approach_target(
box_tag.id[0],
target_distance=0.4, # 与目标箱子保持0.7米的距离
approach_speed=0.2 # 接近速度0.2米/秒
)
if not approach_success:
SDKLogger.info("❌ 接近目标失败,无法继续执行")
return
SDKLogger.info("✅ 已成功接近目标")
time.sleep(1) # 短暂暂停
# 步骤3手臂移动到抓取位置
SDKLogger.info("3. 手臂移动到抓取位置...")
move_success = grasp_strategy.arm_move_to_target(
box_info,
arm_mode="manipulation_mpc"
)
if not move_success:
SDKLogger.info("❌ 手臂移动失败,无法继续执行")
return
SDKLogger.info("✅ 手臂已到达抓取位置")
# grasp_strategy.robot.arm_reset()
time.sleep(1.0) # 短暂暂停
# 步骤4提起箱子
SDKLogger.info("4. 提起箱子...")
transport_up_success = grasp_strategy.arm_transport_target_up(
box_info,
arm_mode="manipulation_mpc",
sim_mode=not real
)
if not transport_up_success:
SDKLogger.info("❌ 提起箱子失败")
return
time.sleep(1.0) # 短暂暂停
SDKLogger.info("✅ 成功提起箱子")
# grasp_strategy.robot.arm_reset()
time.sleep(1.0) # 展示一下成功提起的状态
# return # FIXME:测试提起箱子成功
# 步骤5关闭头部追踪
SDKLogger.info("5. 关闭头部追踪...")
grasp_strategy.robot.disable_head_tracking()
SDKLogger.info("✅ 已关闭头部追踪")
time.sleep(1.0) # 短暂暂停
if not grasp_strategy.head_find_target(
placement_tag,
max_search_time=15.0,
search_pattern="rotate_body" # rotate_head
):
SDKLogger.info("❌ 寻找目标失败,无法继续执行")
return
placement_tag_data = robot_vision.get_data_by_id_from_odom(placement_tag.id[0])
if placement_tag_data is None:
SDKLogger.info(f"❌ 未识别到 AprilTag ID 为{placement_tag.id[0]} 的目标箱子")
return
# 步骤6移动到放置位置
SDKLogger.info("6. 移动到放置位置...")
move_success = grasp_strategy.walk_approach_target(
placement_tag.id[0],
target_distance=0.4,
approach_speed=0.2,
)
if not move_success:
SDKLogger.info("❌ 移动到放置位置失败")
return
time.sleep(1.0) # 短暂暂停
# 步骤7放下箱子
placement_box_info = BoxInfo.from_apriltag(
placement_tag_data,
xyz_offset=(box_size[0]/2, 0.0, -0.5), # tag 粘贴在货架上,需要把箱子放下距离货架的高度 -0.5m
size=box_size, # 箱子尺寸(长、宽、高),单位:米
mass=box_mass # 箱子重量,单位:千克
)
SDKLogger.info("7. 放下箱子...")
transport_down_success = grasp_strategy.arm_transport_target_down(
placement_box_info,
arm_mode="manipulation_mpc"
)
if not transport_down_success:
SDKLogger.info("❌ 放下箱子失败")
return
SDKLogger.info("✅ 成功放下箱子")
time.sleep(1.0) # 短暂暂停
# 步骤8: 回到初始位置
SDKLogger.info("8. 回到初始位置...")
grasp_strategy.robot.control_command_pose_world(0, 0, 0, 0)
time.sleep(10) # 等待10s转身完成
total_time = time.time() - start_time # 计算总时间
SDKLogger.info(f"========== 搬箱子任务完成,总耗时: {total_time:.2f}秒 ==========")
except Exception as e:
SDKLogger.info(f"执行过程中发生错误: {e}")
finally:
# 确保机器人回到安全状态
SDKLogger.info("将机器人恢复到安全姿态...")
# 这里可以添加使机器人回到默认姿态的代码
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--sim', action='store_true', default=False)
args, unknown = parser.parse_known_args()
main(not args.sim)