Tutorial · Iniciante · 30 min

Por que seu robô reinicia quando os motores entram em operação

Entenda por que a queda de tensão reinicia um robô: calcule o orçamento de corrente, considere a resistência interna da bateria e meça a queda sob carga.

Introdução

O robô funciona na bancada. Você o coloca no chão, os motores giram e tudo para — o monitor serial reinicia do início, a sequência do LED começa novamente e o que o robô estava fazendo é esquecido.

O primeiro impulso de quase todo mundo é procurar o problema no código. Não há nada no código.

O que aconteceu é que a partida dos motores exigiu mais corrente do que a bateria conseguia fornecer, fazendo sua tensão cair; a tensão de alimentação ficou abaixo do necessário para o microcontrolador e a placa reiniciou. Isso é uma queda de tensão (brownout) e é a falha mais comum em um primeiro robô — este site afirma isso no caminho de controle dos motores, em quase todas as páginas de componentes e na lista de solução de problemas de metade dos projetos. Esta é a página que explica o assunto.

Primeiro, confirme se é uma reinicialização, não uma falha

Essas situações exigem correções diferentes, mas parecem idênticas de longe.

Coloque uma linha distinta no início de setup():

void setup() {
  Serial.begin(115200);
  Serial.println(F("---- BOOT ----"));
}

Agora execute o robô até ele se comportar mal e observe o monitor:

  • ---- BOOT ---- aparece novamente → a placa reiniciou. É um problema de alimentação. Continue lendo.
  • A saída para ou repete a mesma linha indefinidamente → a placa ficou presa em um laço ou falhou. Esse é um problema de código, e esta não é a página certa.
  • A saída vira caracteres sem sentido → a tensão de alimentação está caindo, mas não o bastante para reiniciar. Também é um problema de alimentação, e as mesmas correções se aplicam.

Em placas AVR, você pode ir além e perguntar ao chip por que ele reiniciou. MCUSR armazena o motivo, mas main() é executado muito depois do momento em que ele precisa ser lido, portanto capture-o em uma função .init3 executada primeiro:

uint8_t resetFlags __attribute__((section(".noinit")));
void captureReset(void) __attribute__((naked, used, section(".init3")));
void captureReset(void) {
  resetFlags = MCUSR;
  MCUSR = 0;
}

void setup() {
  Serial.begin(115200);
  if (resetFlags & _BV(BORF))  Serial.println(F("cause: BROWN-OUT"));
  if (resetFlags & _BV(EXTRF)) Serial.println(F("cause: reset pin"));
  if (resetFlags & _BV(PORF))  Serial.println(F("cause: power-on"));
  if (resetFlags & _BV(WDRF))  Serial.println(F("cause: watchdog"));
}

Uma ressalva honesta: um Uno com Optiboot tem o bootloader lendo MCUSR e limpando-o antes que seu código o veja, guardando o valor no registrador r2. Se todos os indicadores estiverem zerados na sua placa, esse é o motivo — use o teste ---- BOOT ----, que não depende de nada e nunca mente.

Por que a tensão desaba

Uma bateria não é uma fonte de tensão. É uma fonte de tensão em série com uma resistência, e essa resistência determina se o robô funciona:

V_terminal = V_open_circuit − I × R_internal

R_internal é uma propriedade da química e do tamanho da célula, e varia imensamente entre os conjuntos que estão na mesma gaveta.

Gráfico da tensão nos terminais em função da corrente consumida por quatro conjuntos de baterias. Um bloco de 9 volts PP3 começa na maior tensão, 9 volts, mas cai abruptamente, cruzando 5 volts em 2 ampères. Quatro células alcalinas AA começam em 6 volts e caem para 4,4 volts. Duas células Li-ion 18650 começam em 7,4 volts e permanecem quase constantes em 7,2 volts. Quatro células NiMH AA começam na menor tensão, 4,8 volts, e permanecem quase constantes em 4,56 volts. Uma linha vertical pontilhada marca a corrente de surto de 2 ampères necessária para a partida de dois motores.
Dois motorredutores TT dando partida juntos consomem cerca de 2 A. O bloco de 9 V tem a maior tensão em circuito aberto na prateleira e oferece o pior resultado sob carga — ele perde 4 V durante a partida. O conjunto NiMH começa 4,2 V mais baixo e chega 0,6 V mais alto. Baixar SVG
Conjunto Circuito aberto R_internal Com surto de 2 A
2×18650 Li-ion 7,4 V ≈ 0,10 Ω 7,20 V
4×AA NiMH 4,8 V ≈ 0,12 Ω 4,56 V
4×AA alcalina 6,0 V ≈ 0,80 Ω 4,40 V
Bloco de 9 V PP3 9,0 V ≈ 2,0 Ω 5,00 V, e caindo

Três conclusões importam mais do que os números:

O bloco de nove volts é a pior opção de bateria que você pode colocar em um robô. Ele tem a maior tensão impressa, cerca de 500 mAh de capacidade e dois ohms de resistência interna. É uma bateria para detector de fumaça.

Células alcalinas não sustentam a tensão sob carga. Sua resistência interna é cerca de seis vezes a de uma célula NiMH e aumenta conforme se descarga — então o robô funciona por vinte minutos e depois começa a reiniciar, o que parece uma falha intermitente, mas é apenas uma bateria descarregada se comportando exatamente como deveria.

Baterias recarregáveis vencem no que realmente importa. NiMH e Li-ion são as químicas padrão para robôs não por serem recarregáveis, mas porque mantêm a tensão sob carga.

Calcule o orçamento de corrente antes de escolher o conjunto

Some o consumo do robô duas vezes — uma vez para o funcionamento normal e outra para o pior instante.

Componente Em funcionamento Pior caso
Placa Arduino Uno 45 mA 45 mA
Motorredutor TT ×2 400 mA 2000 mA (ambos em travamento)
Matriz de sensores de refletância infravermelha 100 mA 100 mA
HC-SR04 15 mA 15 mA
Servo SG90 150 mA 700 mA (em travamento)
Bluetooth HC-05 30 mA 40 mA
ESP32 (Wi-Fi) 80 mA 250 mA (rajada de transmissão)

Um seguidor de linha básico — Uno, dois motores e uma matriz IR — consome cerca de 545 mA em funcionamento e 2,15 A no pior instante. O pior instante normalmente é breve; a exceção é um robô aplicando força no limite de tração, que permanece na corrente de travamento enquanto a força é aplicada. Use o primeiro número para dimensionar a capacidade da bateria e o segundo para verificar a queda de tensão, porque eles respondem a perguntas diferentes:

runtime  ≈ capacity / running current      2000 mAh / 545 mA ≈ 3.7 h ideal
sag      = worst-case current × R_internal

Espere uma autonomia real em torno de dois terços desse valor. Você não descarregará um conjunto até zero, os surtos custam mais do que sua média e as capacidades são medidas em baixas taxas de descarga.

A faixa que o detector de queda de tensão não detecta

Todo AVR tem um detector de queda de tensão que mantém o chip reiniciado abaixo de uma tensão definida. Em um Arduino Uno, esse fusível vem de fábrica em 2,7 V.

Um ATmega328P a 16 MHz não é especificado para funcionar a 2,7 V. A classe de velocidade de seu datasheet vai de 4 MHz a 1,8 V até 20 MHz a 4,5 V e, ao interpolar para 16 MHz, resulta em um mínimo de aproximadamente 3,8 V.

Gráfico da frequência máxima de trabalho em função da tensão de alimentação do ATmega328P. Uma linha sobe de 4 megahertz a 1,8 volt até 20 megahertz a 4,5 volts e depois fica horizontal, com a área abaixo dela sombreada como região segura. Uma linha horizontal tracejada marca os 16 megahertz usados por um Arduino Uno e encontra o limite seguro em 3,8 volts. Uma faixa vermelha entre 2,7 volts e 3,8 volts está anotada como fora da especificação a 16 megahertz, mas acima do limiar de queda de tensão.
Entre 2,7 V e 3,8 V, o chip está operando mais rápido do que a tensão de alimentação permite, e o detector de queda de tensão — definido em 2,7 V — não vai intervir. Essa faixa de 1,1 V abriga as falhas mais estranhas de robôs. Baixar SVG

Isso explica o sintoma que as pessoas têm mais dificuldade para acreditar: um robô que não reinicia de forma limpa, mas simplesmente se comporta de maneira estranha quando os motores entram em operação. Variáveis corrompidas, um servo que dá um salto, um sensor I²C retornando dados sem sentido, uma máquina de estados em um estado para o qual não há transição. Nessa faixa, o chip executa instruções fora das condições de operação especificadas, e “garantido” é precisamente o termo que dá peso a essa afirmação.

Portanto, não considere “não reiniciou” como prova de que a alimentação está correta.

Um conjunto, dois trilhos

A solução não são duas baterias. É um conjunto alimentando dois caminhos.

  • A corrente dos motores vai do conjunto diretamente para o terminal de alimentação do motor no driver — o +12V de um L298N ou o VM de um TB6612FNG. Ela nunca passa pelo microcontrolador.
  • A corrente lógica vem de uma saída regulada de 5 V — o regulador da placa do driver, um módulo buck separado ou USB durante o desenvolvimento.
  • As massas devem ser conectadas juntas. Todo sinal entre a placa e o driver é uma tensão medida em relação à massa; sem uma referência compartilhada, os pinos de direção não têm efeito. Essa é a segunda falha de ligação mais comum depois da anterior.

Nunca opere motores pelo pino de 5 V de um Arduino nem pelo regulador do conector cilíndrico. O regulador do Uno é um pequeno componente linear que converte em calor a diferença entre entrada e saída: com entrada de 7,4 V, saída de 5 V e 500 mA, isso resulta em (7.4 − 5) × 0.5 = 1.2 W em um encapsulamento sem dissipador. Ele ficará quente, depois entrará em proteção térmica, e o robô reiniciará por um motivo que não tem relação com a bateria.

O que um capacitor realmente corrige

O conselho usual é colocar um capacitor eletrolítico de grande capacidade em paralelo com a alimentação dos motores. O conselho está certo, mas o motivo normalmente dado está errado, e a aritmética esclarece:

ΔV = I × Δt / C

Um capacitor de 1000 µF solicitado para conduzir um surto de partida de 2 A durante 10 ms sofreria uma queda de 2 × 0.010 / 0.001 = 20 V. Ele não pode fazer esse trabalho. Um capacitor não conduz o surto de partida do motor — somente uma bateria com menor resistência interna faz isso.

O que ele conduz são as variações rápidas. A uma frequência de comutação PWM de 8 kHz, o período é 125 µs, então o mesmo capacitor sofre 2 × 0.000125 / 0.001 = 0.25 V de ondulação — um trabalho que realiza com folga. Ele também absorve os picos de comutação que os motores com escovas devolvem à fonte.

Portanto, instale um capacitor eletrolítico de 470 a 1000 µF em paralelo com a alimentação dos motores, mais um cerâmico de 0,1 µF próximo ao driver, e espere que ele reduza o ruído e corrija o comportamento irregular dos sensores. Não espere que ele corrija uma reinicialização. Se um capacitor resolveu sua reinicialização, o conjunto estava no limite e você comprou uma margem muito pequena.

Meça em vez de adivinhar

Dez minutos com um multímetro são melhores do que uma tarde de especulação.

  1. Ajuste o medidor para volts CC e coloque-o nos terminais da bateria, não no Arduino.
  2. Anote a tensão de repouso.
  3. Inicie os motores, de preferência sob carga real, com o robô no chão.
  4. Observe o valor.

Uma queda de mais de alguns décimos de volt já é sua resposta. Para obter R_internal a partir dela, faça a divisão: um conjunto de 6,0 V que cai para 4,4 V enquanto consome cerca de 2 A resulta em (6.0 − 4.4) / 2 = 0.8 Ω.

Depois, repita a medição no trilho de 5 V durante a partida dos motores. Esse é o valor que o microcontrolador realmente enfrenta e, se ele cair na direção de 3,8 V, você encontrou a falha sem precisar de um osciloscópio.

Multímetros baratos fazem médias com lentidão demais para capturar o ponto mais baixo de uma queda de um milissegundo, portanto considere a leitura otimista. A queda real é pelo menos tão grande quanto isso.

Correções, das mais baratas às mais caras

  1. Pare de alimentar motores pela placa. É gratuito e resolve diretamente uma grande parte dos casos.
  2. Troque o conjunto. Alcalinas ou 9 V → NiMH ou 18650. Normalmente, é toda a solução.
  3. Conecte as massas. É gratuito, e sua ausência causa falhas mais estranhas do que uma queda de tensão.
  4. Adicione o capacitor eletrolítico de grande capacidade. Para ruído e falhas transitórias dos sensores, não para reinicializações.
  5. Aumente a velocidade dos motores gradualmente em vez de dar um comando brusco. Um perfil de movimento espalha a corrente de partida ao longo do tempo, em vez de exigir toda ela em um único instante — é o mesmo código que impede as rodas de patinar.
  6. Dimensione os motores corretamente. Se um motor receber um comando de torque acima do necessário, consumirá mais corrente do que deveria; o cálculo de dimensionamento de motorredutor vem antes de todo esse problema.
  7. Separe o regulador. Um pequeno conversor buck para o trilho lógico desacopla esse trilho por completo da queda causada pelos motores.

Depois de organizar o trilho, medi-lo em software é o próximo passo — e medir uma tensão de forma confiável é mais difícil do que parece, porque a referência padrão do ADC é o próprio trilho.

Quando algo dá errado

Sintoma Causa usual
A saída serial reinicia do topo quando os motores entram em operação Queda de tensão; verifique o conjunto antes do código
Funciona com USB, mas falha com bateria O conjunto não fornece o surto; o USB fornece
Funciona por vinte minutos e depois reinicia repetidamente A resistência interna das alcalinas aumenta durante a descarga
Comportamento estranho, sem reinicialização limpa A alimentação está na faixa de 2,7–3,8 V; fora da especificação, mas acima do limiar de queda de tensão
Os sensores retornam dados sem sentido apenas durante a movimentação Ruído na alimentação; use capacitor eletrolítico de grande capacidade e trilhos separados
Os pinos de direção parecem não fazer nada Não há massa comum entre a placa e o driver
Regulador quente demais para tocar A lógica é alimentada por um regulador linear com tensão de entrada alta demais
Um capacitor resolveu, mas o problema voltou O conjunto estava no limite; o capacitor comprou milissegundos, não ampères

A alimentação é a camada sob todas as outras camadas de um robô, e por isso uma falha aqui imita uma falha em qualquer outro lugar. Quando algo inexplicável começa a acontecer no instante em que os motores entram em operação, meça a bateria primeiro — isso leva dez minutos e fica certo mais vezes do que qualquer outra suposição.

Explore o grafo

Faz parte destas montagens

Projetos e caminhos de aprendizagem que incluem este tutorial.

Leitura complementar

Referências