Braço robótico com Arduino: escolha do servo, torque, PCA9685 e Bluetooth
Monte um braço robótico com Arduino passo a passo: estrutura em MDF ou impressa em 3D, cálculo de torque do MG996R, controle por potenciômetro e joystick, gravar/reproduzir, PCA9685 e Bluetooth.
Um braço robótico com Arduino é um robô de mesa cujas articulações, movidas por servos, permitem pegar um objeto, levantá-lo, girar e colocá-lo em outro lugar. Formado por base, ombro, cotovelo, punho e garra, ele ensina projeto mecânico, escolha de motores, gerenciamento de alimentação e programação em um único projeto. Melhor ainda: você pode montar um em casa com um Arduino Uno, alguns servos e peças de MDF ou impressas em 3D, e ter uma pequena cópia de um braço robótico industrial funcionando na sua mesa.
Neste guia, cobrimos braços robóticos de 4 e 6 eixos do começo ao fim: a escolha do material da estrutura, um cálculo de torque para decidir entre SG90, MG90S e MG996R, uma fonte externa de 5 V, controle com potenciômetros e joysticks, gravação e reprodução de movimentos, o driver de servos de 16 canais PCA9685, controle por Bluetooth pelo celular e as soluções para os dois problemas mais comuns: tremedeira e resets. Se você não tem certeza de como um servo funciona, comece por O que é servo motor?.



Como funciona um braço robótico e quantos eixos você precisa?
Pense no braço robótico como um braço humano. Cada articulação tem um servo motor, e o Arduino diz a cada servo “vá para este ângulo”. Graças ao potenciômetro interno, o servo sabe onde está o eixo e mantém esse ângulo mesmo sob carga. Mudando os ângulos das articulações em conjunto, você leva a garra até o ponto desejado. O número de movimentos independentes que um braço consegue fazer se chama graus de liberdade (DOF), ou simplesmente eixos.
| Articulação | Movimento | Carga | Servo recomendado |
|---|---|---|---|
| Base (cintura) | Gira o braço para a esquerda e para a direita | Não levanta nada, mas sustenta o braço inteiro | MG996R + rolamento |
| Ombro | Levanta o braço para frente e para trás | A articulação mais carregada | MG996R ou um servo da classe de 20 kg·cm |
| Cotovelo | Dobra o antebraço | Média a alta | MG996R |
| Punho (inclinação) | Ajusta o ângulo da garra | Baixa | MG90S |
| Rotação do punho | Gira a garra em torno do próprio eixo | Muito baixa | MG90S ou SG90 |
| Garra | Pega e solta o objeto | Força de aperto | SG90 ou MG90S |
A maioria dos kits de “braço robótico de 6 eixos” à venda tem 6 servos; como a garra não conta como eixo, tecnicamente são um braço de 5 DOF mais uma garra. Para o seu primeiro braço, um projeto de 4 eixos (base, ombro, cotovelo, garra) é o melhor começo: 4 servos, 4 potenciômetros e um Arduino Uno bastam, a fiação fica simples e problemas de torque são raros. As articulações do punho ajudam quando você precisa manter a garra nivelada ou pegar objetos de ângulos diferentes; ao passar para 5–6 servos, um driver PCA9685 se torna quase indispensável.
Lista de materiais
| Peça | Braço de 4 eixos | Braço de 6 servos | Observação |
|---|---|---|---|
| Controlador | Arduino Uno ou Nano | Arduino Uno, Nano ou ESP32 | As entradas extras A6 e A7 do Nano permitem mais potenciômetros |
| Servo motores | 4× SG90 ou MG90S | 3× MG996R + 3× MG90S | Confirme a escolha com o cálculo de torque abaixo |
| Driver de servos | Não é necessário | Módulo PCA9685 de 16 canais | Apenas 2 fios de sinal via I2C |
| Fonte de alimentação | Fonte de 5 V 3 A | Fonte de 5–6 V, no mínimo 5 A | Os servos nunca são alimentados pelo Arduino |
| Capacitor | 470–1000 µF, 16 V | 1000–2200 µF, 16 V | Na linha de alimentação dos servos, atenção à polaridade |
| Controles | 4× potenciômetros de 10 kΩ | 2× módulos joystick ou um HC-05 | Você também pode usar os dois |
| Botões | 2 (gravar, reproduzir) | Os botões dos joysticks bastam | Sem resistores extras com INPUT_PULLUP |
| Mecânica | MDF de 3 mm ou peças impressas em 3D | MDF de 4 mm, impressão 3D ou suportes de alumínio | Rolamento 608, parafusos M3 e porcas autotravantes |
Projeto mecânico: MDF ou impressão 3D?
| Material | Vantagens | Desvantagens | Indicado para |
|---|---|---|---|
| MDF de 3–4 mm (corte a laser) | Barato, leve, fácil de parafusar e colar | Sensível à umidade; os furos dos parafusos alargam com o tempo | Primeiros braços no estilo MeArm, projetos escolares |
| Acrílico de 3 mm | Ótima aparência, não é afetado pela umidade | Quebradiço; pode trincar ao apertar os parafusos | Montagens para exposição e vitrine |
| Impressão 3D (PLA / PETG) | Peças complexas, encaixes dos servos na medida exata | Impressões demoradas; o PLA deforma (fluência) no calor e sob carga constante | Seus próprios projetos; PETG nas peças que suportam carga |
| Kit de suportes de alumínio | Muito rígido, peças prontas para o MG996R | Pesado e caro, aumenta a carga no ombro | Braços de 6 servos feitos para levantar objetos mais pesados |
| Papelão, palitos de picolé | Quase de graça, prototipagem rápida | Frágil; as articulações ganham folga | Testar dimensões, primeiras montagens com crianças |
- Mantenha o braço curto e leve: a carga no ombro cresce na mesma proporção da distância. Fazer o braço com 24 cm em vez de 30 cm reduz o torque do ombro em cerca de um quinto.
- Coloque os servos pesados perto da base: levar o servo do cotovelo para a altura do ombro e acionar o cotovelo com uma haste de transmissão (articulação paralela) é um truque inteligente usado em braços como o MeArm; o ombro deixa de ter que levantar esse servo.
- Use um rolamento na base: não pendure o peso do braço inteiro no eixo do servo da base. Um rolamento 608 (furo de 8 mm, 22 mm de diâmetro externo, 7 mm de espessura; o clássico rolamento de skate) ou um rolamento de prato giratório (lazy Susan) suporta a carga, e o servo só faz girar.
- Apoie as articulações dos dois lados: enquanto o servo segura a articulação pelo lado do braço do servo, coloque um pivô no lado oposto com um parafuso M3 e uma porca autotravante. Assim o eixo do servo não sofre esforço de flexão e as engrenagens duram muito mais.
- Use braços de servo metálicos: coloque um braço redondo metálico de 25 dentes (25T) em cada MG996R e prenda-o ao eixo com o parafuso central. Braços plásticos escorregam e espanam o estriado nas articulações mais carregadas.
- Coloque borracha nos dedos da garra: uma tira fina de borracha nas pontas dos dedos permite que a garra segure objetos sem escorregar e com menos força de aperto.
Escolha dos servos: SG90, MG90S ou MG996R?
| Modelo | Torque | Velocidade (por 60°) | Peso | Engrenagens | Corrente de travamento | Função no braço robótico |
|---|---|---|---|---|---|---|
| SG90 | 1,8 kg·cm (4,8 V) | 0,10 s (4,8 V) | 9 g | Plástico | Cerca de 0,6–0,75 A | Garra, punho leve, braço pequeno de 4 eixos |
| MG90S | 1,8 kg·cm (4,8 V), 2,2 kg·cm (6 V) | 0,10 s (4,8 V) | 13,4 g | Metal | Cerca de 0,7–1 A | Punho, rotação do punho, garra |
| MG996R | 9,4 kg·cm (4,8 V), 11 kg·cm (6 V) | 0,17 s (4,8 V) | 55 g | Metal | 2,5 A (6 V) | Base, ombro, cotovelo |
| DS3218 | 19 kg·cm (5 V), 21,5 kg·cm (6,8 V) | 0,16 s (5 V) | 60 g | Metal | Cerca de 2–3 A | Ombro de braços longos ou pesados |
O valor de torque da tabela é o torque de travamento (stall torque): a força máxima que o servo consegue entregar antes de o eixo parar, e não um valor em que ele possa trabalhar continuamente. À medida que o servo se aproxima desse limite, a corrente sobe em direção à corrente de travamento, ele esquenta e começa a tremer. A regra prática é que o torque exigido por uma articulação seja no máximo metade do torque de travamento do servo. A tensão também conta: o MG996R entrega 9,4 kg·cm em 4,8 V e 11 kg·cm em 6 V, ou seja, o mesmo servo fica cerca de 17% mais forte só pela tensão de alimentação. Por isso uma fonte de 6 V faz sentido em braços com MG996R, mas 6 V é o limite superior para o SG90 e o MG90S. Para a ligação e os limites do MG996R, veja também o guia do servo motor MG996R.

Cálculo de torque: o servo do ombro consegue levantar este braço?
O torque que um servo precisa levantar é a soma da massa de cada peça multiplicada pela sua distância horizontal até o eixo da articulação: Torque (kg·cm) = Σ massa (kg) × distância (cm). O pior caso é com o braço esticado na horizontal, porque todas as distâncias estão no máximo; com o braço apontando para cima, esse braço de alavanca cai quase a zero. Para converter em newton-metros, multiplique por 0,098 (1 kg·cm ≈ 0,098 N·m). Como exemplo, vamos calcular a carga no ombro de um braço de mesa com 12 cm do ombro ao cotovelo, 12 cm do cotovelo ao punho, 6 cm do punho até a ponta da garra e um MG996R no cotovelo, com a garra segurando um objeto de 50 g:
| Peça | Massa | Distância até o eixo do ombro | Torque |
|---|---|---|---|
| Peças do braço superior (MDF e parafusos) | 40 g | 6 cm (centro de massa) | 0,04 × 6 = 0,24 kg·cm |
| Servo do cotovelo (MG996R) | 55 g | 12 cm | 0,055 × 12 = 0,66 kg·cm |
| Peças do antebraço | 30 g | 18 cm | 0,03 × 18 = 0,54 kg·cm |
| Servo do punho + garra (MG90S, SG90 e peças) | 50 g | 25 cm | 0,05 × 25 = 1,25 kg·cm |
| Objeto segurado | 50 g | 30 cm | 0,05 × 30 = 1,50 kg·cm |
| Total | 225 g | — | 4,19 kg·cm (≈ 0,41 N·m) |
Parado, este braço precisa de 4,19 kg·cm no ombro. Para cobrir a carga extra de acelerar e frear, e manter o servo bem longe do travamento, multiplique por 2: 8,4 kg·cm. Então o ombro precisa no mínimo de um MG996R (9,4 kg·cm em 4,8 V, 11 kg·cm em 6 V); os 1,8–2,2 kg·cm de um SG90 ou MG90S nem sequer mexem este braço. Fazendo o mesmo para o cotovelo, o antebraço (0,03 × 6), o punho com a garra (0,05 × 13) e o objeto (0,05 × 18) somam 1,73 kg·cm, ou 3,5 kg·cm com a margem de segurança, então o cotovelo também precisa de um MG996R. No punho restam só a garra e o objeto, então a carga fica em torno de 0,4 kg·cm e um MG90S sobra. O mesmo cálculo mostra o objeto mais pesado que o braço consegue carregar: aumente a massa do objeto, recalcule o total e fique abaixo da metade do torque do servo.
Alimentação: por que os servos não são alimentados pelo Arduino?
A maioria dos problemas de braços robóticos vem da alimentação. Um MG996R consome 0,5–0,9 A em movimento e até 2,5 A travado; até um pequeno SG90 pode passar de 0,6 A no travamento. Quando um Arduino Uno funciona pela USB, a corrente total disponível no pino 5V fica em torno de 500 mA, o limite da USB, e a própria placa usa parte disso. Quando três servos grandes começam a se mover ao mesmo tempo, a tensão despenca, o microcontrolador reinicia e o braço volta de repente para a posição inicial. A solução é alimentar os servos com uma fonte separada de 5–6 V e ligar todos os GNDs juntos; o Arduino pode continuar sendo alimentado pela USB ou pela própria fonte. Para opções de alimentação, veja o guia Como alimentar um Arduino e, para estimar quanto tempo um braço a bateria vai funcionar, experimente a calculadora de autonomia da bateria.
| Tipo de braço | Corrente estimada | Fonte recomendada |
|---|---|---|
| Braço pequeno com 4× SG90 ou MG90S | 0,5–1 A em movimento, 2–3 A de pico | Fonte de 5 V 3 A ou um módulo LM2596 (3 A no máximo, cerca de 2 A sem dissipador) |
| Braço de 6 servos com 3× MG996R + 3× MG90S | 2–3 A em movimento, 8–10 A se todos travarem | Fonte chaveada de 5–6 V, no mínimo 5 A (10 A para ter folga) |
| Braço portátil | Depende do braço | LiPo 2S (7,4 V) + um módulo abaixador (UBEC) de 5 A ou mais ajustado para 6 V |
| Fontes a evitar | — | Bateria de 9 V (PP3, não entrega a corrente), o pino 5V do Arduino, 4 pilhas alcalinas AA em um braço com MG996R |
Ligação do braço de 4 eixos
A tabela abaixo mostra a ligação no Arduino Uno e no Raspberry Pi Pico para o braço de 4 eixos controlado por potenciômetros; o código deste guia usa estes pinos. No Uno, a biblioteca Servo consegue acionar um servo em qualquer pino digital, mas, como ela usa o Timer1, o analogWrite deixa de funcionar nos pinos 9 e 10 enquanto houver servos conectados. Você pode conferir a disposição dos pinos da sua placa na ferramenta Pinagem.
| Conexão | Arduino Uno | Raspberry Pi Pico |
|---|---|---|
| Sinal do servo da base (fio laranja) | D3 | GP10 |
| Sinal do servo do ombro | D5 | GP11 |
| Sinal do servo do cotovelo | D6 | GP12 |
| Sinal do servo da garra | D9 | GP13 |
| Cursor dos potenciômetros 1–3 (base, ombro, cotovelo) | A0, A1, A2 | GP26, GP27, GP28 |
| Cursor do potenciômetro 4 (garra) | A3 | Nenhum; a garra usa o botão no GP14 |
| Terminais externos dos potenciômetros | 5V e GND | 3V3 e GND |
| Botões de gravar e reproduzir (outro lado no GND) | D7 e D8 | — |
| Fio vermelho do servo (+) | Positivo da fonte externa de 5–6 V | Positivo da fonte externa de 5–6 V |
| Fio marrom do servo (−) | Negativo da fonte externa + GND do Arduino | Negativo da fonte externa + GND do Pico |

Calibre antes da montagem: centralize os servos
- Antes de colocar os braços dos servos, carregue o código abaixo; os quatro servos vão para 90 graus, um depois do outro, e ficam parados ali.
- Segure o braço em uma posição neutra (por exemplo, braço superior na vertical, antebraço na horizontal, garra meio aberta), encaixe cada braço do servo no dente do estriado mais próximo dessa posição e prenda-o com o parafuso central.
- Mude CENTER_ONLY para false no código, escolha uma articulação com TEST e gire devagar o potenciômetro do A0.
- Acompanhe o ângulo no Monitor Serial e anote o menor e o maior ângulo que a articulação alcança sem bater em nada nem esticar os cabos.
- Defina o ângulo de garra fechada no ponto em que os dedos apenas se tocam; um servo que continua tentando apertar mais fica travado e esquenta.
- Coloque os valores encontrados nos arrays MIN_A e MAX_A dos sketches seguintes.
1#include <Servo.h>
2
3const byte SERVO_PIN[4] = {3, 5, 6, 9}; // taban, omuz, dirsek, kıskaç / base, shoulder, elbow, gripper
4const byte TEST = 1; // denenecek servo (0–3) / servo under test (0–3)
5const bool CENTER_ONLY = true; // true: hepsi 90°'de bekler / true: all wait at 90°
6
7Servo servo[4];
8
9void setup() {
10 Serial.begin(9600);
11 for (byte i = 0; i < 4; i++) {
12 servo[i].write(90); // önce açıyı ver / set the angle first
13 servo[i].attach(SERVO_PIN[i]); // sonra bağla: zıplamaz / then attach: no jump
14 delay(300); // akım darbelerini ayır / spread the current surges
15 }
16}
17
18void loop() {
19 if (CENTER_ONLY) return; // korna takarken burada kal / stay here while fitting horns
20 int angle = map(analogRead(A0), 0, 1023, 0, 180); // A0'daki pot / pot on A0
21 servo[TEST].write(angle);
22 Serial.print(F("Servo "));
23 Serial.print(TEST);
24 Serial.print(F(" aci / angle: "));
25 Serial.println(angle); // sınırları buradan oku / read the limits here
26 delay(50);
27}Há um detalhe pequeno, mas importante, neste código: como servo.write(90) é chamado antes de attach(), o servo recebe o ângulo pedido já no primeiro pulso. Se você inverter a ordem, a biblioteca primeiro envia o pulso padrão de 1500 µs (cerca de 90°); se o seu ângulo inicial não for 90, o braço pula para o meio e depois para o alvo ao ligar. Iniciar os servos um a um, com 300 ms de intervalo, também distribui o pico de corrente na partida.
Controle do braço robótico com potenciômetros
O método de controle mais intuitivo é um potenciômetro por articulação: seja qual for o ângulo do eixo do potenciômetro, a articulação vai para o mesmo ângulo, ou seja, você faz controle de posição. Se você montar os potenciômetros em uma maquete pequena do braço (de papelão ou impressa em 3D, nas mesmas proporções), o braço grande copia um a um os movimentos da maquete enquanto você a move com a mão. As leituras analógicas, porém, oscilam naturalmente alguns pontos, e essa oscilação aparece como tremedeira nos servos; o código tem duas medidas contra isso.
1#include <Servo.h>
2
3const byte SERVO_PIN[4] = {3, 5, 6, 9}; // taban, omuz, dirsek, kıskaç / base, shoulder, elbow, gripper
4const byte POT_PIN[4] = {A0, A1, A2, A3}; // her eklem için bir pot / one pot per joint
5const byte MIN_A[4] = {0, 15, 20, 40}; // kalibrasyonda bulduğun alt sınırlar / lower limits from calibration
6const byte MAX_A[4] = {180, 165, 160, 110}; // üst sınırlar / upper limits
7
8Servo servo[4];
9float smooth[4]; // süzülmüş pot değeri / filtered pot value
10int lastAngle[4]; // son yazılan açı / last written angle
11
12void setup() {
13 for (byte i = 0; i < 4; i++) {
14 smooth[i] = analogRead(POT_PIN[i]);
15 lastAngle[i] = map((int)smooth[i], 0, 1023, MIN_A[i], MAX_A[i]);
16 servo[i].write(lastAngle[i]); // önce açı, sonra attach / angle first, then attach
17 servo[i].attach(SERVO_PIN[i]);
18 delay(300); // servolar sırayla uyansın / wake the servos one by one
19 }
20}
21
22void loop() {
23 for (byte i = 0; i < 4; i++) {
24 smooth[i] += (analogRead(POT_PIN[i]) - smooth[i]) * 0.2; // yumuşatma filtresi / low-pass filter
25 int angle = map((int)smooth[i], 0, 1023, MIN_A[i], MAX_A[i]);
26 if (abs(angle - lastAngle[i]) >= 2) { // ölü bant: küçük gürültüyü yok say / deadband: ignore small noise
27 servo[i].write(angle);
28 lastAngle[i] = angle;
29 }
30 }
31 delay(15);
32}O array smooth é um filtro passa-baixa simples: a cada ciclo ele soma só 20% da nova leitura, então saltos repentinos são suavizados e o braço continua respondendo rápido. Troque 0.2 por 0.1 e o movimento fica mais suave, porém mais atrasado. A segunda medida é uma zona morta (deadband): se o novo ângulo não diferir do último escrito em pelo menos 2 graus, nada é enviado ao servo, o que acaba com a tremedeira enquanto o braço está parado. Como map() converte a faixa do potenciômetro direto para os limites seguros de cada articulação, a articulação nunca bate no batente mecânico, mesmo com o potenciômetro girado até o fim.
Gravar e reproduzir movimentos
O que realmente faz de um braço robótico um robô é repetir sozinho um movimento que você mostrou a ele. O método é simples: você leva o braço até uma posição com os potenciômetros e aperta o botão de gravar, e o Arduino guarda os ângulos das quatro articulações. Depois de gravar algumas posições, aperte reproduzir e o braço as repete em ordem, suavizando as transições entre elas. As posições são gravadas na EEPROM de 1024 bytes do Arduino Uno, então sobrevivem quando a placa é desligada; cada posição ocupa 4 bytes, então uma gravação de 100 posições usa só 401 bytes.
1#include <Servo.h>
2#include <EEPROM.h>
3
4const byte SERVO_PIN[4] = {3, 5, 6, 9}; // taban, omuz, dirsek, kıskaç / base, shoulder, elbow, gripper
5const byte POT_PIN[4] = {A0, A1, A2, A3};
6const byte MIN_A[4] = {0, 15, 20, 40}; // güvenli sınırlar / safe limits
7const byte MAX_A[4] = {180, 165, 160, 110};
8const byte BTN_REC = 7, BTN_PLAY = 8, LED = 13; // butonların diğer ucu GND'de / buttons go to GND
9const byte MAX_STEPS = 100; // 100 adım x 4 bayt = 400 bayt / 100 steps x 4 bytes
10
11Servo servo[4];
12float smooth[4]; // süzülmüş pot değeri / filtered pot value
13byte pos[4]; // servoların şu anki açısı / current servo angles
14byte stepCount; // kayıtlı adım sayısı / number of saved steps
15
16bool pressed(byte pin) { // basılıyken true / true while pressed
17 return digitalRead(pin) == LOW;
18}
19
20byte potAngle(byte i) {
21 smooth[i] += (analogRead(POT_PIN[i]) - smooth[i]) * 0.2; // yumuşatma / smoothing
22 return map((int)smooth[i], 0, 1023, MIN_A[i], MAX_A[i]);
23}
24
25void blink(byte n) {
26 for (byte k = 0; k < n; k++) {
27 digitalWrite(LED, HIGH); delay(80);
28 digitalWrite(LED, LOW); delay(80);
29 }
30}
31
32// Tüm eklemleri aynı anda hedefe götürür / moves all joints to the target together
33void moveTo(const byte target[4], byte msPerDegree) {
34 byte start[4];
35 int steps = 0;
36 for (byte i = 0; i < 4; i++) {
37 start[i] = pos[i];
38 int d = abs((int)target[i] - (int)start[i]);
39 if (d > steps) steps = d; // en uzun hareket / longest move
40 }
41 for (int s = 1; s <= steps; s++) {
42 for (byte i = 0; i < 4; i++) {
43 pos[i] = start[i] + (long)((int)target[i] - (int)start[i]) * s / steps; // ara açı / in-between angle
44 servo[i].write(pos[i]);
45 }
46 delay(msPerDegree);
47 }
48}
49
50void saveStep() {
51 if (stepCount >= MAX_STEPS) { blink(3); return; } // hafıza dolu / memory full
52 for (byte i = 0; i < 4; i++) EEPROM.update(1 + stepCount * 4 + i, pos[i]);
53 stepCount++;
54 EEPROM.update(0, stepCount); // 0. bayt adım sayısını tutar / byte 0 holds the step count
55 blink(1);
56}
57
58void playBack() {
59 byte target[4];
60 for (byte s = 0; s < stepCount; s++) {
61 for (byte i = 0; i < 4; i++) target[i] = EEPROM.read(1 + s * 4 + i);
62 moveTo(target, 12); // derece başına 12 ms / 12 ms per degree
63 delay(400); // her pozda kısa bekleme / short pause at each pose
64 if (pressed(BTN_PLAY)) break; // oynatırken basınca durur / press again to stop
65 }
66}
67
68void syncToPots() { // potların konumuna yumuşakça dön / ease back to the pots
69 byte target[4];
70 for (byte i = 0; i < 4; i++) {
71 smooth[i] = analogRead(POT_PIN[i]);
72 target[i] = map((int)smooth[i], 0, 1023, MIN_A[i], MAX_A[i]);
73 }
74 moveTo(target, 12);
75}
76
77void setup() {
78 pinMode(BTN_REC, INPUT_PULLUP);
79 pinMode(BTN_PLAY, INPUT_PULLUP);
80 pinMode(LED, OUTPUT);
81 stepCount = EEPROM.read(0);
82 if (stepCount > MAX_STEPS) stepCount = 0; // boş EEPROM 255 okur / a blank EEPROM reads 255
83 for (byte i = 0; i < 4; i++) {
84 smooth[i] = analogRead(POT_PIN[i]);
85 pos[i] = potAngle(i);
86 servo[i].write(pos[i]); // önce açı, sonra attach / angle first, then attach
87 servo[i].attach(SERVO_PIN[i]);
88 delay(300);
89 }
90}
91
92void loop() {
93 // Kayıt: kısa bas = pozu kaydet, 2 sn basılı tut = hepsini sil / Record: short press = save pose, hold 2 s = erase all
94 if (pressed(BTN_REC)) {
95 unsigned long t0 = millis();
96 while (pressed(BTN_REC) && millis() - t0 < 2000) {}
97 if (millis() - t0 >= 2000) {
98 stepCount = 0;
99 EEPROM.update(0, 0);
100 blink(5);
101 } else {
102 saveStep();
103 }
104 while (pressed(BTN_REC)) {} // bırakılmasını bekle / wait for release
105 delay(50); // buton arkı / debounce
106 }
107
108 // Oynat: kaydedilen pozları sırayla tekrarla / play: repeat the saved poses in order
109 if (pressed(BTN_PLAY) && stepCount > 0) {
110 while (pressed(BTN_PLAY)) {}
111 delay(50);
112 digitalWrite(LED, HIGH);
113 playBack();
114 while (pressed(BTN_PLAY)) {}
115 syncToPots();
116 digitalWrite(LED, LOW);
117 }
118
119 // Normal mod: kolu potlarla sür / normal mode: drive the arm with the pots
120 for (byte i = 0; i < 4; i++) {
121 byte a = potAngle(i);
122 if (abs((int)a - (int)pos[i]) >= 2) {
123 pos[i] = a;
124 servo[i].write(a);
125 }
126 }
127 delay(15);
128}| Ação | O que você faz | O que o braço faz |
|---|---|---|
| Salvar uma posição | Toque curto no botão de gravar (D7) | O LED pisca uma vez e a posição é gravada na EEPROM |
| Apagar as gravações | Segure o botão de gravar por 2 segundos | O LED pisca cinco vezes e a contagem de passos é zerada |
| Reproduzir | Aperte e solte o botão de reproduzir (D8) | O LED acende e as posições são reproduzidas em ordem, com transições suaves |
| Parar a reprodução | Segure o botão de reproduzir durante a reprodução | O braço termina a posição atual e para |
| Voltar ao modo normal | Nada; acontece sozinho quando a reprodução termina | O braço volta devagar para onde os potenciômetros apontam e o LED apaga |
A função moveTo() é o coração do sketch: ela encontra a articulação com o maior caminho a percorrer, divide o movimento nesse número de passos e avança todas as articulações proporcionalmente a cada passo. Assim, todas as articulações chegam ao alvo ao mesmo tempo e o braço se move com fluidez, em vez de dar trancos como um robô que mexe uma articulação por vez. Com 12 ms por grau, um movimento de 90 graus leva cerca de 1,1 segundo. Você pode diminuir esse valor para uma reprodução mais rápida, mas mesmo sem carga um MG996R gira 60 graus em 0,17 segundo, cerca de 3 ms por grau; abaixo disso os servos não acompanham os comandos e o movimento fica aos trancos.
Driver de servos PCA9685: 6 servos e um sinal sem tremedeira
Quando você passa para 5–6 servos ou adiciona módulos extras, como o Bluetooth, um módulo PCA9685 facilita muito a vida. Essa placa é um gerador de PWM de 16 canais e 12 bits; ela conversa com o Arduino por apenas dois fios usando I2C e gera os pulsos dos servos com o próprio clock, independentemente do processador. O endereço padrão é 0x40; mudando o endereço com os jumpers de solda A0–A5, você pode encadear até 62 placas, ou 992 servos. Em 50 Hz, o período de 20 ms é dividido em 4096 passos, então um passo dura cerca de 4,9 µs; a faixa de 544–2400 µs cobre cerca de 380 passos, o que dá uma resolução de aproximadamente meio grau.
| Pino do PCA9685 | Arduino Uno | ESP32 | Raspberry Pi Pico |
|---|---|---|---|
| GND | GND | GND | GND |
| VCC (só alimenta o chip) | 5V | 3V3 | 3V3 |
| SDA | A4 | GPIO 21 | GP4 |
| SCL | A5 | GPIO 22 | GP5 |
| Borne V+ (alimentação dos servos) | Fonte externa de 5–6 V | Fonte externa de 5–6 V | Fonte externa de 5–6 V |
| OE | Deixe desconectado | Deixe desconectado | Deixe desconectado |
| Conectores de servo 0–5 | Base, ombro, cotovelo, punho, rotação do punho, garra | Mesma ordem | Mesma ordem |
Controle do braço robótico com joysticks
Um joystick funciona de um jeito diferente do potenciômetro: ao ser solto, ele volta para o centro por causa da mola. Se você ligar o ângulo diretamente à posição do joystick, a articulação salta para 90 graus no instante em que você o solta. O jeito certo é o controle de velocidade: quanto mais você empurra o joystick, mais rápido a articulação gira, e quando você solta, a articulação fica onde está. No código abaixo, dois joysticks controlam quatro articulações (joystick esquerdo para base e ombro, joystick direito para cotovelo e punho); o botão do joystick esquerdo abre e fecha a garra, e o do direito manda o braço para a posição inicial. Ligue as saídas VRx e VRy do joystick esquerdo em A0 e A1, as saídas VRy e VRx do joystick direito em A2 e A3 e os pinos SW em D2 e D4; os joysticks podem ser alimentados pelo pino 5V do Arduino. Para compilar o código, instale a Adafruit PWM Servo Driver Library pelo Gerenciador de Bibliotecas e aceite a dependência Adafruit BusIO.

1#include <Wire.h>
2#include <Adafruit_PWMServoDriver.h>
3
4Adafruit_PWMServoDriver pca = Adafruit_PWMServoDriver(0x40); // varsayılan adres / default address
5
6// Kanal: 0 taban, 1 omuz, 2 dirsek, 3 bilek, 4 bilek dönüşü, 5 kıskaç / Channel: 0 base, 1 shoulder, 2 elbow, 3 wrist, 4 wrist roll, 5 gripper
7const byte N = 6;
8const float MIN_A[N] = {0, 15, 20, 10, 0, 40}; // güvenli sınırlar / safe limits
9const float MAX_A[N] = {180, 165, 160, 170, 180, 110};
10const float HOME[N] = {90, 90, 90, 90, 90, 40}; // başlangıç pozu, kıskaç açık / home pose, gripper open
11const byte JOY[4] = {A0, A1, A2, A3}; // J1 X, J1 Y, J2 Y, J2 X → kanal / channel 0, 1, 2, 3
12const int8_t DIR[4] = {1, -1, 1, 1}; // ters giden ekseni -1 yap / set -1 to invert an axis
13const byte BTN_GRIP = 2, BTN_HOME = 4; // joystick SW pinleri / joystick SW pins
14const float MAX_SPEED = 90; // en yüksek hız, derece/sn / top speed, degrees/s
15const float DT = 0.02; // 20 ms döngü / 20 ms loop
16const int DEADZONE = 60; // ortadaki ölü bölge / dead zone around center
17
18float target[N], current[N];
19bool gripClosed = false;
20
21void writeServo(byte ch, float a) {
22 // Servo.h ile aynı 544–2400 µs aralığı / same 544–2400 µs range as Servo.h
23 pca.writeMicroseconds(ch, (uint16_t)(544 + a * (2400 - 544) / 180.0));
24}
25
26bool newPress(byte pin, byte k) { // her basışta bir kez true / true once per press
27 static bool prev[2] = {HIGH, HIGH};
28 bool now = digitalRead(pin);
29 bool edge = (prev[k] == HIGH && now == LOW);
30 prev[k] = now;
31 return edge;
32}
33
34void setup() {
35 pinMode(BTN_GRIP, INPUT_PULLUP);
36 pinMode(BTN_HOME, INPUT_PULLUP);
37 pca.begin();
38 pca.setOscillatorFrequency(27000000); // çoğu modülde ~27 MHz / ~27 MHz on most boards
39 pca.setPWMFreq(50); // servolar için 50 Hz / 50 Hz for servos
40 Wire.setClock(400000); // hızlı I2C / fast I2C
41 for (byte i = 0; i < N; i++) {
42 target[i] = current[i] = HOME[i];
43 writeServo(i, HOME[i]);
44 delay(300); // servolar sırayla uyansın / wake servos one by one
45 }
46}
47
48void loop() {
49 static unsigned long last = 0;
50 if (millis() - last < 20) return; // 50 Hz güncelleme / 50 Hz update
51 last = millis();
52
53 // Joystick hızı belirler, konumu değil / the joystick sets speed, not position
54 for (byte i = 0; i < 4; i++) {
55 int v = analogRead(JOY[i]) - 512;
56 if (abs(v) > DEADZONE) {
57 target[i] += DIR[i] * (v / 512.0) * MAX_SPEED * DT;
58 target[i] = constrain(target[i], MIN_A[i], MAX_A[i]);
59 }
60 }
61 if (newPress(BTN_GRIP, 0)) { // kıskaç aç/kapa / toggle gripper
62 gripClosed = !gripClosed;
63 target[5] = gripClosed ? MAX_A[5] : MIN_A[5];
64 }
65 if (newPress(BTN_HOME, 1)) { // başlangıç pozuna dön / go to home pose
66 for (byte i = 0; i < N; i++) target[i] = HOME[i];
67 gripClosed = false;
68 }
69
70 // Her eklem hedefe hız sınırıyla gider / each joint follows its target with a speed limit
71 for (byte i = 0; i < N; i++) {
72 float d = constrain(target[i] - current[i], -MAX_SPEED * DT, MAX_SPEED * DT);
73 if (d != 0) {
74 current[i] += d;
75 writeServo(i, current[i]);
76 }
77 }
78}DEADZONE impede que pequenos desvios, como os valores de 490–530 lidos no centro, façam o braço se arrastar sozinho. MAX_SPEED define a velocidade, em graus por segundo, com o joystick empurrado até o fim; 90 graus por segundo é um valor seguro para começar. Se uma articulação se mover no sentido oposto ao do joystick, não troque fios: basta colocar -1 no valor correspondente do array DIR. O código guarda um alvo (target) e uma posição real (current) para cada articulação; como a posição real se aproxima do alvo com limite de velocidade, o braço desliza de volta com suavidade mesmo quando você aperta o botão da posição inicial. A rotação do punho fica fixa em 90 graus neste sketch; você pode controlá-la com o comando R na seção de Bluetooth. Essa técnica de temporização sem bloqueio é explicada em detalhes em millis() vs delay().
Controle por Bluetooth pelo celular (HC-05)
O módulo HC-05 cria uma conexão serial sem fio entre o seu celular e o Arduino. O pino TXD vai no D10 do Arduino, e o pino RXD se liga ao D11 através de um divisor de tensão: D11 → 1 kΩ → RXD → 2 kΩ → GND. O divisor reduz o sinal de 5 V do Arduino para os cerca de 3,3 V que o HC-05 espera. A taxa de dados padrão do módulo é 9600 baud, e o PIN de pareamento costuma ser 1234. O celular envia comandos de texto simples: uma letra escolhe a articulação, o número depois dela dá o ângulo, e uma quebra de linha ou um ponto e vírgula encerra o comando.

| Comando | Significado | Exemplo |
|---|---|---|
| B + ângulo | Base | B90 |
| S + ângulo | Ombro | S120 |
| E + ângulo | Cotovelo | E45 |
| W + ângulo | Punho (inclinação) | W100 |
| R + ângulo | Rotação do punho | R0 |
| G + ângulo | Garra | G110 (fechar), G40 (abrir) |
| H | Voltar à posição inicial | H |
| K / P / X / C | Salvar posição / reproduzir em loop / parar / apagar posições | K |
1#include <Wire.h>
2#include <SoftwareSerial.h>
3#include <Adafruit_PWMServoDriver.h>
4
5SoftwareSerial bt(10, 11); // D10 ← HC-05 TXD, D11 → bölücü / divider → HC-05 RXD
6Adafruit_PWMServoDriver pca = Adafruit_PWMServoDriver(0x40);
7
8const byte N = 6;
9const char NAME[N] = {'B', 'S', 'E', 'W', 'R', 'G'}; // taban, omuz, dirsek, bilek, dönüş, kıskaç / base, shoulder, elbow, wrist, roll, gripper
10const byte MIN_A[N] = {0, 15, 20, 10, 0, 40}; // güvenli sınırlar / safe limits
11const byte MAX_A[N] = {180, 165, 160, 170, 180, 110};
12const byte HOME[N] = {90, 90, 90, 90, 90, 40};
13const byte MAX_POSES = 30;
14const float SPEED = 1.5; // 20 ms'de en fazla 1,5° (75°/sn) / max 1.5° per 20 ms (75°/s)
15
16float current[N];
17byte target[N];
18byte poses[MAX_POSES][N]; // kaydedilen pozlar (RAM) / recorded poses (RAM)
19byte poseCount = 0, playIndex = 0;
20bool playing = false;
21char buf[12];
22byte len = 0;
23
24void writeServo(byte ch, float a) {
25 pca.writeMicroseconds(ch, (uint16_t)(544 + a * (2400 - 544) / 180.0)); // 544–2400 µs
26}
27
28void handle(char *cmd) { // ör. / e.g. "S120", "H", "K", "P"
29 char c = toupper(cmd[0]);
30 if (c == 'H') { // başlangıç pozu / home pose
31 for (byte i = 0; i < N; i++) target[i] = HOME[i];
32 playing = false;
33 } else if (c == 'K') { // pozu kaydet / save pose
34 if (poseCount < MAX_POSES) {
35 for (byte i = 0; i < N; i++) poses[poseCount][i] = target[i];
36 poseCount++;
37 }
38 bt.print(F("Poz / pose: "));
39 bt.println(poseCount);
40 } else if (c == 'P') { // döngüyle oynat / play in a loop
41 if (poseCount > 0) { playing = true; playIndex = 0; }
42 } else if (c == 'X') { // durdur / stop
43 playing = false;
44 } else if (c == 'C') { // kayıtları sil / clear poses
45 poseCount = 0;
46 playing = false;
47 } else {
48 for (byte i = 0; i < N; i++) {
49 if (c == NAME[i]) {
50 target[i] = constrain(atoi(cmd + 1), MIN_A[i], MAX_A[i]);
51 playing = false; // elle komut oynatmayı keser / a manual command stops playback
52 }
53 }
54 }
55}
56
57bool arrived() {
58 for (byte i = 0; i < N; i++)
59 if (fabs(target[i] - current[i]) > 0.5) return false;
60 return true;
61}
62
63void setup() {
64 bt.begin(9600); // HC-05 varsayılan hızı / HC-05 default baud
65 pca.begin();
66 pca.setOscillatorFrequency(27000000);
67 pca.setPWMFreq(50);
68 for (byte i = 0; i < N; i++) {
69 target[i] = HOME[i];
70 current[i] = HOME[i];
71 writeServo(i, HOME[i]);
72 delay(300); // servolar sırayla uyansın / wake servos one by one
73 }
74}
75
76void loop() {
77 // Komutları satır satır topla / collect commands line by line
78 while (bt.available()) {
79 char ch = bt.read();
80 if (ch == '\n' || ch == '\r' || ch == ';') {
81 if (len > 0) { buf[len] = '\0'; handle(buf); len = 0; }
82 } else if (len < sizeof(buf) - 1) {
83 buf[len++] = ch;
84 }
85 }
86
87 static unsigned long last = 0, arrivedAt = 0;
88 if (millis() - last < 20) return; // 50 Hz güncelleme / 50 Hz update
89 last = millis();
90
91 if (playing) {
92 if (!arrived()) arrivedAt = millis(); // hareket sürüyor / still moving
93 else if (millis() - arrivedAt > 300) { // her pozda 300 ms bekle / hold each pose 300 ms
94 for (byte i = 0; i < N; i++) target[i] = poses[playIndex][i];
95 playIndex = (playIndex + 1) % poseCount; // sona gelince başa dön / wrap around
96 arrivedAt = millis();
97 }
98 }
99
100 for (byte i = 0; i < N; i++) {
101 float d = constrain(target[i] - current[i], -SPEED, SPEED); // hız sınırı / speed limit
102 if (d != 0) {
103 current[i] += d;
104 writeServo(i, current[i]);
105 }
106 }
107}Neste sketch, os servos estão ligados ao PCA9685, e não direto ao Arduino, e isso é proposital. A SoftwareSerial desativa as interrupções por cerca de 1 ms enquanto recebe cada byte; se os servos fossem acionados pelos pinos do Arduino com a biblioteca Servo, os pulsos se alongariam nesse intervalo e o braço daria um tranco a cada comando. Como o PCA9685 gera os pulsos sozinho, o sinal fica firme como uma rocha, não importa o quanto a conexão Bluetooth esteja ocupada. A gravação e a reprodução agora também são feitas pelo celular: leve o braço até uma posição com os controles deslizantes e envie K; depois de algumas posições, P faz o braço repeti-las em loop e X o faz parar. Nesta versão, as posições ficam na RAM e se perdem quando a placa é desligada; se quiser que elas fiquem salvas, adicione o método da EEPROM do sketch anterior.
Braço robótico sem fio com ESP32
Como o ESP32 já tem Bluetooth clássico embutido, você não precisa de um HC-05: com a biblioteca BluetoothSerial, a placa aparece no seu celular como “BlueGrays-RobotKol” e entende os mesmos comandos. Ligue o PCA9685 ao GPIO 21 (SDA) e ao GPIO 22 (SCL) e alimente o VCC dele pelo 3V3; os sinais dos servos passam então a sair em 3,3 V, o que a grande maioria dos servos lê sem problema. A BluetoothSerial só funciona no ESP32 clássico (ESP32-WROOM-32, DevKit); os ESP32-S2, S3 e C3 não têm suporte a Bluetooth clássico.
1#include <Wire.h>
2#include <BluetoothSerial.h>
3#include <Adafruit_PWMServoDriver.h>
4
5BluetoothSerial bt; // klasik Bluetooth SPP / classic Bluetooth SPP
6Adafruit_PWMServoDriver pca = Adafruit_PWMServoDriver(0x40);
7
8const int N = 6;
9const char NAME[N] = {'B', 'S', 'E', 'W', 'R', 'G'}; // taban, omuz, dirsek, bilek, dönüş, kıskaç / base, shoulder, elbow, wrist, roll, gripper
10const int MIN_A[N] = {0, 15, 20, 10, 0, 40};
11const int MAX_A[N] = {180, 165, 160, 170, 180, 110};
12const int HOME[N] = {90, 90, 90, 90, 90, 40};
13float current[N], target[N];
14String line;
15
16void writeServo(int ch, float a) {
17 pca.writeMicroseconds(ch, (uint16_t)(544 + a * (2400 - 544) / 180.0)); // 544–2400 µs
18}
19
20void handle(String cmd) { // ör. / e.g. "E45", "H"
21 cmd.trim();
22 if (cmd.length() == 0) return;
23 char c = toupper(cmd[0]);
24 if (c == 'H') {
25 for (int i = 0; i < N; i++) target[i] = HOME[i];
26 return;
27 }
28 int value = cmd.substring(1).toInt();
29 for (int i = 0; i < N; i++)
30 if (c == NAME[i]) target[i] = constrain(value, MIN_A[i], MAX_A[i]);
31}
32
33void setup() {
34 Serial.begin(115200);
35 bt.begin("BlueGrays-RobotKol"); // telefonda görünen ad / name shown on the phone
36 Wire.begin(21, 22); // SDA = GPIO 21, SCL = GPIO 22
37 pca.begin();
38 pca.setOscillatorFrequency(27000000);
39 pca.setPWMFreq(50);
40 for (int i = 0; i < N; i++) {
41 current[i] = target[i] = HOME[i];
42 writeServo(i, HOME[i]);
43 delay(300);
44 }
45 Serial.println("Bluetooth hazir / ready");
46}
47
48void loop() {
49 while (bt.available()) {
50 char ch = bt.read();
51 if (ch == '\n' || ch == ';') { handle(line); line = ""; }
52 else if (line.length() < 12) line += ch;
53 }
54
55 static unsigned long last = 0;
56 if (millis() - last < 20) return; // 50 Hz güncelleme / 50 Hz update
57 last = millis();
58 for (int i = 0; i < N; i++) {
59 float d = constrain(target[i] - current[i], -1.5f, 1.5f); // yumuşak hareket / smooth motion
60 if (d != 0) {
61 current[i] += d;
62 writeServo(i, current[i]);
63 }
64 }
65}Braço robótico com Raspberry Pi Pico (MicroPython)
Você não precisa de nenhuma biblioteca extra para acionar servos no Raspberry Pi Pico: ajuste o PWM para 50 Hz e informe a largura do pulso em nanossegundos com duty_ns(). Com 16 canais PWM, o Pico consegue acionar 6 servos diretamente; pares de pinos que compartilham o mesmo slice compartilham a frequência, mas como todo servo usa 50 Hz, isso não é problema. A limitação está no lado analógico: o Pico tem só três pinos de ADC utilizáveis (GP26, GP27, GP28). Por isso, no código abaixo, três articulações são controladas por potenciômetros e a garra abre e fecha com um botão no GP14. Como o Pico trabalha em 3,3 V, ligue os potenciômetros ao 3V3; alimente os servos com uma fonte externa de 5 V, como antes.
1from machine import Pin, PWM, ADC
2import time
3
4# Servo pinleri: taban, omuz, dirsek, kıskaç / servo pins: base, shoulder, elbow, gripper
5servos = [PWM(Pin(p)) for p in (10, 11, 12, 13)]
6for s in servos:
7 s.freq(50) # 50 Hz servo sinyali / 50 Hz servo signal
8
9pots = [ADC(26), ADC(27), ADC(28)] # Pico'da 3 ADC pini var / the Pico has 3 ADC pins
10button = Pin(14, Pin.IN, Pin.PULL_UP) # kıskaç butonu GND'ye / gripper button to GND
11
12MIN_A = (0, 15, 20, 40) # güvenli sınırlar / safe limits
13MAX_A = (180, 165, 160, 110)
14
15def write(i, angle):
16 angle = max(MIN_A[i], min(MAX_A[i], angle))
17 servos[i].duty_ns(544000 + int(angle * 10311)) # 544–2400 µs aralığı / 544–2400 µs range
18
19smooth = [p.read_u16() for p in pots]
20grip_closed = False
21last_btn = 1
22write(3, MIN_A[3]) # kıskaç açık başlar / gripper starts open
23
24while True:
25 for i in range(3):
26 smooth[i] += (pots[i].read_u16() - smooth[i]) * 0.2 # yumuşatma / smoothing
27 write(i, MIN_A[i] + (MAX_A[i] - MIN_A[i]) * smooth[i] / 65535)
28 b = button.value()
29 if b == 0 and last_btn == 1: # yeni basış / new press
30 grip_closed = not grip_closed
31 write(3, MAX_A[3] if grip_closed else MIN_A[3])
32 last_btn = b
33 time.sleep_ms(20) # 50 Hz döngü / 50 Hz loopIndo além: cinemática inversa
Até aqui, definimos o ângulo de cada articulação uma por uma; isso se chama cinemática direta. A cinemática inversa faz o contrário: você informa o ponto (x, y) que a garra deve alcançar e o código calcula os ângulos das articulações necessários. Para um braço de dois elos com comprimento ombro–cotovelo L1 e cotovelo–punho L2, calcule primeiro D = (x² + y² − L1² − L2²) / (2·L1·L2). O ângulo do cotovelo é θ2 = acos(D) e o ângulo do ombro é θ1 = atan2(y, x) + atan2(L2·sin θ2, L1 + L2·cos θ2) (a solução com o cotovelo para cima). Por exemplo, com L1 = L2 = 12 cm e um ponto 15 cm à frente e 5 cm acima do ombro, você obtém D ≈ −0,13, θ2 ≈ 97,6° e θ1 ≈ 67,2°: o braço superior aponta 67 graus acima da horizontal e o antebraço se dobra 97,6 graus para baixo em relação a ele. Se o valor absoluto de D for maior que 1, o ponto está fora do alcance do braço. O ângulo da base é calculado à parte, a partir da posição do alvo vista de cima. Ao converter os resultados em ângulos de servo, leve em conta o sentido de montagem e o ponto central de cada servo.
Tremedeira e resets: erros comuns e soluções
| Sintoma | Causa provável | Solução |
|---|---|---|
| Os servos tremem e zumbem com o braço parado | Ruído nas leituras dos potenciômetros ou fonte fraca | Adicione um filtro de suavização e uma zona morta de 2°, use uma fonte externa e um capacitor de 1000 µF |
| O Arduino reinicia quando o braço se move, o HC-05 perde a conexão | A corrente de partida dos servos derruba a tensão | Alimente os servos com uma fonte separada de 5–6 V, junte os GNDs e inicie os servos um a um ao ligar |
| Os servos dão um tranco sempre que chega um comando Bluetooth | As interrupções da SoftwareSerial atrapalham os pulsos da biblioteca Servo | Passe os servos para um PCA9685 ou use o Bluetooth embutido do ESP32 |
| O braço dá um bote para algum lado ao ligar | Os servos não lembram a última posição e se movem em velocidade máxima no primeiro comando | Estacione o braço na posição inicial antes de desligar e chame write() antes de attach() |
| O ombro não consegue levantar o braço ou vai cedendo devagar | Torque insuficiente | Faça o cálculo de torque; use um MG996R, um braço mais curto, um contrapeso ou uma mola |
| Uma articulação trava em uma das pontas e esquenta | O servo está forçando contra um batente mecânico | Coloque no código os limites MIN_A e MAX_A obtidos na calibração |
| O servo da garra esquenta ao segurar um objeto | A garra continua tentando fechar e o servo fica travado | Defina o ângulo de fechamento no ponto em que a garra apenas encosta no objeto e coloque borracha nos dedos |
| O PCA9685 está conectado, mas nenhum servo se mexe | Sem alimentação no borne V+ ou sem GND comum | Leve 5–6 V ao V+ e confira o endereço I2C (0x40) |
| Uma articulação escorrega sob carga | Um braço de servo plástico espanou ou falta o parafuso central | Use um braço de servo metálico e prenda-o ao eixo com o parafuso central |
Ideias de projetos com braço robótico
- Braço separador de cores: leia a cor de cubos com um sensor de cor TCS3200 e deixe o braço colocar cada cor na sua própria caixa.
- Controle por gestos: com um MPU6050 em uma luva, o braço robótico se inclina para o mesmo lado que o seu punho.
- Controle remoto sem fio: ligue dois joysticks a outro Arduino e envie os comandos com um nRF24L01; você ganha um controle remoto que dispensa o celular.
- Controle pelo navegador: crie controles deslizantes em uma página web com um ESP32 e controle o braço de qualquer dispositivo na mesma rede Wi-Fi; um WebSocket no ESP32 reduz a latência ao mínimo.
- Pegar peças de uma esteira: monte uma pequena esteira transportadora com um motor de passo; quando um TCRT5000 detecta um objeto, o braço o tira da esteira.
- Projeto escolar e de competição: um braço que grava e reproduz movimentos é uma escolha forte entre as ideias de projetos para feira de ciências, mostrando mecânica, eletrônica e software juntos.
Um braço robótico com Arduino é um projeto que ensina projeto mecânico, cálculo de torque, gerenciamento de alimentação e programação de movimentos suaves de uma vez só, e ele cresce conforme o esforço que você coloca nele. Comece com um braço de 4 servos controlado por potenciômetros, adicione a gravação e a reprodução e depois passe para 6 servos com um PCA9685 e Bluetooth. No app BlueGrays, você encontra projetos como controle de servo com potenciômetro e joystick, controle por Bluetooth pelo celular e uma coreografia com 32 servos, com esquemas do circuito e código passo a passo, para testar antes cada articulação do seu braço separadamente.
Perguntas frequentes
Qual servo motor devo usar em um braço robótico com Arduino?
Para articulações que suportam carga, como base, ombro e cotovelo, o MG996R com engrenagens metálicas e 9–11 kg·cm de torque é uma boa escolha. Para articulações leves, como punho e garra, um MG90S ou SG90 basta. Braços pequenos feitos só com SG90 funcionam se forem curtos e leves, mas só conseguem levantar objetos de algumas dezenas de gramas.
De que fonte de alimentação um braço robótico precisa?
Uma fonte de 5 V 3 A basta para um braço pequeno com 4 servos SG90 ou MG90S. Para um braço de 6 servos com 3 MG996R e 3 servos pequenos, use uma fonte chaveada de 5–6 V de no mínimo 5 A, ou 10 A para ter folga. Não esqueça de ligar o negativo da fonte ao GND do Arduino.
Quantos servos um Arduino consegue controlar?
A biblioteca Servo consegue acionar até 12 servos em um Arduino Uno e 48 em um Mega. O limite real, porém, é a corrente: todos os servos devem ser alimentados por uma fonte externa. Um módulo PCA9685 aciona 16 servos usando apenas dois pinos I2C e pode ser encadeado em até 62 módulos.
Por que os servos do meu braço robótico estão tremendo?
As causas mais comuns são fonte fraca, falta de GND comum e ruído nas leituras dos potenciômetros. Use uma fonte externa com um capacitor de 1000 µF na linha dos servos e adicione um filtro de suavização e uma zona morta no código. Se a SoftwareSerial e a biblioteca Servo forem usadas juntas, passar os servos para um PCA9685 elimina a tremedeira por completo.
Quanto peso um braço robótico com SG90 consegue levantar?
O torque de travamento do SG90 é de cerca de 1,8 kg·cm; para uma operação segura, conte com metade disso, 0,9 kg·cm. Como o próprio peso do braço e dos servos consome parte desse orçamento, um braço com SG90 de cerca de 15 cm de comprimento, na prática, só carrega objetos leves de 20–30 g, como uma tampinha de garrafa ou um pequeno cubo de espuma.
Como controlar um braço robótico pelo celular?
Ligue um módulo Bluetooth HC-05 ao Arduino e use no celular um terminal serial Bluetooth ou um app controlador com controles deslizantes para enviar comandos de texto, como “S120”. Com um ESP32, o Bluetooth embutido dispensa um módulo extra. O HC-05 não funciona com iPhone, então, para iPhone, você precisa de um módulo BLE ou do ESP32 BLE.
Projetos para montar depois desta leitura
Ver todos os projetos
Uso de servo motor com potenciômetro
Conforme você gira o botão do potenciômetro, o braço do servo motor gira junto: uma extremidade do botão corresponde a zero grau, e a outra, a meia volta. O Arduino lê continuamente a posição do botão

Controle de servos com joystick
Controle dois motores com um joystick, como ao girar uma câmera de segurança. Empurre a alavanca para os lados e o servo motor inferior gira lentamente; mova para cima ou para baixo e o servo superior

Uso de servo motor
O braço de um pequeno servo motor gira para três posições em sequência: o início, o meio e o fim do percurso, esperando dois segundos em cada parada. O Arduino informa ao motor em qual ângulo ficar, e

Servo motor com ESP32 (controle por potenciômetro)
Neste projeto, controlamos um servo motor SG90 com um potenciômetro. Ajustamos o ângulo do servo mapeando o valor analógico lido do potenciômetro para a faixa de 0 a 180 graus. A biblioteca ESP32Servo gera sinais para o servo nos GPIOs do ESP32 adequados e capazes de operar como saída; este projeto usa o GPIO 18. Esse é um método básico de controle para braços robóticos, estabilizadores de câmera e mecanismos de portas automáticas.

Controle de LED pelo celular via Bluetooth
Um pequeno ensaio para acender e apagar as luzes do seu quarto pelo celular. O módulo Bluetooth repassa ao Arduino as letras enviadas pelo celular; uma letra acende o LED vermelho, outra acende o verd

Carrinho controlado por Bluetooth com L298N
Transforme seu celular em um controle remoto e dirija seu próprio carrinho robô. O Arduino recebe os comandos de um aplicativo de controle remoto no celular por meio de um módulo Bluetooth e aciona as

Coreografia em círculo: animações com 32 servos
Um projeto de animação visual com 32 servo motores dispostos em círculo e controlados por um Arduino Mega. Os servos são gerenciados em um único array e conectados aos pinos 22–53 do Mega. Eles executam quatro sequências de movimento: uma vibração caótica em que todos vão para ângulos aleatórios, uma varredura sincronizada em que todos se movem ao mesmo tempo, uma onda que gira suavemente pelo círculo e, por fim, uma agulha de bússola que oscila de um lado para o outro.
Mais artigos
App BlueGrays
Monte este circuito passo a passo pelo celular
Esquema do circuito, código e lista de componentes em uma só tela. Mais de 200 projetos com Arduino, ESP32 e Pico prontos para montar.
Escaneie com seu celular
Aponte a câmera para o código para abrir a loja de aplicativos do seu celular.
ou abrir a loja

