Spaces:
Running
Running
| 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) | |