Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import numpy as np | |
| from robot import LiveReachyMini | |
| import logging | |
| logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s") | |
| import time | |
| # keep one MeshCat session alive | |
| robot = LiveReachyMini() | |
| css = """ | |
| .control-panel .gr-slider { | |
| margin-top: 4px !important; | |
| margin-bottom: 4px !important; | |
| } | |
| .control-panel .gr-form { | |
| gap: 6px !important; /* reduce vertical gaps */ | |
| } | |
| .pending { | |
| opacity: 1.0; | |
| } | |
| .prose{ | |
| color: black !important; | |
| fornt-weight: bold !important; | |
| } | |
| .label-override { | |
| font-weight: 200 !important; | |
| font-size: 1.3em !important; | |
| color: black !important; | |
| }s | |
| """ | |
| with gr.Blocks(css=css, title="Reachy Mini - Interactive Viewer") as demo: | |
| gr.Markdown("# 🤖 Reachy Mini - Interactive Viewer \n" | |
| "🕹️ Move the sliders to control the robot's head and antennas.") | |
| with gr.Row(equal_height=True): | |
| # LEFT: robot view + button | |
| with gr.Column(scale=1, min_width=400): | |
| viewer = gr.HTML(robot.iframe()) | |
| # RIGHT: compact control panel | |
| with gr.Column(scale=1, min_width=450, elem_classes="control-panel"): | |
| with gr.Tab("Body"): | |
| body_yaw = gr.Slider( | |
| -3.14, 3.14, value=0.0, step=0.01, | |
| info="<b class='label-override'>Body Yaw</b>",container=False | |
| ) | |
| with gr.Tab("Head"): | |
| # angles in one block | |
| gr.Markdown("### Head orientation") | |
| with gr.Row(): | |
| head_roll = gr.Slider(-1.57, 1.57, 0.0, 0.01, | |
| info="<b class='label-override'>Roll</b>", container=False) | |
| with gr.Row(): | |
| head_pitch = gr.Slider(-1.57, 1.57, 0.0, 0.01, | |
| info="<b class='label-override'>Pitch</b>", container=False) | |
| with gr.Row(): | |
| head_yaw = gr.Slider(-3.14, 3.14, 0.0, 0.01, | |
| info="<b class='label-override'>Yaw</b>", container=False) | |
| gr.Markdown("### Head position") | |
| head_x = gr.Slider(-0.1, 0.1, 0.0, 0.001, | |
| info="<b class='label-override'>X</b>", container=False) | |
| head_y = gr.Slider(-0.1, 0.1, 0.0, 0.001, | |
| info="<b class='label-override'>Y</b>", container=False) | |
| head_z = gr.Slider(-0.1, 0.1, 0.0, 0.001, | |
| info="<b class='label-override'>Z</b>", container=False) | |
| with gr.Tab("Antennas"): | |
| left_ant = gr.Slider(-3.14, 3.14, 0.0, 0.01, | |
| info ="<b class='label-override'>Left Antenna</b>", container=False) | |
| right_ant = gr.Slider(-3.14, 3.14, 0.0, 0.01, | |
| info ="<b class='label-override'>Right Antenna</b>", container=False) | |
| sliders = [ | |
| body_yaw, | |
| head_roll, head_pitch, head_yaw, | |
| head_x, head_y, head_z, | |
| left_ant, right_ant | |
| ] | |
| # ---------- Callbacks ---------- | |
| last_call_time = time.time() | |
| def on_sliders(*vals): | |
| global last_call_time | |
| logging.debug("Time since last on_sliders call: {:.2f} ms".format(((time.time() -last_call_time) % 1e6)*1000)) | |
| last_call_time = time.time() | |
| """Apply first k slider values to robot joints.""" | |
| robot.set_target(vals) | |
| # viewer iframe persists; nothing to update there | |
| dt = time.time() - last_call_time | |
| logging.debug(f"on_sliders total took {dt*1000:.2f} ms") | |
| # Wire all sliders to the same handler (fixed signature via *vals) | |
| for s in sliders: | |
| s.change(on_sliders, inputs=sliders, outputs=None, queue=False, stream_every=0.01) | |
| # On app load, configure sliders for the initial robot | |
| def _initial(): | |
| return [robot.iframe()] + [gr.update() for _ in sliders] | |
| demo.load(_initial, outputs=[viewer] + sliders, queue=False) | |
| if __name__ == "__main__": | |
| demo.launch(server_name="0.0.0.0", server_port=8501) | |