File size: 4,351 Bytes
79ee8ac
 
 
f22d17e
79ee8ac
f22d17e
 
79ee8ac
f22d17e
 
7a6243f
79ee8ac
f22d17e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79ee8ac
 
7a6243f
 
79ee8ac
 
7a6243f
79ee8ac
 
 
 
f22d17e
79ee8ac
f22d17e
 
 
 
 
 
 
 
 
 
79ee8ac
 
f22d17e
 
 
 
 
519b467
79ee8ac
f22d17e
79ee8ac
519b467
79ee8ac
 
f22d17e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79ee8ac
 
 
 
f22d17e
79ee8ac
 
 
f22d17e
 
 
 
 
 
 
 
 
79ee8ac
f22d17e
79ee8ac
 
 
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
import gradio as gr
import numpy as np
from robots import LiveRobot
import example_robot_data as erd

#ROBOTS = ["erd", "panda", "ur10" , "double_pendulum", "anymal", "talos"]
ROBOTS = [r for r in erd.ROBOTS]


# keep one MeshCat session alive
robot = LiveRobot("talos")

# how many sliders we allow at most (raise if you have bigger robots)
MAX_SLIDERS = 32

def _visible_dofs():
    """Number of actuated DoFs for current robot."""
    return len(robot.idxs)

def _slider_updates_for_current_robot():
    """Return a list of gr.update() objects of length MAX_SLIDERS
    to (re)configure all sliders for the current robot."""
    updates = []
    k = _visible_dofs()
    for i in range(MAX_SLIDERS):
        if i < k:
            label = robot.labels[i]
            lo, hi = robot.bounds[i]
            if lo==hi:
                lo = -np.pi/2
                hi = np.pi/2
            qi = robot.idxs[i]
            val = float((lo+hi)/2)
            updates.append(
                gr.update(
                    minimum=float(lo),
                    maximum=float(hi),
                    value=val,
                    label=label,
                    step=0.01,
                    visible=True,
                )
            )
        else:
            updates.append(gr.update(visible=False))
    return updates

with gr.Blocks(title="Pinocchio + MeshCat — Live") as demo:
    gr.Markdown("### 🤖 Pinocchio + MeshCat — Live Viewer\n"
                "Sliders update the robot in real time.\n"
                "Select a robot from the dropdown to load it.")

    with gr.Row():
        robot_dd = gr.Dropdown(ROBOTS, value="talos", label="Robot")
        neutral_btn = gr.Button("Neutral")

    viewer = gr.HTML(robot.iframe())

    # Pre-create a fixed pool of sliders (initially hidden)
    sliders = []
    with gr.Group():
        for _ in range(MAX_SLIDERS):
            sliders.append(
                gr.Slider(
                    minimum=-3.14, maximum=3.14, value=0.0,
                    step=0.01, label="joint", visible=False
                )
            )

    # ---------- Callbacks ----------

    def on_sliders(*vals):
        """Apply first k slider values to robot joints."""
        k = _visible_dofs()
        # only use the first k values (ignore hidden/unused sliders)
        robot.set_joints(vals[:k])
        # viewer iframe persists; nothing to update there
        #return gr.update()

    # Wire all sliders to the same handler (fixed signature via *vals)
    for s in sliders:
        s.change(on_sliders, inputs=sliders, outputs=None, queue=True)

    def on_neutral():
        """Reset robot to neutral and reflect in visible sliders."""
        values = robot.neutral()  # returns values for actuated DoFs, length k
        bounds = robot.bounds
        
        for i, v in enumerate(values):
            lo, hi = bounds[i]
            if not np.isfinite(lo): lo = -3.14
            if not np.isfinite(hi): hi =  3.14
            
            # clamp neutral value to slider range
            if v < lo: v = lo
            if v > hi: v = hi
            
            values[i] = v
        k = len(values)
        # viewer stays the same + slider value updates for first k; hide the rest
        updates = [gr.update()]  # for viewer
        for i in range(MAX_SLIDERS):
            if i < k:
                updates.append(gr.update(value=float(values[i]), visible=True))
            else:
                updates.append(gr.update(visible=False))
        return updates

    neutral_btn.click(on_neutral, outputs=[viewer] + sliders, queue=False)

    def on_change_robot(name):
        """Rebuild slider labels/ranges/values/visibility to match selected robot."""
        global robot
        robot = LiveRobot(name)
        viewer_html = robot.iframe()
        # 1) update viewer HTML
        # 2) update ALL sliders to reflect new robot
        return [viewer_html] + _slider_updates_for_current_robot()

    robot_dd.change(on_change_robot, inputs=robot_dd, outputs=[viewer] + sliders, queue=True)

    # On app load, configure sliders for the initial robot
    def _initial():
        return [robot.iframe()] + _slider_updates_for_current_robot()

    demo.load(_initial, outputs=[viewer] + sliders, queue=False)

if __name__ == "__main__":
    demo.launch(server_name="0.0.0.0", server_port=8501)