Tutorial · Intermediário · 35 min

Máquina de estados de coleta e colocação resistente a falhas

Implemente coleta e colocação como uma máquina de estados, com verificação da preensão e recuperação de falhas para operar sem supervisão.

Por que a demonstração funciona e o sistema não

A primeira coleta e colocação de qualquer pessoa costuma ser uma sequência de chamadas de delay(). Cada chamada bloqueia a execução por um período fixo: mova para cá, feche a garra, mova para lá, abra. Funciona em um vídeo e em cerca de 80% dos ciclos na bancada, o que parece próximo o suficiente de estar pronto.

A máquina está longe de estar pronta, porque as falhas são silenciosas. A garra fechou no vazio e o braço percorreu a mesa com a garra vazia antes de abrir sobre a caixa. A peça estava levemente inclinada e foi derrubada, sem que a preensão fosse concluída. A tensão de alimentação do servo caiu durante o levantamento e o controlador reiniciou em uma pose desconhecida, com as mandíbulas fechadas.

Uma única medida transforma esses desastres em situações recuperáveis: uma etapa de verificação entre a preensão e o levantamento, acompanhada por uma máquina de estados que tenha um caminho definido para tratar cada falha. Esse é o assunto central desta página.

Os estados

Um ciclo de coleta e colocação tem nove estados. Vale nomear todos eles, em vez de agrupar estados com funções diferentes.

Estado O que acontece Condição de saída
IDLE Aguarda um trabalho Chega uma solicitação de coleta
APPROACH Move o braço para uma pose acima do objeto, com a garra aberta O braço para e se estabiliza
DESCEND Executa um movimento reto para baixo até a pose de preensão A profundidade é atingida ou um sensor de contato é acionado
GRASP Fecha as mandíbulas e aguarda O tempo de espera decorre
VERIFY Verifica se há realmente uma peça segurada Preensão confirmada → LIFT. Sem peça → RECOVER
LIFT Executa um movimento reto para cima até a pose de aproximação O braço para e se estabiliza
TRANSFER Move o braço para cima do alvo de colocação O braço para e se estabiliza
PLACE Desce, abre a garra, aguarda e recua O recuo é concluído
RECOVER Abre novamente a garra, recua, conta a tentativa e tenta de novo ou desiste Nova tentativa → APPROACH. Desistência → IDLE com uma falha

Dois pontos de projeto fazem quase todo o trabalho aqui.

As poses de aproximação e de recuo são estados separados, acima do objeto. Uma garra que se aproxima diretamente de uma peça a partir de uma direção arbitrária pode derrubá-la. Da mesma forma, uma garra que levanta a peça ao longo de uma curva pode arrastá-la lateralmente antes de se afastar dela. Entre sempre diretamente por cima, ou diretamente ao longo do eixo de inserção, usando um pequeno trecho reto; saia da mesma forma.

VERIFY é um estado, não uma linha de código. É o único momento do ciclo em que a máquina descobre se a realidade correspondeu ao plano e precisa de um caminho definido para tratar uma falha.

Verificando a preensão

Quatro maneiras, da mais barata para a mais cara. Você quer pelo menos uma.

Verificação da posição das mandíbulas (gratuita)

Se a garra tiver alguma complacência em série, a preensão de um objeto impede que as mandíbulas cheguem à posição que alcançariam ao fechar no ar. Se você puder ler a posição das mandíbulas, compará-la com a posição de fechamento no ar indicará que há algo entre os dedos.

Em um servo de hobby comum, não é possível ler a posição — ele opera em circuito aberto. Já um servo com o cursor do potenciômetro ligado a um pino do ADC oferece essa leitura pelo custo de um fio, e a modificação leva dez minutos.

Limites: indica que há algo ali, mas não que seja o objeto correto nem que a preensão está firme.

Um microinterruptor no dedo (cerca de 50p)

Um microinterruptor de alavanca na face interna de um dedo, ligado a um pino de entrada com pull-up. Ele fecha quando a placa entra em contato com algum objeto.

Essa é a melhor opção em custo-benefício, por uma larga margem. Fornece uma resposta digital direta para “há algo entre as mandíbulas”, é robusta e pode ter as oscilações de contato tratadas em software com apenas três linhas. Coloque-o na parte complacente do dedo para que seja acionado de forma confiável com uma força repetível.

Sensamento de corrente (cerca de £2)

Um resistor shunt ou sensor Hall na alimentação do servo. Um servo que fecha no ar reduz a corrente até o valor de repouso; um servo que fecha sobre um objeto mantém uma corrente elevada.

Limites: a leitura é ruidosa, exige um limite que você precisa calibrar e se torna imprecisa quando a tensão da bateria cai. Vale a pena quando você também quer detectar esmagamento, e não apenas confirmar a preensão — uma corrente muito acima do valor esperado significa que a peça é mais dura do que se supunha ou que a garra fez uma preensão errada e prendeu o dispositivo de fixação.

Interrupção do feixe entre as mandíbulas (cerca de £1)

Um emissor infravermelho e um fototransistor atravessam a abertura entre as mandíbulas. A interrupção do feixe indica que há algo no espaço entre elas.

Limites: o sensor detecta o objeto antes de a preensão ser executada; portanto, verifica a presença, e não a preensão. Combine-o com outro sensor. É especialmente útil em máquinas que coletam objetos transparentes ou escuros, para os quais a visão por câmera encontra dificuldades.

Escrevendo a máquina de estados

O padrão é uma máquina de estados finita simples com um temporizador não bloqueante. Assim, nada no laço é interrompido por uma espera e a parada de emergência continua respondendo:

enum State { IDLE, APPROACH, DESCEND, GRASP, VERIFY, LIFT, TRANSFER, PLACE, RECOVER };

State state = IDLE;
uint32_t stateEnteredAt = 0;
uint8_t  attempts = 0;

const uint8_t  MAX_ATTEMPTS = 3;
const uint16_t GRASP_DWELL_MS = 350;   // let the compliance settle before you trust it
const uint16_t SETTLE_MS      = 250;

void enter(State next) { state = next; stateEnteredAt = millis(); }
bool elapsed(uint16_t ms) { return millis() - stateEnteredAt >= ms; }

// Debounced: one reading is a glitch, three in a row is a fact.
bool objectHeld() {
  static uint8_t streak = 0;
  streak = digitalRead(GRIP_SWITCH) == LOW ? min(streak + 1, 3) : 0;
  return streak >= 3;
}

void loop() {
  arm.update();          // non-blocking motion, every pass
  gripper.update();

  switch (state) {
    case IDLE:
      if (jobPending()) { attempts = 0; arm.moveTo(approachPose); enter(APPROACH); }
      break;

    case APPROACH:
      gripper.open();
      if (arm.arrived() && elapsed(SETTLE_MS)) { arm.moveTo(graspPose); enter(DESCEND); }
      break;

    case DESCEND:
      if (arm.arrived()) { gripper.close(); enter(GRASP); }
      break;

    case GRASP:
      // The dwell is not politeness. A compliant finger rings after closing,
      // and reading the switch during the ring gives you a coin flip.
      if (elapsed(GRASP_DWELL_MS)) enter(VERIFY);
      break;

    case VERIFY:
      if (objectHeld()) { arm.moveTo(approachPose); enter(LIFT); }
      else              { enter(RECOVER); }
      break;

    case LIFT:
      if (arm.arrived()) { arm.moveTo(placeApproach); enter(TRANSFER); }
      break;

    case TRANSFER:
      if (arm.arrived()) { arm.moveTo(placePose); enter(PLACE); }
      break;

    case PLACE:
      if (arm.arrived() && elapsed(SETTLE_MS)) {
        gripper.open();
        // Open BEFORE retreating, and retreat straight up, or you drag the part.
        if (elapsed(SETTLE_MS + 200)) { arm.moveTo(placeApproach); enter(IDLE); }
      }
      break;

    case RECOVER:
      gripper.open();
      if (elapsed(SETTLE_MS)) {
        if (++attempts < MAX_ATTEMPTS) { arm.moveTo(approachPose); enter(APPROACH); }
        else { raiseFault("grasp failed after 3 attempts"); enter(IDLE); }
      }
      break;
  }
}

Três detalhes desse código merecem atenção:

O tempo de permanência após a preensão. Um dedo complacente pode oscilar por alguns centésimos de segundo depois de fechar. Verificar a preensão durante essa oscilação torna o resultado imprevisível. Em geral, 300–400 ms bastam; meça o tempo necessário registrando o interruptor durante um segundo após o fechamento.

Verificação com antioscilação. Uma leitura isolada do interruptor pode ser um pico de ruído. Três leituras consecutivas fornecem uma confirmação mais confiável, e o custo corresponde a apenas três iterações de um laço que roda a centenas de hertz.

Tentativas limitadas. Tentar indefinidamente pode fazer o robô passar a noite pressionando uma peça que caiu no chão uma hora antes. Limite a três tentativas e, em seguida, registre uma falha que exija a intervenção de uma pessoa.

O que fazer quando uma nova tentativa não ajuda

Tal como está implementado, RECOVER apenas tenta novamente a partir da mesma pose. Isso resolve o caso comum — a peça estava um pouco deslocada, as mandíbulas a empurraram e a segunda tentativa funciona — mas não resolve uma peça que está em outra posição. Algumas alternativas úteis, em ordem:

  1. Desloque a aproximação. A cada nova tentativa, desloque a pose de preensão alguns milímetros em uma pequena espiral. A mudança custa três linhas e resolve uma fração surpreendente dos casos.
  2. Faça uma nova leitura. Se você tiver uma câmera ou um sensor de distância, obtenha uma nova leitura, em vez de confiar na pose recebida.
  3. Aumente a abertura. Uma abertura das mandíbulas dimensionada exatamente para a peça nominal falha quando a peça está girada. Abra mais na nova tentativa.
  4. Sinalize a desistência de forma clara. Uma falha que para a máquina e informa o estado em que ela se encontrava é melhor do que uma máquina que continua operando e enche a caixa de rejeitados em silêncio.

As falhas que não são culpa da garra

Quando a coleta e a colocação são instáveis, muitas vezes o problema não está na preensão:

Sintoma Causa usual
Falha apenas em ciclos rápidos Tempo de estabilização insuficiente. O braço concluiu o movimento, mas ainda está oscilando
Falha após vinte minutos Aquecimento do servo. Consulte a corrente de travamento — as mandíbulas provavelmente permanecem fechadas durante todo o trajeto de retorno
Derruba a peça durante a aproximação Está descendo em ângulo, em vez de descer em linha reta ao longo do eixo de inserção
Solta a peça durante a transferência, mas não durante a coleta Aceleração. A preensão foi dimensionada para uma retenção estática, e o movimento exige mais força
Arrasta a peça ao soltá-la Recua antes de as mandíbulas estarem totalmente abertas ou recua ao longo de uma curva
O controlador reinicia no meio do ciclo A tensão de alimentação do servo cai. Separe a alimentação do servo da alimentação do restante do sistema
Começa a funcionar e depois deixa de funcionar gradualmente Placas sujas. O valor de μ diminui com o acúmulo de poeira, e não há alarme para isso

Vale observar a quarta linha, porque é a que mais parece um mistério. Uma preensão que funciona perfeitamente na bancada pode soltar a peça 40 ms após o início de um levantamento — antes de o braço ter se movido visivelmente — porque o termo de aceleração domina. O simulador de garra mostrará o instante exato para os seus números, e a correção costuma ser desacelerar o perfil de movimento, em vez de apertar mais.

Para onde ir daqui

Depois que o ciclo se torna confiável, as próximas adições que valem a pena são, em ordem de prioridade:

  1. Contagem de ciclos e registro de falhas. Você não pode melhorar um índice de confiabilidade que não está medindo.
  2. Um perfil de movimento adequado para a transferência, com aceleração limitada, para que você não precise superdimensionar a preensão apenas para resistir a movimentos bruscos.
  3. Pose obtida por sensores, em vez de usar valores constantes — é essa a transição de uma demonstração para uma máquina.

Próximo

Explore o grafo

Faz parte destas montagens

Projetos e caminhos de aprendizagem que incluem este tutorial.

Leitura complementar

Referências