From 17c299df876d071fa734917b7534c34b013caf55 Mon Sep 17 00:00:00 2001 From: dengzhuo0119 Date: Fri, 19 Dec 2025 23:11:27 +0800 Subject: [PATCH 01/19] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E9=80=89=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Robot_arm_motion/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/Robot_arm_motion/README.md diff --git a/src/Robot_arm_motion/README.md b/src/Robot_arm_motion/README.md new file mode 100644 index 0000000000..c23571d758 --- /dev/null +++ b/src/Robot_arm_motion/README.md @@ -0,0 +1 @@ +机械臂抓取 \ No newline at end of file From 5e6eb70745871dbb5d2c5531002103d41b15088c Mon Sep 17 00:00:00 2001 From: dengzhuo0119 Date: Sun, 21 Dec 2025 21:09:20 +0800 Subject: [PATCH 02/19] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=88=9D=E5=A7=8B?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Robot_arm_motion/requirements.txt | 0 src/Robot_arm_motion/scripts/simple_grasp.py | 103 +++++++++++++++++++ src/Robot_arm_motion/test_pybullet_final.py | 0 3 files changed, 103 insertions(+) create mode 100644 src/Robot_arm_motion/requirements.txt create mode 100644 src/Robot_arm_motion/scripts/simple_grasp.py create mode 100644 src/Robot_arm_motion/test_pybullet_final.py diff --git a/src/Robot_arm_motion/requirements.txt b/src/Robot_arm_motion/requirements.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/Robot_arm_motion/scripts/simple_grasp.py b/src/Robot_arm_motion/scripts/simple_grasp.py new file mode 100644 index 0000000000..e1f6e82e2b --- /dev/null +++ b/src/Robot_arm_motion/scripts/simple_grasp.py @@ -0,0 +1,103 @@ +import pybullet as p +import time +import math + +# 初始化pybullet,使用GUI模式并重置仿真 +physicsClient = p.connect(p.GUI) +p.resetSimulation() +p.setGravity(0, 0, -9.81) +p.setRealTimeSimulation(0) # 非实时仿真,便于精确控制 +print("✅ pybullet仿真环境初始化完成") + +# ---------------------- 纯代码创建环境和物体 ---------------------- +# 1. 创建地面 +ground_shape = p.createCollisionShape(p.GEOM_PLANE) +ground_id = p.createMultiBody(0, ground_shape, basePosition=[0, 0, 0]) +p.changeDynamics(ground_id, -1, lateralFriction=0.8) +print("✅ 已创建地面") + +# 2. 创建机械臂底座(固定) +base_shape = p.createCollisionShape(p.GEOM_CYLINDER, radius=0.1, height=0.2) +base_id = p.createMultiBody(0, base_shape, basePosition=[0, 0, 0.1]) +print(f"✅ 已创建机械臂底座,ID:{base_id}") + +# 3. 创建机械臂大臂(可动连杆1) +arm1_shape = p.createCollisionShape(p.GEOM_CYLINDER, radius=0.06, height=0.4) +arm1_id = p.createMultiBody(1.0, arm1_shape, basePosition=[0, 0, 0.3]) +p.changeDynamics(arm1_id, -1, lateralFriction=0.5, restitution=0.1) +print(f"✅ 已创建机械臂大臂,ID:{arm1_id}") + +# 4. 创建抓取目标立方体 +cube_shape = p.createCollisionShape(p.GEOM_BOX, halfExtents=[0.05, 0.05, 0.05]) +cube_id = p.createMultiBody(0.2, cube_shape, basePosition=[0.4, 0, 0.2]) +p.changeDynamics(cube_id, -1, lateralFriction=0.5) +print(f"✅ 已创建抓取目标立方体,ID:{cube_id}") + +# ---------------------- 机械臂运动与抓取逻辑(无关节约束版) ---------------------- +def calculate_arm_position(angle): + """根据旋转角度计算大臂的位置和姿态""" + # 大臂的旋转中心在底座顶部(0,0,0.2) + center_x, center_y, center_z = 0, 0, 0.2 + # 大臂长度(半高+底座高度) + arm_length = 0.2 # 大臂半高0.2m + # 计算大臂中心的新位置(绕Y轴旋转) + new_x = center_x + arm_length * math.sin(angle) + new_z = center_z + arm_length * math.cos(angle) + # 计算大臂的姿态(四元数) + orientation = p.getQuaternionFromEuler([0, angle, 0]) # 绕Y轴旋转angle弧度 + return (new_x, 0, new_z), orientation + +def check_grasp(arm_pos, cube_pos, threshold=0.1): + """检测是否可以抓取(距离判断)""" + distance = math.sqrt( + (arm_pos[0]-cube_pos[0])**2 + + (arm_pos[1]-cube_pos[1])**2 + + (arm_pos[2]-cube_pos[2])**2 + ) + return distance < threshold + +# 初始化变量 +grasped = False # 是否已抓取立方体 +angle = 0.0 # 机械臂旋转角度 +angle_speed = 0.02 # 旋转速度(弧度/步) +max_angle = math.pi / 2 # 最大旋转角度(90°) + +print("\n🚀 仿真开始,机械臂将开始运动,靠近立方体后自动抓取...") +print("💡 按下Ctrl+C可终止仿真") + +# ---------------------- 主仿真循环 ---------------------- +try: + while True: + # 1. 更新机械臂旋转角度(来回摆动) + angle += angle_speed + if abs(angle) > max_angle: + angle_speed = -angle_speed # 反向旋转 + + # 2. 计算并设置大臂的位置和姿态 + arm_pos, arm_ori = calculate_arm_position(angle) + p.resetBasePositionAndOrientation(arm1_id, arm_pos, arm_ori) + + # 3. 获取立方体位置,判断是否抓取 + cube_pos, cube_ori = p.getBasePositionAndOrientation(cube_id) + if not grasped: + if check_grasp(arm_pos, cube_pos): + grasped = True + print(f"\n✅ 已抓取立方体!当前机械臂角度:{math.degrees(angle):.1f}°") + else: + # 已抓取:将立方体位置绑定到机械臂末端 + # 机械臂末端位置(大臂顶部) + end_effector_pos = ( + arm_pos[0] + 0.2 * math.sin(angle), + 0, + arm_pos[2] + 0.2 * math.cos(angle) + ) + p.resetBasePositionAndOrientation(cube_id, end_effector_pos, cube_ori) + + # 4. 执行物理仿真步长 + p.stepSimulation() + time.sleep(1/240) # 240Hz仿真频率 + +except KeyboardInterrupt: + # 断开仿真连接 + p.disconnect() + print("\n\n🔚 仿真已手动终止,感谢使用!") \ No newline at end of file diff --git a/src/Robot_arm_motion/test_pybullet_final.py b/src/Robot_arm_motion/test_pybullet_final.py new file mode 100644 index 0000000000..e69de29bb2 From 265bcd4867ed03ce489bb12325ebfb6b6f0fe545 Mon Sep 17 00:00:00 2001 From: dengzhuo0119 Date: Mon, 22 Dec 2025 10:46:30 +0800 Subject: [PATCH 03/19] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=88=9D=E5=A7=8B?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Robot_arm_motion/scripts/robot_arm.py | 68 ++++++++++++ src/Robot_arm_motion/scripts/simple_grasp.py | 103 ------------------ .../{test_pybullet_final.py => test.py} | 0 3 files changed, 68 insertions(+), 103 deletions(-) create mode 100644 src/Robot_arm_motion/scripts/robot_arm.py delete mode 100644 src/Robot_arm_motion/scripts/simple_grasp.py rename src/Robot_arm_motion/{test_pybullet_final.py => test.py} (100%) diff --git a/src/Robot_arm_motion/scripts/robot_arm.py b/src/Robot_arm_motion/scripts/robot_arm.py new file mode 100644 index 0000000000..c12ad7a153 --- /dev/null +++ b/src/Robot_arm_motion/scripts/robot_arm.py @@ -0,0 +1,68 @@ +""" +MuJoCo机械臂仿真初始版本 +功能:基础2关节机械臂可视化+关节角度控制 +项目根目录:Robot_arm_motion +代码目录:scripts +作者:邓卓 +日期:2025-12-22 +""" +import mujoco +import mujoco.viewer as viewer +import numpy as np + +def create_simple_arm_model(): + """创建简易2关节机械臂+立方体模型的XML字符串""" + xml = """ + + + """ + return mujoco.MjModel.from_xml_string(xml) + +def main(): + """主函数:加载模型+启动仿真""" + # 加载模型 + model = create_simple_arm_model() + data = mujoco.MjData(model) + + # 设置初始关节角度 + joint1_id = mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_JOINT, "joint1") + joint2_id = mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_JOINT, "joint2") + data.ctrl[joint1_id] = np.pi/4 # 关节1转45° + data.ctrl[joint2_id] = -np.pi/6 # 关节2转-30° + + # 启动可视化 + print("=== Robot_arm_motion 初始版本仿真启动 ===") + with viewer.launch_passive(model, data) as v: + while v.is_running(): + mujoco.mj_step(model, data) + v.sync() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/src/Robot_arm_motion/scripts/simple_grasp.py b/src/Robot_arm_motion/scripts/simple_grasp.py deleted file mode 100644 index e1f6e82e2b..0000000000 --- a/src/Robot_arm_motion/scripts/simple_grasp.py +++ /dev/null @@ -1,103 +0,0 @@ -import pybullet as p -import time -import math - -# 初始化pybullet,使用GUI模式并重置仿真 -physicsClient = p.connect(p.GUI) -p.resetSimulation() -p.setGravity(0, 0, -9.81) -p.setRealTimeSimulation(0) # 非实时仿真,便于精确控制 -print("✅ pybullet仿真环境初始化完成") - -# ---------------------- 纯代码创建环境和物体 ---------------------- -# 1. 创建地面 -ground_shape = p.createCollisionShape(p.GEOM_PLANE) -ground_id = p.createMultiBody(0, ground_shape, basePosition=[0, 0, 0]) -p.changeDynamics(ground_id, -1, lateralFriction=0.8) -print("✅ 已创建地面") - -# 2. 创建机械臂底座(固定) -base_shape = p.createCollisionShape(p.GEOM_CYLINDER, radius=0.1, height=0.2) -base_id = p.createMultiBody(0, base_shape, basePosition=[0, 0, 0.1]) -print(f"✅ 已创建机械臂底座,ID:{base_id}") - -# 3. 创建机械臂大臂(可动连杆1) -arm1_shape = p.createCollisionShape(p.GEOM_CYLINDER, radius=0.06, height=0.4) -arm1_id = p.createMultiBody(1.0, arm1_shape, basePosition=[0, 0, 0.3]) -p.changeDynamics(arm1_id, -1, lateralFriction=0.5, restitution=0.1) -print(f"✅ 已创建机械臂大臂,ID:{arm1_id}") - -# 4. 创建抓取目标立方体 -cube_shape = p.createCollisionShape(p.GEOM_BOX, halfExtents=[0.05, 0.05, 0.05]) -cube_id = p.createMultiBody(0.2, cube_shape, basePosition=[0.4, 0, 0.2]) -p.changeDynamics(cube_id, -1, lateralFriction=0.5) -print(f"✅ 已创建抓取目标立方体,ID:{cube_id}") - -# ---------------------- 机械臂运动与抓取逻辑(无关节约束版) ---------------------- -def calculate_arm_position(angle): - """根据旋转角度计算大臂的位置和姿态""" - # 大臂的旋转中心在底座顶部(0,0,0.2) - center_x, center_y, center_z = 0, 0, 0.2 - # 大臂长度(半高+底座高度) - arm_length = 0.2 # 大臂半高0.2m - # 计算大臂中心的新位置(绕Y轴旋转) - new_x = center_x + arm_length * math.sin(angle) - new_z = center_z + arm_length * math.cos(angle) - # 计算大臂的姿态(四元数) - orientation = p.getQuaternionFromEuler([0, angle, 0]) # 绕Y轴旋转angle弧度 - return (new_x, 0, new_z), orientation - -def check_grasp(arm_pos, cube_pos, threshold=0.1): - """检测是否可以抓取(距离判断)""" - distance = math.sqrt( - (arm_pos[0]-cube_pos[0])**2 + - (arm_pos[1]-cube_pos[1])**2 + - (arm_pos[2]-cube_pos[2])**2 - ) - return distance < threshold - -# 初始化变量 -grasped = False # 是否已抓取立方体 -angle = 0.0 # 机械臂旋转角度 -angle_speed = 0.02 # 旋转速度(弧度/步) -max_angle = math.pi / 2 # 最大旋转角度(90°) - -print("\n🚀 仿真开始,机械臂将开始运动,靠近立方体后自动抓取...") -print("💡 按下Ctrl+C可终止仿真") - -# ---------------------- 主仿真循环 ---------------------- -try: - while True: - # 1. 更新机械臂旋转角度(来回摆动) - angle += angle_speed - if abs(angle) > max_angle: - angle_speed = -angle_speed # 反向旋转 - - # 2. 计算并设置大臂的位置和姿态 - arm_pos, arm_ori = calculate_arm_position(angle) - p.resetBasePositionAndOrientation(arm1_id, arm_pos, arm_ori) - - # 3. 获取立方体位置,判断是否抓取 - cube_pos, cube_ori = p.getBasePositionAndOrientation(cube_id) - if not grasped: - if check_grasp(arm_pos, cube_pos): - grasped = True - print(f"\n✅ 已抓取立方体!当前机械臂角度:{math.degrees(angle):.1f}°") - else: - # 已抓取:将立方体位置绑定到机械臂末端 - # 机械臂末端位置(大臂顶部) - end_effector_pos = ( - arm_pos[0] + 0.2 * math.sin(angle), - 0, - arm_pos[2] + 0.2 * math.cos(angle) - ) - p.resetBasePositionAndOrientation(cube_id, end_effector_pos, cube_ori) - - # 4. 执行物理仿真步长 - p.stepSimulation() - time.sleep(1/240) # 240Hz仿真频率 - -except KeyboardInterrupt: - # 断开仿真连接 - p.disconnect() - print("\n\n🔚 仿真已手动终止,感谢使用!") \ No newline at end of file diff --git a/src/Robot_arm_motion/test_pybullet_final.py b/src/Robot_arm_motion/test.py similarity index 100% rename from src/Robot_arm_motion/test_pybullet_final.py rename to src/Robot_arm_motion/test.py From 8611cefbf8082c4709652733af6de138cedd34c7 Mon Sep 17 00:00:00 2001 From: dengzhuo0119 Date: Mon, 22 Dec 2025 11:22:00 +0800 Subject: [PATCH 04/19] =?UTF-8?q?feat:=20v0.2-=E6=B7=BB=E5=8A=A0=E5=A4=B9?= =?UTF-8?q?=E7=88=AA=E5=BC=80=E5=90=88=E6=8E=A7=E5=88=B6=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=EF=BC=88=E4=BF=AE=E5=A4=8DXML=20ctrlrange=E5=B1=9E=E6=80=A7?= =?UTF-8?q?=E9=94=99=E8=AF=AF=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Robot_arm_motion/scripts/robot_arm.py | 37 +++++++++++++++++++---- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/src/Robot_arm_motion/scripts/robot_arm.py b/src/Robot_arm_motion/scripts/robot_arm.py index c12ad7a153..a810cb96f1 100644 --- a/src/Robot_arm_motion/scripts/robot_arm.py +++ b/src/Robot_arm_motion/scripts/robot_arm.py @@ -1,17 +1,18 @@ """ -MuJoCo机械臂仿真初始版本 -功能:基础2关节机械臂可视化+关节角度控制 +MuJoCo机械臂仿真v0.2 +功能:基础2关节机械臂可视化+关节角度控制+夹爪开合控制 项目根目录:Robot_arm_motion 代码目录:scripts 作者:邓卓 日期:2025-12-22 +版本:v0.2(添加夹爪开合控制,修复XML Schema错误) """ import mujoco import mujoco.viewer as viewer import numpy as np def create_simple_arm_model(): - """创建简易2关节机械臂+立方体模型的XML字符串""" + """创建简易2关节机械臂+立方体模型的XML字符串(修复ctrlrange属性错误)""" xml = """ """ return mujoco.MjModel.from_xml_string(xml) def main(): - """主函数:加载模型+启动仿真""" + """主函数:加载模型+启动仿真(新增夹爪控制)""" # 加载模型 model = create_simple_arm_model() data = mujoco.MjData(model) @@ -57,8 +75,15 @@ def main(): data.ctrl[joint1_id] = np.pi/4 # 关节1转45° data.ctrl[joint2_id] = -np.pi/6 # 关节2转-30° + # 新增:设置夹爪初始开合角度(半开状态) + left_gripper_id = mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_JOINT, "left_gripper_joint") + right_gripper_id = mujoco.mj_name2id(model, mujoco.mjtObj.mjOBJ_JOINT, "right_gripper_joint") + data.ctrl[left_gripper_id] = 0.03 # 左夹爪张开3mm + data.ctrl[right_gripper_id] = -0.03 # 右夹爪张开3mm + # 启动可视化 - print("=== Robot_arm_motion 初始版本仿真启动 ===") + print("=== Robot_arm_motion v0.2 仿真启动(新增夹爪开合控制) ===") + print("当前夹爪状态:半开(3mm)") with viewer.launch_passive(model, data) as v: while v.is_running(): mujoco.mj_step(model, data) From 81cc517ea8c82d4ff9cd9216977bb5f5f61e4aae Mon Sep 17 00:00:00 2001 From: dengzhuo0119 Date: Mon, 22 Dec 2025 11:37:25 +0800 Subject: [PATCH 05/19] =?UTF-8?q?feat:=20v0.3-=E5=AE=9E=E7=8E=B0=E5=A4=B9?= =?UTF-8?q?=E7=88=AA=E4=B8=8E=E7=AB=8B=E6=96=B9=E4=BD=93=E7=9A=84=E6=8E=A5?= =?UTF-8?q?=E8=A7=A6=E6=A3=80=E6=B5=8B=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Robot_arm_motion/scripts/robot_arm.py | 76 +++++++++++++++++++---- 1 file changed, 64 insertions(+), 12 deletions(-) diff --git a/src/Robot_arm_motion/scripts/robot_arm.py b/src/Robot_arm_motion/scripts/robot_arm.py index a810cb96f1..3a17f8b51a 100644 --- a/src/Robot_arm_motion/scripts/robot_arm.py +++ b/src/Robot_arm_motion/scripts/robot_arm.py @@ -1,18 +1,18 @@ """ -MuJoCo机械臂仿真v0.2 -功能:基础2关节机械臂可视化+关节角度控制+夹爪开合控制 +MuJoCo机械臂仿真v0.3 +功能:基础2关节机械臂可视化+关节角度控制+夹爪开合控制+接触检测 项目根目录:Robot_arm_motion 代码目录:scripts 作者:邓卓 日期:2025-12-22 -版本:v0.2(添加夹爪开合控制,修复XML Schema错误) +版本:v0.3(实现夹爪与立方体接触检测) """ import mujoco import mujoco.viewer as viewer import numpy as np def create_simple_arm_model(): - """创建简易2关节机械臂+立方体模型的XML字符串(修复ctrlrange属性错误)""" + """创建简易2关节机械臂+立方体模型的XML字符串""" xml = """