Reachy Mini guidance for real-time control loops, continuous set_target updates, and reactive motion architecture.
set_target() or continuous motion controlIf the app only needs choreographed, predetermined motions, use goto_target() instead (see reachy-mini-motion-philosophy.md).
One control loop, one place calling set_target(), running at fixed frequency (~100Hz).
import time
from reachy_mini import ReachyMini
with ReachyMini() as mini:
while not stop_event.is_set():
# Compute target pose (can change every tick!)
pose = compute_current_target_pose()
# Send it
mini.set_target(head=pose, antennas=antennas)
# Maintain frequency
time.sleep(0.01) # ~100Hz
Best example: ~/reachy_mini_resources/reachy_mini_conversation_app/src/reachy_mini_conversation_app/moves.py
If this folder doesn't exist, run
skills/reachy-mini-setup-environment.mdto clone reference apps.
This file demonstrates control with:
Uses time.monotonic() to measure elapsed time accurately:
set_target() from multiple threadsimport time
import threading
import numpy as np
from reachy_mini import ReachyMini
from reachy_mini.utils import create_head_pose
class MyController:
def __init__(self):
self.stop_event = threading.Event()
self.target_yaw = 0.0
self.target_pitch = 0.0
def control_loop(self, mini: ReachyMini):
"""Main control loop - only place that calls set_target."""
while not self.stop_event.is_set():
# Build pose from current targets
pose = create_head_pose(
yaw=self.target_yaw,
pitch=self.target_pitch,
degrees=True
)
# Send to robot
mini.set_target(head=pose)
# ~100Hz
time.sleep(0.01)
def update_target(self, yaw: float, pitch: float):
"""Called from other threads/callbacks to update targets."""
self.target_yaw = yaw
self.target_pitch = pitch
# Usage
controller = MyController()
with ReachyMini() as mini:
loop_thread = threading.Thread(target=controller.control_loop, args=(mini,))
loop_thread.start()
# Update targets from elsewhere (e.g., tracking callback)
controller.update_target(yaw=30, pitch=10)
# ... eventually
controller.stop_event.set()
loop_thread.join()
def compute_breathing_offset(t: float) -> float:
"""Subtle pitch oscillation for 'alive' feeling."""
return 2.0 * np.sin(2 * np.pi * 0.2 * t) # 0.2 Hz, 2 degree amplitude
# In control loop:
t = time.monotonic()
breathing = compute_breathing_offset(t)
pose = create_head_pose(yaw=target_yaw, pitch=target_pitch + breathing, degrees=True)
| Frequency | Use case |
|---|---|
| 100 Hz | Real-time tracking, games |
| 50 Hz | Most interactive apps |
| 30 Hz | Minimum for smooth motion |
| < 30 Hz | Might look jerky |