Programming the Reachy Mini robot opens up a world of possibilities for desktop robotics applications. Whether you're a student learning robotics, a researcher developing new applications, or a developer creating commercial solutions, mastering the Reachy Mini Python SDK is essential for unlocking the full potential of this remarkable humanoid robot.
This comprehensive guide will take you from basic setup to advanced programming techniques, providing practical examples and best practices developed through extensive real-world experience with Reachy Mini systems.
What You'll Learn
- Complete Python SDK installation and setup
- Basic movement control and motor management
- Advanced gesture programming and coordination
- Camera integration and computer vision
- Real-time interaction and response systems
- Error handling and debugging techniques
Environment Setup and Installation
Prerequisites
Before diving into Reachy Mini programming, ensure you have the following prerequisites:
- Python 3.8 or higher: Reachy Mini SDK requires modern Python features
- Stable network connection: For remote robot control and updates
- Development environment: VS Code, PyCharm, or your preferred Python IDE
- Basic Python knowledge: Understanding of OOP concepts and async programming
SDK Installation
Install the Reachy Mini Python SDK using pip. The SDK provides comprehensive tools for robot control, monitoring, and development:
# Install the Reachy Mini SDK
pip install reachy-mini-sdk
# Install additional development dependencies
pip install opencv-python numpy matplotlib jupyter
# Verify installation
python -c "import reachy_mini; print('SDK installed successfully')"
Robot Connection Setup
Establishing a reliable connection to your Reachy Mini is crucial for development. The SDK supports both local and remote connections:
from reachy_mini import ReachyMini
# Connect to local robot (USB/Ethernet)
robot = ReachyMini(host='localhost')
# Connect to remote robot (Wi-Fi)
robot = ReachyMini(host='192.168.1.100')
# Verify connection
if robot.is_connected():
print("Successfully connected to Reachy Mini")
print(f"Robot status: {robot.get_status()}")
else:
print("Connection failed - check network and robot status")
Basic Programming Concepts
Understanding the Robot Structure
Reachy Mini's programming model is based on a hierarchical structure of joints and actuators. Understanding this architecture is fundamental to effective programming:
# Explore robot structure
robot = ReachyMini()
# Access individual joints
left_arm = robot.left_arm
right_arm = robot.right_arm
head = robot.head
# List all available joints
print("Available joints:")
for joint_name in robot.joints:
joint = getattr(robot, joint_name)
print(f" {joint_name}: {joint.present_position}°")
# Check joint limits and capabilities
for joint in robot.joints.values():
print(f"{joint.name}: Range {joint.angle_limit} degrees")
Basic Movement Control
Start with simple movements to understand joint control and timing. The SDK provides both direct angle control and higher-level gesture functions:
import time
# Basic joint movement
robot.right_arm.shoulder_pitch.goal_position = 45 # degrees
robot.right_arm.shoulder_roll.goal_position = -30
robot.right_arm.elbow_pitch.goal_position = -90
# Wait for movement completion
time.sleep(2)
# Check if movement is complete
while robot.right_arm.is_moving():
time.sleep(0.1)
print("Movement completed")
# Return to rest position
robot.goto_rest_position()
time.sleep(3)
Coordinated Movements
Create smooth, coordinated movements by synchronizing multiple joints. This is essential for natural-looking gestures:
def wave_gesture():
"""Execute a natural waving gesture"""
# Prepare arm position
robot.right_arm.shoulder_pitch.goal_position = 0
robot.right_arm.shoulder_roll.goal_position = -45
robot.right_arm.elbow_pitch.goal_position = -45
time.sleep(1.5) # Allow positioning
# Wave motion
for i in range(3):
robot.right_arm.shoulder_roll.goal_position = -20
time.sleep(0.5)
robot.right_arm.shoulder_roll.goal_position = -45
time.sleep(0.5)
# Return to rest
robot.goto_rest_position()
# Execute the gesture
wave_gesture()
Advanced Programming Techniques
Asynchronous Programming
For responsive applications, use asynchronous programming to handle multiple operations simultaneously:
import asyncio
class ReachyMiniController:
def __init__(self):
self.robot = ReachyMini()
self.is_running = True
async def monitor_status(self):
"""Continuously monitor robot status"""
while self.is_running:
status = self.robot.get_status()
if status['battery_level'] < 20:
await self.handle_low_battery()
await asyncio.sleep(1)
async def handle_interactions(self):
"""Handle user interactions and commands"""
while self.is_running:
# Check for voice commands, gestures, etc.
command = await self.get_user_command()
if command:
await self.execute_command(command)
await asyncio.sleep(0.1)
async def main_loop(self):
"""Main application loop"""
tasks = [
self.monitor_status(),
self.handle_interactions(),
]
await asyncio.gather(*tasks)
# Run the controller
controller = ReachyMiniController()
asyncio.run(controller.main_loop())
Computer Vision Integration
Integrate Reachy Mini's cameras with computer vision for intelligent interactions:
import cv2
import numpy as np
class VisionController:
def __init__(self, robot):
self.robot = robot
self.face_cascade = cv2.CascadeClassifier(
cv2.data.haarcascades + 'haarcascade_frontalface_default.xml'
)
def detect_faces(self, frame):
"""Detect faces in camera frame"""
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = self.face_cascade.detectMultiScale(
gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30)
)
return faces
def track_face(self):
"""Track faces and orient robot accordingly"""
cap = cv2.VideoCapture(0) # Robot's camera
while True:
ret, frame = cap.read()
if not ret:
break
faces = self.detect_faces(frame)
if len(faces) > 0:
# Get largest face
largest_face = max(faces, key=lambda x: x[2] * x[3])
x, y, w, h = largest_face
# Calculate face center
face_center_x = x + w // 2
frame_center_x = frame.shape[1] // 2
# Orient head towards face
angle_offset = (face_center_x - frame_center_x) * 0.1
current_angle = self.robot.head.neck_roll.present_position
new_angle = current_angle + angle_offset
# Apply limits
new_angle = max(min(new_angle, 45), -45)
self.robot.head.neck_roll.goal_position = new_angle
# Draw face rectangle
cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 2)
cv2.imshow('Reachy Vision', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
# Use vision controller
vision = VisionController(robot)
vision.track_face()
Gesture Library Development
Create a reusable library of gestures for your applications:
class GestureLibrary:
def __init__(self, robot):
self.robot = robot
self.gestures = {}
def record_gesture(self, name, duration=5):
"""Record a gesture by manually moving the robot"""
print(f"Recording gesture '{name}' - move the robot manually")
print("Recording will start in 3 seconds...")
time.sleep(3)
positions = []
start_time = time.time()
while time.time() - start_time < duration:
# Record all joint positions
current_positions = {}
for joint_name, joint in self.robot.joints.items():
current_positions[joint_name] = joint.present_position
positions.append({
'timestamp': time.time() - start_time,
'positions': current_positions
})
time.sleep(0.1)
self.gestures[name] = positions
print(f"Gesture '{name}' recorded successfully")
def play_gesture(self, name, speed_factor=1.0):
"""Play back a recorded gesture"""
if name not in self.gestures:
print(f"Gesture '{name}' not found")
return
gesture = self.gestures[name]
start_time = time.time()
for frame in gesture:
# Calculate when to execute this frame
target_time = frame['timestamp'] / speed_factor
while time.time() - start_time < target_time:
time.sleep(0.01)
# Set all joint positions
for joint_name, position in frame['positions'].items():
if hasattr(self.robot, joint_name):
getattr(self.robot, joint_name).goal_position = position
def save_gestures(self, filename):
"""Save gesture library to file"""
import json
with open(filename, 'w') as f:
json.dump(self.gestures, f, indent=2)
def load_gestures(self, filename):
"""Load gesture library from file"""
import json
with open(filename, 'r') as f:
self.gestures = json.load(f)
# Use gesture library
gestures = GestureLibrary(robot)
gestures.record_gesture("hello_wave", duration=3)
gestures.play_gesture("hello_wave")
gestures.save_gestures("my_gestures.json")
Error Handling and Debugging
Common Error Scenarios
Robust applications require comprehensive error handling for various failure modes:
import logging
# Set up logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class RobustRobotController:
def __init__(self):
self.robot = None
self.max_retries = 3
def connect_with_retry(self, host='localhost'):
"""Connect to robot with automatic retry"""
for attempt in range(self.max_retries):
try:
self.robot = ReachyMini(host=host)
if self.robot.is_connected():
logger.info("Successfully connected to Reachy Mini")
return True
except Exception as e:
logger.warning(f"Connection attempt {attempt + 1} failed: {e}")
time.sleep(2)
logger.error("Failed to connect after all retries")
return False
def safe_move_joint(self, joint, target_angle, timeout=5):
"""Safely move joint with error checking"""
try:
# Check if joint exists and is within limits
if not hasattr(self.robot, joint):
raise ValueError(f"Joint '{joint}' not found")
joint_obj = getattr(self.robot, joint)
# Check angle limits
min_angle, max_angle = joint_obj.angle_limit
if not (min_angle <= target_angle <= max_angle):
raise ValueError(f"Angle {target_angle} outside limits [{min_angle}, {max_angle}]")
# Execute movement
joint_obj.goal_position = target_angle
# Wait for completion with timeout
start_time = time.time()
while joint_obj.is_moving():
if time.time() - start_time > timeout:
raise TimeoutError(f"Joint movement timeout after {timeout}s")
time.sleep(0.1)
return True
except Exception as e:
logger.error(f"Failed to move joint {joint}: {e}")
return False
def emergency_stop(self):
"""Emergency stop all movements"""
try:
for joint in self.robot.joints.values():
joint.compliant = True # Make joints soft
logger.info("Emergency stop executed")
except Exception as e:
logger.error(f"Emergency stop failed: {e}")
# Usage example
controller = RobustRobotController()
if controller.connect_with_retry():
success = controller.safe_move_joint('right_arm.shoulder_pitch', 45)
if not success:
controller.emergency_stop()
Performance Optimization
Efficient Communication
Optimize communication with the robot for smooth, responsive applications:
class OptimizedController:
def __init__(self, robot):
self.robot = robot
self.update_rate = 50 # Hz
self.last_positions = {}
def batch_joint_updates(self, joint_targets):
"""Update multiple joints efficiently"""
# Group updates to minimize communication
updates = {}
for joint_name, target in joint_targets.items():
if joint_name in self.last_positions:
# Only update if position changed significantly
if abs(self.last_positions[joint_name] - target) > 0.5:
updates[joint_name] = target
else:
updates[joint_name] = target
# Apply all updates at once
for joint_name, target in updates.items():
getattr(self.robot, joint_name).goal_position = target
self.last_positions[joint_name] = target
def smooth_interpolation(self, start_pos, end_pos, duration, steps=50):
"""Create smooth movement interpolation"""
positions = []
for i in range(steps + 1):
t = i / steps
# Use cubic interpolation for smoother motion
t_smooth = 3 * t**2 - 2 * t**3
frame_positions = {}
for joint_name in start_pos:
start_val = start_pos[joint_name]
end_val = end_pos[joint_name]
interpolated = start_val + (end_val - start_val) * t_smooth
frame_positions[joint_name] = interpolated
positions.append(frame_positions)
return positions
# Create smooth gesture
optimizer = OptimizedController(robot)
start = {'right_arm.shoulder_pitch': 0, 'right_arm.elbow_pitch': 0}
end = {'right_arm.shoulder_pitch': 45, 'right_arm.elbow_pitch': -90}
smooth_path = optimizer.smooth_interpolation(start, end, duration=2)
for positions in smooth_path:
optimizer.batch_joint_updates(positions)
time.sleep(0.04) # 25 FPS
Real-world Application Examples
Interactive Assistant
Build an interactive assistant that responds to voice commands and visual cues:
import speech_recognition as sr
import pyttsx3
class InteractiveAssistant:
def __init__(self):
self.robot = ReachyMini()
self.speech_engine = pyttsx3.init()
self.recognizer = sr.Recognizer()
self.microphone = sr.Microphone()
# Calibrate microphone
with self.microphone as source:
self.recognizer.adjust_for_ambient_noise(source)
def speak(self, text):
"""Make robot speak and gesture"""
self.speech_engine.say(text)
# Add speaking gesture
self.robot.head.neck_pitch.goal_position = 10
self.speech_engine.runAndWait()
self.robot.head.neck_pitch.goal_position = 0
def listen_for_command(self):
"""Listen for voice commands"""
try:
with self.microphone as source:
print("Listening...")
audio = self.recognizer.listen(source, timeout=5)
command = self.recognizer.recognize_google(audio).lower()
print(f"Heard: {command}")
return command
except sr.UnknownValueError:
return None
except sr.RequestError:
print("Speech recognition service unavailable")
return None
def process_command(self, command):
"""Process and respond to commands"""
if "hello" in command:
self.speak("Hello! Nice to meet you!")
self.wave_gesture()
elif "time" in command:
import datetime
current_time = datetime.datetime.now().strftime("%I:%M %p")
self.speak(f"The current time is {current_time}")
elif "dance" in command:
self.speak("Let me show you my moves!")
self.dance_routine()
elif "goodbye" in command:
self.speak("Goodbye! Have a great day!")
self.wave_gesture()
return False
else:
self.speak("I didn't understand that command")
return True
def run(self):
"""Main assistant loop"""
self.speak("Hello! I'm Reachy Mini. How can I help you today?")
while True:
command = self.listen_for_command()
if command:
continue_running = self.process_command(command)
if not continue_running:
break
time.sleep(0.1)
# Run the assistant
assistant = InteractiveAssistant()
assistant.run()
Best Practices and Tips
Safety First
- Always implement emergency stop functionality
- Check joint limits before movements
- Monitor battery levels and temperature
- Use compliant mode when appropriate
Performance
- Batch multiple joint updates together
- Use asynchronous programming for responsiveness
- Implement proper error handling and retries
- Cache frequently accessed data
User Experience
- Create smooth, natural-looking movements
- Provide feedback for long operations
- Implement graceful degradation for failures
- Design intuitive interaction patterns
Development
- Use version control for your robot programs
- Document your gesture libraries
- Create modular, reusable components
- Test thoroughly before deployment
Conclusion and Next Steps
Mastering Reachy Mini programming opens up unlimited possibilities for desktop robotics applications. From simple movements to complex interactive systems, the Python SDK provides the tools needed to bring your robotic visions to life.
Continue your learning journey by:
- Experimenting with the provided code examples
- Building your own gesture library
- Integrating additional sensors and capabilities
- Contributing to the open-source Reachy Mini community
- Exploring advanced AI integration possibilities
Remember that great robotics programming combines technical skill with creativity and user-centered design. Focus on creating experiences that are not just technically impressive, but genuinely useful and engaging for your users.
Ready to Start Programming?
Download the complete code examples and start building your own Reachy Mini applications today.