askuric's picture
askuric HF Staff
update speed
ca40f21
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)