File size: 9,211 Bytes
581790e
 
 
 
 
 
718d79d
581790e
85e8a2e
789a4c3
 
 
28d8725
718d79d
6111b0a
718d79d
f6dacca
9a1ac54
f6dacca
9a1ac54
 
1d225fe
 
 
 
 
9a1ac54
f6dacca
3827efb
581790e
55b8cf4
9a1ac54
55b8cf4
 
 
 
 
 
 
 
 
 
 
6111b0a
9a1ac54
f6dacca
87933a4
ae34a04
 
87933a4
55b8cf4
 
6111b0a
55b8cf4
87933a4
 
55b8cf4
789a4c3
 
f6dacca
55b8cf4
789a4c3
87933a4
 
 
f6dacca
6111b0a
f5d6cbd
 
 
55b8cf4
f5d6cbd
87933a4
 
 
f5d6cbd
 
 
87933a4
 
6111b0a
f5d6cbd
55b8cf4
ae34a04
6111b0a
87933a4
cec7d8f
 
 
ae34a04
cec7d8f
 
ae34a04
fed0d1b
6111b0a
789a4c3
fed0d1b
 
 
 
 
 
 
 
 
 
55b8cf4
87933a4
fed0d1b
87933a4
 
 
fed0d1b
 
 
 
 
cec7d8f
 
 
ae34a04
fed0d1b
6111b0a
ae34a04
fed0d1b
55b8cf4
87933a4
fed0d1b
87933a4
 
 
6111b0a
87933a4
55b8cf4
 
fed0d1b
576f97f
 
 
 
6111b0a
86611cc
55b8cf4
86611cc
55b8cf4
 
 
 
 
 
 
 
 
576f97f
55b8cf4
576f97f
1c8f6a7
86611cc
 
 
576f97f
1c8f6a7
86611cc
 
 
 
1c8f6a7
576f97f
86611cc
 
 
55b8cf4
576f97f
55b8cf4
6111b0a
 
 
 
 
55b8cf4
6111b0a
 
 
55b8cf4
 
6111b0a
55b8cf4
 
 
576f97f
cec7d8f
6111b0a
cec7d8f
6111b0a
 
cec7d8f
 
d7c02d7
576f97f
cec7d8f
576f97f
 
 
 
 
 
 
 
 
 
 
 
 
cec7d8f
6111b0a
 
55b8cf4
 
 
 
34d6946
86611cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
import pybullet as p
import pybullet_data
import numpy as np
import matplotlib.pyplot as plt
import tempfile
import gradio as gr
import time

p.connect(p.DIRECT)
p.setAdditionalSearchPath(pybullet_data.getDataPath())
p.setGravity(0, 0, -9.8)
p.loadURDF("plane.urdf")
robot = p.loadURDF("franka_panda/panda.urdf", basePosition=[0, 0, 0], useFixedBase=True)
cube_id = p.loadURDF("cube_small.urdf", basePosition=[0.6, 0, 0.02])
p.changeVisualShape(cube_id, -1, rgbaColor=[0, 0, 0, 1])

def get_panda_joints(robot):
    arm, fingers = [], []
    for i in range(p.getNumJoints(robot)):
        info = p.getJointInfo(robot, i)
        name = info[1].decode()
        joint_type = info[2]
        if "finger" in name and joint_type == p.JOINT_PRISMATIC:
            fingers.append(i)
        elif joint_type == p.JOINT_REVOLUTE:
            arm.append(i)
    return arm, fingers

arm_joints, finger_joints = get_panda_joints(robot)

debug_labels = []
def add_joint_labels():
    global debug_labels
    for i in debug_labels:
        p.removeUserDebugItem(i)
    debug_labels.clear()
    for idx in arm_joints:
        link_state = p.getLinkState(robot, idx)
        pos = link_state[0]
        lbl = f"J{arm_joints.index(idx)+1}"
        text_id = p.addUserDebugText(lbl, pos, textColorRGB=[1, 0, 0], textSize=1.2)
        debug_labels.append(text_id)

def render_sim(joint_values, gripper_val, cam_xyz, target_xyz):
    for idx, tgt in zip(arm_joints, joint_values):
        p.setJointMotorControl2(robot, idx, p.POSITION_CONTROL, targetPosition=tgt)
    if len(finger_joints) == 2:
        for fj in finger_joints:
            p.setJointMotorControl2(robot, fj, p.POSITION_CONTROL, targetPosition=gripper_val)
    for _ in range(10): p.stepSimulation()
    add_joint_labels()
    width, height = 1280, 1280
    view_matrix = p.computeViewMatrix(cam_xyz, target_xyz, [0, 0, 1])
    proj_matrix = p.computeProjectionMatrixFOV(60, width / height, 0.1, 3.1)
    _, _, img, _, _ = p.getCameraImage(width, height, view_matrix, proj_matrix)
    rgb = np.reshape(img, (height, width, 4))[:, :, :3]
    fig, ax = plt.subplots(figsize=(5, 5))
    ax.imshow(rgb.astype(np.uint8))
    ax.axis("off")
    tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".png")
    plt.savefig(tmp.name, bbox_inches='tight', dpi=200)
    plt.close()
    joint_text = "Joint Angles:\n" + "\n".join([f"J{i+1} = {v:.2f} rad" for i, v in enumerate(joint_values)])
    joint_text += f"\nGripper = {gripper_val:.3f} m"
    return tmp.name, joint_text

def move_to_input_angles(joint_str, cam_xyz, target_xyz):
    try:
        target_angles = [float(x.strip()) for x in joint_str.split(",")]
        if len(target_angles) != 7:
            return None, "❌ Please enter exactly 7 joint angles."
        current = [p.getJointState(robot, idx)[0] for idx in arm_joints]
        steps = 100
        for i in range(steps):
            blend = [(1 - i/steps) * c + (i/steps) * t for c, t in zip(current, target_angles)]
            for idx, val in zip(arm_joints, blend):
                p.setJointMotorControl2(robot, idx, p.POSITION_CONTROL, targetPosition=val)
            p.stepSimulation()
            time.sleep(0.01)
        current_grip = p.getJointState(robot, finger_joints[0])[0]
        return render_sim(target_angles, current_grip, cam_xyz, target_xyz)
    except Exception as e:
        return None, f"Error: {str(e)}"

def pick_and_place(position_str, approach_str, place_str, cam_xyz, target_xyz):
    try:
        position_angles = [float(x.strip()) for x in position_str.split(",")]
        approach_angles = [float(x.strip()) for x in approach_str.split(",")]
        place_angles = [float(x.strip()) for x in place_str.split(",")]

        if len(position_angles) != 7 or len(approach_angles) != 7 or len(place_angles) != 7:
            return None, "❌ All inputs must have 7 joint angles."

        # Move to pre-grasp approach pose
        move_to_input_angles(approach_str, cam_xyz, target_xyz)

        # Grasping: move to actual grasp pose (over the object)
        steps = 50
        for i in range(steps):
            interpolated = [(1 - i/steps) * approach_angles[j] + (i/steps) * position_angles[j] for j in range(7)]
            for idx, val in zip(arm_joints, interpolated):
                p.setJointMotorControl2(robot, idx, p.POSITION_CONTROL, targetPosition=val)
            p.stepSimulation()
            time.sleep(0.01)

        # Close the gripper to grasp
        for _ in range(30):
            for fj in finger_joints:
                p.setJointMotorControl2(robot, fj, p.POSITION_CONTROL, targetPosition=0.0)  # Closed
            p.stepSimulation()
            time.sleep(0.01)

        # Lift object slightly from grasp position
        lifted_angles = [a + 0.1 for a in position_angles]  # Add a small lift to each joint
        for i in range(steps):
            lifted_pose = [(1 - i/steps) * position_angles[j] + (i/steps) * lifted_angles[j] for j in range(7)]
            for idx, val in zip(arm_joints, lifted_pose):
                p.setJointMotorControl2(robot, idx, p.POSITION_CONTROL, targetPosition=val)
            p.stepSimulation()
            time.sleep(0.01)

        # Move to place location
        move_to_input_angles(place_str, cam_xyz, target_xyz)

        # Release the gripper
        for _ in range(30):
            for fj in finger_joints:
                p.setJointMotorControl2(robot, fj, p.POSITION_CONTROL, targetPosition=0.04)  # Open
            p.stepSimulation()
            time.sleep(0.01)

        return render_sim(place_angles, 0.04, cam_xyz, target_xyz)
    except Exception as e:
        return None, f"Error: {str(e)}"


# Copy current joint angles
def copy_current_joint_angles(*vals):
    return ", ".join([f"{v:.4f}" for v in vals])

with gr.Blocks(title="Franka Arm with 3D Camera Control") as demo:
    gr.Markdown("## πŸ€– Franka Robot with Camera + Joint Control")

    # Joint and gripper sliders
    joint_sliders = []
    with gr.Row():
        for i in range(4):
            joint_sliders.append(gr.Slider(-3.14, 3.14, value=0, label=f"Joint {i+1}"))
    with gr.Row():
        for i in range(4, 7):
            joint_sliders.append(gr.Slider(-3.14, 3.14, value=0, label=f"Joint {i+1}"))
        gripper = gr.Slider(0.0, 0.04, value=0.02, step=0.001, label="Gripper")

    # Compact camera + target controls
    with gr.Row():
        with gr.Column(scale=1):
            gr.Markdown("**Camera Position**", elem_id="camera-position-label")
            cam_x = gr.Slider(-3, 3, value=1.5, label="X")
            cam_y = gr.Slider(-3, 3, value=0.0, label="Y")
            cam_z = gr.Slider(-1, 3, value=1.0, label="Z")
        with gr.Column(scale=1):
            gr.Markdown("**Target Point**", elem_id="target-point-label")
            tgt_x = gr.Slider(-1, 1, value=0.0, label="X")
            tgt_y = gr.Slider(-1, 1, value=0.0, label="Y")
            tgt_z = gr.Slider(0, 2, value=0.5, label="Z")


    # Live image + output
    with gr.Row():
        img_output = gr.Image(type="filepath", label="Simulation View")
        text_output = gr.Textbox(label="Joint States", lines=10)

    # Live simulation update
    def live_update(*vals):
        joints = list(vals[:7])
        grip = vals[7]
        cam = [vals[8], vals[9], vals[10]]
        tgt = [vals[11], vals[12], vals[13]]
        return render_sim(joints, grip, cam, tgt)

    sliders = joint_sliders + [gripper, cam_x, cam_y, cam_z, tgt_x, tgt_y, tgt_z]
    for s in sliders:
        s.change(fn=live_update, inputs=sliders, outputs=[img_output, text_output])

    gr.Button("πŸ”„ Reset Robot").click(
        fn=lambda: render_sim([0]*7, 0.02, [1.5, 0, 1.0], [0, 0, 0.5]),
        inputs=[], outputs=[img_output, text_output]
    )

    # Move to angles box
    gr.Markdown("### ✍️ Move Robot to Custom Joint Angles")
    joint_input_box = gr.Textbox(label="Enter 7 Joint Angles (comma-separated)")
    gr.Button("▢️ Move to Angles").click(
        fn=lambda s, x, y, z, tx, ty, tz: move_to_input_angles(s, [x, y, z], [tx, ty, tz]),
        inputs=[joint_input_box, cam_x, cam_y, cam_z, tgt_x, tgt_y, tgt_z],
        outputs=[img_output, text_output]
    )

    # Pick and Place section
    gr.Markdown("### 🧾 Pick and Place Input (3 sets of joint angles)")

    with gr.Row():
        position_input = gr.Textbox(label="Object Position Angles")
        gr.Button("πŸ“‹ Copy").click(fn=copy_current_joint_angles, inputs=joint_sliders, outputs=position_input)

    with gr.Row():
        approach_input = gr.Textbox(label="Approach Angles")
        gr.Button("πŸ“‹ Copy").click(fn=copy_current_joint_angles, inputs=joint_sliders, outputs=approach_input)

    with gr.Row():
        place_input = gr.Textbox(label="Place Angles")
        gr.Button("πŸ“‹ Copy").click(fn=copy_current_joint_angles, inputs=joint_sliders, outputs=place_input)

    gr.Button("πŸ€– Perform Pick and Place").click(
        fn=lambda p, a, pl, x, y, z, tx, ty, tz: pick_and_place(p, a, pl, [x, y, z], [tx, ty, tz]),
        inputs=[position_input, approach_input, place_input, cam_x, cam_y, cam_z, tgt_x, tgt_y, tgt_z],
        outputs=[img_output, text_output]
    )

demo.launch(debug=True)