LeRobot documentation

Telefone

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v0.6.1).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Telefone

Use seu celular (iOS ou Android) para controlar seu robô.

Neste guia, você aprenderá:

  • Como conectar um celular iOS/Android
  • Como a pose do telefone é mapeada para os alvos do efetuor final (EE) do robô
  • Como ajustar limites de segurança, controle do garfo e configurações de IK

Para usar o telefone para controlar seu robô, instale as dependências relevantes com:

pip install 'lerobot[phone,kinematics,feetech,core_scripts]'

kinematics fornece a cinemática inversa usada nos exemplos, feetech os motores SO-100/SO-101 e core_scripts as ferramentas de gravação e visualização.

Comece

Plataformas suportadas

  • iOS: usa o aplicativo HEBI Mobile I/O (pose ARKit + botões). Baixe o aplicativo primeiro, abra-o e os exemplos o descobrirão na sua rede e transmitirão a pose do celular e as entradas.
  • Android: usa o pacote teleop (WebXR). Ao iniciar o processo Python, ele imprime uma URL local. Abra o link no seu celular, toque em Start e, em seguida, use Move para transmitir a pose.

Links:

Orientação do telefone e controles

  • Orientação: segure o celular com a tela voltada para cima e a borda superior apontando na mesma direção do garfo do robô. Isso garante que a calibração alinhe o referencial do celular com o referencial do robô, para que o movimento pareça natural. Veja a imagem abaixo como referência.
  • Ativar/desativar — este é um interruptor de segurança, você precisa mantê-lo pressionado durante todo o movimento:
    • iOS: Segure B1 para mover o robô e solte para congelar o braço na posição em que ele estiver. Cada pressionamento reancora o celular à pose atual do braço, permitindo que você solte, leve a mão de volta para uma posição confortável, pressione novamente e continue — o robô não dá um salto.
    • Android: O mesmo com o botão Move na página WebXR.
  • Controle do garfo (funciona independentemente de o botão de ativação estar pressionado):
    • iOS: O controle deslizante analógico A3 controla a garra como uma entrada de velocidade — empurre para cima para abrir, puxe para baixo para fechar e solte no centro para manter.
    • Android: Os botões A e B funcionam como incremento/decremento (A abre, B fecha). Você pode ajustar a velocidade na etapa GripperVelocityToJoint.
  • Grip: segure o telefone com as duas mãos, um polegar no botão de ativação (B1) e o outro no controle deslizante do garra (A3), para que você possa controlar o braço e a garra ao mesmo tempo sem mudar a pegada. Mantenha o telefone plano enquanto faz isso — sua posição é o comando, então mudar a pegada no meio do movimento desloca o robô.
  • Pose inicial do robô: teleoperate.py move o braço para sua pose de retorno na inicialização (antes da calibração do telefone) e, ao pressionar Ctrl+C, o devolve à posição em que estava quando o script começou. Os comandos de retorno mandam cada junta do corpo para o valor de meia-volta centralizado por set_half_turn_homings() durante a calibração — a pose mantida no diagrama de calibração —, enquanto a garra é deixada onde está, para que o retorno nunca a feche sobre algo. Isso é importante porque os alvos são resolvidos com IK a partir da posição em que o braço está quando você pressiona o botão de habilitação — um braço dobrado ou totalmente esticado tem pouco espaço restante e atinge seus limites de junta. Os outros scripts de exemplo (record.py, evaluate.py, replay.py) não fazem o retorno do braço, então posicione-o lá você mesmo antes de iniciá-los.
Phone teleop orientation

Etapa 1: Escolha a plataforma

Modifique os exemplos para usar PhoneOS.IOS ou PhoneOS.ANDROID em PhoneConfig. A API é idêntica entre as plataformas, apenas a fonte de entrada difere. Todos os exemplos estão em examples/phone_to_so100/: teleoperate.py, record.py, replay.py, evaluate.py e rollout.py.

Exemplo de teleoperação:

from lerobot.teleoperators.phone import Phone, PhoneConfig
from lerobot.teleoperators.phone.config_phone import PhoneOS

teleop_config = PhoneConfig(phone_os=PhoneOS.IOS)  # or PhoneOS.ANDROID
teleop_device = Phone(teleop_config)

Etapa 2: Conectar e calibrar

Quando Phone(teleop_config) é criado e connect() é chamado, a calibração é solicitada automaticamente. Segure o celular na orientação descrita acima e, em seguida:

  • iOS: pressione e segure B1 para capturar a pose de referência.
  • Android: pressione o botão Move na página WebXR para capturar a pose de referência.

Por que calibrar? Capturamos a pose atual para que as poses subsequentes sejam expressas em um referencial alinhado ao robô. Quando você pressionar o botão novamente para habilitar o controle, a posição será recapturada para evitar deriva caso o celular seja reposicionado enquanto o controle estava desabilitado.

Etapa 3: Executar um exemplo

Execute um dos scripts de exemplo para teleoperar, gravar um conjunto de dados, reproduzir um conjunto de dados ou avaliar uma política.

Todos os scripts pressupõem que você configurou e calibrou seu robô (por exemplo, um seguidor SO-100).

Você deve fornecer o URDF do robô. Cada exemplo resolve a cinemática inversa, que requer um modelo cinemático do braço, e o URDF não é distribuído com o LeRobot.

Para o SO-100/SO-101 usado neste tutorial, copie a pasta SO101 do repositório SO-ARM100 para examples/phone_to_so100/, para que o arquivo fique em examples/phone_to_so100/SO101/so101_new_calib.urdf, estando no repositório LeRobot:

git clone --depth 1 https://github.com/TheRobotStudio/SO-ARM100.git /tmp/SO-ARM100
cp -r /tmp/SO-ARM100/Simulation/SO101 examples/phone_to_so100/SO101

Aponte os scripts para um arquivo diferente com --urdf se você o armazenar em outro local, ou se estiver controlando outro braço.

  • Execute este exemplo para teleoperar, passando a porta serial do seu braço seguidor (encontre-a com lerobot-find-port):

    cd examples/phone_to_so100
    python teleoperate.py --port /dev/tty.usbmodem5A460814411

    --id seleciona qual calibração armazenada usar, e --urdf aponta para o URDF acima.

Após executar o exemplo:

  • Android: após iniciar o script, abra a URL local impressa no seu celular, toque em Start e, em seguida, pressione e segure Move.
  • iOS: abra primeiro o HEBI Mobile I/O; mantenha B1 pressionado para mover o robô. A3 controla o garra.

Além disso, você pode personalizar o mapeamento ou os limites de segurança editando as etapas do processador mostradas nos exemplos. Você também pode remapear as entradas (por exemplo, usar uma entrada analógica diferente) ou adaptar o pipeline para outros robôs (por exemplo, LeKiwi) modificando as etapas de entrada e cinemática. Mais sobre isso no guia Processadores para Robôs e Teleoperadores.

  • Execute este exemplo para gravar um conjunto de dados, que salva observações e ações absolutas do efetuador final:

    cd examples/phone_to_so100
    python record.py
  • Execute este exemplo para reproduzir episódios gravados:

    cd examples/phone_to_so100
    python replay.py
  • Execute este exemplo para avaliar uma política pré-treinada:

    cd examples/phone_to_so100
    python evaluate.py

Etapas e opções importantes do pipeline

  • A cinemática é utilizada em múltiplas etapas. Utilizamos o Placo, que é um wrapper em torno do Pinocchio para lidar com a nossa cinemática. Construímos o objeto de cinemática passando o URDF do robô e o frame de destino. Definimos target_frame_name como o frame do gripper.

    kinematics_solver = RobotKinematics(
      urdf_path="./SO101/so101_new_calib.urdf",
      target_frame_name="gripper_frame_link",
      joint_names=list(robot.bus.motors.keys()),
    )
    
  • A etapa MapPhoneActionToRobotAction converte a pose calibrada do telefone e as entradas em deltas de destino e comandos de garra; abaixo é mostrado o que a etapa produz.

    action["enabled"] = enabled
    action["target_x"] = pos[1] if enabled else 0.0
    action["target_y"] = -pos[0] if enabled else 0.0
    action["target_z"] = pos[2] if enabled else 0.0
    action["target_wx"] = rotvec[1] if enabled else 0.0
    action["target_wy"] = -rotvec[0] if enabled else 0.0
    action["target_wz"] = rotvec[2] if enabled else 0.0
    action["gripper_vel"] = gripper_vel  # Still send gripper action when disabled
  • A etapa EEReferenceAndDelta converte os deltas do alvo em uma pose absoluta desejada do EE, armazenando uma referência na ativação; os end_effector_step_sizes são os tamanhos de passo para a pose do EE e podem ser modificados para alterar a velocidade do movimento.

    EEReferenceAndDelta(
        kinematics=kinematics_solver,
        end_effector_step_sizes={"x": 0.5, "y": 0.5, "z": 0.5},
        motor_names=list(robot.bus.motors.keys()),
        use_latched_reference=True,
    ),
  • A etapa EEBoundsAndSafety limita o movimento do EE a um espaço de trabalho e verifica saltos grandes na etapa do EE para garantir a segurança. Os end_effector_bounds são os limites para a pose do EE e podem ser modificados para alterar o espaço de trabalho. Os max_ee_step_m são os limites de etapa para a pose do EE e podem ser modificados para alterar os limites de segurança.

    EEBoundsAndSafety(
        end_effector_bounds={"min": [-1.0, -1.0, -1.0], "max": [1.0, 1.0, 1.0]},
        max_ee_step_m=0.10,
    )
  • A etapa GripperVelocityToJoint converte uma entrada de garra semelhante a velocidade em posição absoluta da garra usando o estado medido atual. O speed_factor é o fator pelo qual a velocidade é multiplicada.

    GripperVelocityToJoint(speed_factor=20.0)

Diferentes estimativas iniciais de IK

Utilizamos diferentes estimativas iniciais de IK nas etapas cinemáticas. Como estimativa inicial, são utilizados as juntas medidas atuais ou a solução de IK anterior.

  • Loop fechado (usado em gravação/avaliação): define initial_guess_current_joints=True para que o IK comece das juntas medidas em cada quadro.

    InverseKinematicsEEToJoints(
        kinematics=kinematics_solver,
        motor_names=list(robot.bus.motors.keys()),
        initial_guess_current_joints=True,  # closed loop
    )
  • Loop aberto (usado em replay): define initial_guess_current_joints=False para que a IK continue a partir da solução de IK anterior, em vez do estado medido. Isso preserva a estabilidade da ação quando fazemos replay sem feedback.

    InverseKinematicsEEToJoints(
        kinematics=kinematics_solver,
        motor_names=list(robot.bus.motors.keys()),
        initial_guess_current_joints=False,  # open loop
    )

Etapas do Pipeline explicadas

  • MapPhoneActionToRobotAction: converte a pose calibrada do telefone e as entradas em deltas de destino e um comando de garra. O movimento é controlado por um sinal de habilitação (B1 no iOS, Move no Android).
  • EEReferenceAndDelta: fixa uma pose de referência do EE ao ser habilitado e a combina com os deltas do alvo para produzir uma pose absoluta desejada do EE a cada quadro. Quando desabilitado, continua enviando a última pose comandada.
  • EEBoundsAndSafety: limita a pose do EE a um espaço de trabalho e aplica limites de taxa aos saltos por segurança. Também declara os recursos action.ee.*.
  • InverseKinematicsEEToJoints: converte uma pose do EE em posições de juntas com IK. initial_guess_current_joints=True é recomendado para controle em malha fechada; defina False para reprodução em malha aberta para estabilidade.
  • GripperVelocityToJoint: integra uma entrada de garra semelhante a velocidade em uma posição absoluta da garra usando o estado medido atual.
  • ForwardKinematicsJointsToEE: calcula observation.state.ee.* a partir das juntas observadas para registro e treinamento no estado do EE.

Solução de problemas

  • iOS não detectado: verifique se o HEBI Mobile I/O está aberto e se seu laptop/celular estão na mesma rede.
  • URL do Android inacessível: verifique se você usou https em vez de http, use o IP exato impresso pelo script e permita que o navegador entre e ignore o problema do certificado.
  • O movimento parece invertido: verifique um eixo de cada vez e, em seguida, ajuste as inversões de sinal em MapPhoneActionToRobotAction ou troque os eixos para corresponder à sua configuração.
  • O braço mal se move ou luta contra seus limites: reinicie a partir de uma pose inicial de faixa média (veja acima) — o IK é resolvido a partir da configuração atual do braço.
Update on GitHub