Pular para o conteúdo principal

Criando e Publicando Apps

Reachy Mini tem um ecossistema de apps baseado em Hugging Face Spaces. Você pode criar apps em Python, publicá-los, e qualquer proprietário de um Reachy Mini pode instalá-los com um clique a partir do painel.

Para um tutorial passo a passo com capturas de tela, veja o post no blog: Make and Publish Your Reachy Mini Apps.


Usando Agentes de IA

Se você usar um agente de codificação com IA (Claude Code, Cursor, Copilot, etc.), ele pode criar apps para você. Aponte-o para o arquivo AGENTS.md do projeto:

I'd like to create a Reachy Mini app. Start by reading https://github.com/pollen-robotics/reachy_mini/blob/main/AGENTS.md

O repositório inclui um diretório skills/ com guias detalhados que agentes de IA usam para criar apps corretamente:

SkillO que ele cobre
create-app.mdFluxo de criação de app e templates
ai-integration.mdCriação de apps com LLM
control-loops.mdApps reativos em tempo real (rastreamento, jogos)
motion-philosophy.mdEscolhendo entre goto_target e set_target
interaction-patterns.mdAntenas como botões, cabeça como controle
symbolic-motion.mdDefinindo movimento matematicamente (danças, ritmos)

Como os Apps Funcionam

O daemon do Reachy Mini gerencia todo o ciclo de vida do seu app:

  1. Você envia uma requisição de "start app" (a partir do painel ou da REST API).
  2. O daemon inicia seu app como um subprocesso Python (python -u -m your_app.main).
  3. Seu app recebe uma instância conectada de ReachyMini e um stop_event.
  4. Ao ser interrompido, o daemon envia SIGINT para o seu processo, o que dispara o desligamento gracioso.
  5. Depois que o app termina, o daemon retorna o robô para a posição padrão.

Restrições principais:

  • Apenas um app pode ser executado por vez.
  • Seu app roda dentro do subprocesso do daemon — ele não gerencia suas próprias conexões de hardware.
  • No robô Wireless, seu app roda em um ambiente virtual compartilhado em /venvs/apps_venv/.

Criando um App

Sempre use a ferramenta de CLI para criar apps — ela gera a estrutura correta, metadados e pontos de entrada:

# Install reachy-mini if not already done
uv pip install reachy-mini

# Create and publish in one step (recommended)
reachy-mini-app-assistant create my_app_name /path/to/destination --publish

# Or create locally first
reachy-mini-app-assistant create my_app_name /path/to/destination

Nunca crie pastas de app manualmente. O assistente cuida do boilerplate, tags do Hugging Face, pontos de entrada e da estrutura de pacote correta. A criação manual leva a problemas sutis que são difíceis de depurar.

Escolha um Template

TemplateComandoUse quando
Defaultreachy-mini-app-assistant create my_app .A maioria dos apps. Estrutura mínima funcional.
Conversationreachy-mini-app-assistant create --template conversation my_app .Integração com LLM, fala, fazer o robô falar. Inclui pipeline de áudio, ferramentas de LLM, fusão de movimento e toda a infraestrutura.

Estrutura Gerada

my_app/
├── index.html # Hugging Face Space landing page
├── style.css # Landing page styles
├── pyproject.toml # Package config with entry points
├── README.md # Must contain reachy_mini_python_app tag
└── my_app/
├── __init__.py
├── main.py # Your app logic
└── static/ # Optional web UI
├── index.html
├── style.css
└── main.js

O Contrato ReachyMiniApp

Seu app é uma classe que estende ReachyMiniApp e implementa um método run(). Aqui está a estrutura mínima:

import threading
import time

import numpy as np

from reachy_mini import ReachyMini, ReachyMiniApp
from reachy_mini.utils import create_head_pose


class MyApp(ReachyMiniApp):
def run(self, reachy_mini: ReachyMini, stop_event: threading.Event):
t0 = time.time()

while not stop_event.is_set():
t = time.time() - t0

# Move the head
yaw = 30.0 * np.sin(2.0 * np.pi * 0.2 * t)
head_pose = create_head_pose(yaw=yaw, degrees=True)

# Move the antennas
a = np.deg2rad(25.0 * np.sin(2.0 * np.pi * 0.5 * t))
antennas = np.array([a, -a])

reachy_mini.set_target(head=head_pose, antennas=antennas)
time.sleep(0.02)


if __name__ == "__main__":
app = MyApp()
try:
app.wrapped_run()
except KeyboardInterrupt:
app.stop()

Pontos principais

  • run(reachy_mini, stop_event): O único método que você deve implementar. A instância ReachyMini já está conectada e pronta. Consulte (poll) o stop_event no seu loop principal para sair de forma graciosa.
  • wrapped_run(): Chamado a partir do bloco __main__. Ele cuida de conectar ao robô, iniciar serviços opcionais e chamar seu método run().
  • stop(): Define o stop_event. O daemon chama isso via SIGINT ao interromper seu app.
  • Bloco __main__: Obrigatório. O daemon executa seu app como um módulo (python -m my_app.main), então esse bloco é o ponto de entrada real.

O Ponto de Entrada em pyproject.toml

O daemon descobre seu app por meio de um ponto de entrada padrão do Python. O assistente gera isso para você:

[project.entry-points."reachy_mini_apps"]
my_app = "my_app.main:MyApp"

O nome do grupo é reachy_mini_apps (com underscores). O valor aponta para sua classe (module.main:ClassName).

Qualquer dependência adicional para o seu projeto deve ser adicionada neste arquivo.


Opcional: Web UI para Seu App

Se você quiser uma página de configurações ou qualquer interface web para seu app, defina custom_app_url na sua classe:

class MyApp(ReachyMiniApp):
custom_app_url: str | None = "http://0.0.0.0:8042"

def run(self, reachy_mini: ReachyMini, stop_event: threading.Event):
# Define FastAPI routes on self.settings_app
@self.settings_app.post("/my_endpoint")
def my_endpoint():
return {"status": "ok"}

# Your main loop...

Quando custom_app_url é definido, o app inicia automaticamente um servidor web FastAPI que serve arquivos do diretório static/ dentro do seu pacote. O painel mostra um ícone de configurações para abrir essa UI. A página pode ser acessada em http://localhost:8042 com uma lite ou em http://reachy-mini.local:8042 com uma wireless.

Defina custom_app_url = None se seu app não precisar de uma Web UI.

Para um exemplo funcional com um toggle e reprodução de som, veja o template app.


Testando Seu App

1. Validar estrutura

reachy-mini-app-assistant check /path/to/my_app

Isso verifica se seu app tem a estrutura correta, pontos de entrada e metadados.

2. Executar diretamente

Você pode executar o main.py do seu app diretamente para iterar rapidamente (certifique-se de que o daemon esteja em execução):

python -m my_app.main

3. Testar pelo painel

Instale seu app localmente e teste-o pelo painel, como os usuários fariam:

# Install in development mode
uv pip install -e /path/to/my_app

# Start the daemon
reachy-mini-daemon # Lite
reachy-mini-daemon --sim # Simulation

Depois abra http://127.0.0.1:8000/ — seu app aparece na lista de instalados.


Publicando no Hugging Face

1. Fazer login no Hugging Face

uv pip install --upgrade huggingface_hub
hf auth login

Use um token com permissões de Write.

2. Publicar

Se você usou --publish ao criar o app, ele já é um Space do Hugging Face com um remoto Git. Basta fazer push:

git add . && git commit -m "my changes" && git push

Se você criou sem --publish, pode publicar depois:

reachy-mini-app-assistant publish /path/to/my_app

3. Descoberta

Para que seu app apareça na loja de apps do Reachy Mini, o README.md dele deve conter a tag reachy_mini_python_app no frontmatter YAML:

---
tags:
- reachy_mini_python_app
---

O assistente adiciona isso automaticamente. Se você criar o README manualmente, não se esqueça disso.


Instalando Apps

Pelo painel

Abra o painel do Reachy Mini e clique em Install em qualquer app da comunidade. Este é o jeito mais fácil.

Via REST API

# Install from Hugging Face
curl -X POST http://localhost:8000/api/apps/install \
-H "Content-Type: application/json" \
-d '{"url": "https://huggingface.co/spaces/<user>/<app_name>"}'

# Start an app
curl -X POST http://localhost:8000/api/apps/start-app/<app_name>

# Stop the current app
curl -X POST http://localhost:8000/api/apps/stop-current-app

# List installed apps
curl http://localhost:8000/api/apps/list

Substitua localhost por reachy-mini.local ou pelo endereço IP do robô para a versão Wireless.

Implantação offline / manual para uma unidade Wireless

Se você não tiver acesso à internet no robô (por exemplo, em uma conferência), pode instalar seu app diretamente:

# Copy and install your app on the robot
scp -r /path/to/my_app [email protected]:/tmp/my_app
ssh [email protected] "/venvs/apps_venv/bin/pip install /tmp/my_app"

Depois de atualizar o código manualmente, reinicie o daemon ou o app para que as alterações entrem em vigor.


Depurando Apps

Visualizando logs

Lite / Simulation

Se você executar o daemon em um terminal, os logs do app (stdout/stderr) aparecem diretamente ali.

reachy-mini-daemon          # Lite
reachy-mini-daemon --sim # Simulation
# App logs will print here
Wireless

A saída do app é capturada pelo daemon e fica disponível via journalctl:

ssh [email protected]

# Live logs
sudo journalctl -u reachy-mini-daemon -f

# Recent logs, filtered (daemon logs are noisy with HTTP access logs)
sudo journalctl -u reachy-mini-daemon --since '5 min ago' | grep -v "uvicorn\|GET \|POST "

Problemas comuns

ProblemaSolução
"An app is already running"Pare primeiro o app atual: curl -X POST http://localhost:8000/api/apps/stop-current-app
Daemon em um estado ruimReinicie-o: sudo systemctl restart reachy-mini-daemon (espere ~30s antes de iniciar um app)
App não detecta alterações no códigoReinicie o app. Se você fez o deploy manualmente, também limpe o bytecode: rm -rf __pycache__

Dica: registre tudo na inicialização

Uma prática útil de depuração é registrar sua configuração quando o app inicia:

import logging
import sys

logger = logging.getLogger(__name__)

def run(self, reachy_mini, stop_event):
logger.info("=" * 50)
logger.info("MY APP STARTING")
logger.info(f" Python: {sys.version}")
logger.info("=" * 50)
# ...

Configuração do App

O subprocesso do app herda as variáveis de ambiente do daemon. Não há nenhum mecanismo especial de injeção — seu app vê tudo o que o processo do daemon vê.

Se o seu app precisar de configuração em tempo de execução (chaves de API, URLs de servidor, etc.), a abordagem recomendada é usar a interface web do app. Defina custom_app_url na sua classe e adicione uma página de configurações onde os usuários possam inserir valores (chaves de API, endereços de servidor, etc.) diretamente pelo navegador. Esta é a opção mais amigável para o usuário e funciona em todas as plataformas. Veja Opcional: Interface Web para o Seu App acima para saber como configurar isso.

Outras abordagens:

  • Arquivo de configuração: Leia de um caminho conhecido (por exemplo, .env veja exemplo aqui).
  • Padrões fixos em código: Simples e fácil de depurar durante o desenvolvimento.

Usando Áudio no Seu App

Gravação de áudio, reprodução e detecção de direção de chegada funcionam da mesma forma dentro de um app e em um script independente — use diretamente os métodos do SDK (start_recording(), get_audio_sample(), push_audio_sample(), play_sound()).

Consulte os exemplos oficiais para ver código funcional:

Para detalhes sobre como os fluxos de áudio diferem entre Wireless e Lite, veja Arquitetura de Mídia.


Leituras adicionais

AppPadrões principaisLink
Conversation AppFerramentas de LLM, pipeline de áudio, laços de controleGitHub
MarionetteGravação de movimento, torque seguro, datasets do HFHF Space
RadioPadrão de interação com antenaHF Space
SimonPadrão sem GUI (antena para iniciar)HF Space
Hand TrackerLaço de controle em tempo real baseado em câmeraHF Space
Spaceship GameCabeça como joystick, botões da antenaHF Space
Loading Comments...